Cleaned up audio device detection. Cleared out a lot of cut-and-paste.
authorRyan C. Gordon <icculus@icculus.org>
Thu, 04 Aug 2011 00:31:11 -0400
changeset 5593 ab22ca13c47f
parent 5592 2e88d0742f4d
child 5594 e741303e08a8
Cleaned up audio device detection. Cleared out a lot of cut-and-paste.
src/audio/SDL_audio.c
src/audio/SDL_audiodev.c
src/audio/SDL_audiodev_c.h
src/audio/SDL_sysaudio.h
src/audio/bsd/SDL_bsdaudio.c
src/audio/directsound/SDL_directsound.c
src/audio/dsp/SDL_dspaudio.c
src/audio/macosx/SDL_coreaudio.c
src/audio/qsa/SDL_qsa_audio.c
src/audio/winmm/SDL_winmm.c
src/audio/xaudio2/SDL_xaudio2.c
--- a/src/audio/SDL_audio.c	Thu Aug 04 01:07:09 2011 -0400
+++ b/src/audio/SDL_audio.c	Thu Aug 04 00:31:11 2011 -0400
@@ -151,10 +151,9 @@
 
 
 /* stubs for audio drivers that don't need a specific entry point... */
-static int
-SDL_AudioDetectDevices_Default(int iscapture)
-{
-    return -1;
+static void
+SDL_AudioDetectDevices_Default(int iscapture, SDL_AddAudioDevice addfn)
+{                               /* no-op. */
 }
 
 static void
@@ -199,13 +198,6 @@
     return 0;
 }
 
-static const char *
-SDL_AudioGetDeviceName_Default(int index, int iscapture)
-{
-    SDL_SetError("No such device");
-    return NULL;
-}
-
 static void
 SDL_AudioLockDevice_Default(SDL_AudioDevice * device)
 {
@@ -238,7 +230,6 @@
             current_audio.impl.x = SDL_Audio##x##_Default; \
         }
     FILL_STUB(DetectDevices);
-    FILL_STUB(GetDeviceName);
     FILL_STUB(OpenDevice);
     FILL_STUB(ThreadInit);
     FILL_STUB(WaitDevice);
@@ -641,13 +632,64 @@
     return current_audio.name;
 }
 
+static void
+free_device_list(char ***devices, int *devCount)
+{
+    int i = *devCount;
+    if ((i > 0) && (*devices != NULL)) {
+        while (i--) {
+            SDL_free((*devices)[i]);
+        }
+    }
+
+    if (*devices != NULL) {
+        SDL_free(*devices);
+    }
+
+    *devices = NULL;
+    *devCount = 0;
+}
+
+static
+void SDL_AddCaptureAudioDevice(const char *_name)
+{
+    char *name = NULL;
+    void *ptr = SDL_realloc(current_audio.inputDevices,
+                          (current_audio.inputDeviceCount+1) * sizeof(char*));
+    if (ptr == NULL) {
+        return;  /* oh well. */
+    }
+
+    current_audio.inputDevices = (char **) ptr;
+    name = SDL_strdup(_name);  /* if this returns NULL, that's okay. */
+    current_audio.inputDevices[current_audio.inputDeviceCount++] = name;
+}
+
+static
+void SDL_AddOutputAudioDevice(const char *_name)
+{
+    char *name = NULL;
+    void *ptr = SDL_realloc(current_audio.outputDevices,
+                          (current_audio.outputDeviceCount+1) * sizeof(char*));
+    if (ptr == NULL) {
+        return;  /* oh well. */
+    }
+
+    current_audio.outputDevices = (char **) ptr;
+    name = SDL_strdup(_name);  /* if this returns NULL, that's okay. */
+    current_audio.outputDevices[current_audio.outputDeviceCount++] = name;
+}
+
 
 int
 SDL_GetNumAudioDevices(int iscapture)
 {
+    int retval = 0;
+
     if (!SDL_WasInit(SDL_INIT_AUDIO)) {
         return -1;
     }
+
     if ((iscapture) && (!current_audio.impl.HasCaptureSupport)) {
         return 0;
     }
@@ -660,7 +702,19 @@
         return 1;
     }
 
-    return current_audio.impl.DetectDevices(iscapture);
+    if (iscapture) {
+        free_device_list(&current_audio.inputDevices,
+                         &current_audio.inputDeviceCount);
+        current_audio.impl.DetectDevices(iscapture, SDL_AddCaptureAudioDevice);
+        retval = current_audio.inputDeviceCount;
+    } else {
+        free_device_list(&current_audio.outputDevices,
+                         &current_audio.outputDeviceCount);
+        current_audio.impl.DetectDevices(iscapture, SDL_AddOutputAudioDevice);
+        retval = current_audio.outputDeviceCount;
+    }
+
+    return retval;
 }
 
 
@@ -678,8 +732,7 @@
     }
 
     if (index < 0) {
-        SDL_SetError("No such device");
-        return NULL;
+        goto no_such_device;
     }
 
     if ((iscapture) && (current_audio.impl.OnlyHasDefaultInputDevice)) {
@@ -690,7 +743,21 @@
         return DEFAULT_OUTPUT_DEVNAME;
     }
 
