diff --git a/electron/native/wgc-capture/src/audio_sample_utils_test.cpp b/electron/native/wgc-capture/src/audio_sample_utils_test.cpp index ea235d1e9..3ef9d9f8c 100644 --- a/electron/native/wgc-capture/src/audio_sample_utils_test.cpp +++ b/electron/native/wgc-capture/src/audio_sample_utils_test.cpp @@ -1572,6 +1572,26 @@ int main() { expect("mixer-resume-continues-at-the-pause", first != left.end() && std::abs(at - pausedAtMs) <= 40.0, detail); } + // (5) A pause followed by a stop, as the helper ends every take (#942): + // the track ends at the pause, not at the stop that comes later. + { + const auto packet = dcPacket(0.5f); + double pausedAtMs = 0.0; + const auto left = runTake(false, true, [&](AudioMixer& mixer, Clock::time_point t0) { + capture( + [&] { mixer.pushMicrophone(packet.data(), static_cast(packet.size())); }, + t0, 40, 1000, 0); + pausedAtMs = std::chrono::duration(Clock::now() - t0).count(); + mixer.setPaused(true); + std::this_thread::sleep_for(milliseconds(300)); + }); + const double lengthMs = msAt(left.size()); + char detail[96]{}; + sprintf_s(detail, "track %.1f ms long, paused at %.1f ms", lengthMs, pausedAtMs); + std::cout << "JITTER_RAW stop-after-pause " << detail << std::endl; + expect("mixer-track-ends-at-the-pause-before-a-stop", std::abs(lengthMs - pausedAtMs) <= 20.0, detail); + } + // (4) The same with a resume that follows the pause at once, before the // mixer has had a chance to see the pause: the resume must wait for the // cushion to be written, or it throws the cushion away and what follows diff --git a/electron/native/wgc-capture/src/main.cpp b/electron/native/wgc-capture/src/main.cpp index b094e31f5..7b043d1f3 100644 --- a/electron/native/wgc-capture/src/main.cpp +++ b/electron/native/wgc-capture/src/main.cpp @@ -1549,6 +1549,17 @@ int wmain(int argc, wchar_t* argv[]) { control.waitForStop(); + // The take ends here, for the sound as for the picture: the video writer + // stops on this same request. The mixer is clock-driven, so left running + // it would go on writing chunks through the half second the steps below + // take, and every take ended with ~0.5 s of audio past its video + // (getopenscreen/openscreen#942, measured on three takes). A pause writes + // what the cushion holds up to this instant and then nothing; one already + // in place is left where it is. + if (audioMixer) { + audioMixer->setPaused(true); + } + const auto stopStart = std::chrono::steady_clock::now(); auto stopElapsedMs = [&] { return std::chrono::duration_cast(