Skip to content

Switch to newly-connected output devices automatically, and pause music when the output device disconnects - #876

Open
qq3229311585-jpg wants to merge 2 commits into
kyleneideck:masterfrom
qq3229311585-jpg:pause-music-on-disconnected-output-device
Open

qq3229311585-jpg wants to merge 2 commits into
kyleneideck:masterfrom
qq3229311585-jpg:pause-music-on-disconnected-output-device

Conversation

@qq3229311585-jpg

Copy link
Copy Markdown

Summary

Two related fixes to BGMPreferredOutputDevices, the class that tries to make BGMApp switch its output device the way macOS would if it wasn't running:

  1. Switch to newly-connected external devices automatically. findPreferredDevice's logic relies on the "preferred devices" list CoreAudio stores in /Library/Preferences/Audio/com.apple.audio.SystemSettings.plist, but that list is only updated by CoreAudio when a device actually becomes the systemwide default -- which mostly can't happen while BGMDevice is set as the default, since BGMApp keeps it that way. So in practice a newly-connected device (e.g. USB or Bluetooth headphones, or the built-in headphone jack) was never added to that list, and BGMApp wouldn't switch to it until the user picked it from the output device menu themselves at least once. This adds a separate check that diffs the currently-connected devices against the previous list on every device-list-change notification, and switches immediately to any device that just appeared, can be used as BGMApp's output device, and isn't virtual/aggregate.

  2. Pause the selected music player when its output device disconnects. Previously, unplugging headphones would fall back to another device (e.g. the built-in speakers) and keep playing through it, which can be surprising (e.g. music suddenly playing over speakers after taking headphones off in a quiet room). This pauses the selected music player (if BGMApp can control it -- e.g. Music.app or Spotify) before switching to the fallback device, matching what a lot of apps and macOS itself do by default.

Tested manually on macOS 26.5 (Tahoe) with the built-in headphone jack and Spotify as the selected music player: plugging in headphones now switches to them immediately and playback continues; unplugging switches back to the speakers and pauses Spotify without an audible glitch first.

Test plan

  • Manually verified plugging in/unplugging the built-in headphone jack switches BGMApp's output device automatically in both directions
  • Manually verified Spotify (as the selected music player) pauses immediately when headphones are unplugged, with no audio leaking through the fallback device first
  • xcodebuild -project BGMApp/BGMApp.xcodeproj -target "Background Music" -configuration Release build succeeds with no new warnings

Didn't add a copyright notice to the changed files per CONTRIBUTING.md, since these are small, focused changes -- happy to add one if you'd prefer.

second added 2 commits September 7, 2026 12:45
BGMPreferredOutputDevices tries to mimic macOS's own behaviour of
switching the default output device when the user plugs in headphones
or another output device. But its findPreferredDevice logic only
worked from the "preferred devices" list CoreAudio stores in
/Library/Preferences/Audio/com.apple.audio.SystemSettings.plist, and
that list is only updated by CoreAudio when a device actually becomes
the systemwide default device -- which mostly can't happen while
BGMDevice is set as the default, since BGMApp keeps it that way. So in
practice, a newly-connected device was never added to that list, and
BGMApp wouldn't switch to it until the user picked it from the output
device menu themselves at least once.

Add a separate check that diffs the currently-connected devices
against the previous connected-device list on every device list change
notification (connectedDeviceListChanged already listens for these).
If a device that can be used as BGMApp's output device just appeared
and isn't a virtual/aggregate device, switch to it immediately and
record it as a preferred device, the same as if the user had picked it
from the menu.

Deliberately doesn't exclude kAudioDeviceTransportTypeBuiltIn from the
new device check: macOS reports the built-in headphone jack's device
with that transport type, but unlike the built-in speakers, it only
appears in the connected-devices list while headphones are actually in
the jack, so it needs the same handling as a USB or Bluetooth device
appearing.

Didn't add a copyright notice to the file per CONTRIBUTING.md, since
this is a small, focused change -- happy to add one if the maintainer
prefers.
Previously, unplugging headphones (or another output device) would
switch BGMApp back to a fallback device (e.g. the built-in speakers)
and keep playing through it. That's surprising and can be annoying or
embarrassing -- e.g. music suddenly playing out loud over speakers
after taking headphones off in a quiet room. A lot of apps, and macOS
itself in some circumstances, avoid this by pausing playback when the
output device disappears instead of carrying on through whatever
device is left.

Give BGMPreferredOutputDevices an optional reference to BGMMusicPlayers
(set by BGMAppDelegate once BGMMusicPlayers exists, since it's created
after BGMPreferredOutputDevices) and, in connectedDeviceListChanged,
check whether the device BGMApp was actively using has just
disconnected. If so, pause the selected music player before switching
to the fallback device, the same way BGMAutoPauseMusic pauses it.
Pausing first, rather than after switching, matters because otherwise
whatever's left in the audio buffers can briefly play out loud through
the fallback device before the pause command gets back from the music
player (e.g. over AppleScript, for Spotify).

This only affects music players BGMApp can control directly (the ones
listed in the output device menu's music player picker, e.g. Music.app
or Spotify) -- it can't pause arbitrary apps like a browser tab, since
there's no general way to do that. If musicPlayers hasn't been set yet
(i.e. this happens very early during launch), this is a no-op.

Built on top of the "switch to newly-connected external output
devices automatically" change, since it reuses the connected-device
diffing that adds.

Didn't add a copyright notice to the files per CONTRIBUTING.md, since
these are small, focused changes -- happy to add one if the maintainer
prefers.
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.

1 participant