diff options
author | Wim Taymans <wim.taymans@gmail.com> | 2002-12-07 20:54:47 +0000 |
---|---|---|
committer | Wim Taymans <wim.taymans@gmail.com> | 2002-12-07 20:54:47 +0000 |
commit | 46820010139599cf0ae77e5e75da04b9672f23bf (patch) | |
tree | b3adc39885400c91dec0cad2a7684a659e7b0e2b /sys/oss/gstosscommon.c | |
parent | f5743b63de97d7d5bba29dc769387b42a092cb82 (diff) |
More refactoring osssrc has more features now, like query/convert etc
Original commit message from CVS:
More refactoring
osssrc has more features now, like query/convert etc
Diffstat (limited to 'sys/oss/gstosscommon.c')
-rw-r--r-- | sys/oss/gstosscommon.c | 358 |
1 files changed, 356 insertions, 2 deletions
diff --git a/sys/oss/gstosscommon.c b/sys/oss/gstosscommon.c index cadf5a2d..50128c79 100644 --- a/sys/oss/gstosscommon.c +++ b/sys/oss/gstosscommon.c @@ -21,10 +21,19 @@ */ -#include "gstosscommon.h" +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <fcntl.h> #include <sys/soundcard.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> -gboolean +#include <config.h> +#include "gstosscommon.h" + +static gboolean gst_ossformat_get (gint law, gint endianness, gboolean sign, gint width, gint depth, gint *format, gint *bps) { @@ -89,3 +98,348 @@ gst_ossformat_get (gint law, gint endianness, gboolean sign, gint width, gint de return TRUE; } + +void +gst_osscommon_init (GstOssCommon *common) +{ + common->device = g_strdup ("/dev/dsp"); + common->fd = -1; + + common->law = 0; + common->endianness = G_BYTE_ORDER; + common->sign = TRUE; + common->width = 16; + common->depth = 16; + common->channels = 2; + common->rate = 44100; + common->fragment = 6; + common->bps = 0; + +/* AFMT_*_BE not available on all OSS includes (e.g. FBSD) */ +#ifdef WORDS_BIGENDIAN + common->format = AFMT_S16_BE; +#else + common->format = AFMT_S16_LE; +#endif /* WORDS_BIGENDIAN */ +} + +gboolean +gst_osscommon_parse_caps (GstOssCommon *common, GstCaps *caps) +{ + gint bps, format; + + gst_caps_get_int (caps, "width", &common->width); + gst_caps_get_int (caps, "depth", &common->depth); + + if (common->width != common->depth) + return FALSE; + + gst_caps_get_int (caps, "law", &common->law); + gst_caps_get_int (caps, "endianness", &common->endianness); + gst_caps_get_boolean (caps, "signed", &common->sign); + + if (!gst_ossformat_get (common->law, common->endianness, common->sign, + common->width, common->depth, &format, &bps)) + { + GST_DEBUG (GST_CAT_PLUGIN_INFO, "could not get format"); + return FALSE; + } + + gst_caps_get_int (caps, "channels", &common->channels); + gst_caps_get_int (caps, "rate", &common->rate); + + common->bps = bps * common->channels * common->rate; + common->format = format; + + return TRUE; +} + +#define GET_FIXED_INT(caps, name, dest) \ +G_STMT_START { \ + if (gst_caps_has_fixed_property (caps, name)) \ + gst_caps_get_int (caps, name, dest); \ +} G_STMT_END +#define GET_FIXED_BOOLEAN(caps, name, dest) \ +G_STMT_START { \ + if (gst_caps_has_fixed_property (caps, name)) \ + gst_caps_get_boolean (caps, name, dest); \ +} G_STMT_END + +gboolean +gst_osscommon_merge_fixed_caps (GstOssCommon *common, GstCaps *caps) +{ + gint bps, format; + + /* peel off fixed stuff from the caps */ + GET_FIXED_INT (caps, "law", &common->law); + GET_FIXED_INT (caps, "endianness", &common->endianness); + GET_FIXED_BOOLEAN (caps, "signed", &common->sign); + GET_FIXED_INT (caps, "width", &common->width); + GET_FIXED_INT (caps, "depth", &common->depth); + + if (!gst_ossformat_get (common->law, common->endianness, common->sign, + common->width, common->depth, &format, &bps)) + { + return FALSE; + } + + GET_FIXED_INT (caps, "rate", &common->rate); + GET_FIXED_INT (caps, "channels", &common->channels); + + common->bps = bps * common->channels * common->rate; + common->format = format; + + return TRUE; +} + +gboolean +gst_osscommon_sync_parms (GstOssCommon *common) +{ + audio_buf_info space; + int frag; + gint target_format; + gint target_channels; + gint target_rate; + gint fragscale, frag_ln; + + if (common->fd == -1) + return FALSE; + + if (common->fragment >> 16) + frag = common->fragment; + else + frag = 0x7FFF0000 | common->fragment; + + GST_INFO (GST_CAT_PLUGIN_INFO, + "common: setting sound card to %dHz %d format %s (%08x fragment)", + common->rate, common->format, + (common->channels == 2) ? "stereo" : "mono", frag); + + ioctl (common->fd, SNDCTL_DSP_SETFRAGMENT, &frag); + ioctl (common->fd, SNDCTL_DSP_RESET, 0); + + target_format = common->format; + target_channels = common->channels; + target_rate = common->rate; + + ioctl (common->fd, SNDCTL_DSP_SETFMT, &common->format); + ioctl (common->fd, SNDCTL_DSP_CHANNELS, &common->channels); + ioctl (common->fd, SNDCTL_DSP_SPEED, &common->rate); + + ioctl (common->fd, SNDCTL_DSP_GETBLKSIZE, &common->fragment_size); + + if (common->mode == GST_OSSCOMMON_WRITE) { + ioctl (common->fd, SNDCTL_DSP_GETOSPACE, &space); + } + else { + ioctl (common->fd, SNDCTL_DSP_GETISPACE, &space); + } + + /* calculate new fragment using a poor man's logarithm function */ + fragscale = 1; + frag_ln = 0; + while (fragscale < space.fragsize) { + fragscale <<= 1; + frag_ln++; + } + common->fragment = space.fragstotal << 16 | frag_ln; + + GST_INFO (GST_CAT_PLUGIN_INFO, + "common: set sound card to %dHz, %d format, %s " + "(%d bytes buffer, %08x fragment)", + common->rate, common->format, + (common->channels == 2) ? "stereo" : "mono", + space.bytes, common->fragment); + + common->fragment_time = (GST_SECOND * common->fragment_size) / common->bps; + GST_INFO (GST_CAT_PLUGIN_INFO, "fragment time %u %llu\n", + common->bps, common->fragment_time); + + if (target_format != common->format || + target_channels != common->channels || + target_rate != common->rate) + { + g_warning ("couldn't set requested OSS parameters, enjoy the noise :)"); + /* we could eventually return FALSE here, or just do some additional tests + * to see that the frequencies don't differ too much etc.. */ + } + return TRUE; +} + +gboolean +gst_osscommon_open_audio (GstOssCommon *common, GstOssOpenMode mode, gchar **error) +{ + gint caps; + g_return_val_if_fail (common->fd == -1, FALSE); + + GST_INFO (GST_CAT_PLUGIN_INFO, "common: attempting to open sound device"); + + /* first try to open the sound card */ + /* FIXME: this code is dubious, why do we need to open and close this ?*/ + if (mode == GST_OSSCOMMON_WRITE) { + common->fd = open (common->device, O_WRONLY | O_NONBLOCK); + if (errno == EBUSY) { + g_warning ("osscommon: unable to open the sound device (in use ?)\n"); + } + + if (common->fd >= 0) + close (common->fd); + + /* re-open the sound device in blocking mode */ + common->fd = open (common->device, O_WRONLY); + } + else { + common->fd = open (common->device, O_RDONLY); + } + + if (common->fd < 0) { + switch (errno) { + case EISDIR: + *error = g_strdup_printf ("osscommon: Device %s is a directory", + common->device); + break; + case EACCES: + case ETXTBSY: + *error = g_strdup_printf ( "osscommon: Cannot access %s, check permissions", + common->device); + break; + case ENXIO: + case ENODEV: + case ENOENT: + *error = g_strdup_printf ("osscommon: Cannot access %s, does it exist ?", + common->device); + break; + case EROFS: + *error = g_strdup_printf ("osscommon: Cannot access %s, read-only filesystem ?", + common->device); + default: + /* FIXME: strerror is not threadsafe */ + *error = g_strdup_printf ("osscommon: Cannot open %s, generic error: %s", + common->device, strerror (errno)); + break; + } + return FALSE; + } + + common->mode = mode; + + /* we have it, set the default parameters and go have fun */ + /* set card state */ + ioctl (common->fd, SNDCTL_DSP_GETCAPS, &caps); + + GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: Capabilities %08x", caps); + + if (caps & DSP_CAP_DUPLEX) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: Full duplex"); + if (caps & DSP_CAP_REALTIME) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: Realtime"); + if (caps & DSP_CAP_BATCH) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: Batch"); + if (caps & DSP_CAP_COPROC) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: Has coprocessor"); + if (caps & DSP_CAP_TRIGGER) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: Trigger"); + if (caps & DSP_CAP_MMAP) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: Direct access"); + +#ifdef DSP_CAP_MULTI + if (caps & DSP_CAP_MULTI) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: Multiple open"); +#endif /* DSP_CAP_MULTI */ + +#ifdef DSP_CAP_BIND + if (caps & DSP_CAP_BIND) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: Channel binding"); +#endif /* DSP_CAP_BIND */ + + ioctl(common->fd, SNDCTL_DSP_GETFMTS, &caps); + + GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: Formats %08x", caps); + if (caps & AFMT_MU_LAW) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: MU_LAW"); + if (caps & AFMT_A_LAW) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: A_LAW"); + if (caps & AFMT_IMA_ADPCM) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: IMA_ADPCM"); + if (caps & AFMT_U8) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: U8"); + if (caps & AFMT_S16_LE) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: S16_LE"); + if (caps & AFMT_S16_BE) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: S16_BE"); + if (caps & AFMT_S8) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: S8"); + if (caps & AFMT_U16_LE) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: U16_LE"); + if (caps & AFMT_U16_BE) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: U16_BE"); + if (caps & AFMT_MPEG) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: MPEG"); +#ifdef AFMT_AC3 + if (caps & AFMT_AC3) GST_INFO (GST_CAT_PLUGIN_INFO, "osscommon: AC3"); +#endif + + GST_INFO (GST_CAT_PLUGIN_INFO, + "osscommon: opened audio (%s) with fd=%d", common->device, common->fd); + + common->caps = caps; + + return TRUE; +} + +void +gst_osscommon_close_audio (GstOssCommon *common) +{ + if (common->fd < 0) + return; + + close(common->fd); + common->fd = -1; +} + +gboolean +gst_osscommon_convert (GstOssCommon *common, GstFormat src_format, gint64 src_value, + GstFormat *dest_format, gint64 *dest_value) +{ + gboolean res = TRUE; + + if (src_format == *dest_format) { + *dest_value = src_value; + return TRUE; + } + + if (common->bps == 0 || common->channels == 0 || common->width == 0) + return FALSE; + + switch (src_format) { + case GST_FORMAT_BYTES: + switch (*dest_format) { + case GST_FORMAT_DEFAULT: + *dest_format = GST_FORMAT_TIME; + case GST_FORMAT_TIME: + *dest_value = src_value * GST_SECOND / common->bps; + break; + case GST_FORMAT_UNITS: + *dest_value = src_value / (common->channels * common->width); + break; + default: + res = FALSE; + } + break; + case GST_FORMAT_TIME: + switch (*dest_format) { + case GST_FORMAT_DEFAULT: + *dest_format = GST_FORMAT_BYTES; + case GST_FORMAT_BYTES: + *dest_value = src_value * common->bps / GST_SECOND; + break; + case GST_FORMAT_UNITS: + *dest_value = src_value * common->rate / GST_SECOND; + break; + default: + res = FALSE; + } + break; + case GST_FORMAT_UNITS: + switch (*dest_format) { + case GST_FORMAT_DEFAULT: + *dest_format = GST_FORMAT_TIME; + case GST_FORMAT_TIME: + *dest_value = src_value * GST_SECOND / common->rate; + break; + case GST_FORMAT_BYTES: + *dest_value = src_value * common->channels * common->width; + break; + default: + res = FALSE; + } + break; + default: + res = FALSE; + } + + return res; +} + |