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
Conversation
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.
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.
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:
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.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
xcodebuild -project BGMApp/BGMApp.xcodeproj -target "Background Music" -configuration Release buildsucceeds with no new warningsDidn'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.