Each tick drains one fixed chunk per source, so if the encoder stalls the
loop never makes the deficit up and the backlog only grows from there. The
queues had no cap, so a long recording against a slow encoder grew for as
long as it ran.
Cap each queue and keep the newest audio; discarding the newest instead
would only push the recording further behind.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Accumulate incoming frames per source and consume fixed-size chunks.
Each speaker's frames were queued whole and one frame was taken per
tick, so a frame that did not match the recorder's frame size was
truncated or padded and the recording drifted out of time with the
audio. Frames of any size now append to a per-source buffer that is
drained in exact chunks.
Tell the recorder whether a frame is stereo instead of guessing from
its length.
Mono microphone frames were being interpreted as stereo, which halved
their duration and produced static in the output.
Let the recorder worker close ffmpeg's stdin.
Stop closed it from the caller while the worker was still writing,
turning a normal stop into a broken pipe and losing the tail of the
recording.
Reserve the output file exclusively and hand ffmpeg the descriptor.
The path was generated, then reopened by name, so another process
could take the name in between. The file is opened once with O_EXCL
and passed to ffmpeg as an inherited descriptor.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>