fix(linux): drain ffmpeg/parecord output so encoding never stalls mid-take - #626
Open
laugustyniak wants to merge 2 commits into
Open
laugustyniak wants to merge 2 commits into
laugustyniak wants to merge 2 commits into
Conversation
ffmpeg writes a progress line to stderr every half second for as long as it encodes. record_linux never read that pipe, so once the kernel buffer was full (64 KiB by default, a single page when the user is past fs.pipe-user-pages-soft) ffmpeg blocked in write(), stopped reading stdin and the output file silently stopped growing mid-take. stop() then awaited _inputPcmController.close(), which waits for the input pipe to drain, and never returned; the file on disk was left without its moov atom. Drain stdout and stderr of the ffmpeg process right after it starts, and parecord's stderr for the same reason. The executables are now injectable through the constructor so the test can stand in a fake ffmpeg that floods stderr before it reads a byte of input: without the drain stop() hangs, with it the take is written in full.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
On Linux,
RecordLinuxstartsffmpegwithProcess.startin_startFfmpegWithAmplitudeMonitoringand never subscribes to its stdout/stderr. ffmpeg writes a progress line to stderr every 0.5 s for as long as it encodes. Once the kernel pipe buffer is full (64 KiB by default; a single page when the user is pastfs.pipe-user-pages-soft), ffmpeg blocks inwrite(2), stops reading stdin, and the output file silently stops growing in the middle of a take.stop()then awaits_inputPcmController.close(), which waits for the input pipe to drain — which never happens — sostop()never returns and the file on disk is left without itsmoovatom.Observed on a real capture: ffmpeg alive for minutes in
anon_pipe_write, stderr pipe at8102/8192bytes queued (FIONREAD); reading that pipe made ffmpeg finish the file and exit immediately. Repro without a mic: feed PCM intoffmpeg -f s16le -i - -c:a aac out.m4awith stderr piped to a reader that never reads.The same file already drains both streams in
_callPactl("Listen to both stdout & stderr to not leak system resources") — this applies the same to the two long-running processes.Change
@visibleForTesting), defaults unchanged, so a test can stand in a fakeffmpegthat writes 1 MiB to stderr before reading stdin.test/record_linux_test.dart:stop()must complete and the output must hold every input byte. Times out after 10 s without the drain; passes in under a second with it.No version/CHANGELOG bump — happy to add one if you prefer it in the PR.