-    return current_audio.impl.GetDeviceName(index, iscapture);
+    if (iscapture) {
+        if (index >= current_audio.inputDeviceCount) {
+            goto no_such_device;
+        }
+        return current_audio.inputDevices[index];
+    } else {
+        if (index >= current_audio.outputDeviceCount) {
+            goto no_such_device;
+        }
+        return current_audio.outputDevices[index];
+    }
+
+no_such_device:
+    SDL_SetError("No such device");
+    return NULL;
 }
 
 
@@ -880,6 +947,11 @@
         }
     }
 
+    /* force a device detection if we haven't done one yet. */
+    if ( ((iscapture) && (current_audio.inputDevices == NULL)) ||
+         ((!iscapture) && (current_audio.outputDevices == NULL)) )
+        SDL_GetNumAudioDevices(iscapture);
+
     if (!current_audio.impl.OpenDevice(device, devname, iscapture)) {
         close_audio_device(device);
         return 0;
@@ -1121,6 +1193,10 @@
 
     /* Free the driver data */
     current_audio.impl.Deinitialize();
+    free_device_list(&current_audio.outputDevices,
+                     &current_audio.outputDeviceCount);
+    free_device_list(&current_audio.inputDevices,
+                     &current_audio.inputDeviceCount);
     SDL_memset(&current_audio, '\0', sizeof(current_audio));
     SDL_memset(open_devices, '\0', sizeof(open_devices));
 }
--- a/src/audio/SDL_audiodev.c	Thu Aug 04 01:07:09 2011 -0400
+++ b/src/audio/SDL_audiodev.c	Thu Aug 04 00:31:11 2011 -0400
@@ -48,46 +48,20 @@
 
 static inline void
 test_device(const char *fname, int flags, int (*test) (int fd),
-            char ***devices, int *devCount)
+            SDL_AddAudioDevice addfn)
 {
     struct stat sb;
     if ((stat(fname, &sb) == 0) && (S_ISCHR(sb.st_mode))) {
-        int audio_fd = open(fname, flags, 0);
-        if ((audio_fd >= 0) && (test(audio_fd))) {
-            void *p =
-                SDL_realloc(*devices, ((*devCount) + 1) * sizeof(char *));
-            if (p != NULL) {
-                size_t len = strlen(fname) + 1;
-                char *str = (char *) SDL_malloc(len);
-                *devices = (char **) p;
-                if (str != NULL) {
-                    SDL_strlcpy(str, fname, len);
-                    (*devices)[(*devCount)++] = str;
-                }
+        const int audio_fd = open(fname, flags, 0);
+        if (audio_fd >= 0) {
+            if (test(audio_fd)) {
+                addfn(fname);
             }
             close(audio_fd);
         }
     }
 }
 
-void
-SDL_FreeUnixAudioDevices(char ***devices, int *devCount)
-{
-    int i = *devCount;
-    if ((i > 0) && (*devices != NULL)) {
-        while (i--) {
-            SDL_free((*devices)[i]);
-        }
-    }
-
-    if (*devices != NULL) {
-        SDL_free(*devices);
-    }
-
-    *devices = NULL;
-    *devCount = 0;
-}
-
 static int
 test_stub(int fd)
 {
@@ -95,9 +69,10 @@
 }
 
 void
-SDL_EnumUnixAudioDevices(int flags, int classic, int (*test) (int fd),
-                         char ***devices, int *devCount)
+SDL_EnumUnixAudioDevices(int iscapture, int classic, int (*test)(int fd),
+                         SDL_AddAudioDevice addfn)
 {
+    const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
     const char *audiodev;
     char audiopath[1024];
 
@@ -122,14 +97,14 @@
             }
         }
     }
-    test_device(audiodev, flags, test, devices, devCount);
+    test_device(audiodev, flags, test, addfn);
 
     if (SDL_strlen(audiodev) < (sizeof(audiopath) - 3)) {
         int instance = 0;
         while (instance++ <= 64) {
             SDL_snprintf(audiopath, SDL_arraysize(audiopath),
                          "%s%d", audiodev, instance);
-            test_device(audiopath, flags, test, devices, devCount);
+            test_device(audiopath, flags, test, addfn);
         }
     }
 }
--- a/src/audio/SDL_audiodev_c.h	Thu Aug 04 01:07:09 2011 -0400
+++ b/src/audio/SDL_audiodev_c.h	Thu Aug 04 00:31:11 2011 -0400
@@ -18,10 +18,22 @@
      misrepresented as being the original software.
   3. This notice may not be removed or altered from any source distribution.
 */
+#include "SDL.h"
 #include "SDL_config.h"
+#include "SDL_sysaudio.h"
+
+/* Open the audio device for playback, and don't block if busy */
+/* #define USE_BLOCKING_WRITES */
 
-void SDL_EnumUnixAudioDevices(int flags, int classic, int (*test) (int fd),
-                              char ***devs, int *count);
-void SDL_FreeUnixAudioDevices(char ***devices, int *devCount);
+#ifdef USE_BLOCKING_WRITES
+#define OPEN_FLAGS_OUTPUT O_WRONLY
+#define OPEN_FLAGS_INPUT O_RDONLY
+#else
+#define OPEN_FLAGS_OUTPUT (O_WRONLY|O_NONBLOCK)
+#define OPEN_FLAGS_INPUT (O_RDONLY|O_NONBLOCK)
+#endif
+
+void SDL_EnumUnixAudioDevices(int iscapture, int classic,
+                              int (*test) (int fd), SDL_AddAudioDevice addfn);
 
 /* vi: set ts=4 sw=4 expandtab: */
