feat: pause media playback while recording#187
Open
cwillison94 wants to merge 2 commits into
Open
Conversation
Optionally pause whatever audio is playing (music, video, browser) when a recording starts, and resume it when recording ends, so playback does not bleed into the dictation. Off by default; toggle in Settings > Recording. Playback is detected via CoreAudio so it only pauses when something is actually playing, and pause/resume simulates the media Play/Pause key so it works with any player without per-app scripting. Wired into AudioRecorder, the single choke point for every trigger mode (shortcut, modifier, mouse, hold-to-record, double-tap). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> AI-Model: claude-sonnet-4.6
Author
|
It introduces a new setting which is currently defaulting to off (though arguable should be on) |
The original approach simulated the hardware Play/Pause media key (a toggle) and gated it on a CoreAudio "output device is running" check. Browsers and YouTube keep that device running even while paused, so the check false-positived and the toggle *started* paused audio the moment a recording began - the opposite of what the feature should do. Switch to discrete pause/play. macOS 15.4+ only lets Apple platform binaries use the private MediaRemote framework, so the app itself gets empty/false state back. Instead we ship a tiny helper dylib (MediaRemoteHelper/OSWMediaRemote.swift) that calls MediaRemote's IsPlaying / SendCommand, and load it through /usr/bin/perl (a platform binary) via osw-media-remote.pl. get reports real playing/paused state and send issues kMRPlay / kMRPause. A discrete pause is a no-op when nothing is playing, so recording can never start audio that was paused; play is only sent to resume media we ourselves paused. The helper is our own ~90-line Swift (no third-party dependency, no submodule), built by run.sh/notarize_app.sh and embedded in Contents/Frameworks (loaded out-of-process by perl, never linked), with the launcher bundled in Resources. Runtime work is on the controller's own serial queue with a timeout and fails safe (does nothing) if the helper is missing or errors. Public API and AudioRecorder call sites are unchanged. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> AI-Model: claude-sonnet-4.6
cwillison94
force-pushed
the
feat/pause-media-while-recording
branch
from
July 17, 2026 23:46
02c2488 to
313f750
Compare
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.
Why
When using push-to-talk dictation, any music or video already playing keeps going during the recording.
It bleeds into the mic and is distracting, and there is currently no way to have it pause automatically.
This adds an opt-in setting that pauses whatever is playing when a recording starts and resumes it when the recording ends.
It is off by default, so existing behavior is unchanged unless a user turns it on in Settings > Recording.
How it works
Pause and resume use discrete commands, never a play/pause toggle.
This matters because the obvious toggle-based approach (simulating the hardware media key, gated on a CoreAudio "output device is running" check) starts paused audio on record-start: browsers and YouTube keep the output device running even while paused, so the check false-positives and the toggle resumes playback the user had deliberately paused.
Discrete pause/play needs the private MediaRemote framework, which macOS 15.4+ restricts to Apple platform binaries.
An app calling it directly just gets empty/false state back (verified on macOS 26).
So a small helper dylib (
MediaRemoteHelper/OSWMediaRemote.swift, ~90 lines, no third-party dependency) is loaded through/usr/bin/perl(a platform binary) viaosw-media-remote.pl; it reads the real Now Playing state and sendskMRPlay/kMRPause.Because the helper runs inside perl's entitled process, it gets accurate state and its commands take effect.
A discrete pause is a no-op when nothing is playing, so recording can never start audio that was not already playing, and play is only ever sent to resume media this feature paused.
It stays player-agnostic (Spotify, Apple Music, Safari/Chrome/YouTube, etc.) with no per-app scripting.
The helper is built by
run.sh/notarize_app.shand embedded inContents/Frameworks(loaded out-of-process by perl, never linked into the app), with the launcher bundled inContents/Resources.It hooks into
AudioRecorder, the single choke point for every trigger mode (keyboard shortcut, single modifier, mouse button, hold-to-record, double-tap), with all subprocess work on a dedicated serial queue so it never delays audio capture, guarded by a timeout, and failing safe (doing nothing) if the helper is ever unavailable.Testing
Built and run on macOS 26 (Apple Silicon).
Verified the helper end to end through perl (reads playing/paused state, sends discrete pause/play, and pausing an already-paused player is a no-op), and verified in-app that recording pauses playback on start and resumes on release when media is playing, while starting a recording with media already paused issues no command and leaves it paused.
Known limitation
If the user manually resumes playback during a recording, stopping the recording will still issue a resume.
Discrete commands make misbehavior far less likely than the old toggle, but true fade in/out is out of scope.
🤖 Generated with Claude Code