Skip to content

fix(macos): keep mic audio when system audio is enabled - #913

Merged
webadderall merged 2 commits into
webadderallorg:mainfrom
AbhijeetDash:fix/mic-audio-sidecars
Sep 10, 2026
Merged

fix(macos): keep mic audio when system audio is enabled#913
webadderall merged 2 commits into
webadderallorg:mainfrom
AbhijeetDash:fix/mic-audio-sidecars

Conversation

@AbhijeetDash

@AbhijeetDash AbhijeetDash commented Sep 9, 2026

Copy link
Copy Markdown

Description

getCompanionAudioFallbackInfo returned only the video path when a macOS system sidecar existed, assuming the inline mp4 track was a complete mix. The capture helper writes system audio alone to that track, so the microphone was dropped from preview and export whenever both sources were enabled — the recorded narration was silent even though it had been captured correctly to recording-<ts>.mic.m4a.

Return both macOS sidecars instead, so the renderer routes them as separate system and mic tracks and mutes the silent embedded track. Existing recordings recover their audio on reopen.

Motivation

Recording with both System audio and Microphone enabled produces a video with no audible narration on macOS. That's the ordinary configuration for a narrated screen recording, so the failure hits a common path — and it's silent in both senses: nothing warns the user, and the loss is only discovered on playback.

Measured on affected recordings:

recording-<ts>.mp4          max_volume: -91.0 dB   # embedded track, digital silence
recording-<ts>.mic.m4a      max_volume: -20.3 dB   # speech, captured correctly
recording-<ts>.system.m4a   max_volume: -91.0 dB   # nothing was playing

Capture works; routing of the captured audio does not.

Root cause. audioRoutingEngine is built around two sidecars — it derives a track id from the filename, plays .system. and .mic. with independent gains, and mutes the embedded track when dedicated sidecars exist. getCompanionAudioFallbackInfo never handed it those sidecars:

} else if (hasUsableMacSystemCompanion) {
    paths = [videoPath];
}

Downstream this collapses to externalAudioPaths: []pathsByTrack: {}includeEmbeddedInExport: true, so preview and export use only the embedded track and .mic.m4a is never opened.

The branch assumed that embedded track was a complete system+mic mix. It isn't: ScreenCaptureKitRecorder.swift appends the mic to the inline track only when system audio is off (if !capturesSystemAudio), so with system audio enabled it carries system audio alone — silence when nothing is playing.

"Usable" is decided purely by stat.size > 0, so a 4 KB silent .system.m4a is enough to trigger the bad branch.

Type of Change

  • New Feature
  • Bug Fix
  • Refactor / Code Cleanup
  • Documentation Update
  • Other (please specify)

Related Issue(s)

Fixes #912

Screenshots / Video

Not applicable in the usual sense — this is an audio-only defect with no visual change, and a screenshot of a silent waveform proves little. The measurements above are the evidence; they're reproducible with the commands in the testing guide below.

Testing Guide

Reproduce (on main):

  1. Run the app on macOS: npm run dev
  2. Enable both System audio and Microphone.
  3. Keep the speakers silent — play no music or video. This matters: the silent .system.m4a is what triggers the bad branch, and with audio playing you'd hear the system track and might not notice the mic is gone.
  4. Record ~10s while speaking, then stop and play back in the editor. It is silent.

Verify the captured files:

cd ~/Library/Application\ Support/Recordly/recordings
for f in *.mp4 *.mic.m4a; do printf "%-40s " "$f"; ffmpeg -i "$f" -map 0:a:0 -af volumedetect -f null - 2>&1 | grep max_volume; done

The newest .mic.m4a sits near -20 dB while the .mp4 sits at -91 dB — the mic captured, the video silent.

Confirm the fix: check out this branch and reopen that same recording. The narration is audible without re-recording, since the change affects which files the editor loads rather than how anything is captured.

Automated:

npx vitest --run          # 1084 tests / 120 files pass
npx tsc --noEmit          # clean
npx biome lint .          # clean

The added regression test was verified non-vacuous: without the fix it fails, returning [videoPath] instead of the two sidecars.

Scope

This fixes preview and export. The raw .mp4 in the recordings folder remains system-audio-only, because the helper still skips the mic on the inline track. Making that file self-contained requires real PCM mixing in the capture path — tracked as the secondary defect in #912 and deliberately kept out of this change.

The fix is guarded to platform === "mac", so the Windows .wav layout is untouched.

Checklist