--- a/src/audio/SDL_sysaudio.h	Thu Aug 04 01:07:09 2011 -0400
+++ b/src/audio/SDL_sysaudio.h	Thu Aug 04 00:31:11 2011 -0400
@@ -30,10 +30,12 @@
 typedef struct SDL_AudioDevice SDL_AudioDevice;
 #define _THIS	SDL_AudioDevice *_this
 
+/* Used by audio targets during DetectDevices() */
+typedef void (*SDL_AddAudioDevice)(const char *name);
+
 typedef struct SDL_AudioDriverImpl
 {
-    int (*DetectDevices) (int iscapture);
-    const char *(*GetDeviceName) (int index, int iscapture);
+    void (*DetectDevices) (int iscapture, SDL_AddAudioDevice addfn);
     int (*OpenDevice) (_THIS, const char *devname, int iscapture);
     void (*ThreadInit) (_THIS); /* Called by audio thread at start */
     void (*WaitDevice) (_THIS);
@@ -67,6 +69,12 @@
     const char *desc;
 
     SDL_AudioDriverImpl impl;
+
+    char **outputDevices;
+    int outputDeviceCount;
+
+    char **inputDevices;
+    int inputDeviceCount;
 } SDL_AudioDriver;
 
 
--- a/src/audio/bsd/SDL_bsdaudio.c	Thu Aug 04 01:07:09 2011 -0400
+++ b/src/audio/bsd/SDL_bsdaudio.c	Thu Aug 04 00:31:11 2011 -0400
@@ -50,91 +50,23 @@
 #define BSD_AUDIO_DRIVER_DESC         "Native OpenBSD audio"
 #endif
 
-/* Open the audio device for playback, and don't block if busy */
-/* #define USE_BLOCKING_WRITES */
-
 /* Use timer for synchronization */
 /* #define USE_TIMER_SYNC */
 
 /* #define DEBUG_AUDIO */
 /* #define DEBUG_AUDIO_STREAM */
 
-#ifdef USE_BLOCKING_WRITES
-#define OPEN_FLAGS_OUTPUT O_WRONLY
-#define OPEN_FLAGS_INPUT O_RDONLY
-#else
-#define OPEN_FLAGS_OUTPUT (O_WRONLY|O_NONBLOCK)
-#define OPEN_FLAGS_INPUT (O_RDONLY|O_NONBLOCK)
-#endif
 
-/* !!! FIXME: so much cut and paste with dsp target... */
-static char **outputDevices = NULL;
-static int outputDeviceCount = 0;
-static char **inputDevices = NULL;
-static int inputDeviceCount = 0;
-
-static inline void
-free_device_list(char ***devs, int *count)
+static void
+BSDAUDIO_Deinitialize(void)
 {
-    SDL_FreeUnixAudioDevices(devs, count);
-}
-
-static inline void
-build_device_list(int iscapture, char ***devs, int *count)
-{
-    const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
-    free_device_list(devs, count);
-    SDL_EnumUnixAudioDevices(flags, 0, NULL, devs, count);
-}
-
-static inline void
-build_device_lists(void)
-{
-    build_device_list(0, &outputDevices, &outputDeviceCount);
-    build_device_list(1, &inputDevices, &inputDeviceCount);
-}
-
-
-static inline void
-free_device_lists(void)
-{
-    free_device_list(&outputDevices, &outputDeviceCount);
-    free_device_list(&inputDevices, &inputDeviceCount);
 }
 
 
 static void
-BSDAUDIO_Deinitialize(void)
-{
-    free_device_lists();
-}
-
-
-static int
-BSDAUDIO_DetectDevices(int iscapture)
+BSDAUDIO_DetectDevices(int iscapture, SDL_AddAudioDevice addfn)
 {
-    if (iscapture) {
-        build_device_list(1, &inputDevices, &inputDeviceCount);
-        return inputDeviceCount;
-    } else {
-        build_device_list(0, &outputDevices, &outputDeviceCount);
-        return outputDeviceCount;
-    }
-
-    return 0;                   /* shouldn't ever hit this. */
-}
-
-static const char *
-BSDAUDIO_GetDeviceName(int index, int iscapture)
-{
-    if ((iscapture) && (index < inputDeviceCount)) {
-        return inputDevices[index];
-    } else if ((!iscapture) && (index < outputDeviceCount)) {
-        return outputDevices[index];
-    }
-
-    SDL_SetError("No such device");
-    return NULL;
+    SDL_EnumUnixAudioDevices(iscapture, 0, NULL, addfn);
 }
 
 
