Skip to content

fix(audio): unbreak bluetooth audio - no sound, and freeze on disconnect - #811

Open
dalexanco wants to merge 1 commit into
LoveRetro:mainfrom
dalexanco:fix/bt-audio-alsa-deadlock
Open

fix(audio): unbreak bluetooth audio - no sound, and freeze on disconnect#811
dalexanco wants to merge 1 commit into
LoveRetro:mainfrom
dalexanco:fix/bt-audio-alsa-deadlock

Conversation

@dalexanco

Copy link
Copy Markdown

Two bugs, one cause. Over a bluetooth headset games had no sound at all, and disconnecting the headset mid-game froze the emulator for good.

alsa-lib guards every PCM with a recursive lock, and on the bluealsa sink that lock is never released once the PCM is open. SDL's audio thread blocks inside libasound and never runs our callback - that is the silence. The freeze follows from it: on disconnect minarch resets the audio device from the game loop, and SDL_CloseAudioDevice() waits forever for that stuck thread to exit.

LIBASOUND_THREAD_SAFE=0 fixes both. SDL already serialises opening and closing a device against its own audio thread, so alsa's internal locking buys us nothing.

The same lock is why SND_quit() was commented out, with a note blaming SDL stream reconnection: closing the device on exit hit the same deadlock. It works now, so the call comes back at the end of main(). It stays out of Core_unload(), which runs while the core is still loaded and can still emit audio into the buffer SND_quit() frees.

Tested on a Brick (tg5040): sound in the headset, no freeze on disconnect, clean exit back to the launcher, and audio still fine on the next launch.

#810

Two bugs, one cause. Over a bluetooth headset games had no sound at all, and
disconnecting the headset mid-game froze the emulator for good.

alsa-lib guards every PCM with a recursive lock, and on the bluealsa sink that
lock is never released once the PCM is open. SDL's audio thread blocks inside
libasound and never runs our callback - that is the silence. The freeze
follows from it: on disconnect minarch resets the audio device from the game
loop, and SDL_CloseAudioDevice() waits forever for that stuck thread to exit.

LIBASOUND_THREAD_SAFE=0 fixes both. SDL already serialises opening and closing
a device against its own audio thread, so alsa's internal locking buys us
nothing.

The same lock is why SND_quit() was commented out, with a note blaming SDL
stream reconnection: closing the device on exit hit the same deadlock. It
works now, so the call comes back at the end of main(). It stays out of
Core_unload(), which runs while the core is still loaded and can still emit
audio into the buffer SND_quit() frees.

Tested on a Brick (tg5040): sound in the headset, no freeze on disconnect,
clean exit back to the launcher, and audio still fine on the next launch.
@frysee

frysee commented Aug 16, 2026

Copy link
Copy Markdown
Member

I'm not ready yet to touch BT again, it has only been three months or so. Its an absolute clusterfuck to get right. 💀

@frysee

frysee commented Aug 18, 2026

Copy link
Copy Markdown
Member

We will revisit this after h700 lands, maybe together with !736.

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