You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
On native macOS meeting recordings (mic + system audio), the system-audio track can begin ahead of the microphone track, so the two are misaligned in the saved/mixed meeting. The gap equals the microphone's startup delay — usually small, but up to ~5s when the microphone health-check/recovery path runs.
Originally raised as a Codex review comment on PR #105 (AudioRecorderViewModel+MacEngine.swift). Deferred from the v2.2 review pass because a safe implementation needs on-device verification (see "Why deferred").
Root cause
When a meeting recording starts, system-audio capture begins immediately:
AudioRecorderViewModel+MacEngine.swift:~50 — MacSystemAudioCapture(outputURL:) then try await capture.start() starts writing the system track right away.
The microphone (AVAudioEngine tap) does not produce its first buffer until later; the first successful write is signaled via handleMacFirstSuccessfulWrite().
During finalization, the mix inserts both tracks at time zero, so any delay between "system capture started" and "mic produced its first buffer" shifts the system audio ahead of the mic in the output.
Proposed fix
Start system-audio capture paused, and release it from handleMacFirstSuccessfulWrite() so both tracks effectively begin at the same real moment.
The machinery already exists — MacSystemAudioCapture.setPaused(_:) (MacSystemAudioCapture.swift:116) drops samples while paused (didOutputSampleBuffer returns early when isPaused, ~line 181) and tracks pauseStartedAt / accumulatedPausedDuration to compensate timestamps. So this is mostly a start-ordering + handshake change, not new capture logic.
Alternative: preserve capture timestamps and align the two tracks during mixing instead of inserting both at t=0.
Why this was deferred (please read before implementing)
The naive fix fails toward silence. If system capture waits for the mic's first buffer and that signal never arrives — a silent/failed mic, or the mic getting stuck in the ~5s health-check/recovery path (the exact scenario this fix targets) — the system track stays paused for the whole meeting and no remote-participant audio is captured at all. That is worse than the current sync offset. Any implementation should include a safety timeout that force-unpauses system capture after ~1–2s even if no mic buffer has arrived, so worst case degrades to today's behavior (a small offset) rather than to silence.
Only verifiable on-device. This is an A/V-sync change; confirming it (a) actually aligns the tracks and (b) does not drop the system track requires recording a real meeting on a Mac (system audio playing through the app while speaking into the mic) and listening to the mixed output. It cannot be verified by a build or unit test.
High blast radius. This lives in the Mac recording capture path — the most fragile area of the native-macOS migration — so a mistake risks regressing "recording captures system audio at all."
Acceptance criteria
Mic + system audio are time-aligned in a saved meeting recording, including when mic startup is delayed by the recovery path.
If the mic never produces a first buffer, system audio is still captured (safety-timeout fallback), not lost.
Verified by recording a real meeting on an Apple-silicon Mac and confirming alignment + both tracks present.
Summary
On native macOS meeting recordings (mic + system audio), the system-audio track can begin ahead of the microphone track, so the two are misaligned in the saved/mixed meeting. The gap equals the microphone's startup delay — usually small, but up to ~5s when the microphone health-check/recovery path runs.
Originally raised as a Codex review comment on PR #105 (
AudioRecorderViewModel+MacEngine.swift). Deferred from the v2.2 review pass because a safe implementation needs on-device verification (see "Why deferred").Root cause
When a meeting recording starts, system-audio capture begins immediately:
AudioRecorderViewModel+MacEngine.swift:~50—MacSystemAudioCapture(outputURL:)thentry await capture.start()starts writing the system track right away.handleMacFirstSuccessfulWrite().Proposed fix
Start system-audio capture paused, and release it from
handleMacFirstSuccessfulWrite()so both tracks effectively begin at the same real moment.The machinery already exists —
MacSystemAudioCapture.setPaused(_:)(MacSystemAudioCapture.swift:116) drops samples while paused (didOutputSampleBufferreturns early whenisPaused, ~line 181) and trackspauseStartedAt/accumulatedPausedDurationto compensate timestamps. So this is mostly a start-ordering + handshake change, not new capture logic.Alternative: preserve capture timestamps and align the two tracks during mixing instead of inserting both at t=0.
Why this was deferred (please read before implementing)
The naive fix fails toward silence. If system capture waits for the mic's first buffer and that signal never arrives — a silent/failed mic, or the mic getting stuck in the ~5s health-check/recovery path (the exact scenario this fix targets) — the system track stays paused for the whole meeting and no remote-participant audio is captured at all. That is worse than the current sync offset. Any implementation should include a safety timeout that force-unpauses system capture after ~1–2s even if no mic buffer has arrived, so worst case degrades to today's behavior (a small offset) rather than to silence.
Only verifiable on-device. This is an A/V-sync change; confirming it (a) actually aligns the tracks and (b) does not drop the system track requires recording a real meeting on a Mac (system audio playing through the app while speaking into the mic) and listening to the mixed output. It cannot be verified by a build or unit test.
High blast radius. This lives in the Mac recording capture path — the most fragile area of the native-macOS migration — so a mistake risks regressing "recording captures system audio at all."
Acceptance criteria
References
BisonNotes AI/BisonNotes AI/ViewModels/AudioRecorderViewModel+MacEngine.swift(system capture start)BisonNotes AI/BisonNotes AI/ViewModels/MacSystemAudioCapture.swift(setPaused, pause/timestamp compensation)handleMacFirstSuccessfulWrite()(first-mic-buffer signal)