The SDL forums have moved to discourse.libsdl.org.
This is just a read-only archive of the previous forums, to keep old links working.


SDL Forum Index
SDL
Simple Directmedia Layer Forums
Pulseaudio, selecting Audio Device + multiple Audio
dfrizel


Joined: 14 Sep 2014
Posts: 7
Location: Vienna / Austria
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
dfrizel


Joined: 14 Sep 2014
Posts: 7
Location: Vienna / Austria
Added it to bugzilla - have only found it today Embarrassed
Pulseaudio, selecting Audio Device + multiple Audio
Daniel Holth
Guest

That's great, I've found it very frustrating trying to use HDMI audio - maybe this will fix it.


On Tue, Sep 16, 2014 at 1:39 PM, dfrizel wrote:
Quote:
Added it to bugzilla - have only found it today



void (*segfault)(void) = 0;
int main(int argc, char **argv){segfault(); return 0;}
//Should not work, but does what told


_______________________________________________
SDL mailing list

http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org