*/
-#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)
{
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;
+}
+
* Boston, MA 02111-1307, USA.
*/
-#ifndef __GST_OSSFORMAT_H__
-#define __GST_OSSFORMAT_H__
+#ifndef __GST_OSSCOMMON_H__
+#define __GST_OSSCOMMON_H__
#include <gst/gst.h>
-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__ */
* Boston, MA 02111-1307, USA.
*/
-
-#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>
#include <gstosssink.h>
-#include <gstosscommon.h>
/* elementfactory information */
static GstElementDetails gst_osssink_details = {
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);
{
GstOssSink *osssink = (GstOssSink *) object;
- g_free (osssink->device);
+ g_free (osssink->common.device);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
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;
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 {
gint delay;
GstClockTime res;
- if (!osssink->bps)
+ if (!osssink->common.bps)
return 0;
delay = gst_osssink_get_delay (osssink);
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;
}
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;
{
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);
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;
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);
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,
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;
}
}
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);
}
}
}
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*
{
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) {
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;
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;
{
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);
}
}
-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:
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;
}
#define __GST_OSSSINK_H__
-#include <config.h>
#include <gst/gst.h>
+#include "gstosscommon.h"
#include "gstossclock.h"
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
+G_BEGIN_DECLS
#define GST_TYPE_OSSSINK \
(gst_osssink_get_type())
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 {
gboolean gst_osssink_factory_init(GstPlugin *plugin);
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
+G_END_DECLS
#endif /* __GST_OSSSINK_H__ */
enum {
ARG_0,
ARG_DEVICE,
- ARG_BYTESPERREAD,
+ ARG_BUFFERSIZE,
+ ARG_FRAGMENT,
};
GST_PAD_TEMPLATE_FACTORY (osssrc_src_factory,
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);
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;
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
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)
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 */
"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;
GstOssSrc *src;
GstBuffer *buf;
glong readbytes;
- glong readsamples;
src = GST_OSSSRC(gst_pad_get_parent (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));
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));
{
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;
}
{
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);
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:
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;
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)
#define __GST_OSSSRC_H__
-#include <config.h>
#include <gst/gst.h>
+#include "gstosscommon.h"
G_BEGIN_DECLS
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 {