@@ -318,12 +250,11 @@
     /* We don't care what the devname is...we'll try to open anything. */
     /*  ...but default to first name in the list... */
     if (devname == NULL) {
-        if (((iscapture) && (inputDeviceCount == 0)) ||
-            ((!iscapture) && (outputDeviceCount == 0))) {
+        devname = SDL_GetAudioDeviceName(0, iscapture);
+        if (devname == NULL) {
             SDL_SetError("No such audio device");
             return 0;
         }
-        devname = ((iscapture) ? inputDevices[0] : outputDevices[0]);
     }
 
     /* Initialize all variables that we clean on shutdown */
@@ -434,7 +365,6 @@
 {
     /* Set the function pointers */
     impl->DetectDevices = BSDAUDIO_DetectDevices;
-    impl->GetDeviceName = BSDAUDIO_GetDeviceName;
     impl->OpenDevice = BSDAUDIO_OpenDevice;
     impl->PlayDevice = BSDAUDIO_PlayDevice;
     impl->WaitDevice = BSDAUDIO_WaitDevice;
@@ -442,8 +372,6 @@
     impl->CloseDevice = BSDAUDIO_CloseDevice;
     impl->Deinitialize = BSDAUDIO_Deinitialize;
 
-    build_device_lists();
-
     return 1;   /* this audio target is available. */
 }
 
--- a/src/audio/directsound/SDL_directsound.c	Thu Aug 04 01:07:09 2011 -0400
+++ b/src/audio/directsound/SDL_directsound.c	Thu Aug 04 00:31:11 2011 -0400
@@ -148,96 +148,28 @@
 }
 
 
