chiark / gitweb /
uaudio: pulseaudio support
authorRichard Kettlewell <rjk@terraraq.org.uk>
Thu, 7 Nov 2013 17:03:32 +0000 (17:03 +0000)
committerRichard Kettlewell <rjk@terraraq.org.uk>
Thu, 7 Nov 2013 17:03:32 +0000 (17:03 +0000)
Playback only, no volume setting.

clients/Makefile.am
clients/playrtp.c
configure.ac
disobedience/Makefile.am
doc/disorder-playrtp.1.in
lib/Makefile.am
lib/uaudio-apis.c
lib/uaudio-pulseaudio.c [new file with mode: 0644]
lib/uaudio.h
server/Makefile.am
server/speaker.c

index 6ed9f4ab60e8c9c26a3942285448a42a3aaa9c6c..991554bc47252648fab360e7e6f07da491eb0cb6 100644 (file)
@@ -34,9 +34,10 @@ disorderfm_LDADD=$(LIBOBJS) ../lib/libdisorder.a $(LIBGC) $(LIBICONV)
 disorderfm_DEPENDENCIES=$(LIBOBJS) ../lib/libdisorder.a
 
 disorder_playrtp_SOURCES=playrtp.c playrtp.h playrtp-mem.c
+disorder_playrtp_CFLAGS=$(PULSEAUDIO_CFLAGS) $(PULSEAUDIO_SIMPLE_CFLAGS)
 disorder_playrtp_LDADD=$(LIBOBJS) ../lib/libdisorder.a \
        $(LIBASOUND) $(LIBPCRE) $(LIBICONV) $(LIBGCRYPT) $(COREAUDIO) \
-       $(LIBPTHREAD) -lm
+       $(LIBPTHREAD) $(PULSEAUDIO_SIMPLE_LIBS) $(PULSEAUDIO_LIBS) -lm
 disorder_playrtp_DEPENDENCIES=$(LIBOBJS) ../lib/libdisorder.a
 
 rtpmon_SOURCES=rtpmon.c
