diff --git a/acinclude.m4 b/acinclude.m4 index d89f9f6..1759b50 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -284,6 +284,38 @@ fi dnl ----------------------------------------------------------------------- +dnl TC_CHECK_SNDIO([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +dnl Test for sndio headers +dnl +AC_DEFUN([TC_CHECK_SNDIO], +[ +AC_MSG_CHECKING([whether sndio support is requested]) +AC_ARG_ENABLE(sndio, + AC_HELP_STRING([--enable-sndio], + [enable sndio support (no)]), + [case "${enableval}" in + yes) ;; + no) ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-sndio) ;; + esac], + [enable_sndio=no]) +AC_MSG_RESULT($enable_sndio) + +have_sndio="no" +if test x"$enable_sndio" = x"yes" ; then + AC_CHECK_HEADERS([sndio.h], [have_sndio="yes"]) + + if test x"$have_sndio" = x"yes" ; then + have_sndio="yes" + ifelse([$1], , :, [$1]) + else + AC_MSG_ERROR([sndio is requested, but cannot find headers]) + fi +fi +]) + +dnl ----------------------------------------------------------------------- + dnl TC_CHECK_OSS([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) dnl Test for OSS headers dnl diff --git a/configure.in b/configure.in index 03178c3..65567ae 100644 --- a/configure.in +++ b/configure.in @@ -721,6 +721,12 @@ TC_CHECK_SUNAU(AC_DEFINE([HAVE_SUNAU], 1, [Have Sun style audio(4)])) AM_CONDITIONAL(HAVE_SUNAU, test x"$have_sunau" = x"yes") dnl +dnl sndio +dnl +TC_CHECK_SNDIO(AC_DEFINE([HAVE_SNDIO], 1, [Have sndio(7) audio])) +AM_CONDITIONAL(HAVE_SNDIO, test x"$have_sndio" = x"yes") + +dnl dnl OSS dnl TC_CHECK_OSS(AC_DEFINE([HAVE_OSS], 1, [Have OSS audio])) @@ -1406,6 +1412,7 @@ ALSA $have_alsa OSS $have_oss bktr $have_bktr sunau $have_sunau +sndio $have_sndio optional module support ---------------------------------------- diff --git a/import/Makefile.am b/import/Makefile.am index fa0218f..c1ac26c 100644 --- a/import/Makefile.am +++ b/import/Makefile.am @@ -59,6 +59,10 @@ if HAVE_SUNAU IMPORT_SUNAU = import_sunau.la endif +if HAVE_SNDIO +IMPORT_SNDIO = import_sndio.la +endif + if HAVE_LIBXML2 IMPORT_XML = import_xml.la endif @@ -103,6 +107,7 @@ pkg_LTLIBRARIES = \ import_pvn.la \ import_raw.la \ $(IMPORT_SUNAU) \ + $(IMPORT_SNDIO) \ import_vag.la \ import_vnc.la \ import_vob.la \ @@ -199,6 +204,10 @@ import_raw_la_LDFLAGS = -module -avoid-version import_sunau_la_SOURCES = import_sunau.c import_sunau_la_LDFLAGS = -module -avoid-version +import_sndio_la_SOURCES = import_sndio.c +import_sndio_la_LDFLAGS = -module -avoid-version +import_sndio_la_LIBADD = -lsndio + import_vag_la_SOURCES = import_vag.c import_vag_la_LDFLAGS = -module -avoid-version diff --git b/import/import_sndio.c b/import/import_sndio.c new file mode 100644 index 0000000..864455b --- /dev/null +++ b/import/import_sndio.c @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2009 Jacob Meuser + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +#include "transcode.h" +#include "libtc/optstr.h" + +#include "libtc/tcmodule-plugin.h" + +#define MOD_NAME "import_sndio.so" +#define MOD_VERSION "v0.0.1 (2009-12-24)" +#define MOD_CAP "capture audio using sndio" +#define MOD_FEATURES \ + TC_MODULE_FEATURE_AUDIO | TC_MODULE_FEATURE_DEMULTIPLEX +#define MOD_FLAGS \ + TC_MODULE_FLAG_RECONFIGURABLE + +#include + +static int sndio_init(void *, const char *, int, int, int); +static int sndio_grab(void *, size_t, char *, size_t *); +static int sndio_stop(void *); + +struct tc_sndio_data { + struct sio_hdl *hdl; + struct sio_par par; +}; + +static const char tc_sndio_help[] = + "Overview:\n" + " Captures audio from sndio devices.\n" + "Options:\n" + " device=dev will use 'dev' as the sndio device\n" + " help prints this message\n"; + + +static int +sndio_init(void *data, const char *dev, int rate, int bits, int chan) +{ + struct tc_sndio_data *d = data; + + if (!strncmp(dev, "/dev/null", 9) || + !strncmp(dev, "/dev/zero", 9) || + !strncmp(dev, "default", 7) || + !strncmp(dev, "", 1)) + d->hdl = sio_open(NULL, SIO_REC, 0); + else + d->hdl = sio_open(dev, SIO_REC, 0); + + if (!d->hdl) { + tc_log_error(MOD_NAME, "opening audio device failed"); + return TC_ERROR; + } + + sio_initpar(&d->par); + d->par.bits = bits; + d->par.sig = d->par.bits == 8 ? 0 : 1; + d->par.le = SIO_LE_NATIVE; + d->par.rchan = chan; + d->par.rate = rate; + d->par.xrun = SIO_SYNC; + + if (!sio_setpar(d->hdl, &d->par) || !sio_getpar(d->hdl, &d->par)) { + tc_log_error(MOD_NAME, "setting audio parameters failed"); + return TC_ERROR; + } + + if (d->par.bits != bits || d->par.rchan != chan || d->par.rate != rate) { + tc_log_error(MOD_NAME, "could not set audio parameters as desired"); + return TC_ERROR; + } + + if (!sio_start(d->hdl)) { + tc_log_error(MOD_NAME, "could not start capture"); + return TC_ERROR; + } + + return TC_OK; +} + +static int +sndio_grab(void *data, size_t size, char *buffer, size_t *done) +{ + struct tc_sndio_data *d = data; + size_t bytes_read; + int ret; + + if (!d->hdl) { + tc_log_error(MOD_NAME, "attempt to read NULL handle"); + return TC_ERROR; + } + + bytes_read = 0; + while (size > 0) { + ret = sio_read(d->hdl, buffer + bytes_read, size); + if (!ret) { + tc_log_error(MOD_NAME, "audio read failed"); + return TC_ERROR; + } + bytes_read += ret; + size -= ret; + } + if (done != NULL) + *done = bytes_read; + + return TC_OK; +} + +static int +sndio_stop(void *data) +{ + struct tc_sndio_data *d = data; + + if (d->hdl) + sio_close(d->hdl); + d->hdl = NULL; + + return TC_OK; +} + + +/* ------------------------------------------------------------ + * NMS interface + * ------------------------------------------------------------*/ + +static int +tc_sndio_init(TCModuleInstance *self, uint32_t features) +{ + struct tc_sndio_data *d; + + TC_MODULE_SELF_CHECK(self, "init"); + TC_MODULE_INIT_CHECK(self, MOD_FEATURES, features); + + d = tc_zalloc(sizeof(struct tc_sndio_data)); + if (!d) + return TC_ERROR; + self->userdata = d; + + return TC_OK; +} + +static int +tc_sndio_fini(TCModuleInstance *self) +{ + TC_MODULE_SELF_CHECK(self, "fini"); + + tc_free(self->userdata); + self->userdata = NULL; + + return TC_OK; +} + +static int +tc_sndio_inspect(TCModuleInstance *self, const char *param, const char **value) +{ + TC_MODULE_SELF_CHECK(self, "inspect"); + + if (optstr_lookup(param, "help")) + *value = tc_sndio_help; + + return TC_OK; +} + +static int +tc_sndio_configure(TCModuleInstance *self, const char *options, vob_t *vob) +{ + struct tc_sndio_data *d = NULL; + char device[1024]; + + TC_MODULE_SELF_CHECK(self, "configure"); + + d = self->userdata; + + strlcpy(device, "default", 1024); + if (options) + optstr_get(options, "device", "%1023s", device); + + return sndio_init(d, device, vob->a_rate, vob->a_bits, vob->a_chan); +} + +static int +tc_sndio_stop(TCModuleInstance *self) +{ + struct tc_sndio_data *d = NULL; + + TC_MODULE_SELF_CHECK(self, "stop"); + + d = self->userdata; + + return sndio_stop(d); +} + +static int +tc_sndio_demux(TCModuleInstance *self, vframe_list_t *vf, aframe_list_t *af) +{ + struct tc_sndio_data *d = NULL; + size_t done; + + TC_MODULE_SELF_CHECK(self, "demultiplex"); + + d = self->userdata; + + if (vf) + vf->video_len = 0; + + if (af) { + if (sndio_grab(d, af->audio_size, af->audio_buf, &done) != TC_OK) + return TC_ERROR; + af->audio_len = done; + } + + return TC_OK; +} + +static const TCCodecID tc_sndio_codecs_in[] = + { TC_CODEC_ERROR }; +static const TCCodecID tc_sndio_codecs_out[] = + { TC_CODEC_PCM, TC_CODEC_ERROR }; +static const TCCodecID tc_sndio_formats_in[] = + { TC_FORMAT_RAW, TC_FORMAT_ERROR }; +static const TCCodecID tc_sndio_formats_out[] = + { TC_CODEC_ERROR }; + +static const TCModuleInfo tc_sndio_info = { + .features = MOD_FEATURES, + .flags = MOD_FLAGS, + .name = MOD_NAME, + .version = MOD_VERSION, + .description = MOD_CAP, + .codecs_in = tc_sndio_codecs_in, + .codecs_out = tc_sndio_codecs_out, + .formats_in = tc_sndio_formats_in, + .formats_out = tc_sndio_formats_out +}; + +static const TCModuleClass tc_sndio_class = { + TC_MODULE_CLASS_HEAD(tc_sndio), + .init = tc_sndio_init, + .fini = tc_sndio_fini, + .configure = tc_sndio_configure, + .stop = tc_sndio_stop, + .inspect = tc_sndio_inspect, + .demultiplex = tc_sndio_demux +}; + +TC_MODULE_ENTRY_POINT(tc_sndio) + + +/* ------------------------------------------------------------ + * old interface + * ------------------------------------------------------------*/ + +static int verbose_flag = TC_QUIET; +static int capability_flag = TC_CAP_PCM; + +#define MOD_PRE sndio +#define MOD_CODEC "(audio) pcm" + +#include "import_def.h" + +static struct tc_sndio_data data; + +MOD_open +{ + int ret = TC_OK; + + switch (param->flag) { + case TC_VIDEO: + tc_log_warn(MOD_NAME, "unsupported request (open video)"); + ret = TC_ERROR; + break; + case TC_AUDIO: + if (verbose_flag & TC_DEBUG) + tc_log_info(MOD_NAME, "sndio audio capture"); + ret = sndio_init(&data, vob->audio_in_file, vob->a_rate, + vob->a_bits, vob->a_chan); + break; + default: + tc_log_warn(MOD_NAME, "unsupported request (open)"); + ret = TC_ERROR; + break; + } + + return ret; +} + +MOD_decode +{ + int ret = TC_OK; + + switch (param->flag) { + case TC_VIDEO: + tc_log_error(MOD_NAME, "unsupported request (decode video)"); + ret = TC_ERROR; + break; + case TC_AUDIO: + ret = sndio_grab(&data, param->size, param->buffer, NULL); + break; + default: + tc_log_error(MOD_NAME, "unsupported request (decode)"); + ret = TC_ERROR; + break; + } + + return ret; +} + +MOD_close +{ + int ret = TC_OK; + + switch (param->flag) { + case TC_VIDEO: + tc_log_error(MOD_NAME, "unsupported request (close video)"); + ret = TC_ERROR; + break; + case TC_AUDIO: + ret = sndio_stop(&data); + break; + default: + tc_log_error(MOD_NAME, "unsupported request (close)"); + ret = TC_ERROR; + break; + } + + return ret; +}