-
-/* !!! FIXME: this is a cut and paste of SDL_FreeUnixAudioDevices(),
- * !!! FIXME:  which is more proof this needs to be managed in SDL_audio.c
- * !!! FIXME:  and not in drivers.
- */
-static void
-FreeDSoundAudioDevices(char ***devices, int *devCount)
+static BOOL CALLBACK
+FindAllDevs(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVOID data)
 {
-    int i = *devCount;
-    if ((i > 0) && (*devices != NULL)) {
-        while (i--) {
-            SDL_free((*devices)[i]);
+    SDL_AddAudioDevice addfn = (SDL_AddAudioDevice) data;
+    if (guid != NULL) {  /* skip default device */
+        char *str = utf16_to_utf8(desc);
+        if (str != NULL) {
+            addfn(str);
+            SDL_free(str);  /* addfn() makes a copy of this string. */
         }
     }
-
-    if (*devices != NULL) {
-        SDL_free(*devices);
-    }
-
-    *devices = NULL;
-    *devCount = 0;
-}
-
-
-typedef struct FindAllDevsData
-{
-    const char **devs;
-    unsigned int devcount;
-} FindAllDevsData;
-
-static BOOL CALLBACK
-FindAllDevs(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVOID _data)
-{
-    FindAllDevsData *data = (FindAllDevsData *) _data;
-    void *ptr;
-    char *name;
-
-    if (guid == NULL)
-        return TRUE;  /* skip default device, go to the next one. */
-
-    ptr = SDL_realloc(data->devs, ((data->devcount) + 1) * sizeof(char *));
-    if (ptr == NULL)
-        return TRUE;  /* oh well. */
-
-    data->devs = (const char **) ptr;
-    name = utf16_to_utf8(desc);
-    if (name != NULL)
-        data->devs[data->devcount++] = name;
-
     return TRUE;  /* keep enumerating. */
 }
 
-static char **outputDevices = NULL;
-static int outputDeviceCount = 0;
-static char **inputDevices = NULL;
-static int inputDeviceCount = 0;
-
-static int
-DSOUND_DetectDevices(int iscapture)
+static void
+DSOUND_DetectDevices(int iscapture, SDL_AddAudioDevice addfn)
 {
-    FindAllDevsData data;
-    data.devs = NULL;
-    data.devcount = 0;
-
     if (iscapture) {
-        FreeDSoundAudioDevices(&inputDevices, &inputDeviceCount);
-        pDirectSoundCaptureEnumerateW(FindAllDevs, &devs);
-        inputDevices = data.devs;
-        inputDeviceCount = data.devcount;
+        pDirectSoundCaptureEnumerateW(FindAllDevs, addfn);
     } else {
-        FreeDSoundAudioDevices(&outputDevices, &outputDeviceCount);
-        pDirectSoundEnumerateW(FindAllDevs, &devs);
-        outputDevices = data.devs;
-        outputDeviceCount = data.devcount;
+        pDirectSoundEnumerateW(FindAllDevs, addfn);
     }
-
-    return data.devcount;
-}
-
-static const char *
-DSOUND_GetDeviceName(int index, int iscapture)
-{
-    if ((iscapture) && (index < inputDeviceCount)) {
-        return inputDevices[index];
-    } else if ((!iscapture) && (index < outputDeviceCount)) {
-        return outputDevices[index];
-    }
-
-    SDL_SetError("No such device");
-    return NULL;
 }
 
 
@@ -589,8 +521,6 @@
 static void
 DSOUND_Deinitialize(void)
 {
-    FreeDSoundAudioDevices(&inputDevices, &inputDeviceCount);
-    FreeDSoundAudioDevices(&outputDevices, &outputDeviceCount);
     DSOUND_Unload();
 }
 
@@ -604,7 +534,6 @@
 
     /* Set the function pointers */
     impl->DetectDevices = DSOUND_DetectDevices;
-    impl->GetDeviceName = DSOUND_GetDeviceName;
     impl->OpenDevice = DSOUND_OpenDevice;
     impl->PlayDevice = DSOUND_PlayDevice;
     impl->WaitDevice = DSOUND_WaitDevice;
--- a/src/audio/dsp/SDL_dspaudio.c	Thu Aug 04 01:07:09 2011 -0400
+++ b/src/audio/dsp/SDL_dspaudio.c	Thu Aug 04 00:31:11 2011 -0400
@@ -50,77 +50,16 @@
 /* The tag name used by DSP audio */
 #define DSP_DRIVER_NAME         "dsp"
 
-/* Open the audio device for playback, and don't block if busy */
-#define OPEN_FLAGS_OUTPUT    (O_WRONLY|O_NONBLOCK)
-#define OPEN_FLAGS_INPUT    (O_RDONLY|O_NONBLOCK)
-
-static char **outputDevices = NULL;
-static int outputDeviceCount = 0;
-static char **inputDevices = NULL;
-static int inputDeviceCount = 0;
-
-static inline void
-free_device_list(char ***devs, int *count)
-{
-    SDL_FreeUnixAudioDevices(devs, count);
-}
-
-static inline void
-build_device_list(int iscapture, char ***devs, int *count)
+static void
+DSP_Deinitialize(void)
 {
-    const int flags = ((iscapture) ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT);
-    free_device_list(devs, count);
-    SDL_EnumUnixAudioDevices(flags, 0, NULL, devs, count);
-}
-
-static inline void
-build_device_lists(void)
-{
-    build_device_list(0, &outputDevices, &outputDeviceCount);
-    build_device_list(1, &inputDevices, &inputDeviceCount);
-}
-
-
-static inline void
-free_device_lists(void)
-{
-    free_device_list(&outputDevices, &outputDeviceCount);
-    free_device_list(&inputDevices, &inputDeviceCount);
 }
 
 
 static void
-DSP_Deinitialize(void)
-{
-    free_device_lists();
-}
-
-
-static int
 DSP_DetectDevices(int iscapture)
 {
-    if (iscapture) {
-        build_device_list(1, &inputDevices, &inputDeviceCount);
-        return inputDeviceCount;
-    } else {
-        build_device_list(0, &outputDevices, &outputDeviceCount);
-        return outputDeviceCount;
-    }
-
-    return 0;                   /* shouldn't ever hit this. */
-}
-
-static const char *
-DSP_GetDeviceName(int index, int iscapture)
-{
-    if ((iscapture) && (index < inputDeviceCount)) {
-        return inputDevices[index];
-    } else if ((!iscapture) && (index < outputDeviceCount)) {
-        return outputDevices[index];
-    }
-
-    SDL_SetError("No such device");
-    return NULL;
+    SDL_EnumUnixAudioDevices(iscapture, 0, NULL);
 }
 
 
@@ -154,12 +93,11 @@
     /* We don't care what the devname is...we'll try to open anything. */
     /*  ...but default to first name in the list... */
     if (devname == NULL) {
-        if (((iscapture) && (inputDeviceCount == 0)) ||
-            ((!iscapture) && (outputDeviceCount == 0))) {
+        devname = SDL_GetAudioDeviceName(0, iscapture);
+        if (devname == NULL) {
             SDL_SetError("No such audio device");
             return 0;
         }
-        devname = ((iscapture) ? inputDevices[0] : outputDevices[0]);
     }
 
     /* Make sure fragment size stays a power of 2, or OSS fails. */
@@ -369,15 +307,12 @@
 {
     /* Set the function pointers */
     impl->DetectDevices = DSP_DetectDevices;
-    impl->GetDeviceName = DSP_GetDeviceName;
     impl->OpenDevice = DSP_OpenDevice;
     impl->PlayDevice = DSP_PlayDevice;
     impl->GetDeviceBuf = DSP_GetDeviceBuf;
     impl->CloseDevice = DSP_CloseDevice;
     impl->Deinitialize = DSP_Deinitialize;
 
-    build_device_lists();
-
     return 1;   /* this audio target is available. */
 }
 
--- a/src/audio/macosx/SDL_coreaudio.c	Thu Aug 04 01:07:09 2011 -0400
+++ b/src/audio/macosx/SDL_coreaudio.c	Thu Aug 04 00:31:11 2011 -0400
@@ -34,34 +34,36 @@
 
 #define DEBUG_COREAUDIO 0
 
-typedef struct COREAUDIO_DeviceList
-{
-    AudioDeviceID id;
-    const char *name;
-} COREAUDIO_DeviceList;
-
-static COREAUDIO_DeviceList *inputDevices = NULL;
-static int inputDeviceCount = 0;
-static COREAUDIO_DeviceList *outputDevices = NULL;
-static int outputDeviceCount = 0;
+typedef void (*addDevFn)(const char *name, AudioDeviceID devId, void *data);
 
 static void
-free_device_list(COREAUDIO_DeviceList ** devices, int *devCount)
+addToDevList(const char *name, AudioDeviceID devId, void *data)
 {
-    if (*devices) {
-        int i = *devCount;
-        while (i--)
-            SDL_free((void *) (*devices)[i].name);
-        SDL_free(*devices);
-        *devices = NULL;
-    }
-    *devCount = 0;
+    SDL_AddAudioDevice addfn = (SDL_AddAudioDevice) data;
+    addfn(name);
 }
 
+typedef struct
+{
+    const char *findname;
+    AudioDeviceID devId;
+    int found;
+} FindDevIdData;
 
 static void
-build_device_list(int iscapture, COREAUDIO_DeviceList ** devices,
-                  int *devCount)
+findDevId(const char *name, AudioDeviceID devId, void *_data)
+{
+    FindDevIdData *data = (FindDevIdData *) _data;
+    if (!data->found) {
+        if (SDL_strcmp(name, data->findname) == 0) {
+            data->found = 1;
+            data->devId = devId;
+        }
+    }
+}
+
+static void
+build_device_list(int iscapture, addDevFn addfn, void *addfndata)
 {
     Boolean outWritable = 0;
     OSStatus result = noErr;
@@ -70,8 +72,6 @@
     UInt32 i = 0;
     UInt32 max = 0;
 
-    free_device_list(devices, devCount);
-
     result = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices,
                                           &size, &outWritable);
 
@@ -82,16 +82,12 @@
     if (devs == NULL)
         return;
 
-    max = size / sizeof(AudioDeviceID);
-    *devices = (COREAUDIO_DeviceList *) SDL_malloc(max * sizeof(**devices));
-    if (*devices == NULL)
-        return;
-
     result = AudioHardwareGetProperty(kAudioHardwarePropertyDevices,
                                       &size, devs);
     if (result != kAudioHardwareNoError)
         return;
 
+    max = size / sizeof (AudioDeviceID);
     for (i = 0; i < max; i++) {
         CFStringRef cfstr = NULL;
         char *ptr = NULL;
@@ -156,9 +152,7 @@
             usable = (len > 0);
         }
 
-        if (!usable) {
-            SDL_free(ptr);
-        } else {
+        if (usable) {
             ptr[len] = '\0';
 
 #if DEBUG_COREAUDIO
@@ -166,80 +160,22 @@
                    ((iscapture) ? "capture" : "output"),
                    (int) *devCount, ptr, (int) dev);
 #endif
-
-            (*devices)[*devCount].id = dev;
-            (*devices)[*devCount].name = ptr;
-            (*devCount)++;
+            addfn(ptr, dev, addfndata);
         }
+        SDL_free(ptr);  /* addfn() would have copied the string. */
     }
 }
 
-static inline void
-build_device_lists(void)
-{
-    build_device_list(0, &outputDevices, &outputDeviceCount);
-    build_device_list(1, &inputDevices, &inputDeviceCount);
-}
-
-
-static inline void
-free_device_lists(void)
-{
-    free_device_list(&outputDevices, &outputDeviceCount);
-    free_device_list(&inputDevices, &inputDeviceCount);
-}
-
-
-static int
-find_device_id(const char *devname, int iscapture, AudioDeviceID * id)
+static void
+COREAUDIO_DetectDevices(int iscapture, SDL_AddAudioDevice addfn)
 {
-    int i = ((iscapture) ? inputDeviceCount : outputDeviceCount);
-    COREAUDIO_DeviceList *devs = ((iscapture) ? inputDevices : outputDevices);
-    while (i--) {
-        if (SDL_strcmp(devname, devs->name) == 0) {
-            *id = devs->id;
-            return 1;
-        }
-        devs++;
-    }
-
-    return 0;
-}
-
-
-static int
-COREAUDIO_DetectDevices(int iscapture)
-{
-    if (iscapture) {
-        build_device_list(1, &inputDevices, &inputDeviceCount);
-        return inputDeviceCount;
-    } else {
-        build_device_list(0, &outputDevices, &outputDeviceCount);
-        return outputDeviceCount;
-    }
-
-    return 0;                   /* shouldn't ever hit this. */
-}
-
-
-static const char *
-COREAUDIO_GetDeviceName(int index, int iscapture)
-{
-    if ((iscapture) && (index < inputDeviceCount)) {
-        return inputDevices[index].name;
-    } else if ((!iscapture) && (index < outputDeviceCount)) {
-        return outputDevices[index].name;
-    }
-
-    SDL_SetError("No such device");
-    return NULL;
+    build_device_list(iscapture, addToDevList, addfn);
 }
 
 
 static void
 COREAUDIO_Deinitialize(void)
 {
-    free_device_lists();
 }
 
 
@@ -378,10 +314,15 @@
         result = AudioHardwareGetProperty(propid, &size, &devid);
         CHECK_RESULT("AudioHardwareGetProperty (default device)");
     } else {
-        if (!find_device_id(devname, iscapture, &devid)) {
+        FindDevIdData data;
+        SDL_zero(data);
+        data.findname = devname;
+        build_device_list(iscapture, findDevId, &data);
+        if (!data.found) {
             SDL_SetError("CoreAudio: No such audio device.");
             return 0;
         }
+        devid = data.devId;
     }
 
     size = sizeof(alive);
@@ -565,14 +506,11 @@
 {
     /* Set the function pointers */
     impl->DetectDevices = COREAUDIO_DetectDevices;
-    impl->GetDeviceName = COREAUDIO_GetDeviceName;
     impl->OpenDevice = COREAUDIO_OpenDevice;
     impl->CloseDevice = COREAUDIO_CloseDevice;
     impl->Deinitialize = COREAUDIO_Deinitialize;
     impl->ProvidesOwnCallbackThread = 1;
 
-    build_device_lists();       /* do an initial check for devices... */
-
     return 1;   /* this audio target is available. */
 }
 
--- a/src/audio/qsa/SDL_qsa_audio.c	Thu Aug 04 01:07:09 2011 -0400
+++ b/src/audio/qsa/SDL_qsa_audio.c	Thu Aug 04 00:31:11 2011 -0400
@@ -651,8 +651,8 @@
     return 1;
 }
 
