[Commits] SDL: alsa: Implemented basic device detection.

libsdl.org revision control commits-owner at libsdl.org
Sat Mar 5 20:28:18 PST 2016


details:   https://hg.libsdl.org/SDL/rev/4cd67316b308
changeset: 10104:4cd67316b308
user:      Ryan C. Gordon <icculus at icculus.org>
date:      Sat Mar 05 23:25:23 2016 -0500
description:
alsa: Implemented basic device detection.

This is kind of nasty, because ALSA reports dozens of "devices" that aren't
really things you'd ever want, or things that should be listed this way, but
the default path still works as before, and it at least allows these devices
to be available to apps.

This does not handle hotplugging yet. You get a device list at init time
and that's it.

diffstat:

 src/audio/alsa/SDL_alsa_audio.c |  115 ++++++++++++++++++++++++++++++++++-----
 1 files changed, 99 insertions(+), 16 deletions(-)

diffs (171 lines):

diff -r 9cec5fe32bca -r 4cd67316b308 src/audio/alsa/SDL_alsa_audio.c
--- a/src/audio/alsa/SDL_alsa_audio.c	Fri Mar 04 19:41:16 2016 -0500
+++ b/src/audio/alsa/SDL_alsa_audio.c	Sat Mar 05 23:25:23 2016 -0500
@@ -85,6 +85,9 @@
 static int (*ALSA_snd_pcm_wait)(snd_pcm_t *, int);
 static int (*ALSA_snd_pcm_sw_params_set_avail_min)
   (snd_pcm_t *, snd_pcm_sw_params_t *, snd_pcm_uframes_t);
+static int (*ALSA_snd_device_name_hint) (int, const char *, void ***);
+static char* (*ALSA_snd_device_name_get_hint) (const void *, const char *);
+static int (*ALSA_snd_device_name_free_hint) (void **);
 
 #ifdef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
 #define snd_pcm_hw_params_sizeof ALSA_snd_pcm_hw_params_sizeof
@@ -144,6 +147,10 @@
     SDL_ALSA_SYM(snd_pcm_nonblock);
     SDL_ALSA_SYM(snd_pcm_wait);
     SDL_ALSA_SYM(snd_pcm_sw_params_set_avail_min);
+    SDL_ALSA_SYM(snd_device_name_hint);
+    SDL_ALSA_SYM(snd_device_name_get_hint);
+    SDL_ALSA_SYM(snd_device_name_free_hint);
+
     return 0;
 }
 
@@ -196,25 +203,27 @@
 #endif /* SDL_AUDIO_DRIVER_ALSA_DYNAMIC */
 
 static const char *
-get_audio_device(int channels)
+get_audio_device(void *handle, const int channels)
 {
     const char *device;
 
+    if (handle != NULL) {
+        return (const char *) handle;
+    }
+
+    /* !!! FIXME: we also check "SDL_AUDIO_DEVICE_NAME" at the higher level. */
     device = SDL_getenv("AUDIODEV");    /* Is there a standard variable name? */
-    if (device == NULL) {
-        switch (channels) {
-        case 6:
-            device = "plug:surround51";
-            break;
-        case 4:
-            device = "plug:surround40";
-            break;
-        default:
-            device = "default";
-            break;
-        }
+    if (device != NULL) {
+        return device;
     }
-    return device;
+
+    if (channels == 6) {
+        return "plug:surround51";
+    } else if (channels == 4) {
+        return "plug:surround40";
+    }
+
+    return "default";
 }
 
 
@@ -487,7 +496,7 @@
     /* Open the audio device */
     /* Name of device should depend on # channels in spec */
     status = ALSA_snd_pcm_open(&pcm_handle,
-                               get_audio_device(this->spec.channels),
+                               get_audio_device(handle, this->spec.channels),
                                SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
 
     if (status < 0) {
@@ -656,6 +665,79 @@
     UnloadALSALibrary();
 }
 
+static void
+add_device(const int iscapture, const char *name, const char *_desc)
+{
+    char *desc = SDL_strdup(_desc);
+    char *handle = NULL;
+    char *ptr;
+
+    if (!desc) {
+        return;
+    }
+
+    /* some strings have newlines, like "HDA NVidia, HDMI 0\nHDMI Audio Output" */
+    for (ptr = strchr(desc, '\n'); ptr; ptr = strchr(ptr + 1, '\n')) {
+        *ptr = ' ';
+    }
+
+    handle = SDL_strdup(name);
+    if (handle != NULL) {
+        SDL_AddAudioDevice(iscapture, desc, handle);
+    }
+
+    SDL_free(desc);
+}
+
+static void
+ALSA_DetectDevices(void)
+{
+    void **hints = NULL;
+    int i;
+
+    /* !!! FIXME: use udev instead. */
+    /* We won't deal with disconnects and hotplugs without udev, but at least
+       you'll get a reasonable device list at startup. */
+#if 1 /*!SDL_USE_LIBUDEV */
+    if (ALSA_snd_device_name_hint(-1, "pcm", &hints) == -1) {
+        return;  /* oh well. */
+    }
+
+    for (i = 0; hints[i]; i++) {
+        char *name = ALSA_snd_device_name_get_hint(hints[i], "NAME");
+        char *desc = ALSA_snd_device_name_get_hint(hints[i], "DESC");
+        char *ioid = ALSA_snd_device_name_get_hint(hints[i], "IOID");
+
+        if ((ioid == NULL) || (SDL_strcmp(ioid, "Output") == 0)) {
+            add_device(SDL_FALSE, name, desc);
+        }
+
+        if ((ioid == NULL) || (SDL_strcmp(ioid, "Input") == 0)) {
+            add_device(SDL_TRUE, name, desc);
+        }
+
+        free(name);
+        free(desc);
+        free(ioid);
+    }
+
+    ALSA_snd_device_name_free_hint(hints);
+#else
+#error Fill in udev support here.
+#endif
+}
+
+static void
+ALSA_FreeDeviceHandle(void *handle)
+{
+#if 1 /*!SDL_USE_LIBUDEV*/
+    SDL_free(handle);
+#else
+#error Fill in udev support here.
+#endif
+}
+
+
 static int
 ALSA_Init(SDL_AudioDriverImpl * impl)
 {
@@ -664,13 +746,14 @@
     }
 
     /* Set the function pointers */
+    impl->DetectDevices = ALSA_DetectDevices;
     impl->OpenDevice = ALSA_OpenDevice;
     impl->WaitDevice = ALSA_WaitDevice;
     impl->GetDeviceBuf = ALSA_GetDeviceBuf;
     impl->PlayDevice = ALSA_PlayDevice;
     impl->CloseDevice = ALSA_CloseDevice;
     impl->Deinitialize = ALSA_Deinitialize;
-    impl->OnlyHasDefaultOutputDevice = 1;       /* !!! FIXME: Add device enum! */
+    impl->FreeDeviceHandle = ALSA_FreeDeviceHandle;
 
     return 1;   /* this audio target is available. */
 }


More information about the commits mailing list