From: Wim Taymans Date: Sat, 7 Dec 2002 20:54:47 +0000 (+0000) Subject: More refactoring osssrc has more features now, like query/convert etc X-Git-Tag: CAPS~40 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=46820010139599cf0ae77e5e75da04b9672f23bf;p=platform%2Fupstream%2Fgst-plugins-good.git 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 --- diff --git a/sys/oss/gstosscommon.c b/sys/oss/gstosscommon.c index cadf5a2..50128c7 100644 --- a/sys/oss/gstosscommon.c +++ b/sys/oss/gstosscommon.c @@ -21,10 +21,19 @@ */ -#include "gstosscommon.h" +#include +#include +#include +#include #include +#include +#include +#include -gboolean +#include +#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; +} + diff --git a/sys/oss/gstosscommon.h b/sys/oss/gstosscommon.h index 18bdd90..ab5553f 100644 --- a/sys/oss/gstosscommon.h +++ b/sys/oss/gstosscommon.h @@ -20,12 +20,57 @@ * Boston, MA 02111-1307, USA. */ -#ifndef __GST_OSSFORMAT_H__ -#define __GST_OSSFORMAT_H__ +#ifndef __GST_OSSCOMMON_H__ +#define __GST_OSSCOMMON_H__ #include -gboolean gst_ossformat_get (gint law, gint endianness, gboolean sign, - gint width, gint depth, gint *format, gint *bps); +typedef struct _GstOssCommon GstOssCommon; -#endif /* __GST_OSSFORMAT_H__ */ +typedef enum { + GST_OSSCOMMON_READ, + GST_OSSCOMMON_WRITE, +} GstOssOpenMode; + +struct _GstOssCommon +{ + gchar *device; + /* device state */ + int fd; + int caps; /* the capabilities */ + gint format; + gint fragment; + guint64 fragment_time; + gint fragment_size; + GstOssOpenMode mode; + /* stats */ + guint bps; + + /* parameters */ + gint law; + gint endianness; + gboolean sign; + gint width; + gint depth; + gint channels; + gint rate; +}; + +void gst_osscommon_init (GstOssCommon *common); + +gboolean gst_osscommon_open_audio (GstOssCommon *common, + GstOssOpenMode mode, gchar **error); +void gst_osscommon_close_audio (GstOssCommon *common); + +gboolean gst_osscommon_parse_caps (GstOssCommon *common, GstCaps *caps); +gboolean gst_osscommon_merge_fixed_caps (GstOssCommon *common, GstCaps *caps); + +gboolean gst_osscommon_sync_parms (GstOssCommon *common); + +gboolean gst_osscommon_convert (GstOssCommon *common, + GstFormat src_format, gint64 src_value, + GstFormat *dest_format, gint64 *dest_value); + + + +#endif /* __GST_OSSCOMMON_H__ */ diff --git a/sys/oss/gstosssink.c b/sys/oss/gstosssink.c index 049a3a0..2360302 100644 --- a/sys/oss/gstosssink.c +++ b/sys/oss/gstosssink.c @@ -20,18 +20,10 @@ * Boston, MA 02111-1307, USA. */ - -#include -#include #include -#include #include -#include -#include -#include #include -#include /* elementfactory information */ static GstElementDetails gst_osssink_details = { @@ -49,9 +41,6 @@ static void gst_osssink_class_init (GstOssSinkClass *klass); static void gst_osssink_init (GstOssSink *osssink); static void gst_osssink_finalize (GObject *object); -static gboolean gst_osssink_open_audio (GstOssSink *sink); -static void gst_osssink_close_audio (GstOssSink *sink); -static gboolean gst_osssink_sync_parms (GstOssSink *osssink); static GstElementStateReturn gst_osssink_change_state (GstElement *element); static void gst_osssink_set_clock (GstElement *element, GstClock *clock); static GstClock* gst_osssink_get_clock (GstElement *element); @@ -163,7 +152,7 @@ gst_osssink_finalize (GObject *object) { GstOssSink *osssink = (GstOssSink *) object; - g_free (osssink->device); + g_free (osssink->common.device); G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -227,19 +216,9 @@ gst_osssink_init (GstOssSink *osssink) gst_pad_set_chain_function (osssink->sinkpad, gst_osssink_chain); - osssink->device = g_strdup ("/dev/dsp"); - osssink->fd = -1; - osssink->channels = 1; - osssink->frequency = 11025; - osssink->fragment = 6; -/* AFMT_*_BE not available on all OSS includes (e.g. FBSD) */ -#ifdef WORDS_BIGENDIAN - osssink->format = AFMT_S16_BE; -#else - osssink->format = AFMT_S16_LE; -#endif /* WORDS_BIGENDIAN */ + gst_osscommon_init (&osssink->common); + osssink->bufsize = 4096; - osssink->bps = 0; osssink->resync = FALSE; osssink->sync = TRUE; osssink->sinkpool = NULL; @@ -254,141 +233,32 @@ gst_osssink_init (GstOssSink *osssink) static GstPadConnectReturn gst_osssink_sinkconnect (GstPad *pad, GstCaps *caps) { - gint law, endianness, width, depth, bps; - gboolean sign; - gint format = -1; GstOssSink *osssink = GST_OSSSINK (gst_pad_get_parent (pad)); if (!GST_CAPS_IS_FIXED (caps)) return GST_PAD_CONNECT_DELAYED; - - gst_caps_get_int (caps, "width", &width); - gst_caps_get_int (caps, "depth", &depth); - if (width != depth) + if (!gst_osscommon_parse_caps (&osssink->common, caps)) return GST_PAD_CONNECT_REFUSED; - osssink->width = width; - - /* laws 1 and 2 are 1 bps anyway */ - osssink->bps = 1; - - gst_caps_get_int (caps, "law", &law); - gst_caps_get_int (caps, "endianness", &endianness); - gst_caps_get_boolean (caps, "signed", &sign); - - if (!gst_ossformat_get (law, endianness, sign, - width, depth, &format, &bps)) - { - GST_DEBUG (GST_CAT_PLUGIN_INFO, "could not get format"); - return GST_PAD_CONNECT_REFUSED; - } - - osssink->bps = bps; - osssink->format = format; - - gst_caps_get_int (caps, "channels", &osssink->channels); - gst_caps_get_int (caps, "rate", &osssink->frequency); - - osssink->bps *= osssink->channels; - osssink->bps *= osssink->frequency; - - if (!gst_osssink_sync_parms (osssink)) { + if (!gst_osscommon_sync_parms (&osssink->common)) { return GST_PAD_CONNECT_REFUSED; } return GST_PAD_CONNECT_OK; } -static gboolean -gst_osssink_sync_parms (GstOssSink *osssink) -{ - audio_buf_info ospace; - int frag; - gint target_format; - gint target_channels; - gint target_frequency; - GObject *object; - gint fragscale, frag_ln; - - g_return_val_if_fail (osssink != NULL, FALSE); - g_return_val_if_fail (GST_IS_OSSSINK (osssink), FALSE); - - if (osssink->fd == -1) - return FALSE; - - if (osssink->fragment >> 16) - frag = osssink->fragment; - else - frag = 0x7FFF0000 | osssink->fragment; - - GST_INFO (GST_CAT_PLUGIN_INFO, - "osssink: setting sound card to %dHz %d format %s (%08x fragment)", - osssink->frequency, osssink->format, - (osssink->channels == 2) ? "stereo" : "mono", frag); - - ioctl (osssink->fd, SNDCTL_DSP_SETFRAGMENT, &frag); - - ioctl (osssink->fd, SNDCTL_DSP_RESET, 0); - - target_format = osssink->format; - target_channels = osssink->channels; - target_frequency = osssink->frequency; - - ioctl (osssink->fd, SNDCTL_DSP_SETFMT, &osssink->format); - ioctl (osssink->fd, SNDCTL_DSP_CHANNELS, &osssink->channels); - ioctl (osssink->fd, SNDCTL_DSP_SPEED, &osssink->frequency); - - ioctl (osssink->fd, SNDCTL_DSP_GETBLKSIZE, &osssink->fragment_size); - ioctl (osssink->fd, SNDCTL_DSP_GETOSPACE, &ospace); - - /* calculate new fragment using a poor man's logarithm function */ - fragscale = 1; - frag_ln = 0; - while (fragscale < ospace.fragsize) { - fragscale <<= 1; - frag_ln++; - } - osssink->fragment = ospace.fragstotal << 16 | frag_ln; - - GST_INFO (GST_CAT_PLUGIN_INFO, - "osssink: set sound card to %dHz %d format %s " - "(%d bytes buffer, %08x fragment)", - osssink->frequency, osssink->format, - (osssink->channels == 2) ? "stereo" : "mono", - ospace.bytes, osssink->fragment); - - object = G_OBJECT (osssink); - g_object_freeze_notify (object); - g_object_notify (object, "fragment"); - g_object_thaw_notify (object); - - osssink->fragment_time = (GST_SECOND * osssink->fragment_size) / osssink->bps; - GST_INFO (GST_CAT_PLUGIN_INFO, "fragment time %u %llu\n", - osssink->bps, osssink->fragment_time); - - if (target_format != osssink->format || - target_channels != osssink->channels || - target_frequency != osssink->frequency) - { - 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; -} - static inline gint64 gst_osssink_get_delay (GstOssSink *osssink) { gint delay = 0; - if (osssink->fd == -1) + if (osssink->common.fd == -1) return 0; - if (ioctl (osssink->fd, SNDCTL_DSP_GETODELAY, &delay) < 0) { + if (ioctl (osssink->common.fd, SNDCTL_DSP_GETODELAY, &delay) < 0) { audio_buf_info info; - if (ioctl (osssink->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) { + if (ioctl (osssink->common.fd, SNDCTL_DSP_GETOSPACE, &info) < 0) { delay = 0; } else { @@ -405,7 +275,7 @@ gst_osssink_get_time (GstClock *clock, gpointer data) gint delay; GstClockTime res; - if (!osssink->bps) + if (!osssink->common.bps) return 0; delay = gst_osssink_get_delay (osssink); @@ -416,7 +286,7 @@ gst_osssink_get_time (GstClock *clock, gpointer data) if (((guint64)delay) > osssink->handled) { delay = osssink->handled; } - res = (osssink->handled - delay) * GST_SECOND / osssink->bps; + res = (osssink->handled - delay) * GST_SECOND / osssink->common.bps; return res; } @@ -455,7 +325,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf) switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: - ioctl (osssink->fd, SNDCTL_DSP_SYNC); + ioctl (osssink->common.fd, SNDCTL_DSP_SYNC); gst_oss_clock_set_active (osssink->provided_clock, FALSE); gst_pad_event_default (pad, event); return; @@ -466,7 +336,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf) { gint64 value; - ioctl (osssink->fd, SNDCTL_DSP_RESET); + ioctl (osssink->common.fd, SNDCTL_DSP_RESET); if (gst_event_discont_get_value (event, GST_FORMAT_TIME, &value)) { if (!gst_clock_handle_discont (osssink->clock, value)) gst_oss_clock_set_active (osssink->provided_clock, FALSE); @@ -483,7 +353,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf) return; } - if (!osssink->bps) { + if (!osssink->common.bps) { gst_buffer_unref (buf); gst_element_error (GST_ELEMENT (osssink), "capsnego was never performed, unknown data type"); return; @@ -491,7 +361,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf) buftime = GST_BUFFER_TIMESTAMP (buf); - if (osssink->fd >= 0) { + if (osssink->common.fd >= 0) { if (!osssink->mute) { guchar *data = GST_BUFFER_DATA (buf); gint size = GST_BUFFER_SIZE (buf); @@ -502,7 +372,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf) GstClockTimeDiff jitter; delay = gst_osssink_get_delay (osssink); - queued = delay * GST_SECOND / osssink->bps; + queued = delay * GST_SECOND / osssink->common.bps; if (osssink->resync && osssink->sync) { gst_element_clock_wait (GST_ELEMENT (osssink), osssink->clock, @@ -510,14 +380,14 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf) if (jitter >= 0) { gst_clock_handle_discont (osssink->clock, buftime - queued + jitter); - write (osssink->fd, data, size); + write (osssink->common.fd, data, size); gst_oss_clock_set_active (osssink->provided_clock, TRUE); osssink->resync = FALSE; osssink->handled += size; } } else { - write (osssink->fd, data, size); + write (osssink->common.fd, data, size); osssink->handled += size; } } @@ -525,10 +395,10 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf) else { audio_buf_info ospace; - ioctl (osssink->fd, SNDCTL_DSP_GETOSPACE, &ospace); + ioctl (osssink->common.fd, SNDCTL_DSP_GETOSPACE, &ospace); if (ospace.bytes >= size) { - write (osssink->fd, data, size); + write (osssink->common.fd, data, size); } } } @@ -552,68 +422,12 @@ static gboolean gst_osssink_convert (GstPad *pad, GstFormat src_format, gint64 src_value, GstFormat *dest_format, gint64 *dest_value) { - gboolean res = TRUE; - GstOssSink *osssink; - if (src_format == *dest_format) { - *dest_value = src_value; - return TRUE; - } - osssink = GST_OSSSINK (gst_pad_get_parent (pad)); - - if (osssink->bps == 0 || osssink->channels == 0 || osssink->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 / osssink->bps; - break; - case GST_FORMAT_UNITS: - *dest_value = src_value / (osssink->channels * osssink->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 * osssink->bps / GST_SECOND; - break; - case GST_FORMAT_UNITS: - *dest_value = src_value * osssink->frequency / 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 / osssink->frequency; - break; - case GST_FORMAT_BYTES: - *dest_value = src_value * osssink->channels * osssink->width; - break; - default: - res = FALSE; - } - break; - default: - res = FALSE; - } - - return res; + + return gst_osscommon_convert (&osssink->common, src_format, src_value, + dest_format, dest_value); } static const GstPadQueryType* @@ -673,9 +487,6 @@ gst_osssink_set_property (GObject *object, guint prop_id, const GValue *value, G { GstOssSink *osssink; - /* it's not null if we got it, but it might not be ours */ - g_return_if_fail (GST_IS_OSSSINK (object)); - osssink = GST_OSSSINK (object); switch (prop_id) { @@ -684,8 +495,8 @@ gst_osssink_set_property (GObject *object, guint prop_id, const GValue *value, G get_property("device") should return the right one */ if (!GST_FLAG_IS_SET (osssink, GST_OSSSINK_OPEN)) { - g_free (osssink->device); - osssink->device = g_strdup (g_value_get_string (value)); + g_free (osssink->common.device); + osssink->common.device = g_strdup (g_value_get_string (value)); g_object_notify (object, "device"); } break; @@ -694,8 +505,8 @@ gst_osssink_set_property (GObject *object, guint prop_id, const GValue *value, G g_object_notify (G_OBJECT (osssink), "mute"); break; case ARG_FRAGMENT: - osssink->fragment = g_value_get_int (value); - gst_osssink_sync_parms (osssink); + osssink->common.fragment = g_value_get_int (value); + gst_osscommon_sync_parms (&osssink->common); break; case ARG_BUFFER_SIZE: if (osssink->bufsize == g_value_get_int (value)) break; @@ -718,20 +529,17 @@ gst_osssink_get_property (GObject *object, guint prop_id, GValue *value, GParamS { GstOssSink *osssink; - /* it's not null if we got it, but it might not be ours */ - g_return_if_fail (GST_IS_OSSSINK (object)); - osssink = GST_OSSSINK (object); switch (prop_id) { case ARG_DEVICE: - g_value_set_string (value, osssink->device); + g_value_set_string (value, osssink->common.device); break; case ARG_MUTE: g_value_set_boolean (value, osssink->mute); break; case ARG_FRAGMENT: - g_value_set_int (value, osssink->fragment); + g_value_set_int (value, osssink->common.fragment); break; case ARG_BUFFER_SIZE: g_value_set_int (value, osssink->bufsize); @@ -745,132 +553,24 @@ gst_osssink_get_property (GObject *object, guint prop_id, GValue *value, GParamS } } -static gboolean -gst_osssink_open_audio (GstOssSink *sink) -{ - gint caps; - g_return_val_if_fail (sink->fd == -1, FALSE); - - GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: 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 ?*/ - sink->fd = open (sink->device, O_WRONLY | O_NONBLOCK); - if (errno == EBUSY) { - g_warning ("osssink: unable to open the sound device (in use ?)\n"); - } - - if (sink->fd >= 0) - close (sink->fd); - - /* re-open the sound device in blocking mode */ - sink->fd = open (sink->device, O_WRONLY); - - if (sink->fd < 0) { - switch (errno) { - case EISDIR: - gst_element_error (GST_ELEMENT (sink), - "osssink: Device %s is a directory", - sink->device); - break; - case EACCES: - case ETXTBSY: - gst_element_error (GST_ELEMENT (sink), - "osssink: Cannot access %s, check permissions", - sink->device); - break; - case ENXIO: - case ENODEV: - case ENOENT: - gst_element_error (GST_ELEMENT (sink), - "osssink: Cannot access %s, does it exist ?", - sink->device); - break; - case EROFS: - gst_element_error (GST_ELEMENT (sink), - "osssink: Cannot access %s, read-only filesystem ?", - sink->device); - default: - /* FIXME: strerror is not threadsafe */ - gst_element_error (GST_ELEMENT (sink), - "osssink: Cannot open %s, generic error: %s", - sink->device, strerror (errno)); - break; - } - return FALSE; - } - /* we have it, set the default parameters and go have fun */ - /* set card state */ - ioctl (sink->fd, SNDCTL_DSP_GETCAPS, &caps); - - GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Capabilities %08x", caps); - - if (caps & DSP_CAP_DUPLEX) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Full duplex"); - if (caps & DSP_CAP_REALTIME) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Realtime"); - if (caps & DSP_CAP_BATCH) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Batch"); - if (caps & DSP_CAP_COPROC) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Has coprocessor"); - if (caps & DSP_CAP_TRIGGER) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Trigger"); - if (caps & DSP_CAP_MMAP) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Direct access"); - -#ifdef DSP_CAP_MULTI - if (caps & DSP_CAP_MULTI) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Multiple open"); -#endif /* DSP_CAP_MULTI */ - -#ifdef DSP_CAP_BIND - if (caps & DSP_CAP_BIND) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Channel binding"); -#endif /* DSP_CAP_BIND */ - - ioctl(sink->fd, SNDCTL_DSP_GETFMTS, &caps); - - GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Formats %08x", caps); - if (caps & AFMT_MU_LAW) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: MU_LAW"); - if (caps & AFMT_A_LAW) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: A_LAW"); - if (caps & AFMT_IMA_ADPCM) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: IMA_ADPCM"); - if (caps & AFMT_U8) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: U8"); - if (caps & AFMT_S16_LE) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: S16_LE"); - if (caps & AFMT_S16_BE) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: S16_BE"); - if (caps & AFMT_S8) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: S8"); - if (caps & AFMT_U16_LE) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: U16_LE"); - if (caps & AFMT_U16_BE) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: U16_BE"); - if (caps & AFMT_MPEG) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: MPEG"); -#ifdef AFMT_AC3 - if (caps & AFMT_AC3) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: AC3"); -#endif - - GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: opened audio (%s) with fd=%d", sink->device, sink->fd); - GST_FLAG_SET (sink, GST_OSSSINK_OPEN); - - return TRUE; -} - -static void -gst_osssink_close_audio (GstOssSink *sink) -{ - if (sink->fd < 0) return; - - close(sink->fd); - sink->fd = -1; - - GST_FLAG_UNSET (sink, GST_OSSSINK_OPEN); - - GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: closed sound device"); -} - static GstElementStateReturn gst_osssink_change_state (GstElement *element) { GstOssSink *osssink; - g_return_val_if_fail (GST_IS_OSSSINK (element), FALSE); - osssink = GST_OSSSINK (element); switch (GST_STATE_TRANSITION (element)) { case GST_STATE_NULL_TO_READY: if (!GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN)) { - if (!gst_osssink_open_audio (osssink)) { + gchar *error; + + if (!gst_osscommon_open_audio (&osssink->common, GST_OSSCOMMON_WRITE, &error)) { + gst_element_error (GST_ELEMENT (osssink), error); + g_free (error); return GST_STATE_FAILURE; } + GST_FLAG_SET (element, GST_OSSSINK_OPEN); } break; case GST_STATE_READY_TO_PAUSED: @@ -881,18 +581,23 @@ gst_osssink_change_state (GstElement *element) case GST_STATE_PLAYING_TO_PAUSED: { if (GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN)) - ioctl (osssink->fd, SNDCTL_DSP_RESET, 0); + ioctl (osssink->common.fd, SNDCTL_DSP_RESET, 0); gst_oss_clock_set_active (osssink->provided_clock, FALSE); osssink->resync = TRUE; break; } case GST_STATE_PAUSED_TO_READY: if (GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN)) - ioctl (osssink->fd, SNDCTL_DSP_RESET, 0); + ioctl (osssink->common.fd, SNDCTL_DSP_RESET, 0); + gst_osscommon_init (&osssink->common); break; case GST_STATE_READY_TO_NULL: - if (GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN)) - gst_osssink_close_audio (osssink); + if (GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN)) { + gst_osscommon_close_audio (&osssink->common); + GST_FLAG_UNSET (osssink, GST_OSSSINK_OPEN); + + GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: closed sound device"); + } break; } diff --git a/sys/oss/gstosssink.h b/sys/oss/gstosssink.h index 06a13ea..b61243f 100644 --- a/sys/oss/gstosssink.h +++ b/sys/oss/gstosssink.h @@ -25,15 +25,12 @@ #define __GST_OSSSINK_H__ -#include #include +#include "gstosscommon.h" #include "gstossclock.h" -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - +G_BEGIN_DECLS #define GST_TYPE_OSSSINK \ (gst_osssink_get_type()) @@ -67,23 +64,11 @@ struct _GstOssSink { gboolean sync; guint64 handled; - /* device */ - gchar *device; - - /* soundcard state */ - int fd; - int caps; /* the capabilities */ - gint format; - gint width; - gint channels; - gint frequency; - gint fragment; - gint fragment_size; + GstOssCommon common; + gboolean mute; guint bufsize; - guint bps; - guint64 fragment_time; }; struct _GstOssSinkClass { @@ -97,9 +82,6 @@ GType gst_osssink_get_type(void); gboolean gst_osssink_factory_init(GstPlugin *plugin); -#ifdef __cplusplus -} -#endif /* __cplusplus */ - +G_END_DECLS #endif /* __GST_OSSSINK_H__ */ diff --git a/sys/oss/gstosssrc.c b/sys/oss/gstosssrc.c index 93c048b..b3f5169 100644 --- a/sys/oss/gstosssrc.c +++ b/sys/oss/gstosssrc.c @@ -51,7 +51,8 @@ enum { enum { ARG_0, ARG_DEVICE, - ARG_BYTESPERREAD, + ARG_BUFFERSIZE, + ARG_FRAGMENT, }; GST_PAD_TEMPLATE_FACTORY (osssrc_src_factory, @@ -85,16 +86,23 @@ static void gst_osssrc_class_init (GstOssSrcClass *klass); static void gst_osssrc_init (GstOssSrc *osssrc); static GstPadConnectReturn gst_osssrc_srcconnect (GstPad *pad, GstCaps *caps); +static const GstFormat* gst_osssrc_get_formats (GstPad *pad); +static gboolean gst_osssrc_convert (GstPad *pad, + GstFormat src_format, gint64 src_value, + GstFormat *dest_format, gint64 *dest_value); + static void gst_osssrc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void gst_osssrc_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static GstElementStateReturn gst_osssrc_change_state (GstElement *element); -static gboolean gst_osssrc_send_event (GstElement *element, GstEvent *event); -static void gst_osssrc_close_audio (GstOssSrc *src); -static gboolean gst_osssrc_open_audio (GstOssSrc *src); -static gboolean gst_osssrc_sync_parms (GstOssSrc *osssrc); +static const GstEventMask* gst_osssrc_get_event_masks (GstPad *pad); +static gboolean gst_osssrc_src_event (GstPad *pad, GstEvent *event); +static gboolean gst_osssrc_send_event (GstElement *element, GstEvent *event); +static const GstPadQueryType* gst_osssrc_get_query_types (GstPad *pad); +static gboolean gst_osssrc_src_query (GstPad *pad, GstPadQueryType type, + GstFormat *format, gint64 *value); static GstBuffer * gst_osssrc_get (GstPad *pad); @@ -134,12 +142,16 @@ gst_osssrc_class_init (GstOssSrcClass *klass) parent_class = g_type_class_ref (GST_TYPE_ELEMENT); - g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BYTESPERREAD, - g_param_spec_ulong("bytes_per_read","bytes_per_read","bytes_per_read", - 0,G_MAXULONG,0,G_PARAM_READWRITE)); /* CHECKME */ + g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BUFFERSIZE, + g_param_spec_ulong ("buffersize","Buffer Size","The size of the buffers with samples", + 0, G_MAXULONG, 0, G_PARAM_READWRITE)); g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE, - g_param_spec_string("device","device","oss device (/dev/dspN usually)", - "default",G_PARAM_READWRITE)); + g_param_spec_string ("device", "device", "oss device (/dev/dspN usually)", + "default", G_PARAM_READWRITE)); + g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FRAGMENT, + g_param_spec_int ("fragment", "Fragment", + "The fragment as 0xMMMMSSSS (MMMM = total fragments, 2^SSSS = fragment size)", + 0, G_MAXINT, 6, G_PARAM_READWRITE)); gobject_class->set_property = gst_osssrc_set_property; gobject_class->get_property = gst_osssrc_get_property; @@ -155,25 +167,20 @@ gst_osssrc_init (GstOssSrc *osssrc) GST_PAD_TEMPLATE_GET (osssrc_src_factory), "src"); gst_pad_set_get_function (osssrc->srcpad, gst_osssrc_get); gst_pad_set_connect_function (osssrc->srcpad, gst_osssrc_srcconnect); + gst_pad_set_convert_function (osssrc->srcpad, gst_osssrc_convert); + gst_pad_set_formats_function (osssrc->srcpad, gst_osssrc_get_formats); + gst_pad_set_event_function (osssrc->srcpad, gst_osssrc_src_event); + gst_pad_set_event_mask_function (osssrc->srcpad, gst_osssrc_get_event_masks); + gst_pad_set_query_function (osssrc->srcpad, gst_osssrc_src_query); + gst_pad_set_query_type_function (osssrc->srcpad, gst_osssrc_get_query_types); + + gst_element_add_pad (GST_ELEMENT (osssrc), osssrc->srcpad); - osssrc->device = g_strdup ("/dev/dsp"); - osssrc->fd = -1; - - /* adding some default values */ - osssrc->law = 0; - osssrc->endianness = G_BYTE_ORDER; - osssrc->sign = TRUE; - osssrc->depth = 16; - osssrc->width = 16; - osssrc->channels = 2; - osssrc->rate = 44100; - osssrc->need_eos = FALSE; - - osssrc->bytes_per_read = 4096; + gst_osscommon_init (&osssrc->common); + + osssrc->buffersize = 4096; osssrc->curoffset = 0; - osssrc->basetime = 0; - osssrc->samples_since_basetime = 0; } static GstPadConnectReturn @@ -186,29 +193,14 @@ gst_osssrc_srcconnect (GstPad *pad, GstCaps *caps) if (!GST_CAPS_IS_FIXED (caps)) return GST_PAD_CONNECT_DELAYED; - gst_caps_get_int (caps, "law", &src->law); - gst_caps_get_int (caps, "endianness", &src->endianness); - gst_caps_get_boolean (caps, "signed", &src->sign); - gst_caps_get_int (caps, "width", &src->width); - gst_caps_get_int (caps, "depth", &src->depth); - gst_caps_get_int (caps, "rate", &src->rate); - gst_caps_get_int (caps, "channels", &src->channels); + if (!gst_osscommon_parse_caps (&src->common, caps)) + return GST_PAD_CONNECT_REFUSED; - if (!gst_osssrc_sync_parms (src)) + if (!gst_osscommon_sync_parms (&src->common)) return GST_PAD_CONNECT_REFUSED; return GST_PAD_CONNECT_OK; } -#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 static gboolean gst_osssrc_negotiate (GstPad *pad) @@ -220,16 +212,10 @@ gst_osssrc_negotiate (GstPad *pad) allowed = gst_pad_get_allowed_caps (pad); - /* peel off fixed stuff from the allowed caps */ - GET_FIXED_INT (allowed, "law", &src->law); - GET_FIXED_INT (allowed, "endianness", &src->endianness); - GET_FIXED_BOOLEAN (allowed, "signed", &src->sign); - GET_FIXED_INT (allowed, "width", &src->width); - GET_FIXED_INT (allowed, "depth", &src->depth); - GET_FIXED_INT (allowed, "rate", &src->rate); - GET_FIXED_INT (allowed, "channels", &src->channels); + if (!gst_osscommon_merge_fixed_caps (&src->common, allowed)) + return FALSE; - if (!gst_osssrc_sync_parms (src)) + if (!gst_osscommon_sync_parms (&src->common)) return FALSE; /* set caps on src pad */ @@ -238,13 +224,13 @@ gst_osssrc_negotiate (GstPad *pad) "oss_src", "audio/raw", "format", GST_PROPS_STRING ("int"), - "law", GST_PROPS_INT (src->law), - "endianness", GST_PROPS_INT (src->endianness), - "signed", GST_PROPS_BOOLEAN (src->sign), - "width", GST_PROPS_INT (src->width), - "depth", GST_PROPS_INT (src->depth), - "rate", GST_PROPS_INT (src->rate), - "channels", GST_PROPS_INT (src->channels) + "law", GST_PROPS_INT (src->common.law), + "endianness", GST_PROPS_INT (src->common.endianness), + "signed", GST_PROPS_BOOLEAN (src->common.sign), + "width", GST_PROPS_INT (src->common.width), + "depth", GST_PROPS_INT (src->common.depth), + "rate", GST_PROPS_INT (src->common.rate), + "channels", GST_PROPS_INT (src->common.channels) )) <= 0) { return FALSE; @@ -258,7 +244,6 @@ gst_osssrc_get (GstPad *pad) GstOssSrc *src; GstBuffer *buf; glong readbytes; - glong readsamples; src = GST_OSSSRC(gst_pad_get_parent (pad)); @@ -269,10 +254,10 @@ gst_osssrc_get (GstPad *pad) return GST_BUFFER (gst_event_new (GST_EVENT_EOS)); } - buf = gst_buffer_new_and_alloc (src->bytes_per_read); + buf = gst_buffer_new_and_alloc (src->buffersize); - readbytes = read (src->fd,GST_BUFFER_DATA (buf), - src->bytes_per_read); + readbytes = read (src->common.fd,GST_BUFFER_DATA (buf), + src->buffersize); if (readbytes == 0) { gst_element_set_eos (GST_ELEMENT (src)); @@ -286,16 +271,16 @@ gst_osssrc_get (GstPad *pad) return NULL; } } + if (src->common.bps == 0) { + gst_element_error (GST_ELEMENT (src), "no format negotiated"); + return NULL; + } GST_BUFFER_SIZE (buf) = readbytes; GST_BUFFER_OFFSET (buf) = src->curoffset; - GST_BUFFER_TIMESTAMP (buf) = src->basetime + - src->samples_since_basetime * GST_SECOND / src->rate; + GST_BUFFER_TIMESTAMP (buf) = src->curoffset * GST_SECOND / src->common.bps; src->curoffset += readbytes; - readsamples = readbytes / src->channels; - if (src->width == 16) readsamples /= 2; - src->samples_since_basetime += readsamples; GST_DEBUG (GST_CAT_PLUGIN_INFO, "pushed buffer from soundcard of %ld bytes, timestamp %lld", readbytes, GST_BUFFER_TIMESTAMP (buf)); @@ -308,19 +293,20 @@ gst_osssrc_set_property (GObject *object, guint prop_id, const GValue *value, GP { GstOssSrc *src; - /* it's not null if we got it, but it might not be ours */ - g_return_if_fail (GST_IS_OSSSRC (object)); - src = GST_OSSSRC (object); switch (prop_id) { - case ARG_BYTESPERREAD: - src->bytes_per_read = g_value_get_ulong (value); + case ARG_BUFFERSIZE: + src->buffersize = g_value_get_ulong (value); break; case ARG_DEVICE: - g_free(src->device); - src->device = g_strdup (g_value_get_string (value)); + g_free(src->common.device); + src->common.device = g_strdup (g_value_get_string (value)); break; + case ARG_FRAGMENT: + src->common.fragment = g_value_get_int (value); + gst_osscommon_sync_parms (&src->common); + break; default: break; } @@ -331,17 +317,17 @@ gst_osssrc_get_property (GObject *object, guint prop_id, GValue *value, GParamSp { GstOssSrc *src; - /* it's not null if we got it, but it might not be ours */ - g_return_if_fail (GST_IS_OSSSRC (object)); - src = GST_OSSSRC (object); switch (prop_id) { - case ARG_BYTESPERREAD: - g_value_set_ulong (value, src->bytes_per_read); + case ARG_BUFFERSIZE: + g_value_set_ulong (value, src->buffersize); break; case ARG_DEVICE: - g_value_set_string (value, src->device); + g_value_set_string (value, src->common.device); + break; + case ARG_FRAGMENT: + g_value_set_int (value, src->common.fragment); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -361,8 +347,13 @@ gst_osssrc_change_state (GstElement *element) break; case GST_STATE_READY_TO_PAUSED: if (!GST_FLAG_IS_SET (element, GST_OSSSRC_OPEN)) { - if (!gst_osssrc_open_audio (osssrc)) + gchar *error; + if (!gst_osscommon_open_audio (&osssrc->common, GST_OSSCOMMON_READ, &error)) { + gst_element_error (GST_ELEMENT (osssrc), error); + g_free (error); return GST_STATE_FAILURE; + } + GST_FLAG_SET (osssrc, GST_OSSSRC_OPEN); } break; case GST_STATE_PAUSED_TO_PLAYING: @@ -370,8 +361,11 @@ gst_osssrc_change_state (GstElement *element) case GST_STATE_PLAYING_TO_PAUSED: break; case GST_STATE_PAUSED_TO_READY: - if (GST_FLAG_IS_SET (element, GST_OSSSRC_OPEN)) - gst_osssrc_close_audio (osssrc); + if (GST_FLAG_IS_SET (element, GST_OSSSRC_OPEN)) { + gst_osscommon_close_audio (&osssrc->common); + GST_FLAG_UNSET (osssrc, GST_OSSSRC_OPEN); + } + gst_osscommon_init (&osssrc->common); break; case GST_STATE_READY_TO_NULL: break; @@ -383,103 +377,117 @@ gst_osssrc_change_state (GstElement *element) return GST_STATE_SUCCESS; } +static const GstFormat* +gst_osssrc_get_formats (GstPad *pad) +{ + static const GstFormat formats[] = { + GST_FORMAT_TIME, + GST_FORMAT_UNITS, + GST_FORMAT_BYTES, + 0 + }; + return formats; +} + static gboolean -gst_osssrc_send_event (GstElement *element, - GstEvent *event) +gst_osssrc_convert (GstPad *pad, GstFormat src_format, gint64 src_value, + GstFormat *dest_format, gint64 *dest_value) +{ + GstOssSrc *osssrc; + + osssrc = GST_OSSSRC (gst_pad_get_parent (pad)); + + return gst_osscommon_convert (&osssrc->common, src_format, src_value, + dest_format, dest_value); +} + +static const GstEventMask* +gst_osssrc_get_event_masks (GstPad *pad) +{ + static const GstEventMask gst_osssrc_src_event_masks[] = { + { GST_EVENT_EOS, 0 }, + { GST_EVENT_SIZE, 0 }, + { 0, } + }; + return gst_osssrc_src_event_masks; +} + +static gboolean +gst_osssrc_src_event (GstPad *pad, GstEvent *event) { - gboolean retval = FALSE; GstOssSrc *osssrc; + gboolean retval = FALSE; - osssrc = GST_OSSSRC (element); + osssrc = GST_OSSSRC (gst_pad_get_parent (pad)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: osssrc->need_eos = TRUE; retval = TRUE; break; + case GST_EVENT_SIZE: + { + GstFormat format; + gint64 value; + + format = GST_FORMAT_BYTES; + + /* convert to bytes */ + if (gst_osscommon_convert (&osssrc->common, + GST_EVENT_SIZE_FORMAT (event), + GST_EVENT_SIZE_VALUE (event), + &format, &value)) + { + osssrc->buffersize = GST_EVENT_SIZE_VALUE (event); + g_object_notify (G_OBJECT (osssrc), "buffersize"); + retval = TRUE; + } + } default: break; } - gst_event_unref (event); return retval; } -static gboolean -gst_osssrc_open_audio (GstOssSrc *src) +static gboolean +gst_osssrc_send_event (GstElement *element, + GstEvent *event) { - g_return_val_if_fail (!GST_FLAG_IS_SET (src, GST_OSSSRC_OPEN), FALSE); - - /* first try to open the sound card */ - src->fd = open(src->device, O_RDONLY); - - /* if we have it, set the default parameters and go have fun */ - if (src->fd > 0) { - - /* set card state */ - GST_DEBUG (GST_CAT_PLUGIN_INFO,"opened audio: %s",src->device); - - GST_FLAG_SET (src, GST_OSSSRC_OPEN); - return TRUE; - } + GstOssSrc *osssrc = GST_OSSSRC (element); - return FALSE; + return gst_osssrc_src_event (osssrc->srcpad, event); } -static void -gst_osssrc_close_audio (GstOssSrc *src) +static const GstPadQueryType* +gst_osssrc_get_query_types (GstPad *pad) { - g_return_if_fail (GST_FLAG_IS_SET (src, GST_OSSSRC_OPEN)); + static const GstPadQueryType query_types[] = { + GST_PAD_QUERY_POSITION, + 0, + }; + return query_types; +} - close(src->fd); - src->fd = -1; - - GST_FLAG_UNSET (src, GST_OSSSRC_OPEN); -} - -static gboolean -gst_osssrc_sync_parms (GstOssSrc *osssrc) +static gboolean +gst_osssrc_src_query (GstPad *pad, GstPadQueryType type, GstFormat *format, gint64 *value) { - audio_buf_info ispace; - gint frag; - /* remember : ioctl on samplerate returns the sample rate the card - * is actually set to ! Setting it to 44101 Hz could cause it to - * be set to 44101, for example - */ - guint rate; - gint format; - gint bps; - - g_return_val_if_fail (osssrc->fd > 0, FALSE); - - /* get rate, we don't modify the original rate as the audio device - * might not exactly give us the requested value */ - rate = osssrc->rate; - - /* transform format parameters to oss format */ - if (!gst_ossformat_get (osssrc->law, osssrc->endianness, osssrc->sign, - osssrc->width, osssrc->depth, &format, &bps)) - { - return FALSE; + gboolean res = FALSE; + GstOssSrc *osssrc; + + osssrc = GST_OSSSRC (gst_pad_get_parent (pad)); + + switch (type) { + case GST_PAD_QUERY_POSITION: + res = gst_osscommon_convert (&osssrc->common, + GST_FORMAT_BYTES, osssrc->curoffset, + format, value); + break; + default: + break; } - - frag = 0x7fff0006; - - ioctl(osssrc->fd, SNDCTL_DSP_SETFRAGMENT, &frag); - ioctl(osssrc->fd, SNDCTL_DSP_RESET, 0); - - ioctl(osssrc->fd, SNDCTL_DSP_SETFMT, &format); - ioctl(osssrc->fd, SNDCTL_DSP_CHANNELS, &osssrc->channels); - ioctl(osssrc->fd, SNDCTL_DSP_SPEED, &rate); - ioctl(osssrc->fd, SNDCTL_DSP_GETISPACE, &ispace); - ioctl(osssrc->fd, SNDCTL_DSP_GETBLKSIZE, &frag); - - g_print("setting sound card to %dHz %d bit %s (%d bytes buffer, %d fragment)\n", - rate, osssrc->width, - (osssrc->channels == 2) ? "stereo" : "mono", ispace.bytes, frag); - - return TRUE; -} + return res; +} gboolean gst_osssrc_factory_init (GstPlugin *plugin) diff --git a/sys/oss/gstosssrc.h b/sys/oss/gstosssrc.h index 0c082a1..29596fb 100644 --- a/sys/oss/gstosssrc.h +++ b/sys/oss/gstosssrc.h @@ -25,8 +25,8 @@ #define __GST_OSSSRC_H__ -#include #include +#include "gstosscommon.h" G_BEGIN_DECLS @@ -51,34 +51,18 @@ typedef struct _GstOssSrc GstOssSrc; typedef struct _GstOssSrcClass GstOssSrcClass; struct _GstOssSrc { - GstElement element; + GstElement element; /* pads */ - GstPad *srcpad; + GstPad *srcpad; - /* device */ - gchar *device; + GstOssCommon common; - /* sound card */ - gint fd; - - /* audio parameters */ - gint law; - gint endianness; - gint sign; - gint width; - gint depth; - gint rate; - gint channels; - - gboolean need_eos; /* Do we need to emit an EOS? */ + gboolean need_eos; /* Do we need to emit an EOS? */ /* blocking */ - guint64 basetime; - guint64 samples_since_basetime; - gulong curoffset; - gulong bytes_per_read; - + gulong curoffset; + gulong buffersize; }; struct _GstOssSrcClass {