-static int
-QSA_DetectDevices(int iscapture)
+static void
+QSA_DetectDevices(int iscapture, SDL_AddAudioDevice addfn)
 {
     uint32_t it;
     uint32_t cards;
@@ -667,7 +667,7 @@
     /* of available audio devices                                 */
     if (cards == 0) {
         /* We have no any available audio devices */
-        return 0;
+        return;
     }
 
     /* Find requested devices by type */
@@ -702,6 +702,7 @@
                             devices;
                         status = snd_pcm_close(handle);
                         if (status == EOK) {
+                            addfn(qsa_playback_device[qsa_playback_devices].name);
                             qsa_playback_devices++;
                         }
                     } else {
@@ -757,6 +758,7 @@
                             devices;
                         status = snd_pcm_close(handle);
                         if (status == EOK) {
+                            addfn(qsa_capture_device[qsa_capture_devices].name);
                             qsa_capture_devices++;
                         }
                     } else {
@@ -782,31 +784,6 @@
             }
         }
     }
-
-    /* Return amount of available playback or capture devices */
-    if (!iscapture) {
-        return qsa_playback_devices;
-    } else {
-        return qsa_capture_devices;
-    }
-}
-
-static const char *
-QSA_GetDeviceName(int index, int iscapture)
-{
-    if (!iscapture) {
-        if (index >= qsa_playback_devices) {
-            return "No such playback device";
-        }
-
-        return qsa_playback_device[index].name;
-    } else {
-        if (index >= qsa_capture_devices) {
-            return "No such capture device";
-        }
-
-        return qsa_capture_device[index].name;
-    }
 }
 
 static void
