openbsd-ports/multimedia/transcode/files/import_sndio.c
jakemsr 8df3585b3b - add sndio recording support
- drop sun audio support
- allow non-filenames for audio input names
with feedback from ratchov@
2010-01-11 08:49:27 +00:00

341 lines
8.0 KiB
C

/*
* Copyright (c) 2009 Jacob Meuser <jakemsr@sdf.lonestar.org>
*
* 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 <sndio.h>
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;
}