PulseAudio: Improved multidevice support.
authorRyan C. Gordon <icculus@icculus.org>
Wed, 18 Mar 2015 10:29:04 -0400
changeset 939565e946d15533
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
     1.1 --- a/src/audio/pulseaudio/SDL_pulseaudio.c	Wed Mar 18 02:01:17 2015 -0400
     1.2 +++ b/src/audio/pulseaudio/SDL_pulseaudio.c	Wed Mar 18 10:29:04 2015 -0400
     1.3 @@ -84,6 +84,7 @@
     1.4  static int (*PULSEAUDIO_pa_context_connect) (pa_context *, const char *,
     1.5      pa_context_flags_t, const pa_spawn_api *);
     1.6  static pa_operation * (*PULSEAUDIO_pa_context_get_sink_info_list)(pa_context *, pa_sink_info_cb_t, void *);
     1.7 +static pa_operation * (*PULSEAUDIO_pa_context_get_source_info_list)(pa_context *, pa_source_info_cb_t, void *);
     1.8  static pa_context_state_t (*PULSEAUDIO_pa_context_get_state) (pa_context *);
     1.9  static void (*PULSEAUDIO_pa_context_disconnect) (pa_context *);
    1.10  static void (*PULSEAUDIO_pa_context_unref) (pa_context *);
    1.11 @@ -186,6 +187,7 @@
    1.12      SDL_PULSEAUDIO_SYM(pa_context_new);
    1.13      SDL_PULSEAUDIO_SYM(pa_context_connect);
    1.14      SDL_PULSEAUDIO_SYM(pa_context_get_sink_info_list);
    1.15 +    SDL_PULSEAUDIO_SYM(pa_context_get_source_info_list);
    1.16      SDL_PULSEAUDIO_SYM(pa_context_get_state);
    1.17      SDL_PULSEAUDIO_SYM(pa_context_disconnect);
    1.18      SDL_PULSEAUDIO_SYM(pa_context_unref);
    1.19 @@ -380,6 +382,7 @@
    1.20  static int
    1.21  PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
    1.22  {
    1.23 +    const char *devstr = (const char *) handle;  /* NULL==default in Pulse. */
    1.24      struct SDL_PrivateAudioData *h = NULL;
    1.25      Uint16 test_format = 0;
    1.26      pa_sample_spec paspec;
    1.27 @@ -497,7 +500,7 @@
    1.28          return SDL_SetError("Could not set up PulseAudio stream");
    1.29      }
    1.30  
    1.31 -    if (PULSEAUDIO_pa_stream_connect_playback(h->stream, devname, &paattr, flags,
    1.32 +    if (PULSEAUDIO_pa_stream_connect_playback(h->stream, devstr, &paattr, flags,
    1.33              NULL, NULL) < 0) {
    1.34          PULSEAUDIO_CloseDevice(this);
    1.35          return SDL_SetError("Could not connect PulseAudio stream");
    1.36 @@ -519,50 +522,73 @@
    1.37      return 0;
    1.38  }
    1.39  
    1.40 -typedef struct
    1.41 +static void
    1.42 +get_sinks_cb(pa_context *c, const pa_sink_info *i, int is_last, void *data)
    1.43  {
    1.44 -    uint8_t last;
    1.45 -    SDL_AddAudioDevice addfn;
    1.46 -} sink_struct;
    1.47 +    SDL_bool *done = (SDL_bool *) data;
    1.48  
    1.49 -static void
    1.50 -get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata)
    1.51 -{
    1.52 -    sink_struct *a = (sink_struct *) userdata;
    1.53 -    a->last = is_last;
    1.54 +    *done = (is_list != 0);
    1.55      if (i) {
    1.56 -        a->addfn(i->name);
    1.57 +        char *handle = SDL_strdup(i->name);
    1.58 +        if (handle != NULL) {
    1.59 +            SDL_AddAudioDevice(SDL_FALSE, i->description, handle);
    1.60 +        }
    1.61      }
    1.62  }
    1.63  
    1.64  static void
    1.65 -PULSEAUDIO_DetectDevices(int iscapture, SDL_AddAudioDevice addfn)
    1.66 +get_sources_cb(pa_context *c, const pa_sink_info *i, int is_last, void *data)
    1.67 +{
    1.68 +    SDL_bool *done = (SDL_bool *) data;
    1.69 +
    1.70 +    *done = (is_list != 0);
    1.71 +    if (i) {
    1.72 +        char *handle = SDL_strdup(i->name);
    1.73 +        if (handle != NULL) {
    1.74 +            SDL_AddAudioDevice(SDL_TRUE, i->description, handle);
    1.75 +        }
    1.76 +    }
    1.77 +}
    1.78 +
    1.79 +static void
    1.80 +RunPulseDetectCallback(pa_mainloop *mainloop, pa_operation *o, SDL_bool *done)
    1.81 +{
    1.82 +    do {
    1.83 +        if (PULSEAUDIO_pa_operation_get_state(o) == PA_OPERATION_CANCELLED) {
    1.84 +            break;
    1.85 +        } else if (PULSEAUDIO_pa_mainloop_iterate(mainloop, 1, NULL) < 0) {
    1.86 +            break;
    1.87 +        }
    1.88 +    } while (*done == SDL_FALSE);
    1.89 +}
    1.90 +
    1.91 +static void
    1.92 +PULSEAUDIO_DetectDevices()
    1.93  {
    1.94      pa_mainloop *mainloop = NULL;
    1.95      pa_context *context = NULL;
    1.96 +    pa_operation *o = NULL;
    1.97 +    SDL_bool done;
    1.98  
    1.99      if (ConnectToPulseServer(&mainloop, &context) < 0) {
   1.100          return;
   1.101      }
   1.102  
   1.103 -    if (!iscapture) {
   1.104 -        sink_struct a = { 0, addfn };
   1.105 -        pa_operation *o = PULSEAUDIO_pa_context_get_sink_info_list(context,
   1.106 -                get_sink_info_callback, &a);
   1.107 -        while (!a.last) {
   1.108 -            if (PULSEAUDIO_pa_operation_get_state(o) == PA_OPERATION_CANCELLED) {
   1.109 -                break;
   1.110 -            }
   1.111 -            if (PULSEAUDIO_pa_mainloop_iterate(mainloop, 1, NULL) < 0) {
   1.112 -                break;
   1.113 -            }
   1.114 -        }
   1.115 -    }
   1.116 +    done = SDL_FALSE;
   1.117 +    RunPulseDetectCallback(mainloop, PULSEAUDIO_pa_context_get_sink_info_list(context, get_sinks_cb, &done), &done);
   1.118 +    done = SDL_FALSE;
   1.119 +    RunPulseDetectCallback(mainloop, PULSEAUDIO_pa_context_get_source_info_list(context, get_sources_cb, &done), &done);
   1.120  
   1.121      DisconnectFromPulseServer(mainloop, context);
   1.122  }
   1.123  
   1.124  static void
   1.125 +PULSEAUDIO_FreeDeviceHandle(void *handle)
   1.126 +{
   1.127 +    SDL_free(handle);  /* just a string we copied. */
   1.128 +}
   1.129 +
   1.130 +static void
   1.131  PULSEAUDIO_Deinitialize(void)
   1.132  {
   1.133      UnloadPulseAudioLibrary();
   1.134 @@ -593,6 +619,7 @@
   1.135      impl->GetDeviceBuf = PULSEAUDIO_GetDeviceBuf;
   1.136      impl->CloseDevice = PULSEAUDIO_CloseDevice;
   1.137      impl->WaitDone = PULSEAUDIO_WaitDone;
   1.138 +    impl->FreeDeviceHandle = PULSEAUDIO_FreeDeviceHandle;
   1.139      impl->Deinitialize = PULSEAUDIO_Deinitialize;
   1.140  
   1.141      return 1;   /* this audio target is available. */