diff --git a/skeleton/SYSTEM/tg5040/paks/MinUI.pak/launch.sh b/skeleton/SYSTEM/tg5040/paks/MinUI.pak/launch.sh index e4a585713..7fcf85dfa 100755 --- a/skeleton/SYSTEM/tg5040/paks/MinUI.pak/launch.sh +++ b/skeleton/SYSTEM/tg5040/paks/MinUI.pak/launch.sh @@ -26,6 +26,15 @@ export HOOKS_PATH="$USERDATA_PATH/.hooks" export DATETIME_PATH="$SHARED_USERDATA_PATH/datetime.txt" export HOME="$USERDATA_PATH" +# alsa-lib >= 1.1.2 guards each snd_pcm_t with a recursive lock. On the +# bluealsa sink that lock ends up held by the thread that opened the PCM and +# never released, so SDL's audio thread blocks inside libasound forever: no +# sound over bluetooth, and SDL_CloseAudioDevice() then deadlocks the game +# loop joining that thread when the headset disconnects. We never touch one +# PCM from two threads at once (SDL serialises that itself), so alsa's own +# locking buys us nothing - turn it off. +export LIBASOUND_THREAD_SAFE=0 + ####################################### if [ -f "/tmp/poweroff" ]; then diff --git a/skeleton/SYSTEM/tg5050/paks/MinUI.pak/launch.sh b/skeleton/SYSTEM/tg5050/paks/MinUI.pak/launch.sh index ec5a9af56..52fd3d762 100755 --- a/skeleton/SYSTEM/tg5050/paks/MinUI.pak/launch.sh +++ b/skeleton/SYSTEM/tg5050/paks/MinUI.pak/launch.sh @@ -26,6 +26,15 @@ export HOOKS_PATH="$USERDATA_PATH/.hooks" export DATETIME_PATH="$SHARED_USERDATA_PATH/datetime.txt" export HOME="$USERDATA_PATH" +# alsa-lib >= 1.1.2 guards each snd_pcm_t with a recursive lock. On the +# bluealsa sink that lock ends up held by the thread that opened the PCM and +# never released, so SDL's audio thread blocks inside libasound forever: no +# sound over bluetooth, and SDL_CloseAudioDevice() then deadlocks the game +# loop joining that thread when the headset disconnects. We never touch one +# PCM from two threads at once (SDL serialises that itself), so alsa's own +# locking buys us nothing - turn it off. +export LIBASOUND_THREAD_SAFE=0 + ####################################### if [ -f "/tmp/poweroff" ]; then diff --git a/workspace/all/minarch/ma_core.c b/workspace/all/minarch/ma_core.c index 3572cdbe7..d838049e0 100644 --- a/workspace/all/minarch/ma_core.c +++ b/workspace/all/minarch/ma_core.c @@ -152,10 +152,9 @@ void Core_reset(void) { Rewind_on_state_change(); } void Core_unload(void) { - // Disabling this is a dumb hack for bluetooth, we should really be using - // bluealsa with --keep-alive=-1 - but SDL wont reconnect the stream on next start. - // Reenable as soon as we have a more recent SDL available, if ever. - //SND_quit(); + // Audio teardown deliberately does not happen here: SND_quit() frees the + // sample buffer, and the core can still emit audio from unload_game(), + // which runs later in Core_quit(). It is done at the end of main(). } void Core_quit(void) { if (core.initialized) { diff --git a/workspace/all/minarch/minarch.c b/workspace/all/minarch/minarch.c index b3e156eda..30ac0d26e 100644 --- a/workspace/all/minarch/minarch.c +++ b/workspace/all/minarch/minarch.c @@ -367,10 +367,7 @@ int main(int argc , char* argv[]) { PWR_quit(); VIB_quit(); SND_removeDeviceWatcher(); - // Disabling this is a dumb hack for bluetooth, we should really be using - // bluealsa with --keep-alive=-1 - but SDL wont reconnect the stream on next start. - // Reenable as soon as we have a more recent SDL available, if ever. - //SND_quit(); + SND_quit(); PAD_quit(); GFX_quit(); Menu_waitScreenshot();