shithub: sox

Download patch

ref: d58638ae87b0cd38175037dee2cb1cca71b418f9
parent: eedad64208780414db696a8f2d2e81de80ef2df8
author: cbagwell <cbagwell>
date: Thu Dec 4 21:05:40 EST 2008

Initial pass at a pulse audio driver.

--- a/configure.ac
+++ b/configure.ac
@@ -264,6 +264,21 @@
 AM_CONDITIONAL(HAVE_COREAUDIO, test x$enable_coreaudio = xyes)
 AC_SUBST(COREAUDIO_LIBS)
 
+dnl Check for Pulse Audio
+AC_MSG_CHECKING([whether to try building Pulse Audio driver])
+AC_ARG_ENABLE(pulseaudio,
+    AC_HELP_STRING([--disable-pulseaudio], [Don't build Pulse Audio driver.]),,enable_pulseaudio=yes)
+AC_MSG_RESULT($enable_pulseaudio)
+if test "$enable_pulseaudio" = "yes"; then
+    AC_CHECK_HEADERS(pulse/simple.h, [PULSEAUDIO_LIBS="$PULSEAUDIO_LIBS -lpulse -lpulse-simple"], enable_pulseaudio=no)
+fi
+if test "$enable_pulseaudio" = yes; then
+   AC_DEFINE(HAVE_PULSEAUDIO, 1, [Define to 1 if you have Pulse Audio.])
+   audio_driver_found=yes
+fi
+AM_CONDITIONAL(HAVE_PULSEAUDIO, test x$enable_pulseaudio = xyes)
+AC_SUBST(PULSEAUDIO_LIBS)
+
 dnl Check if we want to disable all symlinks
 AC_MSG_CHECKING([whether to enable symlinks])
 AC_ARG_ENABLE(symlinks,
@@ -619,6 +634,7 @@
 echo "OSS driver........................ $enable_oss"
 echo "SUN audio driver.................. $enable_sun_audio"
 echo "CoreAudio driver.................. $enable_coreaudio"
+echo "Pulse Audio driver................ $enable_pulseaudio"
 echo "symlinks enabled.................. $enable_symlinks"
 echo "play and rec symlinks............. $enable_playrec_symlinks"
 echo "libgsm............................ $gsm_option"
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -128,6 +128,11 @@
 libsox_fmt_maud_la_LIBADD = libsox.la
 libsox_fmt_prc_la_SOURCES = prc.c
 libsox_fmt_prc_la_LIBADD = libsox.la
+if HAVE_PULSEAUDIO
+libsox_fmt_pulseaudio_la_SOURCES = pulseaudio.c
+libsox_fmt_pulseaudio_la_LIBADD = libsox.la @PULSEAUDIO_LIBS@
+pkglib_LTLIBRARIES += libsox_fmt_pulseaudio.la
+endif
 libsox_fmt_sf_la_SOURCES = sf.c
 libsox_fmt_sf_la_LIBADD = libsox.la
 libsox_fmt_smp_la_SOURCES = smp.c
@@ -330,6 +335,11 @@
     libsox_la_SOURCES += coreaudio.c
     libsox_la_LIBADD += @COREAUDIO_LIBS@
     sox_LDADD += @COREAUDIO_LIBS@
+endif
+if HAVE_PULSEAUDIO
+    libsox_la_SOURCES += pulseaudio.c
+    libsox_la_LIBADD += @PULSEAUDIO_LIBS@
+    sox_LDADD += @PULSEAUDIO_LIBS@
 endif
 if HAVE_WAVPACK
     libsox_la_SOURCES += wavpack.c
--- a/src/coreaudio.c
+++ b/src/coreaudio.c
@@ -104,6 +104,21 @@
     return SOX_EOF;
   }
 
+  /* If user doesn't specify, default to some reasonable values.
+   * Since this is mainly for recording case, default to typical
+   * 16-bit values to prevent saving larger files then average user
+   * wants.  Power users can override to 32-bit if they wish.
+   */
+  if (ft->signal.channels == 0)
+    ft->signal.channels = 2;
+  if (ft->signal.rate == 0)
+    ft->signal.rate = 44100;
+  if (ft->encoding.bits_per_sample == 0)
+  {
+    ft->encoding.bits_per_sample = 16;
+    ft->encoding.encoding = SOX_ENCODING_SIGN2;
+  }
+
   /* TODO: My limited experience with hardware can only get floats working which a fixed sample
    * rate and stereo.  I know that is a limitiation of audio device I have so this may not be
    * standard operating orders.  If some hardware supports setting sample rates and channel counts
--- /dev/null
+++ b/src/pulseaudio.c
@@ -1,0 +1,169 @@
+/* Pulse Audio sound handler
+ *
+ * Copyright 2008 Chris Bagwell And Sundry Contributors
+ */
+
+#include "sox_i.h"
+
+#include <pulse/simple.h>
+#include <pulse/error.h>
+
+typedef struct {
+  pa_simple *pasp;
+} priv_t;
+
+static int setup(sox_format_t *ft, int is_input)
+{
+  priv_t *pa = (priv_t *)ft->priv;
+  char *server;
+  pa_stream_direction_t dir;
+  char *app_str;
+  char *dev;
+  pa_sample_spec spec;
+  int error;
+
+  /* TODO: If user specified device of type "server:dev" then
+   * break up and override server.
+   */
+  server = NULL;
+
+  if (is_input)
+  {
+    dir = PA_STREAM_RECORD;
+    app_str = "record";
+  }
+  else
+  {
+    dir = PA_STREAM_PLAYBACK;
+    app_str = "playback";
+  }
+
+  if (strncmp(ft->filename, "default", 7) == 0)
+    dev = NULL;
+  else
+    dev = ft->filename;
+
+  /* If user doesn't specify, default to some reasonable values.
+   * Since this is mainly for recording case, default to typical
+   * 16-bit values to prevent saving larger files then average user
+   * wants.  Power users can override to 32-bit if they wish.
+   */
+  if (ft->signal.channels == 0)
+    ft->signal.channels = 2;
+  if (ft->signal.rate == 0)
+    ft->signal.rate = 44100;
+  if (ft->encoding.bits_per_sample == 0)
+  {
+    ft->encoding.bits_per_sample = 16;
+    ft->encoding.encoding = SOX_ENCODING_SIGN2;
+  }
+ 
+  spec.format = PA_SAMPLE_S32NE;
+  spec.rate = ft->signal.rate;
+  spec.channels = ft->signal.channels;
+
+  pa->pasp = pa_simple_new(server, "SoX", dir, dev, app_str, &spec,
+                          NULL, NULL, &error);
+
+  if (pa->pasp == NULL)
+  {
+    lsx_fail_errno(ft, SOX_EPERM, "can not open audio device: %s", pa_strerror(error));
+    return SOX_EOF;
+  }
+
+  /* TODO: Is it better to convert format/rates in SoX or in
+   * always let Pulse Audio do it?  Since we don't know what
+   * hardware prefers, assume it knows best and give it
+   * what user specifies.
+   */
+
+  return SOX_SUCCESS;
+}
+
+static int startread(sox_format_t *ft)
+{
+    return setup(ft, 1);
+}
+
+static int stopread(sox_format_t * ft)
+{
+  priv_t *pa = (priv_t *)ft->priv;
+
+  pa_simple_free(pa->pasp);
+
+  return SOX_SUCCESS;
+}
+
+static size_t read_samples(sox_format_t *ft, sox_sample_t *buf, size_t nsamp)
+{
+  priv_t *pa = (priv_t *)ft->priv;
+  size_t len;
+  int rc, error;
+
+  /* Pulse Audio buffer lengths are true buffer lengths and not
+   * count of samples. */
+  len = nsamp * sizeof(sox_sample_t);
+
+  rc = pa_simple_read(pa->pasp, buf, len, &error);
+
+  if (rc < 0)
+  {
+    lsx_fail_errno(ft, SOX_EPERM, "error reading from pulse audio device: %s", pa_strerror(error));
+    return SOX_EOF;
+  }
+  else
+    return nsamp;
+}
+
+static int startwrite(sox_format_t * ft)
+{
+    return setup(ft, 0);
+}
+
+static size_t write_samples(sox_format_t *ft, const sox_sample_t *buf, size_t nsamp)
+{
+  priv_t *pa = (priv_t *)ft->priv;
+  size_t len;
+  int rc, error;
+
+  /* Pulse Audio buffer lengths are true buffer lengths and not
+   * count of samples. */
+  len = nsamp * sizeof(sox_sample_t);
+
+  rc = pa_simple_write(pa->pasp, buf, len, &error);
+
+  if (rc < 0)
+  {
+    lsx_fail_errno(ft, SOX_EPERM, "error writing to pulse audio device: %s", pa_strerror(error));
+    return SOX_EOF;
+  }
+
+  return nsamp;
+}
+
+static int stopwrite(sox_format_t * ft)
+{
+  priv_t *pa = (priv_t *)ft->priv;
+  int error;
+
+  pa_simple_drain(pa->pasp, &error);
+  pa_simple_free(pa->pasp);
+
+  return SOX_SUCCESS;
+}
+
+SOX_FORMAT_HANDLER(pulseaudio)
+{
+  static char const *const names[] = { "pulseaudio", NULL };
+  static unsigned const write_encodings[] = {
+    SOX_ENCODING_SIGN2, 32, 0,
+    0};
+  static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE,
+    "Pulse Audio client",
+    names, SOX_FILE_DEVICE | SOX_FILE_NOSTDIO,
+    startread, read_samples, stopread,
+    startwrite, write_samples, stopwrite,
+    NULL, write_encodings, NULL, sizeof(priv_t)
+  };
+  return &handler;
+}
--- a/src/sox.c
+++ b/src/sox.c
@@ -2142,7 +2142,7 @@
     return NULL;
   if (!strcmp(type, "sunau")) name = "/dev/audio";
   else if (!strcmp(type, "oss" ) || !strcmp(type, "ossdsp")) name = "/dev/dsp";
-  else if (!strcmp(type, "alsa") || !strcmp(type, "ao") || !strcmp(type, "coreaudio")) name = "default";
+  else if (!strcmp(type, "alsa") || !strcmp(type, "ao") || !strcmp(type, "coreaudio") || !strcmp(type, "pulseaudio")) name = "default";
   return name? from_env? from_env : name : NULL;
 }
 
@@ -2153,6 +2153,7 @@
   if (!f->filetype && sox_find_format("coreaudio", sox_false)) f->filetype = "coreaudio";
   if (!f->filetype && sox_find_format("alsa", sox_false)) f->filetype = "alsa";
   if (!f->filetype && sox_find_format("oss" , sox_false)) f->filetype = "oss";
+  if (!f->filetype && sox_find_format("pulseaudio" , sox_false)) f->filetype = "pulseaudio";
   if (!f->filetype && sox_find_format("sunau",sox_false)) f->filetype = "sunau";
   if (!f->filetype && sox_find_format("ao"  , sox_false) && file_count) /*!rec*/
     f->filetype = "ao";