PulseAudio: Improved multidevice support.
authorRyan C. Gordon <icculus@icculus.org>
Wed, 18 Mar 2015 10:29:04 -0400
changeset 9395 65e946d15533
parent 9394 bb28e5281770
child 9396 69c501ed36f3
PulseAudio: Improved multidevice support. Added capture device enumeration, report human-readable device name, other cleanups.
src/audio/pulseaudio/SDL_pulseaudio.c
--- a/src/audio/pulseaudio/SDL_pulseaudio.c	Wed Mar 18 02:01:17 2015 -0400
+++ b/src/audio/pulseaudio/SDL_pulseaudio.c	Wed Mar 18 10:29:04 2015 -0400
@@ -84,6 +84,7 @@
 static int (*PULSEAUDIO_pa_context_connect) (pa_context *, const char *,
     pa_context_flags_t, const pa_spawn_api *);
 static pa_operation * (*PULSEAUDIO_pa_context_get_sink_info_list)(pa_context *, pa_sink_info_cb_t, void *);
+static pa_operation * (*PULSEAUDIO_pa_context_get_source_info_list)(pa_context *, pa_source_info_cb_t, void *);
 static pa_context_state_t (*PULSEAUDIO_pa_context_get_state) (pa_context *);
 static void (*PULSEAUDIO_pa_context_disconnect) (pa_context *);
 static void (*PULSEAUDIO_pa_context_unref) (pa_context *);
@@ -186,6 +187,7 @@
     SDL_PULSEAUDIO_SYM(pa_context_new);
     SDL_PULSEAUDIO_SYM(pa_context_connect);
     SDL_PULSEAUDIO_SYM(pa_context_get_sink_info_list);
+    SDL_PULSEAUDIO_SYM(pa_context_get_source_info_list);
     SDL_PULSEAUDIO_SYM(pa_context_get_state);
     SDL_PULSEAUDIO_SYM(pa_context_disconnect);
     SDL_PULSEAUDIO_SYM(pa_context_unref);
@@ -380,6 +382,7 @@
 static int
 PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
 {
+    const char *devstr = (const char *) handle;  /* NULL==default in Pulse. */
     struct SDL_PrivateAudioData *h = NULL;
     Uint16 test_format = 0;
     pa_sample_spec paspec;
@@ -497,7 +500,7 @@
         return SDL_SetError("Could not set up PulseAudio stream");
     }
 
-    if (PULSEAUDIO_pa_stream_connect_playback(h->stream, devname, &paattr, flags,
+    if (PULSEAUDIO_pa_stream_connect_playback(h->stream, devstr, &paattr, flags,
             NULL, NULL) < 0) {
         PULSEAUDIO_CloseDevice(this);
         return SDL_SetError("Could not connect PulseAudio stream");
@@ -519,50 +522,73 @@
     return 0;
 }
 
-typedef struct
+static void
+get_sinks_cb(pa_context *c, const pa_sink_info *i, int is_last, void *data)
 {
-    uint8_t last;
-    SDL_AddAudioDevice addfn;
-} sink_struct;
+    SDL_bool *done = (SDL_bool *) data;
 
-static void
-get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata)
-{
-    sink_struct *a = (sink_struct *) userdata;
-    a->last = is_last;
+    *done = (is_list != 0);
     if (i) {
-        a->addfn(i->name);
+        char *handle = SDL_strdup(i->name);
+        if (handle != NULL) {
+            SDL_AddAudioDevice(SDL_FALSE, i->description, handle);
+        }
     }
 }
 
 static void
-PULSEAUDIO_DetectDevices(int iscapture, SDL_AddAudioDevice addfn)
+get_sources_cb(pa_context *c, const pa_sink_info *i, int is_last, void *data)
+{
+    SDL_bool *done = (SDL_bool *) data;
+
+    *done = (is_list != 0);
+    if (i) {
+        char *handle = SDL_strdup(i->name);
+        if (handle != NULL) {
+            SDL_AddAudioDevice(SDL_TRUE, i->description, handle);
+        }
+    }
+}
+
+static void
+RunPulseDetectCallback(pa_mainloop *mainloop, pa_operation *o, SDL_bool *done)
+{
+    do {
+        if (PULSEAUDIO_pa_operation_get_state(o) == PA_OPERATION_CANCELLED) {
+            break;
+        } else if (PULSEAUDIO_pa_mainloop_iterate(mainloop, 1, NULL) < 0) {
+            break;
+        }
+    } while (*done == SDL_FALSE);
+}
+
+static void
+PULSEAUDIO_DetectDevices()
 {
     pa_mainloop *mainloop = NULL;
     pa_context *context = NULL;
+    pa_operation *o = NULL;
+    SDL_bool done;
 
     if (ConnectToPulseServer(&mainloop, &context) < 0) {
         return;
     }
 
-    if (!iscapture) {
-        sink_struct a = { 0, addfn };
-        pa_operation *o = PULSEAUDIO_pa_context_get_sink_info_list(context,
-                get_sink_info_callback, &a);
-        while (!a.last) {
-            if (PULSEAUDIO_pa_operation_get_state(o) == PA_OPERATION_CANCELLED) {
-                break;
-            }
-            if (PULSEAUDIO_pa_mainloop_iterate(mainloop, 1, NULL) < 0) {
-                break;
-            }
-        }
-    }
+    done = SDL_FALSE;
+    RunPulseDetectCallback(mainloop, PULSEAUDIO_pa_context_get_sink_info_list(context, get_sinks_cb, &done), &done);
+    done = SDL_FALSE;
+    RunPulseDetectCallback(mainloop, PULSEAUDIO_pa_context_get_source_info_list(context, get_sources_cb, &done), &done);
 
     DisconnectFromPulseServer(mainloop, context);
 }
 
 static void
+PULSEAUDIO_FreeDeviceHandle(void *handle)
+{
+    SDL_free(handle);  /* just a string we copied. */
+}
+
+static void
 PULSEAUDIO_Deinitialize(void)
 {
     UnloadPulseAudioLibrary();
@@ -593,6 +619,7 @@
     impl->GetDeviceBuf = PULSEAUDIO_GetDeviceBuf;
     impl->CloseDevice = PULSEAUDIO_CloseDevice;
     impl->WaitDone = PULSEAUDIO_WaitDone;
+    impl->FreeDeviceHandle = PULSEAUDIO_FreeDeviceHandle;
     impl->Deinitialize = PULSEAUDIO_Deinitialize;
 
     return 1;   /* this audio target is available. */