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";