Initial work on a pulse audio backend, already plays back audio but needs more work.
authorAlexander Koenig <alex@lisas.de>
Mon, 27 Oct 2014 21:46:47 +0000 (22:46 +0100)
committerAlexander Koenig <alex@lisas.de>
Mon, 27 Oct 2014 21:46:47 +0000 (22:46 +0100)
configure.ac
src/tX_audiodevice.cc
src/tX_audiodevice.h
src/tX_dialog.cc
src/tX_engine.cc
src/tX_global.c
src/tX_global.h
src/tX_ui_interface.cc

index 2796e6ca333e6e13d7b0c1ef71851f3b65f9b084..bf327bbfc5e6c8758773f9660ba8ccc5e2e5861d 100644 (file)
@@ -16,6 +16,7 @@ AC_ARG_ENABLE(xsetpointer,    [  --enable-xsetpointer    enables executing of xsetp
 AC_ARG_ENABLE(alsa,            [  --enable-alsa           use ALSA for sound output (default=auto) ])
 AC_ARG_ENABLE(jack,            [  --enable-jack           use JACK for sound output (default=auto) ])
 AC_ARG_ENABLE(oss,             [  --enable-oss            use OSS for sound output (default=auto) ])
+AC_ARG_ENABLE(pulse,           [  --enable-pulse          use PULSE for sound output (default=auto) ])
 dnl AC_ARG_ENABLE(dga2,                [  --enable-dga2           use DGA2 instead of DGA1. (experimental) (default=no) ])
 AC_ARG_ENABLE(libxml2,         [  --disable-libxml2       use libxml even if verion 2 detected (default=auto) ])
 AC_ARG_ENABLE(mad,             [  --disable-mad           disable mad for mp3 support (default=auto) ])
@@ -40,6 +41,7 @@ AC_PROG_RANLIB
 OPTION_OSS="no"
 OPTION_ALSA="no"
 OPTION_JACK="no"
+OPTION_PULSE="no"
 OPTION_SOX="no"
 OPTION_MPG123="no"
 OPTION_MAD="no"
@@ -301,12 +303,13 @@ if test "$enable_xsetpointer" != "no"; then
 fi
 
 if test "$enable_movqfix" = "no"; then
-       AC_DEFINE_UNQUOTED([OVERRIDE_MOVQ_AUTODETECT], 1, [Don't use movqfix])
+       AC_DEFINE_UNQUOTED([OVERRIDE_MOVQ_AUTODETECT], 1, [Do nott use movqfix])
 fi
 
 using_alsa=no
 using_oss=no
 using_jack=no
+using_pulse=no
 
 if test "$enable_alsa" != "no"; then
     AC_CHECK_LIB(asound, snd_pcm_writei,alsalib=yes,alsalib=no)
@@ -320,12 +323,12 @@ if test "$enable_alsa" != "no"; then
                    OPTION_ALSA=yes
            else 
                    if test "$enable_alsa" = "yes"; then
-                           AC_MSG_ERROR([** Coulnd't find ALSA header file sys/asoundlib.h **])
+                           AC_MSG_ERROR([** Could not find ALSA header file sys/asoundlib.h **])
                    fi
            fi
     else
            if test "$enable_alsa" = "yes"; then
-                   AC_MSG_ERROR([** Coulnd'f find ALSA library libasound. **])
+                   AC_MSG_ERROR([** Could not find ALSA library libasound. **])
            fi
     fi
 fi
@@ -342,16 +345,39 @@ if test "$enable_jack" != "no"; then
                    OPTION_JACK=yes
            else 
                    if test "$enable_jack" = "yes"; then
-                           AC_MSG_ERROR([** Coulnd't find JACK header file jack/jack.h **])
+                           AC_MSG_ERROR([** Could not find JACK header file jack/jack.h **])
                    fi
            fi
     else
            if test "$enable_jack" = "yes"; then
-                   AC_MSG_ERROR([** Coulnd'f find JACK library libjack. **])
+                   AC_MSG_ERROR([** Could not find JACK library libjack. **])
            fi
     fi
 fi
 
+if test "$enable_pulse" != "no"; then
+    AC_CHECK_LIB(pulse-simple,pa_simple_new,pulselib=yes,pulselib=no)
+    AC_CHECK_HEADERS(pulse/pulseaudio.h,pulseheader=yes,pulseheader=no)
+
+    if test "$pulselib" = "yes"; then
+           if test "$pulseheader" = "yes"; then
+                   AC_DEFINE_UNQUOTED([USE_PULSE], 1, [ Define to enable PULSE audio backend.])
+                   LIBS="$LIBS -lpulse-simple -lpulse"
+                   using_pulse=yes
+                   OPTION_PULSE=yes
+           else 
+                   if test "$enable_pulse" = "yes"; then
+                           AC_MSG_ERROR([** Could not find PULSE header file pulse/pulseaudio.h **])
+                   fi
+           fi
+    else
+           if test "$enable_pulse" = "yes"; then
+                   AC_MSG_ERROR([** Could not find PULSE library libpulse. **])
+           fi
+    fi
+
+fi
+
 
 if test "$enable_oss" != "no"; then
        AC_CHECK_HEADERS(sys/ioctl.h sys/soundcard.h,oss=yes,oss=no)
@@ -362,7 +388,7 @@ if test "$enable_oss" != "no"; then
                using_oss=yes;
        else
                if test "$enable_oss" = "yes"; then
-                       AC_MSG_ERROR([** Couldn't find OSS header files. ***])
+                       AC_MSG_ERROR([** Could not find OSS header files. ***])
                fi
        fi
 fi
@@ -396,7 +422,9 @@ fi
 if test "$using_alsa" != "yes"; then
        if test "$using_oss" != "yes"; then
                if test "$using_jack" != "yes"; then
-                       AC_MSG_ERROR([** Found neither OSS, ALSA nor JACK - no output device! **])
+                       if test "$using_pulse" != "yes"; then
+                               AC_MSG_ERROR([** Found neither OSS, ALSA, JACK nor PULSE - no output device! **])
+                       fi
                fi
        fi
 fi     
@@ -614,6 +642,9 @@ option_info;
 option=jack; option_val=$OPTION_JACK; option_url=http://jackit.sourceforge.net
 option_info;
 
+option=pulse; option_val=$OPTION_PULSE; option_url=http://www.freedesktop.org/wiki/Software/PulseAudio/
+option_info;
+
 option=mad; option_val=$OPTION_MAD; option_url=http://www.mars.org/home/rob/proj/mpeg/
 option_info;
 
index 905aa3f253a82cd1244befb110244e9e3217dbcc..e3b16f51b264c2e648c67a5a3b61466f72239fa4 100644 (file)
@@ -351,6 +351,81 @@ void tX_audiodevice_alsa :: play(int16_t *buffer)
 
 #endif //USE_ALSA
 
+#ifdef USE_PULSE
+#include <pulse/error.h>
+
+int tX_audiodevice_pulse :: open()
+{
+       int error;
+
+       /* pulse client based on pacat-simple.c API demo */
+       pa_sample_spec spec = {
+               .format = PA_SAMPLE_S16LE,
+               .rate = 44100,
+               .channels = 2
+       };
+
+       
+       pa_buffer_attr attr = {
+               .maxlength = -1,
+               .tlength = 2048,
+               .prebuf = 1,
+               .minreq = -1,
+               .fragsize = -1
+       };
+
+       attr.minreq = attr.tlength / 4;
+       attr.maxlength = attr.tlength + attr.minreq;
+
+       samples_per_buffer = attr.tlength / 2;
+       
+       /* Create a new playback stream */
+       if (!(stream = pa_simple_new(NULL, "terminatorX", PA_STREAM_PLAYBACK, NULL, "playback", &spec, NULL, &attr, &error))) {
+               tX_error("PULSE: Failed to open stream: %s", pa_strerror(error));
+               return -1;
+       }
+       
+       is_open = true;
+
+        pa_usec_t latency;
+
+        if ((latency = pa_simple_get_latency(stream, &error)) == (pa_usec_t) -1) {
+            tX_error("PULSE: Error getting latency  %s\n", pa_strerror(error));
+        }
+
+        tX_debug( "%0.0f usec    \r", (float)latency);
+
+       return 0;
+}
+
+int tX_audiodevice_pulse :: close()
+{
+       if (is_open) {
+               pa_simple_free(stream);
+               stream = NULL;
+       }
+
+       is_open=false;
+       
+       return 0;
+}
+
+tX_audiodevice_pulse :: tX_audiodevice_pulse() : tX_audiodevice(),
+stream(NULL) {}
+
+void tX_audiodevice_pulse :: play(int16_t *buffer)
+{
+       int error;
+
+        if (pa_simple_write(stream, buffer, (size_t) samples_per_buffer * 2, &error) < 0) {
+               tX_error("PULSE: playback failed: %s\n", pa_strerror(error));
+           return;
+        }
+}
+
+
+#endif //USE_PULSE
+
 #ifdef USE_JACK
 
 tX_jack_client tX_jack_client::instance;
index b2afd17690a470473d91d87173b938e86c9c45e7..2fe798c9ea98aea3a2fa46fe2b98c1501adc8024 100644 (file)
 #include <jack/jack.h>
 #endif
 
+#ifdef USE_PULSE
+#include <pulse/simple.h>
+#endif
+
 class tX_engine;
 
 class tX_audiodevice
@@ -107,6 +111,22 @@ class tX_audiodevice_alsa : public tX_audiodevice
 
 #endif
 
+#ifdef USE_PULSE
+
+class tX_audiodevice_pulse : public tX_audiodevice
+{
+       pa_simple *stream;
+       
+       public:
+       virtual int open();
+       virtual int close();
+       virtual void play(int16_t*);
+       
+       tX_audiodevice_pulse();
+};
+
+#endif
+
 #ifdef USE_JACK
 
 class tX_jack_client;
index 84b37e39428354253bf2632af7b87c965914bd9d..0332b6cb866d79abe6819a1b992029ac9de06555 100644 (file)
@@ -71,6 +71,9 @@ void apply_options(GtkWidget *dialog) {
                globals.audiodevice_type=OSS;
        } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(dialog, "jack_driver")))) {
                globals.audiodevice_type=JACK;
+       } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(dialog, "pulse_driver")))) {
+               printf("pulse\n");
+               globals.audiodevice_type=PULSE;
        }
        globals.use_realtime=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(dialog, "use_realtime")));
        
@@ -342,6 +345,9 @@ void init_tx_options(GtkWidget *dialog) {
                case JACK: gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(dialog, "jack_driver")), 1);
                        break;
 
+               case PULSE: gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(dialog, "pulse_driver")), 1);
+                       break;
+
                case OSS: 
                default:
                        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lookup_widget(dialog, "oss_driver")), 1);
index 7adf96a477e994be9bf3629c1508218c0b84192f..6004000f530da2acb7d6ebcde509074bc41f809e 100644 (file)
@@ -205,19 +205,25 @@ tX_engine_error tX_engine :: run() {
 #ifdef USE_OSS 
                case OSS:
                        device=new tX_audiodevice_oss(); 
-               break;
+                       break;
 #endif                 
 
 #ifdef USE_ALSA                        
                case ALSA:
                        device=new tX_audiodevice_alsa(); 
-               break;
+                       break;
 #endif
 
 #ifdef USE_JACK
                case JACK:
                        device=new tX_audiodevice_jack();
-               break;
+                       break;
+#endif
+
+#ifdef USE_PULSE
+               case PULSE:
+                       device=new tX_audiodevice_pulse();
+                       break;
 #endif
                
                default:
index 62ca1a7a24812d196f9942510248c6653a498804..276668fef049a4a30c9abcc9ba3e5f4e1e7d5f18 100644 (file)
@@ -269,8 +269,9 @@ int load_globals_xml() {
 
        xmlFreeDoc(doc);
        
-       if (strcmp(device_type, "alsa")==0) globals.audiodevice_type=ALSA;
-       else if (strcmp(device_type, "jack")==0) globals.audiodevice_type=JACK;
+       if (strcmp(device_type, "alsa")==0) { globals.audiodevice_type=ALSA; }
+       else if (strcmp(device_type, "jack")==0) { globals.audiodevice_type=JACK; }
+       else if (strcmp(device_type, "pulse")==0) { globals.audiodevice_type=PULSE; }
        else globals.audiodevice_type=OSS;
        
        return 0;
@@ -290,6 +291,9 @@ void store_globals() {
        rc=fopen(rc_name, "w");
        
        switch (globals.audiodevice_type) {
+               case PULSE:
+                       strcpy(device_type, "pulse");
+                       break;
                case JACK:
                        strcpy(device_type, "jack");
                        break;
index 84e2f8fb4db28e5fc49e057c959836672863fcfc..d9e5477ca1f721aad604e90841195ed0cbb675c9 100644 (file)
@@ -72,7 +72,8 @@ extern "C" {
 typedef enum {
        OSS =0,
        ALSA = 1,
-       JACK = 2
+       JACK = 2,
+       PULSE = 3
 } tX_audiodevice_type;
        
 typedef struct {
index d7aa644c88881d93dac8df69e52bfb754e22d63c..d091108a231033827e3fc98c4bded8b5a0e5c64a 100644 (file)
@@ -138,6 +138,7 @@ create_tx_options (void)
   GSList *oss_driver_group = NULL;
   GtkWidget *alsa_driver;
   GtkWidget *jack_driver;
+  GtkWidget *pulse_driver;
   GtkWidget *use_realtime_label;
   GtkWidget *use_realtime;
   GtkWidget *label1;
@@ -292,6 +293,13 @@ create_tx_options (void)
   gtk_widget_set_tooltip_text(jack_driver, "Use the JACK (JACK Audio Connection Kit) driver for audio output.");
   gtk_radio_button_set_group (GTK_RADIO_BUTTON (jack_driver), oss_driver_group);
   oss_driver_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (jack_driver));
+  pulse_driver = gtk_radio_button_new_with_mnemonic (NULL, "PULSE");
+  gtk_widget_show (pulse_driver);
+  gtk_box_pack_start (GTK_BOX (hbox2), pulse_driver, FALSE, FALSE, 0);
+  gtk_widget_set_tooltip_text(pulse_driver, "Use the PULSE (PulseAudio) driver for audio output.");
+  gtk_radio_button_set_group (GTK_RADIO_BUTTON (pulse_driver), oss_driver_group);
+  oss_driver_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (pulse_driver));
 
   use_realtime_label = gtk_label_new ("Scheduling:");
   gtk_widget_show (use_realtime_label);
@@ -899,6 +907,7 @@ create_tx_options (void)
   TX_UI_HOOKUP_OBJECT (tx_options, oss_driver, "oss_driver");
   TX_UI_HOOKUP_OBJECT (tx_options, alsa_driver, "alsa_driver");
   TX_UI_HOOKUP_OBJECT (tx_options, jack_driver, "jack_driver");
+  TX_UI_HOOKUP_OBJECT (tx_options, pulse_driver, "pulse_driver");
   TX_UI_HOOKUP_OBJECT (tx_options, use_realtime_label, "use_realtime_label");
   TX_UI_HOOKUP_OBJECT (tx_options, use_realtime, "use_realtime");
   TX_UI_HOOKUP_OBJECT (tx_options, label1, "label1");