I just did some work with audio on SDL2. I had some troubles with selecting an audio device on pulseaudio. Somehow it always seemed to fall back to the default device.
A had a quick look over the code and fixed the problem (at least for me). Additionally it adds support for multi-device audio and device detection. If you are interested here is the patch for (SDL2-2.0.3) but I found no difference with the current repo.
Code:
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 */
And I assume it is necessary to add: It is ok the add it to the SDL2 Codebase under the zlib license
void (*segfault)(void) = 0;
int main(int argc, char **argv){segfault(); return 0;}
//Should not work, but does what told