SDL: alsa: Add back in code to guess the correct ALSA device prefix.

From ff96c59df4f0b706458ac8fe059c566011cf58e5 Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Sun, 15 Dec 2024 13:55:25 -0500
Subject: [PATCH] alsa: Add back in code to guess the correct ALSA device
 prefix.

---
 src/audio/alsa/SDL_alsa_audio.c | 52 +++++++++++++++++++++++++++++++--
 1 file changed, 50 insertions(+), 2 deletions(-)

diff --git a/src/audio/alsa/SDL_alsa_audio.c b/src/audio/alsa/SDL_alsa_audio.c
index effa180871f77..4a6bfa8b31952 100644
--- a/src/audio/alsa/SDL_alsa_audio.c
+++ b/src/audio/alsa/SDL_alsa_audio.c
@@ -246,6 +246,51 @@ static bool LoadALSALibrary(void)
 
 #endif // SDL_AUDIO_DRIVER_ALSA_DYNAMIC
 
+static const char *ALSA_device_prefix = NULL;
+static void ALSA_guess_device_prefix(void)
+{
+    if (ALSA_device_prefix) {
+        return;  // already calculated.
+    }
+
+    // Apparently there are several different ways that ALSA lists
+    //  actual hardware. It could be prefixed with "hw:" or "default:"
+    //  or "sysdefault:" and maybe others. Go through the list and see
+    //  if we can find a preferred prefix for the system.
+
+    static const char *const prefixes[] = {
+        "hw:", "sysdefault:", "default:"
+    };
+
+    void **hints = NULL;
+    if (ALSA_snd_device_name_hint(-1, "pcm", &hints) == 0) {
+        for (int i = 0; hints[i]; i++) {
+            char *name = ALSA_snd_device_name_get_hint(hints[i], "NAME");
+            if (name) {
+                for (int j = 0; j < SDL_arraysize(prefixes); j++) {
+                    const char *prefix = prefixes[j];
+                    const size_t prefixlen = SDL_strlen(prefix);
+                    if (SDL_strncmp(name, prefix, prefixlen) == 0) {
+                        ALSA_device_prefix = prefix;
+                        break;
+                    }
+                }
+                free(name); // This should NOT be SDL_free()
+
+                if (ALSA_device_prefix) {
+                    break;
+                }
+            }
+        }
+    }
+
+    if (!ALSA_device_prefix) {
+        ALSA_device_prefix = prefixes[0];  // oh well.
+    }
+
+    LOGDEBUG("device prefix is probably '%s'", ALSA_device_prefix);
+}
+
 typedef struct ALSA_Device
 {
     // the unicity key is the couple (id,recording)
@@ -293,7 +338,7 @@ static char *get_pcm_str(void *handle)
     if (SDL_strlen(dev->id) == 0) {
         pcm_str = SDL_strdup("default");
     } else {
-        SDL_asprintf(&pcm_str, "default:CARD=%s", dev->id);
+        SDL_asprintf(&pcm_str, "%sCARD=%s", ALSA_device_prefix, dev->id);
     }
     return pcm_str;
 }
@@ -1512,7 +1557,8 @@ static void ALSA_HotplugIteration(bool *has_default_output, bool *has_default_re
         }
 
         char ctl_name[64];
-        SDL_snprintf(ctl_name, sizeof (ctl_name), "hw:%d", card_idx); // card_idx >= 0
+        SDL_snprintf(ctl_name, sizeof (ctl_name), "%s%d", ALSA_device_prefix, card_idx); // card_idx >= 0
+        LOGDEBUG("hotplug ctl_name = '%s'", ctl_name);
 
         r = ALSA_snd_ctl_open(&ctl, ctl_name, 0);
         if (r < 0) {
@@ -1616,6 +1662,8 @@ static int SDLCALL ALSA_HotplugThread(void *arg)
 
 static void ALSA_DetectDevices(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording)
 {
+    ALSA_guess_device_prefix();
+
     // ALSA doesn't have a concept of a changeable default device, afaik, so we expose a generic default
     // device here. It's the best we can do at this level.
     bool has_default_playback = false, has_default_recording = false;