@@ -857,7 +834,6 @@
     /* DeviceLock and DeviceUnlock functions are used default,   */
     /* provided by SDL, which uses pthread_mutex for lock/unlock */
     impl->DetectDevices = QSA_DetectDevices;
-    impl->GetDeviceName = QSA_GetDeviceName;
     impl->OpenDevice = QSA_OpenDevice;
     impl->ThreadInit = QSA_ThreadInit;
     impl->WaitDevice = QSA_WaitDevice;
--- a/src/audio/winmm/SDL_winmm.c	Thu Aug 04 01:07:09 2011 -0400
+++ b/src/audio/winmm/SDL_winmm.c	Thu Aug 04 00:31:11 2011 -0400
@@ -33,89 +33,33 @@
 #include "win_ce_semaphore.h"
 #endif
 
-
-/* !!! FIXME: this is a cut and paste of SDL_FreeUnixAudioDevices(),
- * !!! FIXME:  which is more proof this needs to be managed in SDL_audio.c
- * !!! FIXME:  and not in drivers.
- */
-static void
-FreeWaveOutAudioDevices(char ***devices, int *devCount)
-{
-    int i = *devCount;
-    if ((i > 0) && (*devices != NULL)) {
-        while (i--) {
-            SDL_free((*devices)[i]);
-        }
-    }
-
-    if (*devices != NULL) {
-        SDL_free(*devices);
-    }
-
-    *devices = NULL;
-    *devCount = 0;
+#define DETECT_DEV_IMPL(typ, capstyp) \
+static void DetectWave##typ##Devs(SDL_AddAudioDevice addfn) { \
+    const UINT devcount = wave##typ##GetNumDevs(); \
+    capstyp caps; \
+    UINT i; \
+    for (i = 0; i < devcount; i++) { \
+        if (wave##typ##GetDevCaps(i,&caps,sizeof(caps))==MMSYSERR_NOERROR) { \
+            char *name = WIN_StringToUTF8(caps.szPname); \
+            if (name != NULL) { \
+                addfn(name); \
+                SDL_free(name); \
+            } \
+        } \
+    } \
 }
 
-static char **outputDevices = NULL;
-static int outputDeviceCount = 0;
-static char **inputDevices = NULL;
-static int inputDeviceCount = 0;
+DETECT_DEV_IMPL(Out, WAVEOUTCAPS)
+DETECT_DEV_IMPL(In, WAVEINCAPS)
 
