/* Pulse Audio sound handler * * Copyright 2008 Chris Bagwell And Sundry Contributors */ #include "sox_i.h" #include #include 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", (size_t)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; if (!nsamp) return 0; /* 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; } LSX_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; }