index 59561224c9e03e2af40e10ae2d6f4ffca1db1679..600aae164e59bac9137216054b35cba83625a6c7 100644 (file)
@@ -855,6 +855,7 @@ int main(int argc, char **argv) {
    * the format before we know what it is! */
   uaudio_set_format(44100/*Hz*/, 2/*channels*/,
                     16/*bits/channel*/, 1/*signed*/);
+  uaudio_set("application", "disorder-playrtp");
   backend->start(playrtp_callback, NULL);
   /* We receive and convert audio data in a background thread */
   if((err = pthread_create(&ltid, 0, listen_thread, 0)))
index 37ef7cc4223904a4bacde21b4485a770626cdd1b..11085e0e9bbef47523947b3b4f3c74294ed8ebca 100644 (file)
@@ -39,6 +39,7 @@ want_cgi=yes
 want_alsa=yes
 want_oss=yes
 want_coreaudio=yes
+want_pulseaudio=yes
 
 # By default we don't want gtk-osx.  But if you ask for --with-gtk-osx...
 #
@@ -79,6 +80,10 @@ AC_ARG_WITH([alsa],
            [AS_HELP_STRING([--without-alsa],
                            [do not build with ALSA support])],
            [want_alsa=$withval])
+AC_ARG_WITH([pulseaudio],
+           [AS_HELP_STRING([--without-pulseaudio],
+                           [do not build with PulseAudio support])],
+           [want_pulseaudio=$withval])
 AC_ARG_WITH([oss],
            [AS_HELP_STRING([--without-oss],
                            [do not build with OSS support])],
@@ -446,6 +451,13 @@ if test $want_alsa = yes; then
   AC_CHECK_LIB([asound], [snd_pcm_open],
                [AC_SUBST(LIBASOUND,[-lasound])])
 fi
+if test $want_pulseaudio = yes; then
+  PKG_CHECK_MODULES([PULSEAUDIO],[libpulse],
+                    [AC_DEFINE([HAVE_PULSEAUDIO],[1],[define to 1 for PulseAudio support])],
+                    [missing_libraries="$missing_libraries libpulse"])
+  PKG_CHECK_MODULES([PULSEAUDIO_SIMPLE],[libpulse-simple],,
+                    [missing_libraries="$missing_libraries libpulse-simple"])
+fi
 AC_CHECK_LIB([samplerate],[src_new],
              [AC_SUBST([LIBSAMPLERATE],[-lsamplerate])])
 if test $want_server = yes; then
index fa41a2c3403ee6c7b51cd2603bc7db057f4e8ee4..4f7961477bed095d7ccb81b24b5c58555c85bf58 100644 (file)
@@ -30,7 +30,8 @@ disobedience_SOURCES=disobedience.h disobedience.c client.c queue.c   \
        popup.h playlists.c multidrag.c multidrag.h autoscroll.c        \
        autoscroll.h globals.c
 disobedience_LDADD=../lib/libdisorder.a $(LIBPCRE) $(LIBGC) $(LIBGCRYPT) \
-       $(LIBASOUND) $(COREAUDIO) $(LIBICONV) -lm
+       $(LIBASOUND) $(COREAUDIO) $(LIBICONV) -lm \
+       $(PULSEAUDIO_SIMPLE_LIBS) $(PULSEAUDIO_LIBS)
 disobedience_LDFLAGS=$(GTK_LIBS)
 
 install-data-local:
index abbeed5824d53517ceb585fe4e79197aab587d9d..228ae60bfdc613fd36405e31758d1dcfb22aa1fd 100644 (file)
@@ -43,6 +43,9 @@ Select the playback API.
 The possibilities are, depending on platform and compilation options:
 .RS 8
 .TP
+.B pulseaudio
+PulseAudio.
+.TP
 .B alsa
 ALSA.
 Linux only.
index 241c71e732b91d3dbb4a4e573f2fdd7179f4f0b1..4f7be92daf7a7d9929533add79d91c7719203ff0 100644 (file)
@@ -85,6 +85,7 @@ libdisorder_a_SOURCES=charset.c charsetf.c charset.h  \
        tracksort.c                                     \
        uaudio.c uaudio-thread.c uaudio.h uaudio-apis.c \
        uaudio-oss.c uaudio-alsa.c                      \
+       uaudio-pulseaudio.c                             \
        uaudio-coreaudio.c                              \
        uaudio-rtp.c uaudio-command.c uaudio-schedule.c \
        url.h url.c                                     \
index 568ae36ce8a22b4d22df1100ff264c6dedc127e2..867b1fdcc3503398d6636dd217018bcba3e5c780 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * This file is part of DisOrder.
- * Copyright (C) 2009 Richard Kettlewell
+ * Copyright (C) 2009, 2013 Richard Kettlewell
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -35,6 +35,9 @@ const struct uaudio *const uaudio_apis[] = {
 #if HAVE_COREAUDIO_AUDIOHARDWARE_H
   &uaudio_coreaudio,
 #endif  
+#if HAVE_PULSEAUDIO
+  &uaudio_pulseaudio,
+#endif
 #if HAVE_ALSA_ASOUNDLIB_H
   &uaudio_alsa,
 #endif
diff --git a/lib/uaudio-pulseaudio.c b/lib/uaudio-pulseaudio.c
new file mode 100644 (file)
index 0000000..f0124be
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * This file is part of DisOrder.
+ * Copyright (C) 2013 Richard Kettlewell
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/** @file lib/uaudio-pulseaudio.c
+ * @brief Support for PulseAudio backend */
+#include "common.h"
+
+#if HAVE_PULSEAUDIO
+
+#include <pulse/simple.h>
+#include <pulse/error.h>
+
+#include "mem.h"
+#include "log.h"
+#include "uaudio.h"
+#include "configuration.h"
+
+static const char *const pulseaudio_options[] = {
+  "application",
+  NULL
+};
+
+static pa_simple *pulseaudio_simple_handle;
+
+/** @brief Open the PulseAudio sound device */
+static void pulseaudio_open() {
+  pa_sample_spec ss;
+  int error;
+  ss.format = -1;
+  switch(uaudio_bits) {
+  case 8:
+    if(!uaudio_signed)
+      ss.format = PA_SAMPLE_U8;
+    break;
+  case 16:
+    if(uaudio_signed)
+      ss.format = PA_SAMPLE_S16NE;
+    break;
+  case 32:
+    if(uaudio_signed)
+      ss.format = PA_SAMPLE_S32NE;
+    break;
+  }
+  if(ss.format == -1)
+    disorder_fatal(0, "unsupported uaudio format (%d, %d)",
+                   uaudio_bits, uaudio_signed);
+  ss.channels = uaudio_channels;
+  ss.rate = uaudio_rate;
+  pulseaudio_simple_handle = pa_simple_new(NULL,
+                                           uaudio_get("application", "DisOrder"),
+                                           PA_STREAM_PLAYBACK,
+                                           NULL,
+                                           "DisOrder",
+                                           &ss,
+                                           NULL,
+                                           NULL,
+                                           &error);
+  if(!pulseaudio_simple_handle)
+    disorder_fatal(0, "pa_simple_new: %s", pa_strerror(error));
+}
+
+/** @brief Close the PulseAudio sound device */
+static void pulseaudio_close(void) {
+  pa_simple_free(pulseaudio_simple_handle);
+  pulseaudio_simple_handle = NULL;
+}
+
+/** @brief Actually play sound via PulseAudio */
+static size_t pulseaudio_play(void *buffer, size_t samples,
+                              unsigned attribute((unused)) flags) {
+  int error;
+  int ret = pa_simple_write(pulseaudio_simple_handle,
+                            buffer,
+                            samples * uaudio_sample_size,
+                            &error);
+  if(ret < 0)
+    disorder_fatal(0, "pa_simple_write: %s", pa_strerror(error));
+  return samples;
+}
+
+static void pulseaudio_start(uaudio_callback *callback,
+                             void *userdata) {
+  pulseaudio_open();
+  uaudio_thread_start(callback, userdata, pulseaudio_play,
+                      32 / uaudio_sample_size,
+                      4096 / uaudio_sample_size,
+                      0);
+}
+
+static void pulseaudio_stop(void) {
+  uaudio_thread_stop();
+  pulseaudio_close();
+}
+
+static void pulseaudio_open_mixer(void) {
+  disorder_error(0, "no pulseaudio mixer support yet");
+}
+
+static void pulseaudio_close_mixer(void) {
+}
+
+static void pulseaudio_get_volume(int *left, int *right) {
+  *left = *right = 0;
+}
+
+static void pulseaudio_set_volume(int *left, int *right) {
+  *left = *right = 0;
+}
+
+static void pulseaudio_configure(void) {
+}
+
+const struct uaudio uaudio_pulseaudio = {
+  .name = "pulseaudio",
+  .options = pulseaudio_options,
+  .start = pulseaudio_start,
+  .stop = pulseaudio_stop,
+  .activate = uaudio_thread_activate,
+  .deactivate = uaudio_thread_deactivate,
+  .open_mixer = pulseaudio_open_mixer,
+  .close_mixer = pulseaudio_close_mixer,
+  .get_volume = pulseaudio_get_volume,
+  .set_volume = pulseaudio_set_volume,
+  .configure = pulseaudio_configure,
+  .flags = UAUDIO_API_CLIENT,
+};
+
+#endif
+
+/*
+Local Variables:
+c-basic-offset:2
+comment-column:40
+fill-column:79
+indent-tabs-mode:nil
+End:
+*/
index 2a32d40d5148ae096b6be17f52344d4883ece836..631828f7cb54c04cfb82b400eec8464304d57a6d 100644 (file)
@@ -195,6 +195,10 @@ extern const struct uaudio uaudio_alsa;
 extern const struct uaudio uaudio_oss;
 #endif
 
+#if HAVE_PULSEAUDIO
+extern const struct uaudio uaudio_pulseaudio;
+#endif
+
 extern const struct uaudio uaudio_rtp;
 
 extern const struct uaudio uaudio_command;
index 8233cffabb3e198395f36297a736e940bbfb7123..400b0ab06e48ca45172cde6987707b59b657700a 100644 (file)
@@ -29,7 +29,8 @@ disorderd_SOURCES=disorderd.c api.c api-server.c daemonize.c play.c   \
        exports.c ../lib/memgc.c disorder-server.h
 disorderd_LDADD=$(LIBOBJS) ../lib/libdisorder.a \
        $(LIBPCRE) $(LIBDB) $(LIBGC) $(LIBGCRYPT) $(LIBICONV) \
-       $(LIBASOUND) $(COREAUDIO) $(LIBPTHREAD) $(LIBDL)
+       $(LIBASOUND) $(COREAUDIO) $(LIBPTHREAD) $(LIBDL) \
+       $(PULSEAUDIO_SIMPLE_LIBS) $(PULSEAUDIO_LIBS)
 disorderd_LDFLAGS=-export-dynamic
 disorderd_DEPENDENCIES=../lib/libdisorder.a
 
@@ -41,7 +42,8 @@ disorder_deadlock_DEPENDENCIES=../lib/libdisorder.a
 disorder_speaker_SOURCES=speaker.c
 disorder_speaker_LDADD=$(LIBOBJS) ../lib/libdisorder.a \
        $(LIBASOUND) $(LIBPCRE) $(LIBICONV) $(LIBGCRYPT) $(COREAUDIO) \
-       $(LIBPTHREAD)
+       $(LIBPTHREAD) \
+       $(PULSEAUDIO_SIMPLE_LIBS) $(PULSEAUDIO_LIBS)
 disorder_speaker_DEPENDENCIES=../lib/libdisorder.a
 
 disorder_decode_SOURCES=decode.c decode.h disorder-server.h    \
index a1b2d1d5f28d485412f106cf0167e26b3bf35a9b..fcfcf361a316beb8ec433c765f8c2f1370090024 100644 (file)
@@ -801,6 +801,7 @@ int main(int argc, char **argv) {
   /* backend-specific initialization */
   if(backend->configure)
     backend->configure();
+  uaudio_set("application", "disorder-speaker");
   backend->start(speaker_callback, NULL);
   /* create the private socket directory */
   byte_xasprintf(&dir, "%s/private", config->home);