SDL: alsa: Don't start the hardware until the device thread is ready to do work. (a1b88)

From a1b888f6220fb96747aa6385191d013226c6d122 Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Mon, 24 Mar 2025 19:35:19 -0400
Subject: [PATCH] alsa: Don't start the hardware until the device thread is
 ready to do work.

Otherwise, in the time it takes the thread to start and other init tasks to
complete, we tend to get an underrun on some systems, which ALSA logs to
stderr.

So this is moved to an InitThread implementation, which runs from the device
thread, right before it begins its main loop.

Reference PR #12632.

(cherry picked from commit ae17b04c0dcb272a5ecedaa130e691b9b972f843)
---
 src/audio/alsa/SDL_alsa_audio.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/src/audio/alsa/SDL_alsa_audio.c b/src/audio/alsa/SDL_alsa_audio.c
index 308eb235934c5..badbc43ec867e 100644
--- a/src/audio/alsa/SDL_alsa_audio.c
+++ b/src/audio/alsa/SDL_alsa_audio.c
@@ -1187,7 +1187,6 @@ static bool ALSA_OpenDevice(SDL_AudioDevice *device)
         ALSA_snd_pcm_nonblock(cfg_ctx.device->hidden->pcm, 0);
     }
 #endif
-    ALSA_snd_pcm_start(cfg_ctx.device->hidden->pcm);
     return true;  // We're ready to rock and roll. :-)
 
 err_cleanup_ctx:
@@ -1200,6 +1199,13 @@ static bool ALSA_OpenDevice(SDL_AudioDevice *device)
     return false;
 }
 
+static void ALSA_ThreadInit(SDL_AudioDevice *device)
+{
+    SDL_SetCurrentThreadPriority(device->recording ? SDL_THREAD_PRIORITY_HIGH : SDL_THREAD_PRIORITY_TIME_CRITICAL);
+    // do snd_pcm_start as close to the first time we PlayDevice as possible to prevent an underrun at startup.
+    ALSA_snd_pcm_start(device->hidden->pcm);
+}
+
 static ALSA_Device *hotplug_devices = NULL;
 
 static int hotplug_device_process(snd_ctl_t *ctl, snd_ctl_card_info_t *ctl_card_info, int dev_idx,
@@ -1497,6 +1503,7 @@ static bool ALSA_Init(SDL_AudioDriverImpl *impl)
 
     impl->DetectDevices = ALSA_DetectDevices;
     impl->OpenDevice = ALSA_OpenDevice;
+    impl->ThreadInit = ALSA_ThreadInit;
     impl->WaitDevice = ALSA_WaitDevice;
     impl->GetDeviceBuf = ALSA_GetDeviceBuf;
     impl->PlayDevice = ALSA_PlayDevice;