Skip to content

Keep audio device open across pause for instant play/pause#358

Draft
IsaiahWitzke wants to merge 1 commit into
LargeModGames:mainfrom
IsaiahWitzke:fix/native-pause-resume-latency
Draft

Keep audio device open across pause for instant play/pause#358
IsaiahWitzke wants to merge 1 commit into
LargeModGames:mainfrom
IsaiahWitzke:fix/native-pause-resume-latency

Conversation

@IsaiahWitzke

Copy link
Copy Markdown

Problem

On macOS, native play/pause was noticeably (~500ms) slower than the Spotify desktop app. Instrumenting the transport pipeline showed the entire cost is librespot's PortAudio sink being torn down on pause and reopened on resume:

  • keypress → play dispatch: ~20µs
  • librespot Playing event: ~50µs
  • audio sink start() (PortAudio open + start): ~621ms
  • keypress → Paused (PortAudio stop/close): ~887ms

CoreAudio stream open/start/stop on macOS is inherently slow; the native app keeps its output device open permanently.

Fix

RecoveringSink now keeps the underlying device open across pause:

  • stop() no longer tears down the stream — librespot silences output by ceasing to feed packets, so the reopen was pure overhead.
  • start() is a no-op when the stream is already running.
  • The stream still closes on player shutdown/replacement (sink drop) and resets via the existing error-recovery path (with_inner clears the started flag when it drops the sink).

Only the first play after launch (or a post-error recovery) pays the ~600ms device-open cost.

Results (measured, same session)

Action Before After
Resume (keypress → Playing) ~621 ms ~0.11 ms
Pause (keypress → Paused) ~887 ms ~7–9 ms

Testing

  • cargo build, cargo clippy -- -D warnings, cargo fmt --all clean (default features).
  • Manually verified on macOS with the full cargo run build: pause silences audio, resume is instant, no glitches.

Worth an extra check on Bluetooth (AirPods) and when switching to a decoded source (local/YouTube) while librespot is paused, since the device now stays open across pause.

librespot's PortAudio sink was torn down and reopened on every
pause/resume, costing ~600ms on resume and ~900ms on pause on macOS
(measured). RecoveringSink now keeps the device open across pause —
librespot silences output by ceasing to feed packets, so tearing the
stream down only forces a slow reopen — and treats a redundant start()
as a no-op when the stream is already running. Only the first play after
launch (or a post-error recovery) pays the device-open cost.

Co-Authored-By: Oz <oz-agent@warp.dev>
@IsaiahWitzke IsaiahWitzke marked this pull request as draft July 10, 2026 00:57
@LargeModGames

Copy link
Copy Markdown
Owner

manual testing with airpods would be much appreciated as i have neither a mac nor airpods

@IsaiahWitzke

Copy link
Copy Markdown
Author

Sorry, meant to keep this as draft. This pr was vibecoded and I dont totally feel it fixed pausing latency 100%, although with my Bluetooth headset on mac it seems to pause faster.

When I get a free moment I'll try to actually read the code and see what claude did here lol

@LargeModGames

Copy link
Copy Markdown
Owner

Sorry, meant to keep this as draft. This pr was vibecoded and I dont totally feel it fixed pausing latency 100%, although with my Bluetooth headset on mac it seems to pause faster.

When I get a free moment I'll try to actually read the code and see what claude did here lol

dont worry take your time

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.

2 participants