diff -r 5bf21e9e191f src/audio/pulseaudio/SDL_pulseaudio.c --- a/src/audio/pulseaudio/SDL_pulseaudio.c Sun Sep 14 19:44:53 2014 +0200 +++ b/src/audio/pulseaudio/SDL_pulseaudio.c Sun Sep 14 21:40:27 2014 +0200 @@ -106,6 +106,7 @@ static int load_pulseaudio_syms(void); +pa_operation* (*PULSEAUDIO_pa_context_get_sink_info_list)(pa_context *c, pa_sink_info_cb_t cb, void *userdata); #ifdef SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC @@ -202,11 +203,31 @@ SDL_PULSEAUDIO_SYM(pa_stream_disconnect); SDL_PULSEAUDIO_SYM(pa_stream_unref); SDL_PULSEAUDIO_SYM(pa_channel_map_init_auto); + SDL_PULSEAUDIO_SYM(pa_context_get_sink_info_list); SDL_PULSEAUDIO_SYM(pa_strerror); return 0; } +static void DeInit(struct SDL_PrivateAudioData *pulse_local_server) +{ + if (pulse_local_server != NULL) + { + if (pulse_local_server->context != NULL) + { + PULSEAUDIO_pa_context_disconnect(pulse_local_server->context); + PULSEAUDIO_pa_context_unref(pulse_local_server->context); + pulse_local_server->context = NULL; + } + if (pulse_local_server->mainloop != NULL) { + PULSEAUDIO_pa_mainloop_free(pulse_local_server->mainloop); + pulse_local_server->mainloop = NULL; + } + SDL_free(pulse_local_server); + } +} + + /* Check to see if we can connect to PulseAudio */ static SDL_bool CheckPulseAudioAvailable() @@ -307,16 +328,7 @@ PULSEAUDIO_pa_stream_unref(this->hidden->stream); this->hidden->stream = NULL; } - if (this->hidden->context != NULL) { - PULSEAUDIO_pa_context_disconnect(this->hidden->context); - PULSEAUDIO_pa_context_unref(this->hidden->context); - this->hidden->context = NULL; - } - if (this->hidden->mainloop != NULL) { - PULSEAUDIO_pa_mainloop_free(this->hidden->mainloop); - this->hidden->mainloop = NULL; - } - SDL_free(this->hidden); + DeInit(this->hidden); this->hidden = NULL; } } @@ -344,6 +356,53 @@ return "SDL Application"; /* oh well. */ } + +static struct SDL_PrivateAudioData *ThreadInit() +{ + struct SDL_PrivateAudioData *h = NULL; + int state = 0; + + struct SDL_PrivateAudioData *pulse_local_server = SDL_malloc((sizeof *pulse_local_server)); + + if (pulse_local_server == NULL) { + return 0; + } + SDL_memset(pulse_local_server, 0, (sizeof *pulse_local_server)); + h = pulse_local_server; + + /* Set up a new main loop */ + if (!(h->mainloop = PULSEAUDIO_pa_mainloop_new())) { + DeInit(pulse_local_server); + return 0; + } + + h->mainloop_api = PULSEAUDIO_pa_mainloop_get_api(h->mainloop); + h->context = PULSEAUDIO_pa_context_new(h->mainloop_api, getAppName()); + if (!h->context) { + DeInit(pulse_local_server); + return 0; + } + + /* Connect to the PulseAudio server */ + if (PULSEAUDIO_pa_context_connect(h->context, NULL, 0, NULL) < 0) { + DeInit(pulse_local_server); + return 0; + } + + do { + if (PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) { + DeInit(pulse_local_server); + return 0; + } + state = PULSEAUDIO_pa_context_get_state(h->context); + if (!PA_CONTEXT_IS_GOOD(state)) { + DeInit(pulse_local_server); + return 0; + } + } while (state != PA_CONTEXT_READY); + return pulse_local_server; +} + static int PULSEAUDIO_OpenDevice(_THIS, const char *devname, int iscapture) { @@ -356,12 +415,12 @@ int state = 0; /* Initialize all variables that we clean on shutdown */ - this->hidden = (struct SDL_PrivateAudioData *) - SDL_malloc((sizeof *this->hidden)); + this->hidden = ThreadInit(); + if (this->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_memset(this->hidden, 0, (sizeof *this->hidden)); + h = this->hidden; paspec.format = PA_SAMPLE_INVALID; @@ -448,36 +507,6 @@ PA_CHANNEL_MAP_WAVEEX); /* Set up a new main loop */ - if (!(h->mainloop = PULSEAUDIO_pa_mainloop_new())) { - PULSEAUDIO_CloseDevice(this); - return SDL_SetError("pa_mainloop_new() failed"); - } - - h->mainloop_api = PULSEAUDIO_pa_mainloop_get_api(h->mainloop); - h->context = PULSEAUDIO_pa_context_new(h->mainloop_api, getAppName()); - if (!h->context) { - PULSEAUDIO_CloseDevice(this); - return SDL_SetError("pa_context_new() failed"); - } - - /* Connect to the PulseAudio server */ - if (PULSEAUDIO_pa_context_connect(h->context, NULL, 0, NULL) < 0) { - PULSEAUDIO_CloseDevice(this); - return SDL_SetError("Could not setup connection to PulseAudio"); - } - - do { - if (PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) { - PULSEAUDIO_CloseDevice(this); - return SDL_SetError("pa_mainloop_iterate() failed"); - } - state = PULSEAUDIO_pa_context_get_state(h->context); - if (!PA_CONTEXT_IS_GOOD(state)) { - PULSEAUDIO_CloseDevice(this); - return SDL_SetError("Could not connect to PulseAudio"); - } - } while (state != PA_CONTEXT_READY); - h->stream = PULSEAUDIO_pa_stream_new( h->context, "Simple DirectMedia Layer", /* stream description */ @@ -490,7 +519,7 @@ return SDL_SetError("Could not set up PulseAudio stream"); } - if (PULSEAUDIO_pa_stream_connect_playback(h->stream, NULL, &paattr, flags, + if (PULSEAUDIO_pa_stream_connect_playback(h->stream, devname, &paattr, flags, NULL, NULL) < 0) { PULSEAUDIO_CloseDevice(this); return SDL_SetError("Could not connect PulseAudio stream"); @@ -519,6 +548,58 @@ UnloadPulseAudioLibrary(); } + + +typedef struct +{ + uint8_t last; + SDL_AddAudioDevice addfn; +} sink_struct; + +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; + if(i) + { + a->addfn(i->name); + } +} + +void PULSEAUDIO_DetectDevices(int iscapture, SDL_AddAudioDevice addfn) +{ + struct SDL_PrivateAudioData *h = NULL; + struct SDL_PrivateAudioData *pulse_local_server = ThreadInit(); + + if(pulse_local_server == NULL) + { + //Out of Memory + return; + } + + sink_struct a; + h = pulse_local_server; + + if(iscapture != 1) + { + a.last = 0; + a.addfn = addfn; + pa_operation* o = PULSEAUDIO_pa_context_get_sink_info_list(h->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(h->mainloop, 1, NULL) < 0) { + break; + } + } + } + DeInit(pulse_local_server); +} + static int PULSEAUDIO_Init(SDL_AudioDriverImpl * impl) { @@ -530,8 +611,9 @@ UnloadPulseAudioLibrary(); return 0; } - + /* Set the function pointers */ + impl->DetectDevices = PULSEAUDIO_DetectDevices; impl->OpenDevice = PULSEAUDIO_OpenDevice; impl->PlayDevice = PULSEAUDIO_PlayDevice; impl->WaitDevice = PULSEAUDIO_WaitDevice; @@ -539,7 +621,7 @@ impl->CloseDevice = PULSEAUDIO_CloseDevice; impl->WaitDone = PULSEAUDIO_WaitDone; impl->Deinitialize = PULSEAUDIO_Deinitialize; - impl->OnlyHasDefaultOutputDevice = 1; + impl->OnlyHasDefaultOutputDevice = 0; return 1; /* this audio target is available. */ } diff -r 5bf21e9e191f src/audio/pulseaudio/SDL_pulseaudio.h --- a/src/audio/pulseaudio/SDL_pulseaudio.h Sun Sep 14 19:44:53 2014 +0200 +++ b/src/audio/pulseaudio/SDL_pulseaudio.h Sun Sep 14 21:40:27 2014 +0200 @@ -30,6 +30,7 @@ /* Hidden "this" pointer for the audio functions */ #define _THIS SDL_AudioDevice *this + struct SDL_PrivateAudioData { /* pulseaudio structures */