Skip to content

Commit

Permalink
PulseAudio: Improved multidevice support.
Browse files Browse the repository at this point in the history
Added capture device enumeration, report human-readable device name, other
cleanups.
  • Loading branch information
icculus committed Mar 18, 2015
1 parent f9cfd9f commit 7c4b88f
Showing 1 changed file with 50 additions and 23 deletions.
73 changes: 50 additions & 23 deletions src/audio/pulseaudio/SDL_pulseaudio.c
Expand Up @@ -84,6 +84,7 @@ static pa_context * (*PULSEAUDIO_pa_context_new) (pa_mainloop_api *,
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 *);
Expand Down Expand Up @@ -186,6 +187,7 @@ load_pulseaudio_syms(void)
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);
Expand Down Expand Up @@ -380,6 +382,7 @@ PULSEAUDIO_CloseDevice(_THIS)
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;
Expand Down Expand Up @@ -497,7 +500,7 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
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");
Expand All @@ -519,49 +522,72 @@ PULSEAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
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;

*done = (is_list != 0);
if (i) {
char *handle = SDL_strdup(i->name);
if (handle != NULL) {
SDL_AddAudioDevice(SDL_FALSE, i->description, handle);
}
}
}

static void
get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata)
get_sources_cb(pa_context *c, const pa_sink_info *i, int is_last, void *data)
{
sink_struct *a = (sink_struct *) userdata;
a->last = is_last;
SDL_bool *done = (SDL_bool *) data;

*done = (is_list != 0);
if (i) {
a->addfn(i->name);
char *handle = SDL_strdup(i->name);
if (handle != NULL) {
SDL_AddAudioDevice(SDL_TRUE, i->description, handle);
}
}
}

static void
PULSEAUDIO_DetectDevices(int iscapture, SDL_AddAudioDevice addfn)
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)
{
Expand Down Expand Up @@ -593,6 +619,7 @@ PULSEAUDIO_Init(SDL_AudioDriverImpl * impl)
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. */
Expand Down

0 comments on commit 7c4b88f

Please sign in to comment.