Summary by CodeRabbit

  • Tests

    • Added regression coverage for macOS recordings with embedded system audio and a separate microphone track.
    • Verified that both system-audio and microphone sidecar paths are retained during audio processing, preventing microphone audio from being omitted.
  • Documentation

    • Clarified audio-track selection when recordings include embedded audio alongside separate system-audio or microphone tracks.
    • Documented when sidecar tracks take precedence over embedded audio during processing.

getCompanionAudioFallbackInfo returned only the video path when a macOS
system sidecar existed, assuming the inline mp4 track was a complete mix.
The capture helper writes system audio alone to that track, so the
microphone was dropped from preview and export whenever both sources were
enabled — the recorded narration was silent even though it had been
captured correctly to recording-<ts>.mic.m4a.

Return both macOS sidecars instead, so the renderer routes them as
separate system and mic tracks and mutes the silent embedded track.
Existing recordings recover their audio on reopen.

Fixes webadderallorg#912
@coderabbitai

coderabbitai Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: e1edc419-5e2c-43b9-a61a-3111376395bd

📥 Commits

Reviewing files that changed from the base of the PR and between c1876ff and b9bdda4.

📒 Files selected for processing (1)
  • electron/ipc/recording/diagnostics.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • electron/ipc/recording/diagnostics.test.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 8 remain after this review.


📝 Walkthrough

Walkthrough

The macOS recording diagnostics fallback now documents sidecar precedence. A regression test verifies that embedded audio with system and microphone sidecars returns both sidecar paths.

Changes

macOS audio routing

Layer / File(s) Summary
Preserve macOS audio sidecars
electron/ipc/recording/diagnostics.ts, electron/ipc/recording/diagnostics.test.ts
The documentation describes the renderer’s system and microphone sidecar contract. The regression test verifies that both sidecar paths are returned when embedded audio is detected.

Estimated code review effort: 2 (Simple) | ~10 minutes

Severity of issue fixed: Medium

Merge Risk: ⚪ Minimal · up to b9bdd

The change restores routing of macOS system and microphone sidecars for preview and export, with no unresolved merge-readiness risk identified.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes satisfy issue #912 by returning both macOS system and microphone sidecars for preview and export while preserving other recording layouts. The raw MP4 mixing defect remains correctly out o…
Out of Scope Changes check ✅ Passed The regression test and diagnostic documentation directly support the macOS audio-routing fix. No unrelated code or scope changes are evident.
Title check ✅ Passed The title clearly identifies the macOS audio bug and the microphone-audio fix. It is concise and directly related to the primary change.
Description check ✅ Passed The description is complete and follows the repository template. It explains the defect, motivation, root cause, scope, testing steps, linked issue, and checklist status.
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@AbhijeetDash AbhijeetDash changed the title fix: keep mic audio when system audio is enabled fix(macos): keep mic audio when system audio is enabled Sep 10, 2026
@AbhijeetDash

Copy link
Copy Markdown
Author

The executable change is in commit 1c2df93, not the tip commit — I think the review looked at 9b72ff0 alone, which is docs-only (added in response to the earlier docstring-coverage check).

The full diff against main deletes the faulty line and replaces it with resolution of both macOS sidecars:

  } else if (hasUsableMacSystemCompanion) {
-     paths = [videoPath];
+     paths = Array.from(
+         new Set(
+             companionCandidates.flatMap((candidate) =>
+                 candidate.platform === "mac" ? candidate.usablePaths : [],
+             ),
+         ),
+     );
  }

paths = [videoPath]; is the bug, and its deletion is the only deletion in the entire PR (diagnostics.ts +21 −1).

The regression test asserts exactly the behaviour called for — that both sidecars are returned:

await expect(getCompanionAudioFallbackPaths(videoPath)).resolves.toEqual([
    systemPath,
    micPath,
]);

It fails against main, where the function returns [videoPath], and passes on this branch; I verified that by reverting the fix and re-running, so it isn't vacuous.

@AbhijeetDash

Copy link
Copy Markdown
Author

@mvanhorn I've made this fix for audio track not reaching sidecar. Is there a process for getting this PR reviewed by the team?

@webadderall
webadderall merged commit a1fbfe7 into webadderallorg:main Sep 10, 2026
1 check passed
LcpMarvel added a commit to LcpMarvel/Recordly that referenced this pull request Sep 11, 2026
Use the macOS-only sidecar selection and documentation from upstream
PR webadderallorg#913. Preserve both sets of regression tests and the preview/export
routing, timing, and committed callback fixes on this branch.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: macOS: microphone audio missing from recordings when system audio is also enabled

2 participants