ref:03ad9a4e72b710c20f0d1cfb49075fd56989f36b

test(e2e): write the decoded audio to a WAV with --audio-out

The client reported a dominant frequency, which says nothing about distortion. Writing the decoded stream out makes it measurable: harmonics, intermodulation, discontinuities, and whether anything clips. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BPNw4PCgkEfhyCjQT19wsb
SHA: 03ad9a4e72b710c20f0d1cfb49075fd56989f36b
Author: Cole Christensen <cole.christensen@gmail.com>
Date: 2026-09-17 21:05
Parents: fc18594
1 files changed +42 -0
Type
tests/e2e/moonlight_client/main.cpp +42 −0
@@ -69,6 +69,7 @@
std::string api_user; ///< Web UI user.
std::string api_pass; ///< Web UI password.
std::string pin_file; ///< When set, write the PIN here and let someone else approve it.
std::string audio_out; ///< When set, write the decoded audio there as a WAV, to analyze it offline.
std::string state_dir {"e2e-client"}; ///< Directory for the client identity.
int width {1280}; ///< Stream width.
int height {800}; ///< Stream height.
@@ -590,7 +591,46 @@
* @brief Write the last frame as a binary PPM.
*
* @param path Output path.
*/
/**
* @brief Write the decoded audio as a 16-bit WAV, so it can be measured or listened to.
*
* @param path Output path; nothing is written when empty.
*/
void write_wav(const std::string &path) {
std::lock_guard lock {audio.mutex};
if (path.empty() || audio.pcm.empty() || audio.channels <= 0) {
return;
}
const auto rate = (std::uint32_t) audio.sample_rate;
const auto channels = (std::uint16_t) audio.channels;
const auto data_bytes = (std::uint32_t) (audio.pcm.size() * 2);
std::ofstream out {path, std::ios::binary};
auto u32 = [&](std::uint32_t v) {
out.write(reinterpret_cast<const char *>(&v), 4);
};
auto u16 = [&](std::uint16_t v) {
out.write(reinterpret_cast<const char *>(&v), 2);
};
out.write("RIFF", 4);
u32(36 + data_bytes);
out.write("WAVEfmt ", 8);
u32(16);
u16(1); // PCM
u16(channels);
u32(rate);
u32(rate * channels * 2);
u16((std::uint16_t) (channels * 2));
u16(16);
out.write("data", 4);
u32(data_bytes);
for (float sample : audio.pcm) {
const auto clamped = std::clamp(sample, -1.0f, 1.0f);
const auto value = (std::int16_t) std::lround(clamped * 32767.0f);
out.write(reinterpret_cast<const char *>(&value), 2);
}
}
void write_ppm(const std::string &path) {
std::lock_guard lock {state.mutex};
if (path.empty() || state.rgb.empty()) {
@@ -624,6 +664,7 @@
{"--wait-file", &opts.wait_file},
{"--input", &opts.input},
{"--pin-file", &opts.pin_file},
{"--audio-out", &opts.audio_out},
};
std::map<std::string, int *> ints {
{"--port", &opts.port},
@@ -856,6 +897,7 @@
const auto elapsed = std::chrono::duration<double>(std::chrono::steady_clock::now() - stream_start).count();
write_ppm(opts.out);
write_wav(opts.audio_out);
if (input_thread.joinable()) {
input_thread.join();
}