-static int
-DetectWaveOutDevices(void)
-{
-    UINT i;
-    const UINT devcount = waveOutGetNumDevs();
-    WAVEOUTCAPS caps;
-    FreeWaveOutAudioDevices(&outputDevices, &outputDeviceCount);
-    outputDevices = (const char **) SDL_malloc(sizeof (char *) * devcount);
-    for (i = 0; i < devcount; i++) {
-        if (waveOutGetDevCaps(i, &caps, sizeof (caps)) == MMSYSERR_NOERROR) {
-            outputDevices[outputDeviceCount] = WIN_StringToUTF8(caps.szPname);
-            if (outputDevices[outputDeviceCount] != NULL) {
-                outputDeviceCount++;
-            }
-        }
-    }
-    return outputDeviceCount;
-}
-
-static int
-DetectWaveInDevices(void)
+static void
+WINMM_DetectDevices(int iscapture, SDL_AddAudioDevice addfn)
 {
-    UINT i;
-    const UINT devcount = waveInGetNumDevs();
-    WAVEINCAPS caps;
-    FreeWaveInAudioDevices(&inputDevices, &inputDeviceCount);
-    inputDevices = (const char **) SDL_malloc(sizeof (char *) * devcount);
-    for (i = 0; i < devcount; i++) {
-        if (waveInGetDevCaps(i, &caps, sizeof (caps)) == MMSYSERR_NOERROR) {
-            inputDevices[inputDeviceCount] = WIN_StringToUTF8(caps.szPname);
-            if (inputDevices[inputDeviceCount] != NULL) {
-                inputDeviceCount++;
-            }
-        }
+    if (iscapture) {
+        DetectWaveInDevs(addfn);
+    } else {
+        DetectWaveOutDevs(addfn);
     }
-    return inputDeviceCount;
-}
-
-static int
-WINMM_DetectDevices(int iscapture)
-{
-    return (iscapture) ? DetectWaveInDevices() : DetectWaveOutDevices();
-}
-
-static const char *
-WINMM_GetDeviceName(int index, int iscapture)
-{
-    if ((iscapture) && (index < inputDeviceCount)) {
-        return inputDevices[index];
-    } else if ((!iscapture) && (index < outputDeviceCount)) {
-        return outputDevices[index];
-    }
-
-    SDL_SetError("No such device");
-    return NULL;
 }
 
 static void CALLBACK
@@ -448,7 +392,6 @@
 {
     /* Set the function pointers */
     impl->DetectDevices = WINMM_DetectDevices;
-    impl->GetDeviceName = WINMM_GetDeviceName;
     impl->OpenDevice = WINMM_OpenDevice;
     impl->PlayDevice = WINMM_PlayDevice;
     impl->WaitDevice = WINMM_WaitDevice;
--- a/src/audio/xaudio2/SDL_xaudio2.c	Thu Aug 04 01:07:09 2011 -0400
+++ b/src/audio/xaudio2/SDL_xaudio2.c	Thu Aug 04 00:31:11 2011 -0400
@@ -24,35 +24,9 @@
 #include "../SDL_audio_c.h"
 #include "SDL_assert.h"
 
-#define INITGUID 1
+#define INITGUID 1
 #include "SDL_xaudio2.h"
 
-/* !!! FIXME: this is a cut and paste of SDL_FreeUnixAudioDevices(),
- * !!! FIXME:  which is more proof this needs to be managed in SDL_audio.c
- * !!! FIXME:  and not in drivers.
- */
-static void
-FreeXAudio2AudioDevices(char ***devices, int *devCount)
-{
-    int i = *devCount;
-    if ((i > 0) && (*devices != NULL)) {
-        while (i--) {
-            SDL_free((*devices)[i]);
-        }
-    }
-
-    if (*devices != NULL) {
-        SDL_free(*devices);
-    }
-
-    *devices = NULL;
-    *devCount = 0;
-}
-
-
-static char **outputDevices = NULL;
-static int outputDeviceCount = 0;
-
 static __inline__ char *
 utf16_to_utf8(const WCHAR *S)
 {
@@ -61,59 +35,38 @@
                             (SDL_wcslen(S)+1)*sizeof(WCHAR));
 }
 
-static int
-XAUDIO2_DetectDevices(int iscapture)
+static void
+XAUDIO2_DetectDevices(int iscapture, SDL_AddAudioDevice addfn)
 {
     IXAudio2 *ixa2 = NULL;
     UINT32 devcount = 0;
     UINT32 i = 0;
     void *ptr = NULL;
 
-    if (!iscapture) {
-        FreeXAudio2AudioDevices(&outputDevices, &outputDeviceCount);
-    }
-
     if (iscapture) {
         SDL_SetError("XAudio2: capture devices unsupported.");
-        return 0;
+        return;
     } else if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) {
         SDL_SetError("XAudio2: XAudio2Create() failed.");
-        return 0;
+        return;
     } else if (IXAudio2_GetDeviceCount(ixa2, &devcount) != S_OK) {
         SDL_SetError("XAudio2: IXAudio2::GetDeviceCount() failed.");
         IXAudio2_Release(ixa2);
-        return 0;
-    } else if ((ptr = SDL_malloc(sizeof (char *) * devcount)) == NULL) {
-        SDL_OutOfMemory();
-        IXAudio2_Release(ixa2);
-        return 0;
+        return;
     }
 
-    outputDevices = (char **) ptr;
     for (i = 0; i < devcount; i++) {
         XAUDIO2_DEVICE_DETAILS details;
         if (IXAudio2_GetDeviceDetails(ixa2, i, &details) == S_OK) {
             char *str = utf16_to_utf8(details.DisplayName);
             if (str != NULL) {
-                outputDevices[outputDeviceCount++] = str;
+                addfn(str);
+                SDL_free(str);  /* addfn() made a copy of the string. */
             }
         }
     }
 
     IXAudio2_Release(ixa2);
-
-    return outputDeviceCount;
-}
-
-static const char *
-XAUDIO2_GetDeviceName(int index, int iscapture)
-{
-    if ((!iscapture) && (index < outputDeviceCount)) {
-        return outputDevices[index];
-    }
-
-    SDL_SetError("XAudio2: No such device");
-    return NULL;
 }
 
 static void STDMETHODCALLTYPE
@@ -436,7 +389,6 @@
 
     /* Set the function pointers */
     impl->DetectDevices = XAUDIO2_DetectDevices;
-    impl->GetDeviceName = XAUDIO2_GetDeviceName;
     impl->OpenDevice = XAUDIO2_OpenDevice;
     impl->PlayDevice = XAUDIO2_PlayDevice;
     impl->WaitDevice = XAUDIO2_WaitDevice;