diff --git a/sys/oss/Makefile.am b/sys/oss/Makefile.am index 37b0f8fe39..21d957b5a4 100644 --- a/sys/oss/Makefile.am +++ b/sys/oss/Makefile.am @@ -3,11 +3,12 @@ plugin_LTLIBRARIES = libgstossaudio.la EXTRA_LTLIBRARIES = libgstosshelper.la -libgstossaudio_la_SOURCES = gstosssink.c \ +libgstossaudio_la_SOURCES = gstossaudio.c \ + gstosselement.c \ + gstossmixer.c \ + gstosssink.c \ gstosssrc.c \ - gstossaudio.c \ - gstossgst.c \ - gstosscommon.c + gstossgst.c libgstossaudio_la_CFLAGS = $(GST_CFLAGS) libgstossaudio_la_LIBADD = @@ -16,4 +17,9 @@ libgstossaudio_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstosshelper_la_SOURCES = gstosshelper.c libgstosshelper_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -noinst_HEADERS = gstosssink.h gstosssrc.h gstossgst.h gstosshelper.h gstosscommon.h +noinst_HEADERS = gstosssink.h \ + gstosssrc.h \ + gstossgst.h \ + gstosshelper.h \ + gstosselement.h \ + gstossmixer.c diff --git a/sys/oss/gstossaudio.c b/sys/oss/gstossaudio.c index e1d54c3adb..8c9421a7f5 100644 --- a/sys/oss/gstossaudio.c +++ b/sys/oss/gstossaudio.c @@ -17,7 +17,11 @@ * Boston, MA 02111-1307, USA. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "gstosselement.h" #include "gstosssink.h" #include "gstosssrc.h" #include "gstossgst.h" @@ -25,19 +29,16 @@ static gboolean plugin_init (GModule *module, GstPlugin *plugin) { - gboolean ret; - if (!gst_library_load ("gstaudio")) return FALSE; - ret = gst_osssink_factory_init (plugin); - g_return_val_if_fail (ret == TRUE, FALSE); - - ret = gst_osssrc_factory_init (plugin); - g_return_val_if_fail (ret == TRUE, FALSE); - - ret = gst_ossgst_factory_init (plugin); - g_return_val_if_fail (ret == TRUE, FALSE); + if (!gst_osselement_factory_init (plugin) || + !gst_osssrc_factory_init (plugin) || + !gst_osssink_factory_init (plugin) || + !gst_ossgst_factory_init (plugin)) { + g_warning ("Failed to register OSS elements!"); + return FALSE; + } return TRUE; } diff --git a/sys/oss/gstosselement.c b/sys/oss/gstosselement.c new file mode 100644 index 0000000000..f43799868d --- /dev/null +++ b/sys/oss/gstosselement.c @@ -0,0 +1,681 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * gstosssink.c: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gstosselement.h" +#include "gstossmixer.h" + +enum { + ARG_0, + ARG_DEVICE, + ARG_MIXERDEV, +}; + +/* elementfactory information */ +static GstElementDetails gst_osselement_details = { + "Audio Element (OSS)", + "Generic/Audio", + "LGPL", + "Generic OSS element", + VERSION, + "Erik Walthinsen ", + "(C) 1999", +}; + +static void gst_osselement_class_init (GstOssElementClass *klass); +static void gst_osselement_init (GstOssElement *oss); +static void gst_osselement_dispose (GObject *object); + +static void gst_osselement_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void gst_osselement_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static GstElementStateReturn gst_osselement_change_state (GstElement *element); + +static GstElementClass *parent_class = NULL; +/*static guint gst_osssrc_signals[LAST_SIGNAL] = { 0 }; */ + +GType +gst_osselement_get_type (void) +{ + static GType osselement_type = 0; + + if (!osselement_type) { + static const GTypeInfo osselement_info = { + sizeof(GstOssElementClass), + NULL, + NULL, + (GClassInitFunc)gst_osselement_class_init, + NULL, + NULL, + sizeof(GstOssElement), + 0, + (GInstanceInitFunc)gst_osselement_init, + }; + static const GInterfaceInfo ossiface_info = { + (GInterfaceInitFunc) gst_oss_interface_init, + NULL, + NULL, + }; + static const GInterfaceInfo ossmixer_info = { + (GInterfaceInitFunc) gst_ossmixer_interface_init, + NULL, + NULL, + }; + + osselement_type = g_type_register_static (GST_TYPE_ELEMENT, + "GstOssElement", + &osselement_info, 0); + g_type_add_interface_static (osselement_type, + GST_TYPE_INTERFACE, + &ossiface_info); + g_type_add_interface_static (osselement_type, + GST_TYPE_MIXER, + &ossmixer_info); + } + + return osselement_type; +} + +static void +gst_osselement_class_init (GstOssElementClass *klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass*)klass; + gstelement_class = (GstElementClass*)klass; + + parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + + 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_object_class_install_property(G_OBJECT_CLASS(klass), ARG_MIXERDEV, + g_param_spec_string ("mixerdev", "mixer device", + "oss mixer device (/dev/mixerN usually)", + "default", G_PARAM_READWRITE)); + + gobject_class->set_property = gst_osselement_set_property; + gobject_class->get_property = gst_osselement_get_property; + gobject_class->dispose = gst_osselement_dispose; + + gstelement_class->change_state = gst_osselement_change_state; +} + +static void +gst_osselement_init (GstOssElement *oss) +{ + oss->device = g_strdup ("/dev/dsp"); + oss->mixer_dev = g_strdup ("/dev/mixer"); + oss->fd = -1; + oss->mixer_fd = -1; + oss->channellist = NULL; + + gst_osselement_reset (oss); +} + +static void +gst_osselement_dispose (GObject *object) +{ + GstOssElement *oss = (GstOssElement *) object; + + g_free (oss->device); + g_free (oss->mixer_dev); + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +void +gst_osselement_reset (GstOssElement *oss) +{ + oss->law = 0; + oss->endianness = G_BYTE_ORDER; + oss->sign = TRUE; + oss->width = 16; + oss->depth = 16; + oss->channels = 2; + oss->rate = 44100; + oss->fragment = 6; + oss->bps = 0; + +/* AFMT_*_BE not available on all OSS includes (e.g. FBSD) */ +#ifdef WORDS_BIGENDIAN + oss->format = AFMT_S16_BE; +#else + oss->format = AFMT_S16_LE; +#endif /* WORDS_BIGENDIAN */ +} + +static gboolean +gst_ossformat_get (gint law, gint endianness, gboolean sign, gint width, gint depth, + gint *format, gint *bps) +{ + if (width != depth) + return FALSE; + + *bps = 1; + + if (law == 0) { + if (width == 16) { + if (sign == TRUE) { + if (endianness == G_LITTLE_ENDIAN) { + *format = AFMT_S16_LE; + GST_DEBUG ( + "16 bit signed LE, no law (%d)", *format); + } + else if (endianness == G_BIG_ENDIAN) { + *format = AFMT_S16_BE; + GST_DEBUG ( + "16 bit signed BE, no law (%d)", *format); + } + } + else { + if (endianness == G_LITTLE_ENDIAN) { + *format = AFMT_U16_LE; + GST_DEBUG ( + "16 bit unsigned LE, no law (%d)", *format); + } + else if (endianness == G_BIG_ENDIAN) { + *format = AFMT_U16_BE; + GST_DEBUG ( + "16 bit unsigned BE, no law (%d)", *format); + } + } + *bps = 2; + } + else if (width == 8) { + if (sign == TRUE) { + *format = AFMT_S8; + GST_DEBUG ( + "8 bit signed, no law (%d)", *format); + } + else { + *format = AFMT_U8; + GST_DEBUG ( + "8 bit unsigned, no law (%d)", *format); + } + *bps = 1; + } + } else if (law == 1) { + *format = AFMT_MU_LAW; + GST_DEBUG ( + "mu law (%d)", *format); + } else if (law == 2) { + *format = AFMT_A_LAW; + GST_DEBUG ( + "a law (%d)", *format); + } else { + g_critical ("unknown law"); + return FALSE; + } + + return TRUE; +} + +gboolean +gst_osselement_parse_caps (GstOssElement *oss, GstCaps *caps) +{ + gint bps, format; + + gst_caps_get_int (caps, "width", &oss->width); + gst_caps_get_int (caps, "depth", &oss->depth); + + if (oss->width != oss->depth) + return FALSE; + + gst_caps_get_int (caps, "law", &oss->law); + gst_caps_get_int (caps, "endianness", &oss->endianness); + gst_caps_get_boolean (caps, "signed", &oss->sign); + + if (!gst_ossformat_get (oss->law, oss->endianness, oss->sign, + oss->width, oss->depth, &format, &bps)) + { + GST_DEBUG ("could not get format"); + return FALSE; + } + + gst_caps_get_int (caps, "channels", &oss->channels); + gst_caps_get_int (caps, "rate", &oss->rate); + + oss->bps = bps * oss->channels * oss->rate; + oss->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_osselement_merge_fixed_caps (GstOssElement *oss, GstCaps *caps) +{ + gint bps, format; + + /* peel off fixed stuff from the caps */ + GET_FIXED_INT (caps, "law", &oss->law); + GET_FIXED_INT (caps, "endianness", &oss->endianness); + GET_FIXED_BOOLEAN (caps, "signed", &oss->sign); + GET_FIXED_INT (caps, "width", &oss->width); + GET_FIXED_INT (caps, "depth", &oss->depth); + + if (!gst_ossformat_get (oss->law, oss->endianness, oss->sign, + oss->width, oss->depth, &format, &bps)) + { + return FALSE; + } + + GET_FIXED_INT (caps, "rate", &oss->rate); + GET_FIXED_INT (caps, "channels", &oss->channels); + + oss->bps = bps * oss->channels * oss->rate; + oss->format = format; + + return TRUE; +} + +gboolean +gst_osselement_sync_parms (GstOssElement *oss) +{ + audio_buf_info space; + int frag; + gint target_format; + gint target_channels; + gint target_rate; + gint fragscale, frag_ln; + + if (oss->fd == -1) + return FALSE; + + if (oss->fragment >> 16) + frag = oss->fragment; + else + frag = 0x7FFF0000 | oss->fragment; + + GST_INFO ("osselement: setting sound card to %dHz %d format %s (%08x fragment)", + oss->rate, oss->format, + (oss->channels == 2) ? "stereo" : "mono", frag); + + ioctl (oss->fd, SNDCTL_DSP_SETFRAGMENT, &frag); + ioctl (oss->fd, SNDCTL_DSP_RESET, 0); + + target_format = oss->format; + target_channels = oss->channels; + target_rate = oss->rate; + + ioctl (oss->fd, SNDCTL_DSP_SETFMT, &oss->format); + ioctl (oss->fd, SNDCTL_DSP_CHANNELS, &oss->channels); + ioctl (oss->fd, SNDCTL_DSP_SPEED, &oss->rate); + + ioctl (oss->fd, SNDCTL_DSP_GETBLKSIZE, &oss->fragment_size); + + if (oss->mode == GST_OSSELEMENT_WRITE) { + ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &space); + } + else { + ioctl (oss->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++; + } + oss->fragment = space.fragstotal << 16 | frag_ln; + + GST_INFO ("osselement: set sound card to %dHz, %d format, %s " + "(%d bytes buffer, %08x fragment)", + oss->rate, oss->format, + (oss->channels == 2) ? "stereo" : "mono", + space.bytes, oss->fragment); + + oss->fragment_time = (GST_SECOND * oss->fragment_size) / oss->bps; + GST_INFO ("fragment time %u %" G_GUINT64_FORMAT "\n", + oss->bps, oss->fragment_time); + + if (target_format != oss->format || + target_channels != oss->channels || + target_rate != oss->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; +} + +static gboolean +gst_osselement_open_audio (GstOssElement *oss) +{ + gint caps; + GstOssOpenMode mode = GST_OSSELEMENT_READ; + const GList *padlist; + + g_return_val_if_fail (oss->fd == -1, FALSE); + GST_INFO ("osselement: attempting to open sound device"); + + /* Ok, so how do we open the device? We assume that we have (max.) one + * pad, and if this is a sinkpad, we're osssink (w). else, we're osssrc (r) */ + padlist = gst_element_get_pad_list (GST_ELEMENT (oss)); + if (padlist != NULL) { + GstPad *firstpad = padlist->data; + if (GST_PAD_IS_SINK (firstpad)) { + mode = GST_OSSELEMENT_WRITE; + } + } + + /* first try to open the sound card */ + if (mode == GST_OSSELEMENT_WRITE) { + /* open non blocking first so that it returns immediatly with an error + * when we cannot get to the device */ + oss->fd = open (oss->device, O_WRONLY | O_NONBLOCK); + + if (oss->fd >= 0) { + close (oss->fd); + + /* re-open the sound device in blocking mode */ + oss->fd = open (oss->device, O_WRONLY); + } + } + else { + oss->fd = open (oss->device, O_RDONLY); + } + + if (oss->fd < 0) { + switch (errno) { + case EBUSY: + gst_element_error (GST_ELEMENT (oss), + "osselement: Unable to open %s (in use ?)", + oss->device); + break; + case EISDIR: + gst_element_error (GST_ELEMENT (oss), + "osselement: Device %s is a directory", + oss->device); + break; + case EACCES: + case ETXTBSY: + gst_element_error (GST_ELEMENT (oss), + "osselement: Cannot access %s, check permissions", + oss->device); + break; + case ENXIO: + case ENODEV: + case ENOENT: + gst_element_error (GST_ELEMENT (oss), + "osselement: Cannot access %s, does it exist ?", + oss->device); + break; + case EROFS: + gst_element_error (GST_ELEMENT (oss), + "osselement: Cannot access %s, read-only filesystem ?", + oss->device); + default: + /* FIXME: strerror is not threadsafe */ + gst_element_error (GST_ELEMENT (oss), + "osselement: Cannot open %s, generic error: %s", + oss->device, strerror (errno)); + break; + } + return FALSE; + } + + oss->mode = mode; + + /* we have it, set the default parameters and go have fun */ + /* set card state */ + ioctl (oss->fd, SNDCTL_DSP_GETCAPS, &caps); + + GST_INFO ("osselement: Capabilities %08x", caps); + + if (caps & DSP_CAP_DUPLEX) GST_INFO ( "osselement: Full duplex"); + if (caps & DSP_CAP_REALTIME) GST_INFO ( "osselement: Realtime"); + if (caps & DSP_CAP_BATCH) GST_INFO ( "osselement: Batch"); + if (caps & DSP_CAP_COPROC) GST_INFO ( "osselement: Has coprocessor"); + if (caps & DSP_CAP_TRIGGER) GST_INFO ( "osselement: Trigger"); + if (caps & DSP_CAP_MMAP) GST_INFO ( "osselement: Direct access"); + +#ifdef DSP_CAP_MULTI + if (caps & DSP_CAP_MULTI) GST_INFO ( "osselement: Multiple open"); +#endif /* DSP_CAP_MULTI */ + +#ifdef DSP_CAP_BIND + if (caps & DSP_CAP_BIND) GST_INFO ( "osselement: Channel binding"); +#endif /* DSP_CAP_BIND */ + + ioctl(oss->fd, SNDCTL_DSP_GETFMTS, &caps); + + GST_INFO ( "osselement: Formats %08x", caps); + if (caps & AFMT_MU_LAW) GST_INFO ( "osselement: MU_LAW"); + if (caps & AFMT_A_LAW) GST_INFO ( "osselement: A_LAW"); + if (caps & AFMT_IMA_ADPCM) GST_INFO ( "osselement: IMA_ADPCM"); + if (caps & AFMT_U8) GST_INFO ( "osselement: U8"); + if (caps & AFMT_S16_LE) GST_INFO ( "osselement: S16_LE"); + if (caps & AFMT_S16_BE) GST_INFO ( "osselement: S16_BE"); + if (caps & AFMT_S8) GST_INFO ( "osselement: S8"); + if (caps & AFMT_U16_LE) GST_INFO ( "osselement: U16_LE"); + if (caps & AFMT_U16_BE) GST_INFO ( "osselement: U16_BE"); + if (caps & AFMT_MPEG) GST_INFO ( "osselement: MPEG"); +#ifdef AFMT_AC3 + if (caps & AFMT_AC3) GST_INFO ( "osselement: AC3"); +#endif + + GST_INFO ("osselement: opened audio (%s) with fd=%d", + oss->device, oss->fd); + + oss->caps = caps; + + gst_ossmixer_build_list (oss); + + return TRUE; +} + +static void +gst_osselement_close_audio (GstOssElement *oss) +{ + if (oss->fd < 0) + return; + + gst_ossmixer_free_list (oss); + close(oss->fd); + oss->fd = -1; +} + +gboolean +gst_osselement_convert (GstOssElement *oss, + 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 (oss->bps == 0 || oss->channels == 0 || oss->width == 0) + return FALSE; + + switch (src_format) { + case GST_FORMAT_BYTES: + switch (*dest_format) { + case GST_FORMAT_TIME: + *dest_value = src_value * GST_SECOND / oss->bps; + break; + case GST_FORMAT_DEFAULT: + *dest_value = src_value / (oss->channels * oss->width); + break; + default: + res = FALSE; + } + break; + case GST_FORMAT_TIME: + switch (*dest_format) { + case GST_FORMAT_BYTES: + *dest_value = src_value * oss->bps / GST_SECOND; + break; + case GST_FORMAT_DEFAULT: + *dest_value = src_value * oss->rate / GST_SECOND; + break; + default: + res = FALSE; + } + break; + case GST_FORMAT_DEFAULT: + switch (*dest_format) { + case GST_FORMAT_TIME: + *dest_value = src_value * GST_SECOND / oss->rate; + break; + case GST_FORMAT_BYTES: + *dest_value = src_value * oss->channels * oss->width; + break; + default: + res = FALSE; + } + break; + default: + res = FALSE; + } + + return res; +} + +static void +gst_osselement_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GstOssElement *oss = GST_OSSELEMENT (object); + + switch (prop_id) { + case ARG_DEVICE: + /* disallow changing the device while it is opened + get_property("device") should return the right one */ + if (gst_element_get_state (GST_ELEMENT (oss)) != GST_STATE_NULL) { + g_free (oss->device); + oss->device = g_strdup (g_value_get_string (value)); + } + break; + case ARG_MIXERDEV: + /* disallow changing the device while it is opened + get_property("mixerdev") should return the right one */ + if (gst_element_get_state (GST_ELEMENT (oss)) != GST_STATE_NULL) { + g_free (oss->mixer_dev); + oss->mixer_dev = g_strdup (g_value_get_string (value)); + } + break; + default: + break; + } +} + +static void +gst_osselement_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GstOssElement *oss = GST_OSSELEMENT (object); + + switch (prop_id) { + case ARG_DEVICE: + g_value_set_string (value, oss->device); + break; + case ARG_MIXERDEV: + g_value_set_string (value, oss->mixer_dev); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstElementStateReturn +gst_osselement_change_state (GstElement *element) +{ + GstOssElement *oss = GST_OSSELEMENT (element); + + switch (GST_STATE_TRANSITION (element)) { + case GST_STATE_NULL_TO_READY: + if (!gst_osselement_open_audio (oss)) { + return GST_STATE_FAILURE; + } + GST_INFO ("osselement: opened sound device"); + break; + case GST_STATE_READY_TO_NULL: + gst_osselement_close_audio (oss); + gst_osselement_reset (oss); + GST_INFO ("osselement: closed sound device"); + break; + default: + break; + } + + if (GST_ELEMENT_CLASS (parent_class)->change_state) + return GST_ELEMENT_CLASS (parent_class)->change_state (element); + + return GST_STATE_SUCCESS; +} + +gboolean +gst_osselement_factory_init (GstPlugin *plugin) +{ + GstElementFactory *factory; + + factory = gst_element_factory_new ("osselement", + GST_TYPE_OSSELEMENT, + &gst_osselement_details); + g_return_val_if_fail (factory != NULL, FALSE); + + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); + + return TRUE; +} diff --git a/sys/oss/gstosselement.h b/sys/oss/gstosselement.h new file mode 100644 index 0000000000..eeae84b071 --- /dev/null +++ b/sys/oss/gstosselement.h @@ -0,0 +1,113 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * gstosselement.h: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_OSS_ELEMENT_H__ +#define __GST_OSS_ELEMENT_H__ + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_OSSELEMENT \ + (gst_osselement_get_type()) +#define GST_OSSELEMENT(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OSSELEMENT,GstOssElement)) +#define GST_OSSELEMENT_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OSSELEMENT,GstOssElementClass)) +#define GST_IS_OSSELEMENT(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OSSELEMENT)) +#define GST_IS_OSSELEMENT_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OSSELEMENT)) + +typedef struct _GstOssElement GstOssElement; +typedef struct _GstOssElementClass GstOssElementClass; + +typedef enum { + GST_OSSELEMENT_READ, + GST_OSSELEMENT_WRITE, +} GstOssOpenMode; + +struct _GstOssElement +{ + /* yes, we're a gstelement too */ + GstElement parent; + + gchar *device, + *mixer_dev; + + /* 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; + + /* mixer stuff */ + GList *channellist; + guint32 stereomask, + recdevs, + recmask, + mixcaps; + gint mixer_fd; +}; + +struct _GstOssElementClass { + GstElementClass klass; +}; + +GType gst_osselement_get_type (void); + +/* factory register function */ +gboolean gst_osselement_factory_init (GstPlugin *plugin); + +/* some useful functions */ +gboolean gst_osselement_parse_caps (GstOssElement *oss, + GstCaps *caps); +gboolean gst_osselement_merge_fixed_caps (GstOssElement *oss, + GstCaps *caps); + +gboolean gst_osselement_sync_parms (GstOssElement *oss); +void gst_osselement_reset (GstOssElement *oss); + +gboolean gst_osselement_convert (GstOssElement *oss, + GstFormat src_format, + gint64 src_value, + GstFormat *dest_format, + gint64 *dest_value); + +G_END_DECLS + +#endif /* __GST_OSS_ELEMENT_H__ */ diff --git a/sys/oss/gstossmixer.c b/sys/oss/gstossmixer.c new file mode 100644 index 0000000000..50efc2f4a1 --- /dev/null +++ b/sys/oss/gstossmixer.c @@ -0,0 +1,323 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * gstossmixer.h: mixer interface implementation for OSS + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gstossmixer.h" + +#define MASK_BIT_IS_SET(mask, bit) \ + (mask & (1 << bit)) + +static gboolean gst_ossmixer_supported (GstInterface *iface); + +static const GList * gst_ossmixer_list_channels (GstMixer *ossmixer); + +static void gst_ossmixer_set_volume (GstMixer *ossmixer, + GstMixerChannel *channel, + gint *volumes); +static void gst_ossmixer_get_volume (GstMixer *ossmixer, + GstMixerChannel *channel, + gint *volumes); + +static void gst_ossmixer_set_record (GstMixer *ossmixer, + GstMixerChannel *channel, + gboolean record); +static void gst_ossmixer_set_mute (GstMixer *ossmixer, + GstMixerChannel *channel, + gboolean mute); + +static const gchar *labels[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_LABELS; + +GstMixerChannel * +gst_ossmixer_channel_new (GstOssElement *oss, + gint channel_num, + gint max_chans, + gint flags) +{ + GstMixerChannel *channel = (GstMixerChannel *) g_new (GstOssMixerChannel, 1); + gint volumes[2]; + + channel->label = g_strdup (labels[channel_num]); + channel->num_channels = max_chans; + channel->flags = flags; + channel->min_volume = 0; + channel->max_volume = 100; + ((GstOssMixerChannel *) channel)->channel_num = channel_num; + + /* volume */ + gst_ossmixer_get_volume (GST_MIXER (oss), + channel, volumes); + if (max_chans == 1) { + volumes[1] = 0; + } + ((GstOssMixerChannel *) channel)->lvol = volumes[0]; + ((GstOssMixerChannel *) channel)->rvol = volumes[1]; + + return channel; +} + +void +gst_ossmixer_channel_free (GstMixerChannel *channel) +{ + g_free (channel->label); + g_free (channel); +} + +void +gst_oss_interface_init (GstInterfaceClass *klass) +{ + /* default virtual functions */ + klass->supported = gst_ossmixer_supported; +} + +void +gst_ossmixer_interface_init (GstMixerClass *klass) +{ + /* default virtual functions */ + klass->list_channels = gst_ossmixer_list_channels; + klass->set_volume = gst_ossmixer_set_volume; + klass->get_volume = gst_ossmixer_get_volume; + klass->set_mute = gst_ossmixer_set_mute; + klass->set_record = gst_ossmixer_set_record; +} + +static gboolean +gst_ossmixer_supported (GstInterface *iface) +{ + return (GST_OSSELEMENT (iface)->mixer_fd != -1); +} + +static const GList * +gst_ossmixer_list_channels (GstMixer *mixer) +{ + GstOssElement *oss = GST_OSSELEMENT (mixer); + + g_return_val_if_fail (oss->mixer_fd != -1, NULL); + + return (const GList *) GST_OSSELEMENT (mixer)->channellist; +} + +static void +gst_ossmixer_get_volume (GstMixer *mixer, + GstMixerChannel *channel, + gint *volumes) +{ + gint volume; + GstOssElement *oss = GST_OSSELEMENT (mixer); + GstOssMixerChannel *osschannel = (GstOssMixerChannel *) channel; + + g_return_if_fail (oss->mixer_fd != -1); + + if (channel->flags & GST_MIXER_CHANNEL_MUTE) { + volumes[0] = osschannel->lvol; + if (channel->num_channels == 2) { + volumes[1] = osschannel->rvol; + } + } else { + /* get */ + if (ioctl(oss->mixer_fd, MIXER_READ (osschannel->channel_num), &volume) < 0) { + g_warning("Error getting recording device (%d) volume (0x%x): %s\n", + osschannel->channel_num, volume, strerror(errno)); + volume = 0; + } + + osschannel->lvol = volumes[0] = (volume & 0xff); + if (channel->num_channels == 2) { + osschannel->rvol = volumes[1] = ((volume >> 8) & 0xff); + } + } +} + +static void +gst_ossmixer_set_volume (GstMixer *mixer, + GstMixerChannel *channel, + gint *volumes) +{ + gint volume; + GstOssElement *oss = GST_OSSELEMENT (mixer); + GstOssMixerChannel *osschannel = (GstOssMixerChannel *) channel; + + g_return_if_fail (oss->mixer_fd != -1); + + /* prepare the value for ioctl() */ + if (!(channel->flags & GST_MIXER_CHANNEL_MUTE)) { + volume = (volumes[0] & 0xff); + if (channel->num_channels == 2) { + volume |= ((volumes[1] & 0xff) << 8); + } + + /* set */ + if (ioctl(oss->mixer_fd, MIXER_WRITE (osschannel->channel_num), &volume) < 0) { + g_warning("Error setting recording device (%d) volume (0x%x): %s\n", + osschannel->channel_num, volume, strerror(errno)); + return; + } + } + + osschannel->lvol = volumes[0]; + if (channel->num_channels == 2) { + osschannel->rvol = volumes[1]; + } +} + +static void +gst_ossmixer_set_mute (GstMixer *mixer, + GstMixerChannel *channel, + gboolean mute) +{ + int volume; + GstOssElement *oss = GST_OSSELEMENT (mixer); + GstOssMixerChannel *osschannel = (GstOssMixerChannel *) channel; + + g_return_if_fail (oss->mixer_fd != -1); + + if (mute) { + volume = 0; + } else { + volume = (osschannel->lvol & 0xff); + if (MASK_BIT_IS_SET (oss->stereomask, osschannel->channel_num)) { + volume |= ((osschannel->rvol & 0xff) << 8); + } + } + + if (ioctl(oss->mixer_fd, MIXER_WRITE(osschannel->channel_num), &volume) < 0) { + g_warning("Error setting mixer recording device volume (0x%x): %s", + volume, strerror(errno)); + return; + } + + if (mute) { + channel->flags |= GST_MIXER_CHANNEL_MUTE; + } else { + channel->flags &= ~GST_MIXER_CHANNEL_MUTE; + } +} + +static void +gst_ossmixer_set_record (GstMixer *mixer, + GstMixerChannel *channel, + gboolean record) +{ + GstOssElement *oss = GST_OSSELEMENT (mixer); + GstOssMixerChannel *osschannel = (GstOssMixerChannel *) channel; + + g_return_if_fail (oss->mixer_fd != -1); + + /* if we're exclusive, then we need to unset the current one(s) */ + if (oss->mixcaps & SOUND_CAP_EXCL_INPUT) { + GList *channel; + for (channel = oss->channellist; channel != NULL; channel = channel->next) { + GstMixerChannel *turn = (GstMixerChannel *) channel->data; + turn->flags &= ~GST_MIXER_CHANNEL_RECORD; + } + oss->recdevs = 0; + } + + /* set new record bit, if needed */ + if (record) { + oss->recdevs |= (1 << osschannel->channel_num); + } else { + oss->recdevs &= ~(1 << osschannel->channel_num); + } + + /* set it to the device */ + if (ioctl(oss->mixer_fd, SOUND_MIXER_WRITE_RECSRC, &oss->recdevs) < 0) { + g_warning("Error setting mixer recording devices (0x%x): %s", + oss->recdevs, strerror(errno)); + return; + } + + if (record) { + channel->flags |= GST_MIXER_CHANNEL_RECORD; + } else { + channel->flags &= ~GST_MIXER_CHANNEL_RECORD; + } +} + +void +gst_ossmixer_build_list (GstOssElement *oss) +{ + gint i, devmask; + + g_return_if_fail (oss->mixer_fd == -1); + + oss->mixer_fd = open (oss->mixer_dev, O_RDWR); + if (oss->mixer_fd == -1) { + g_warning ("Failed to open mixer device %s, mixing disabled: %s", + oss->mixer_dev, strerror (errno)); + return; + } + + /* get masks */ + ioctl (oss->mixer_fd, SOUND_MIXER_READ_RECMASK, &oss->recmask); + ioctl (oss->mixer_fd, SOUND_MIXER_READ_RECSRC, &oss->recdevs); + ioctl (oss->mixer_fd, SOUND_MIXER_READ_STEREODEVS, &oss->stereomask); + ioctl (oss->mixer_fd, SOUND_MIXER_READ_DEVMASK, &devmask); + ioctl (oss->mixer_fd, SOUND_MIXER_READ_CAPS, &oss->mixcaps); + + /* build channel list */ + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { + if (devmask & (1 << i)) { + GstMixerChannel *channel; + gboolean input = FALSE, stereo = FALSE, record = FALSE; + + /* channel exists, make up capabilities */ + if (MASK_BIT_IS_SET (oss->stereomask, i)) + stereo = TRUE; + if (MASK_BIT_IS_SET (oss->recmask, i)) + input = TRUE; + if (MASK_BIT_IS_SET (oss->recdevs, i)) + record = TRUE; + + /* add channel to list */ + channel = gst_ossmixer_channel_new (oss, i, stereo ? 2 : 1, + (record ? GST_MIXER_CHANNEL_RECORD : 0) | + (input ? GST_MIXER_CHANNEL_INPUT : + GST_MIXER_CHANNEL_OUTPUT)); + oss->channellist = g_list_append (oss->channellist, channel); + } + } +} + +void +gst_ossmixer_free_list (GstOssElement *oss) +{ + g_return_if_fail (oss->mixer_fd != -1); + + g_list_foreach (oss->channellist, (GFunc) gst_ossmixer_channel_free, NULL); + g_list_free (oss->channellist); + oss->channellist = NULL; + + close (oss->mixer_fd); + oss->mixer_fd = -1; +} diff --git a/sys/oss/gstossmixer.h b/sys/oss/gstossmixer.h new file mode 100644 index 0000000000..eddb40ac0f --- /dev/null +++ b/sys/oss/gstossmixer.h @@ -0,0 +1,45 @@ +/* GStreamer + * Copyright (C) 1999,2000 Erik Walthinsen + * 2000 Wim Taymans + * + * gstossmixer.h: mixer interface implementation for OSS + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_OSS_MIXER_H__ +#define __GST_OSS_MIXER_H__ + +#include +#include +#include "gstosselement.h" + +G_BEGIN_DECLS + +typedef struct _GstOssMixerChannel { + GstMixerChannel parent; + gint lvol, rvol; + gint channel_num; +} GstOssMixerChannel; + +void gst_ossmixer_interface_init (GstMixerClass *klass); +void gst_oss_interface_init (GstInterfaceClass *klass); +void gst_ossmixer_build_list (GstOssElement *oss); +void gst_ossmixer_free_list (GstOssElement *oss); + +G_END_DECLS + +#endif /* __GST_OSS_MIXER_H__ */ diff --git a/sys/oss/gstosssink.c b/sys/oss/gstosssink.c index 05a0419dfc..067f69cebe 100644 --- a/sys/oss/gstosssink.c +++ b/sys/oss/gstosssink.c @@ -45,7 +45,6 @@ static GstElementDetails gst_osssink_details = { static void gst_osssink_class_init (GstOssSinkClass *klass); static void gst_osssink_init (GstOssSink *osssink); static void gst_osssink_dispose (GObject *object); -static void gst_osssink_finalize (GObject *object); static GstElementStateReturn gst_osssink_change_state (GstElement *element); static void gst_osssink_set_clock (GstElement *element, GstClock *clock); @@ -78,7 +77,6 @@ enum { enum { ARG_0, - ARG_DEVICE, ARG_MUTE, ARG_FRAGMENT, ARG_BUFFER_SIZE, @@ -132,7 +130,7 @@ gst_osssink_get_type (void) 0, (GInstanceInitFunc)gst_osssink_init, }; - osssink_type = g_type_register_static (GST_TYPE_ELEMENT, "GstOssSink", &osssink_info, 0); + osssink_type = g_type_register_static (GST_TYPE_OSSELEMENT, "GstOssSink", &osssink_info, 0); } return osssink_type; @@ -162,16 +160,6 @@ gst_osssink_dispose (GObject *object) G_OBJECT_CLASS (parent_class)->dispose (object); } -static void -gst_osssink_finalize (GObject *object) -{ - GstOssSink *osssink = (GstOssSink *) object; - - g_free (osssink->common.device); - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - static void gst_osssink_class_init (GstOssSinkClass *klass) { @@ -181,11 +169,8 @@ gst_osssink_class_init (GstOssSinkClass *klass) gobject_class = (GObjectClass*)klass; gstelement_class = (GstElementClass*)klass; - parent_class = g_type_class_ref(GST_TYPE_ELEMENT); + parent_class = g_type_class_ref(GST_TYPE_OSSELEMENT); - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DEVICE, - g_param_spec_string ("device", "Device", "The device to use for output", - "/dev/dsp", G_PARAM_READWRITE)); g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MUTE, g_param_spec_boolean ("mute", "Mute", "Mute the audio", FALSE, G_PARAM_READWRITE)); @@ -211,7 +196,6 @@ gst_osssink_class_init (GstOssSinkClass *klass) gobject_class->set_property = gst_osssink_set_property; gobject_class->get_property = gst_osssink_get_property; gobject_class->dispose = gst_osssink_dispose; - gobject_class->finalize = gst_osssink_finalize; gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_osssink_change_state); gstelement_class->query = GST_DEBUG_FUNCPTR (gst_osssink_query); @@ -235,8 +219,6 @@ gst_osssink_init (GstOssSink *osssink) gst_pad_set_chain_function (osssink->sinkpad, gst_osssink_chain); - gst_osscommon_init (&osssink->common); - osssink->bufsize = 4096; osssink->chunk_size = 4096; osssink->resync = FALSE; @@ -260,10 +242,10 @@ gst_osssink_sinkconnect (GstPad *pad, GstCaps *caps) if (!GST_CAPS_IS_FIXED (caps)) return GST_PAD_LINK_DELAYED; - if (!gst_osscommon_parse_caps (&osssink->common, caps)) + if (!gst_osselement_parse_caps (GST_OSSELEMENT (osssink), caps)) return GST_PAD_LINK_REFUSED; - if (!gst_osscommon_sync_parms (&osssink->common)) { + if (!gst_osselement_sync_parms (GST_OSSELEMENT (osssink))) { return GST_PAD_LINK_REFUSED; } @@ -275,12 +257,12 @@ gst_osssink_get_delay (GstOssSink *osssink) { gint delay = 0; - if (osssink->common.fd == -1) + if (GST_OSSELEMENT (osssink)->fd == -1) return 0; - if (ioctl (osssink->common.fd, SNDCTL_DSP_GETODELAY, &delay) < 0) { + if (ioctl (GST_OSSELEMENT (osssink)->fd, SNDCTL_DSP_GETODELAY, &delay) < 0) { audio_buf_info info; - if (ioctl (osssink->common.fd, SNDCTL_DSP_GETOSPACE, &info) < 0) { + if (ioctl (GST_OSSELEMENT (osssink)->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) { delay = 0; } else { @@ -297,7 +279,7 @@ gst_osssink_get_time (GstClock *clock, gpointer data) gint delay; GstClockTime res; - if (!osssink->common.bps) + if (!GST_OSSELEMENT (osssink)->bps) return 0; delay = gst_osssink_get_delay (osssink); @@ -308,7 +290,7 @@ gst_osssink_get_time (GstClock *clock, gpointer data) if (((guint64)delay) > osssink->handled) { delay = osssink->handled; } - res = (osssink->handled - delay) * GST_SECOND / osssink->common.bps; + res = (osssink->handled - delay) * GST_SECOND / GST_OSSELEMENT (osssink)->bps; return res; } @@ -347,7 +329,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf) switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: - ioctl (osssink->common.fd, SNDCTL_DSP_SYNC); + ioctl (GST_OSSELEMENT (osssink)->fd, SNDCTL_DSP_SYNC); gst_audio_clock_set_active (GST_AUDIO_CLOCK (osssink->provided_clock), FALSE); gst_pad_event_default (pad, event); return; @@ -355,7 +337,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf) { gint64 value; - ioctl (osssink->common.fd, SNDCTL_DSP_RESET); + ioctl (GST_OSSELEMENT (osssink)->fd, SNDCTL_DSP_RESET); if (gst_event_discont_get_value (event, GST_FORMAT_TIME, &value)) { if (!gst_clock_handle_discont (osssink->clock, value)) gst_audio_clock_set_active (GST_AUDIO_CLOCK (osssink->provided_clock), FALSE); @@ -372,7 +354,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf) return; } - if (!osssink->common.bps) { + if (!GST_OSSELEMENT (osssink)->bps) { gst_buffer_unref (buf); gst_element_error (GST_ELEMENT (osssink), "capsnego was never performed, unknown data type"); return; @@ -380,7 +362,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf) buftime = GST_BUFFER_TIMESTAMP (buf); - if (osssink->common.fd >= 0) { + if (GST_OSSELEMENT (osssink)->fd >= 0) { if (!osssink->mute) { guchar *data = GST_BUFFER_DATA (buf); gint size = GST_BUFFER_SIZE (buf); @@ -392,7 +374,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf) GstClockTimeDiff jitter; delay = gst_osssink_get_delay (osssink); - queued = delay * GST_SECOND / osssink->common.bps; + queued = delay * GST_SECOND / GST_OSSELEMENT (osssink)->bps; if (osssink->resync && osssink->sync) { GstClockID id = gst_clock_new_single_shot_id (osssink->clock, buftime - queued); @@ -415,7 +397,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf) else { audio_buf_info ospace; - ioctl (osssink->common.fd, SNDCTL_DSP_GETOSPACE, &ospace); + ioctl (GST_OSSELEMENT (osssink)->fd, SNDCTL_DSP_GETOSPACE, &ospace); if (ospace.bytes >= size) { to_write = size; @@ -423,7 +405,7 @@ gst_osssink_chain (GstPad *pad, GstBuffer *buf) } while (to_write > 0) { - gint done = write (osssink->common.fd, data, + gint done = write (GST_OSSELEMENT (osssink)->fd, data, MIN (to_write, osssink->chunk_size)); if (done == -1) { @@ -464,8 +446,9 @@ gst_osssink_convert (GstPad *pad, GstFormat src_format, gint64 src_value, osssink = GST_OSSSINK (gst_pad_get_parent (pad)); - return gst_osscommon_convert (&osssink->common, src_format, src_value, - dest_format, dest_value); + return gst_osselement_convert (GST_OSSELEMENT (osssink), + src_format, src_value, + dest_format, dest_value); } static const GstQueryType* @@ -528,23 +511,13 @@ gst_osssink_set_property (GObject *object, guint prop_id, const GValue *value, G osssink = GST_OSSSINK (object); switch (prop_id) { - case ARG_DEVICE: - /* disallow changing the device while it is opened - get_property("device") should return the right one */ - if (!GST_FLAG_IS_SET (osssink, GST_OSSSINK_OPEN)) - { - g_free (osssink->common.device); - osssink->common.device = g_strdup (g_value_get_string (value)); - g_object_notify (object, "device"); - } - break; case ARG_MUTE: osssink->mute = g_value_get_boolean (value); g_object_notify (G_OBJECT (osssink), "mute"); break; case ARG_FRAGMENT: - osssink->common.fragment = g_value_get_int (value); - gst_osscommon_sync_parms (&osssink->common); + GST_OSSELEMENT (osssink)->fragment = g_value_get_int (value); + gst_osselement_sync_parms (GST_OSSELEMENT (osssink)); break; case ARG_BUFFER_SIZE: osssink->bufsize = g_value_get_uint (value); @@ -572,14 +545,11 @@ gst_osssink_get_property (GObject *object, guint prop_id, GValue *value, GParamS osssink = GST_OSSSINK (object); switch (prop_id) { - case ARG_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->common.fragment); + g_value_set_int (value, GST_OSSELEMENT (osssink)->fragment); break; case ARG_BUFFER_SIZE: g_value_set_uint (value, osssink->bufsize); @@ -604,43 +574,23 @@ gst_osssink_change_state (GstElement *element) osssink = GST_OSSSINK (element); switch (GST_STATE_TRANSITION (element)) { - case GST_STATE_NULL_TO_READY: - if (!GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN)) { - 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: break; case GST_STATE_PAUSED_TO_PLAYING: osssink->resync = TRUE; break; case GST_STATE_PLAYING_TO_PAUSED: - { if (GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN)) - ioctl (osssink->common.fd, SNDCTL_DSP_RESET, 0); + ioctl (GST_OSSELEMENT (osssink)->fd, SNDCTL_DSP_RESET, 0); gst_audio_clock_set_active (GST_AUDIO_CLOCK (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->common.fd, SNDCTL_DSP_RESET, 0); - gst_osscommon_reset (&osssink->common); + ioctl (GST_OSSELEMENT (osssink)->fd, SNDCTL_DSP_RESET, 0); + gst_osselement_reset (GST_OSSELEMENT (osssink)); break; - case GST_STATE_READY_TO_NULL: - if (GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN)) { - gst_osscommon_close_audio (&osssink->common); - GST_FLAG_UNSET (osssink, GST_OSSSINK_OPEN); - - GST_INFO ( "osssink: closed sound device"); - } + default: break; } diff --git a/sys/oss/gstosssink.h b/sys/oss/gstosssink.h index 7427769d2d..590ce7f23e 100644 --- a/sys/oss/gstosssink.h +++ b/sys/oss/gstosssink.h @@ -27,7 +27,7 @@ #include -#include "gstosscommon.h" +#include "gstosselement.h" #include G_BEGIN_DECLS @@ -53,7 +53,7 @@ typedef struct _GstOssSink GstOssSink; typedef struct _GstOssSinkClass GstOssSinkClass; struct _GstOssSink { - GstElement element; + GstOssElement element; GstPad *sinkpad; GstBufferPool *sinkpool; @@ -64,12 +64,9 @@ struct _GstOssSink { gboolean sync; guint64 handled; - GstOssCommon common; - gboolean mute; guint bufsize; guint chunk_size; - }; struct _GstOssSinkClass { diff --git a/sys/oss/gstosssrc.c b/sys/oss/gstosssrc.c index 0e41d247bc..c2ff002596 100644 --- a/sys/oss/gstosssrc.c +++ b/sys/oss/gstosssrc.c @@ -33,7 +33,7 @@ #include #include -#include +#include #include /* elementfactory information */ @@ -56,7 +56,6 @@ enum { enum { ARG_0, - ARG_DEVICE, ARG_BUFFERSIZE, ARG_FRAGMENT, }; @@ -89,7 +88,6 @@ GST_PAD_TEMPLATE_FACTORY (osssrc_src_factory, static void gst_osssrc_class_init (GstOssSrcClass *klass); static void gst_osssrc_init (GstOssSrc *osssrc); static void gst_osssrc_dispose (GObject *object); -static void gst_osssrc_finalize (GObject *object); static GstPadLinkReturn gst_osssrc_srcconnect (GstPad *pad, GstCaps *caps); static const GstFormat* gst_osssrc_get_formats (GstPad *pad); @@ -136,7 +134,7 @@ gst_osssrc_get_type (void) 0, (GInstanceInitFunc)gst_osssrc_init, }; - osssrc_type = g_type_register_static (GST_TYPE_ELEMENT, "GstOssSrc", &osssrc_info, 0); + osssrc_type = g_type_register_static (GST_TYPE_OSSELEMENT, "GstOssSrc", &osssrc_info, 0); } return osssrc_type; } @@ -150,14 +148,11 @@ gst_osssrc_class_init (GstOssSrcClass *klass) gobject_class = (GObjectClass*)klass; gstelement_class = (GstElementClass*)klass; - parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + parent_class = g_type_class_ref (GST_TYPE_OSSELEMENT); 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_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)", @@ -166,7 +161,6 @@ gst_osssrc_class_init (GstOssSrcClass *klass) gobject_class->set_property = gst_osssrc_set_property; gobject_class->get_property = gst_osssrc_get_property; gobject_class->dispose = gst_osssrc_dispose; - gobject_class->finalize = gst_osssrc_finalize; gstelement_class->change_state = gst_osssrc_change_state; gstelement_class->send_event = gst_osssrc_send_event; @@ -192,8 +186,6 @@ gst_osssrc_init (GstOssSrc *osssrc) gst_element_add_pad (GST_ELEMENT (osssrc), osssrc->srcpad); - gst_osscommon_init (&osssrc->common); - osssrc->buffersize = 4096; osssrc->curoffset = 0; @@ -202,6 +194,7 @@ gst_osssrc_init (GstOssSrc *osssrc) osssrc->clock = NULL; } + static void gst_osssrc_dispose (GObject *object) { @@ -211,16 +204,6 @@ gst_osssrc_dispose (GObject *object) G_OBJECT_CLASS (parent_class)->dispose (object); } -static void -gst_osssrc_finalize (GObject *object) -{ - GstOssSrc *osssrc = (GstOssSrc *) object; - - g_free (osssrc->common.device); - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - static GstPadLinkReturn gst_osssrc_srcconnect (GstPad *pad, GstCaps *caps) @@ -232,10 +215,10 @@ gst_osssrc_srcconnect (GstPad *pad, GstCaps *caps) if (!GST_CAPS_IS_FIXED (caps)) return GST_PAD_LINK_DELAYED; - if (!gst_osscommon_parse_caps (&src->common, caps)) + if (!gst_osselement_parse_caps (GST_OSSELEMENT (src), caps)) return GST_PAD_LINK_REFUSED; - if (!gst_osscommon_sync_parms (&src->common)) + if (!gst_osselement_sync_parms (GST_OSSELEMENT (src))) return GST_PAD_LINK_REFUSED; return GST_PAD_LINK_OK; @@ -251,10 +234,10 @@ gst_osssrc_negotiate (GstPad *pad) allowed = gst_pad_get_allowed_caps (pad); - if (!gst_osscommon_merge_fixed_caps (&src->common, allowed)) + if (!gst_osselement_merge_fixed_caps (GST_OSSELEMENT (src), allowed)) return FALSE; - if (!gst_osscommon_sync_parms (&src->common)) + if (!gst_osselement_sync_parms (GST_OSSELEMENT (src))) return FALSE; /* set caps on src pad */ @@ -262,12 +245,12 @@ gst_osssrc_negotiate (GstPad *pad) GST_CAPS_NEW ( "oss_src", "audio/x-raw-int", - "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) + "endianness", GST_PROPS_INT (GST_OSSELEMENT (src)->endianness), + "signed", GST_PROPS_BOOLEAN (GST_OSSELEMENT (src)->sign), + "width", GST_PROPS_INT (GST_OSSELEMENT (src)->width), + "depth", GST_PROPS_INT (GST_OSSELEMENT (src)->depth), + "rate", GST_PROPS_INT (GST_OSSELEMENT (src)->rate), + "channels", GST_PROPS_INT (GST_OSSELEMENT (src)->channels) )) <= 0) { return FALSE; @@ -281,13 +264,13 @@ gst_osssrc_get_time (GstClock *clock, gpointer data) GstOssSrc *osssrc = GST_OSSSRC (data); audio_buf_info info; - if (!osssrc->common.bps) + if (!GST_OSSELEMENT (osssrc)->bps) return 0; - if (ioctl(osssrc->common.fd, SNDCTL_DSP_GETISPACE, &info) < 0) + if (ioctl(GST_OSSELEMENT (osssrc)->fd, SNDCTL_DSP_GETISPACE, &info) < 0) return 0; - return (osssrc->curoffset + info.bytes) * GST_SECOND / osssrc->common.bps; + return (osssrc->curoffset + info.bytes) * GST_SECOND / GST_OSSELEMENT (osssrc)->bps; } static GstClock* @@ -336,13 +319,13 @@ gst_osssrc_get (GstPad *pad) return GST_BUFFER (gst_event_new (GST_EVENT_INTERRUPT)); } } - if (src->common.bps == 0) { + if (GST_OSSELEMENT (src)->bps == 0) { gst_buffer_unref (buf); gst_element_error (GST_ELEMENT (src), "no format negotiated"); return GST_BUFFER (gst_event_new (GST_EVENT_INTERRUPT)); } - readbytes = read (src->common.fd,GST_BUFFER_DATA (buf), + readbytes = read (GST_OSSELEMENT (src)->fd,GST_BUFFER_DATA (buf), src->buffersize); if (readbytes < 0) { gst_buffer_unref (buf); @@ -361,7 +344,9 @@ gst_osssrc_get (GstPad *pad) GST_BUFFER_OFFSET (buf) = src->curoffset; /* FIXME: we are falsely assuming that we are the master clock here */ - GST_BUFFER_TIMESTAMP (buf) = src->curoffset * GST_SECOND / src->common.bps; + GST_BUFFER_TIMESTAMP (buf) = src->curoffset * GST_SECOND / GST_OSSELEMENT (src)->bps; + GST_BUFFER_DURATION (buf) = (GST_SECOND * GST_BUFFER_SIZE (buf)) / + (GST_OSSELEMENT (src)->bps * GST_OSSELEMENT (src)->rate); src->curoffset += readbytes; @@ -382,13 +367,9 @@ gst_osssrc_set_property (GObject *object, guint prop_id, const GValue *value, GP case ARG_BUFFERSIZE: src->buffersize = g_value_get_ulong (value); break; - case ARG_DEVICE: - 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); + GST_OSSELEMENT (src)->fragment = g_value_get_int (value); + gst_osselement_sync_parms (GST_OSSELEMENT (src)); break; default: break; @@ -406,11 +387,8 @@ gst_osssrc_get_property (GObject *object, guint prop_id, GValue *value, GParamSp case ARG_BUFFERSIZE: g_value_set_ulong (value, src->buffersize); break; - case ARG_DEVICE: - g_value_set_string (value, src->common.device); - break; case ARG_FRAGMENT: - g_value_set_int (value, src->common.fragment); + g_value_set_int (value, GST_OSSELEMENT (src)->fragment); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -426,17 +404,6 @@ gst_osssrc_change_state (GstElement *element) GST_DEBUG ("osssrc: state change"); switch (GST_STATE_TRANSITION (element)) { - case GST_STATE_NULL_TO_READY: - if (!GST_FLAG_IS_SET (element, GST_OSSSRC_OPEN)) { - 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_READY_TO_PAUSED: osssrc->curoffset = 0; break; @@ -448,14 +415,9 @@ gst_osssrc_change_state (GstElement *element) break; case GST_STATE_PAUSED_TO_READY: if (GST_FLAG_IS_SET (element, GST_OSSSRC_OPEN)) - ioctl (osssrc->common.fd, SNDCTL_DSP_RESET, 0); + ioctl (GST_OSSELEMENT (osssrc)->fd, SNDCTL_DSP_RESET, 0); break; - case GST_STATE_READY_TO_NULL: - 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); + default: break; } @@ -485,7 +447,7 @@ gst_osssrc_convert (GstPad *pad, GstFormat src_format, gint64 src_value, osssrc = GST_OSSSRC (gst_pad_get_parent (pad)); - return gst_osscommon_convert (&osssrc->common, src_format, src_value, + return gst_osselement_convert (GST_OSSELEMENT (osssrc), src_format, src_value, dest_format, dest_value); } @@ -521,10 +483,10 @@ gst_osssrc_src_event (GstPad *pad, GstEvent *event) 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)) + if (gst_osselement_convert (GST_OSSELEMENT (osssrc), + 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"); @@ -567,9 +529,9 @@ gst_osssrc_src_query (GstPad *pad, GstQueryType type, GstFormat *format, gint64 switch (type) { case GST_QUERY_POSITION: - res = gst_osscommon_convert (&osssrc->common, - GST_FORMAT_BYTES, osssrc->curoffset, - format, value); + res = gst_osselement_convert (GST_OSSELEMENT (osssrc), + GST_FORMAT_BYTES, osssrc->curoffset, + format, value); break; default: break; diff --git a/sys/oss/gstosssrc.h b/sys/oss/gstosssrc.h index befbaf9315..dff5aef557 100644 --- a/sys/oss/gstosssrc.h +++ b/sys/oss/gstosssrc.h @@ -26,7 +26,7 @@ #include -#include "gstosscommon.h" +#include "gstosselement.h" G_BEGIN_DECLS @@ -51,13 +51,11 @@ typedef struct _GstOssSrc GstOssSrc; typedef struct _GstOssSrcClass GstOssSrcClass; struct _GstOssSrc { - GstElement element; + GstOssElement element; /* pads */ GstPad *srcpad; - GstOssCommon common; - gboolean need_eos; /* Do we need to emit an EOS? */ /* blocking */