From d1d21600f86907f1dbd1fe4204be443eeda6cafc Mon Sep 17 00:00:00 2001 From: Andy Wingo Date: Tue, 23 Aug 2005 13:26:21 +0000 Subject: sys/oss/gstossmixer.*: Refactored to be more like alsamixer. Original commit message from CVS: 2005-08-23 Andy Wingo * sys/oss/gstossmixer.h: * sys/oss/gstossmixer.c: Refactored to be more like alsamixer. * sys/oss/gstossmixertrack.h: * sys/oss/gstossmixertrack.c: Split out from gstossmixer.[ch], like gstalsamixer. * sys/oss/gstosssrc.c: * sys/oss/gstosssink.c: Where before we used a gstosselement object as a helper library, now just call functions from gstosshelper. * sys/oss/gstosshelper.h: * sys/oss/gstosshelper.c: Made a real library. Removed propertyprobe for now, should add it back later. * sys/oss/gstosselement.h: * sys/oss/gstosselement.c: Removed, we don't have a shared base class. * sys/oss/gstosshelper.c (gst_oss_helper_probe_caps): Search higher-to-lower, makes 16 bit appear earlier in the caps, which makes it preferred. --- sys/oss/Makefile.am | 6 +- sys/oss/gstossaudio.c | 1 - sys/oss/gstossdmabuffer.h | 2 +- sys/oss/gstosselement.c | 1319 -------------------------------------------- sys/oss/gstosselement.h | 122 ---- sys/oss/gstosshelper.c | 907 ++---------------------------- sys/oss/gstosshelper.h | 122 +--- sys/oss/gstossmixer.c | 475 +++++----------- sys/oss/gstossmixer.h | 167 ++++-- sys/oss/gstossmixertrack.c | 180 ++++++ sys/oss/gstossmixertrack.h | 62 +++ sys/oss/gstosssink.c | 13 +- sys/oss/gstosssink.h | 4 +- sys/oss/gstosssrc.c | 14 +- sys/oss/gstosssrc.h | 4 +- 15 files changed, 594 insertions(+), 2804 deletions(-) delete mode 100644 sys/oss/gstosselement.c delete mode 100644 sys/oss/gstosselement.h create mode 100644 sys/oss/gstossmixertrack.c create mode 100644 sys/oss/gstossmixertrack.h (limited to 'sys/oss') diff --git a/sys/oss/Makefile.am b/sys/oss/Makefile.am index d298b7ce..d4fc2394 100644 --- a/sys/oss/Makefile.am +++ b/sys/oss/Makefile.am @@ -1,9 +1,9 @@ plugin_LTLIBRARIES = libgstossaudio.la libgstossaudio_la_SOURCES = gstossaudio.c \ - gstosselement.c \ gstosshelper.c \ gstossmixer.c \ + gstossmixertrack.c \ gstosssink.c \ gstosssrc.c @@ -17,10 +17,10 @@ libgstossaudio_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) noinst_HEADERS = gstosssink.h \ gstosssrc.h \ - gstosselement.h \ gstosshelper.h \ gstossdmabuffer.h \ - gstossmixer.h + gstossmixer.h \ + gstossmixertrack.h # noinst_PROGRAMS = #oss_probe diff --git a/sys/oss/gstossaudio.c b/sys/oss/gstossaudio.c index 65cf7037..219a0367 100644 --- a/sys/oss/gstossaudio.c +++ b/sys/oss/gstossaudio.c @@ -23,7 +23,6 @@ #include "gst/gst-i18n-plugin.h" -#include "gstosselement.h" #include "gstosssink.h" #include "gstosssrc.h" diff --git a/sys/oss/gstossdmabuffer.h b/sys/oss/gstossdmabuffer.h index 3a2c6ea7..fef24923 100644 --- a/sys/oss/gstossdmabuffer.h +++ b/sys/oss/gstossdmabuffer.h @@ -25,7 +25,7 @@ #include -#include "gstosselement.h" +#include "gstosshelper.h" #include G_BEGIN_DECLS diff --git a/sys/oss/gstosselement.c b/sys/oss/gstosselement.c deleted file mode 100644 index 5b59bd7f..00000000 --- a/sys/oss/gstosselement.c +++ /dev/null @@ -1,1319 +0,0 @@ -/* 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 "gst/gst-i18n-plugin.h" -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include "gstosselement.h" -#include "gstossmixer.h" - -enum -{ - ARG_ZERO, - ARG_DEVICE, - ARG_MIXERDEV, - ARG_DEVICE_NAME -}; - -/* elementfactory information */ -static GstElementDetails gst_osselement_details = -GST_ELEMENT_DETAILS ("OSS Mixer", - "Generic/Audio", - "OSS-based mixer element", - "Ronald Bultje "); - -static void gst_osselement_base_init (GstOssElementClass * klass); -static void gst_osselement_class_init (GstOssElementClass * klass); - -static void gst_ossprobe_interface_init (GstPropertyProbeInterface * iface); -static void gst_osselement_init (GstOssElement * oss); -static void gst_osselement_finalize (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 GstElementClass *parent_class = NULL; - -/*static guint gst_oss_src_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), - (GBaseInitFunc) gst_osselement_base_init, - 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 - }; - static const GInterfaceInfo ossprobe_info = { - (GInterfaceInitFunc) gst_ossprobe_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_IMPLEMENTS_INTERFACE, &ossiface_info); - g_type_add_interface_static (osselement_type, - GST_TYPE_MIXER, &ossmixer_info); - g_type_add_interface_static (osselement_type, - GST_TYPE_PROPERTY_PROBE, &ossprobe_info); - } - - return osselement_type; -} - -static void -gst_osselement_base_init (GstOssElementClass * klass) -{ - GstElementClass *element_class = GST_ELEMENT_CLASS (klass); - - klass->device_combinations = NULL; - - gst_element_class_set_details (element_class, &gst_osselement_details); -} - -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); - - gobject_class->set_property = gst_osselement_set_property; - gobject_class->get_property = gst_osselement_get_property; - - 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)); - g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DEVICE_NAME, - g_param_spec_string ("device_name", "Device name", "Name of the device", - NULL, G_PARAM_READABLE)); - - gobject_class->finalize = gst_osselement_finalize; -} - -static const GList * -gst_ossprobe_get_properties (GstPropertyProbe * probe) -{ - GObjectClass *klass = G_OBJECT_GET_CLASS (probe); - static GList *list = NULL; - - if (!list) { - list = g_list_append (NULL, g_object_class_find_property (klass, "device")); - } - - return list; -} - -/* OSS (without devfs) allows at max. 16 devices */ -#define MAX_OSS_DEVICES 16 - -static void -gst_osselement_probe (gchar * device_base, - gint device_num, gchar ** name, dev_t * devno) -{ - gchar *device = NULL; - struct stat s; - - if ((name == NULL) || (devno == NULL)) { - goto end; - } - - *name = NULL; - *devno = 0; - - if (device_num == -1) - device = g_strdup (device_base); - else if ((device_num >= -1) && (device_num <= MAX_OSS_DEVICES)) { - device = g_strdup_printf ("%s%d", device_base, device_num); - } else { - goto end; - } - - if (stat (device, &s) || !S_ISCHR (s.st_mode)) - goto end; - - *name = device; - *devno = s.st_rdev; - return; - -end: - g_free (device); -} - -static GList * -device_combination_append (GList * device_combinations, - GstOssDeviceCombination * combi) -{ - GList *it; - - for (it = device_combinations; it != NULL; it = it->next) { - GstOssDeviceCombination *cur; - - cur = (GstOssDeviceCombination *) it->data; - if (cur->dev == combi->dev) { - return device_combinations; - } - } - - return g_list_append (device_combinations, combi); -} - -static gboolean -gst_osselement_class_probe_devices (GstOssElementClass * klass, gboolean check) -{ - GstElementClass *eklass = GST_ELEMENT_CLASS (klass); - static gboolean init = FALSE; - static GList *device_combinations; - GList *padtempllist; - gint openmode = O_RDONLY; - gboolean mixer = FALSE; - - /* 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) */ - padtempllist = gst_element_class_get_pad_template_list (eklass); - if (padtempllist != NULL) { - GstPadTemplate *firstpadtempl = padtempllist->data; - - if (GST_PAD_TEMPLATE_DIRECTION (firstpadtempl) == GST_PAD_SINK) { - openmode = O_WRONLY; - } - mixer = TRUE; - } - - if (!init && !check) { -#define MIXER 0 -#define DSP 1 - gchar *dev_base[][2] = { {"/dev/mixer", "/dev/dsp"} - , - {"/dev/sound/mixer", "/dev/sound/dsp"} - , - {NULL, NULL} - }; - gint n; - gint base; - - while (device_combinations) { - GList *item = device_combinations; - GstOssDeviceCombination *combi = item->data; - - device_combinations = g_list_remove (device_combinations, item); - - g_free (combi->dsp); - g_free (combi->mixer); - g_free (combi); - } - - /* probe for all /dev entries */ - for (base = 0; dev_base[base][DSP] != NULL; base++) { - gint fd; - - for (n = -1; n < MAX_OSS_DEVICES; n++) { - gchar *dsp = NULL; - gchar *mixer = NULL; - dev_t dsp_dev; - dev_t mixer_dev; - - gst_osselement_probe (dev_base[base][DSP], n, &dsp, &dsp_dev); - if (dsp == NULL) { - continue; - } - gst_osselement_probe (dev_base[base][MIXER], n, &mixer, &mixer_dev); - /* does the device exist (can we open them)? */ - - /* we just check the dsp. we assume the mixer always works. - * we don't need a mixer anyway (says OSS)... If we are a - * mixer element, we use the mixer anyway. */ - if ((fd = open (mixer ? mixer : - dsp, openmode | O_NONBLOCK)) > 0 || errno == EBUSY) { - GstOssDeviceCombination *combi; - - if (fd > 0) - close (fd); - - /* yay! \o/ */ - combi = g_new0 (GstOssDeviceCombination, 1); - combi->dsp = dsp; - combi->mixer = mixer; - combi->dev = mixer ? mixer_dev : dsp_dev; - device_combinations = device_combination_append (device_combinations, - combi); - } else { - g_free (dsp); - g_free (mixer); - } - } - } - - init = TRUE; - } - - klass->device_combinations = device_combinations; - - return init; -} - -static GValueArray * -gst_osselement_class_list_devices (GstOssElementClass * klass) -{ - GValueArray *array; - GValue value = { 0 }; - GList *item; - - if (!klass->device_combinations) - return NULL; - - array = g_value_array_new (g_list_length (klass->device_combinations)); - item = klass->device_combinations; - g_value_init (&value, G_TYPE_STRING); - while (item) { - GstOssDeviceCombination *combi = item->data; - - g_value_set_string (&value, combi->dsp); - g_value_array_append (array, &value); - - item = item->next; - } - g_value_unset (&value); - - return array; -} - -static void -gst_ossprobe_probe_property (GstPropertyProbe * probe, - guint prop_id, const GParamSpec * pspec) -{ - GstOssElementClass *klass = GST_OSSELEMENT_GET_CLASS (probe); - - switch (prop_id) { - case ARG_DEVICE: - gst_osselement_class_probe_devices (klass, FALSE); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); - break; - } -} - -static gboolean -gst_ossprobe_needs_probe (GstPropertyProbe * probe, - guint prop_id, const GParamSpec * pspec) -{ - GstOssElementClass *klass = GST_OSSELEMENT_GET_CLASS (probe); - gboolean ret = FALSE; - - switch (prop_id) { - case ARG_DEVICE: - ret = !gst_osselement_class_probe_devices (klass, TRUE); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); - break; - } - - return ret; -} - -static GValueArray * -gst_ossprobe_get_values (GstPropertyProbe * probe, - guint prop_id, const GParamSpec * pspec) -{ - GstOssElementClass *klass = GST_OSSELEMENT_GET_CLASS (probe); - GValueArray *array = NULL; - - switch (prop_id) { - case ARG_DEVICE: - array = gst_osselement_class_list_devices (klass); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); - break; - } - - return array; -} - -static void -gst_ossprobe_interface_init (GstPropertyProbeInterface * iface) -{ - iface->get_properties = gst_ossprobe_get_properties; - iface->probe_property = gst_ossprobe_probe_property; - iface->needs_probe = gst_ossprobe_needs_probe; - iface->get_values = gst_ossprobe_get_values; -} - -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->tracklist = NULL; - oss->device_name = NULL; - - gst_osselement_reset (oss); -} - -static void -gst_osselement_finalize (GObject * object) -{ - GstOssElement *oss = (GstOssElement *) object; - - g_free (oss->device); - g_free (oss->mixer_dev); - - G_OBJECT_CLASS (parent_class)->finalize (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 = 0; - oss->bps = 0; - oss->sample_width = 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, const GstCaps * caps) -{ - gint bps, format; - GstStructure *structure; - gboolean res; - - structure = gst_caps_get_structure (caps, 0); - - res = gst_structure_get_int (structure, "width", &oss->width); - res &= gst_structure_get_int (structure, "depth", &oss->depth); - - if (!res || oss->width != oss->depth) - return FALSE; - - res = gst_structure_get_int (structure, "law", &oss->law); - res &= gst_structure_get_int (structure, "endianness", &oss->endianness); - res &= gst_structure_get_boolean (structure, "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_structure_get_int (structure, "channels", &oss->channels); - gst_structure_get_int (structure, "rate", &oss->rate); - - oss->sample_width = bps * oss->channels; - 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_structure_get_int (structure, name, dest); \ -} G_STMT_END -#define GET_FIXED_BOOLEAN(caps, name, dest) \ -G_STMT_START { \ - if (gst_caps_has_fixed_property (caps, name)) \ - gst_structure_get_boolean (structure, name, dest); \ -} G_STMT_END - -gboolean -gst_osselement_merge_fixed_caps (GstOssElement * oss, GstCaps * caps) -{ - gint bps, format; - GstStructure *structure; - - structure = gst_caps_get_structure (caps, 0); - - /* peel off fixed stuff from the caps */ - gst_structure_get_int (structure, "law", &oss->law); - gst_structure_get_int (structure, "endianness", &oss->endianness); - gst_structure_get_boolean (structure, "signed", &oss->sign); - gst_structure_get_int (structure, "width", &oss->width); - gst_structure_get_int (structure, "depth", &oss->depth); - - if (!gst_ossformat_get (oss->law, oss->endianness, oss->sign, - oss->width, oss->depth, &format, &bps)) { - return FALSE; - } - - gst_structure_get_int (structure, "rate", &oss->rate); - gst_structure_get_int (structure, "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) { - GST_INFO ("osselement: no fd"); - return FALSE; - } - - if ((oss->fragment & 0xFFFF) == 0) { - frag = 0; - } else 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); - - if (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 == 1) { - ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &space); - } else { - ioctl (oss->fd, SNDCTL_DSP_GETISPACE, &space); - } - -#if 0 - /* FIXME: make the current fragment info available somehow - * the current way overrides preset values and that sucks */ - /* 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; -#endif - - 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, - oss->bps, oss->fragment_time); - - if (target_format != oss->format || - target_channels != oss->channels || target_rate != oss->rate) { - if (target_channels != oss->channels) - g_warning - ("couldn't set the right number of channels (wanted %d, got %d), enjoy the tone difference", - target_channels, oss->channels); - if (target_rate < oss->rate - 1 || target_rate > oss->rate + 1) - g_warning - ("couldn't set the right sample rate (wanted %d, got %d), enjoy the speed difference", - target_rate, oss->rate); - if (target_format != oss->format) - g_warning ("couldn't set requested OSS format, 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_osselement_open_audio (GstOssElement * oss, GstOssOpenMode mode) -{ - gint caps; - - g_return_val_if_fail (oss->fd == -1, FALSE); - GST_INFO ("osselement: attempting to open sound device"); - - if (mode == GST_OSS_MODE_MIXER) - goto do_mixer; - - /* first try to open the sound card */ - if (mode == 1) { - /* 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 (oss, RESOURCE, BUSY, - (_("OSS device \"%s\" is already in use by another program."), - oss->device), (NULL)); - break; - case EACCES: - case ETXTBSY: - if (mode == 1) - GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_WRITE, - (_("Could not access device \"%s\", check its permissions."), - oss->device), GST_ERROR_SYSTEM); - else - GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_READ, - (_("Could not access device \"%s\", check its permissions."), - oss->device), GST_ERROR_SYSTEM); - break; - case ENXIO: - case ENODEV: - case ENOENT: - GST_ELEMENT_ERROR (oss, RESOURCE, NOT_FOUND, - (_("Device \"%s\" does not exist."), oss->device), - GST_ERROR_SYSTEM); - break; - default: - if (mode == 1) - GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_WRITE, - (_("Could not open device \"%s\" for writing."), oss->device), - GST_ERROR_SYSTEM); - else - GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_READ, - (_("Could not open device \"%s\" for reading."), oss->device), - GST_ERROR_SYSTEM); - 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; - -do_mixer: - gst_ossmixer_build_list (NULL, NULL); - - return TRUE; -} - -void -gst_osselement_close_audio (GstOssElement * oss) -{ - gst_ossmixer_free_list (NULL); - if (oss->probed_caps) { - gst_caps_unref (oss->probed_caps); - oss->probed_caps = NULL; - } - - if (oss->fd < 0) - return; - - 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->width * oss->channels / 8); - 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->width * oss->channels / 8; - 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 (oss->fd == -1) { - g_free (oss->device); - oss->device = g_strdup (g_value_get_string (value)); - - /* let's assume that if we have a device map for the mixer, - * we're allowed to do all that automagically here */ - if (GST_OSSELEMENT_GET_CLASS (oss)->device_combinations != NULL) { - GList *list = GST_OSSELEMENT_GET_CLASS (oss)->device_combinations; - - while (list) { - GstOssDeviceCombination *combi = list->data; - - if (!strcmp (combi->dsp, oss->device)) { - g_free (oss->mixer_dev); - oss->mixer_dev = g_strdup (combi->mixer); - break; - } - - list = list->next; - } - } - } - break; - case ARG_MIXERDEV: - /* disallow changing the device while it is opened - get_property("mixerdev") should return the right one */ - if (oss->fd == -1) { - 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; - case ARG_DEVICE_NAME: - g_value_set_string (value, oss->device_name); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -/* rate probing code */ - - -#if 0 - -#ifdef HAVE_OSS_INCLUDE_IN_SYS -#include -#else - -#ifdef HAVE_OSS_INCLUDE_IN_ROOT -#include -#else - -#include - -#endif /* HAVE_OSS_INCLUDE_IN_ROOT */ - -#endif /* HAVE_OSS_INCLUDE_IN_SYS */ - -#include -#include -#include -#include -#include -#include -#endif - -typedef struct _GstOssProbe GstOssProbe; -struct _GstOssProbe -{ - int fd; - int format; - int n_channels; - GArray *rates; - int min; - int max; -}; - -typedef struct _GstOssRange GstOssRange; -struct _GstOssRange -{ - int min; - int max; -}; - -static GstStructure *gst_osselement_get_format_structure (unsigned int - format_bit); -static gboolean gst_osselement_rate_probe_check (GstOssProbe * probe); -static int gst_osselement_rate_check_rate (GstOssProbe * probe, int irate); -static void gst_osselement_rate_add_range (GQueue * queue, int min, int max); -static void gst_osselement_rate_add_rate (GArray * array, int rate); -static int gst_osselement_rate_int_compare (gconstpointer a, gconstpointer b); - -void -gst_osselement_probe_caps (GstOssElement * oss) -{ - GstOssProbe *probe; - int i; - gboolean ret; - GstStructure *structure; - unsigned int format_bit; - unsigned int format_mask; - GstCaps *caps; - - if (oss->probed_caps != NULL) - return; - if (oss->fd == -1) - return; - - /* FIXME test make sure we're not currently playing */ - /* FIXME test both mono and stereo */ - - format_mask = AFMT_U8 | AFMT_S16_LE | AFMT_S16_BE | AFMT_S8 | - AFMT_U16_LE | AFMT_U16_BE; - format_mask &= oss->caps; - - caps = gst_caps_new_empty (); - - /* assume that the most significant bit of format_mask is 0 */ - for (format_bit = 1; format_bit <= format_mask; format_bit <<= 1) { - if (format_bit & format_mask) { - GValue rate_value = { 0 }; - - probe = g_new0 (GstOssProbe, 1); - probe->fd = oss->fd; - probe->format = format_bit; - probe->n_channels = 2; - - ret = gst_osselement_rate_probe_check (probe); - if (probe->min == -1 || probe->max == -1) { - g_array_free (probe->rates, TRUE); - g_free (probe); - continue; - } - - if (ret) { - GValue value = { 0 }; - - g_array_sort (probe->rates, gst_osselement_rate_int_compare); - - g_value_init (&rate_value, GST_TYPE_LIST); - g_value_init (&value, G_TYPE_INT); - - for (i = 0; i < probe->rates->len; i++) { - g_value_set_int (&value, g_array_index (probe->rates, int, i)); - - gst_value_list_append_value (&rate_value, &value); - } - - g_value_unset (&value); - } else { - /* one big range */ - g_value_init (&rate_value, GST_TYPE_INT_RANGE); - gst_value_set_int_range (&rate_value, probe->min, probe->max); - } - - g_array_free (probe->rates, TRUE); - g_free (probe); - - structure = gst_osselement_get_format_structure (format_bit); - gst_structure_set (structure, "channels", GST_TYPE_INT_RANGE, 1, 2, NULL); - gst_structure_set_value (structure, "rate", &rate_value); - g_value_unset (&rate_value); - - gst_caps_append_structure (caps, structure); - } - } - - if (gst_caps_is_empty (caps)) { - GST_ELEMENT_ERROR (oss, RESOURCE, SETTINGS, - (_("Your OSS device could not be probed correctly")), (NULL)); - return; - } - GST_DEBUG ("probed caps: %" GST_PTR_FORMAT, caps); - oss->probed_caps = caps; -} - -static GstStructure * -gst_osselement_get_format_structure (unsigned int format_bit) -{ - GstStructure *structure; - int endianness; - gboolean sign; - int width; - - switch (format_bit) { - case AFMT_U8: - endianness = 0; - sign = FALSE; - width = 8; - break; - case AFMT_S16_LE: - endianness = G_LITTLE_ENDIAN; - sign = TRUE; - width = 16; - break; - case AFMT_S16_BE: - endianness = G_BIG_ENDIAN; - sign = TRUE; - width = 16; - break; - case AFMT_S8: - endianness = 0; - sign = TRUE; - width = 8; - break; - case AFMT_U16_LE: - endianness = G_LITTLE_ENDIAN; - sign = FALSE; - width = 16; - break; - case AFMT_U16_BE: - endianness = G_BIG_ENDIAN; - sign = FALSE; - width = 16; - break; - default: - g_assert_not_reached (); - return NULL; - } - - structure = gst_structure_new ("audio/x-raw-int", - "width", G_TYPE_INT, width, - "depth", G_TYPE_INT, width, "signed", G_TYPE_BOOLEAN, sign, NULL); - - if (endianness) { - gst_structure_set (structure, "endianness", G_TYPE_INT, endianness, NULL); - } - - return structure; -} - -static gboolean -gst_osselement_rate_probe_check (GstOssProbe * probe) -{ - GstOssRange *range; - GQueue *ranges; - int exact_rates = 0; - gboolean checking_exact_rates = TRUE; - int n_checks = 0; - gboolean result = TRUE; - - ranges = g_queue_new (); - - probe->rates = g_array_new (FALSE, FALSE, sizeof (int)); - - probe->min = gst_osselement_rate_check_rate (probe, 1000); - n_checks++; - probe->max = gst_osselement_rate_check_rate (probe, 100000); - /* a little bug workaround */ - { - int max; - - max = gst_osselement_rate_check_rate (probe, 48000); - if (max > probe->max) { - GST_ERROR - ("Driver bug recognized (driver does not round rates correctly). Please file a bug report."); - probe->max = max; - } - } - n_checks++; - if (probe->min == -1 || probe->max == -1) { - /* This is a workaround for drivers that return -EINVAL (or another - * error) for rates outside of [8000,48000]. If this fails, the - * driver is seriously buggy, and probably doesn't work with other - * media libraries/apps. */ - probe->min = gst_osselement_rate_check_rate (probe, 8000); - probe->max = gst_osselement_rate_check_rate (probe, 48000); - } - if (probe->min == -1 || probe->max == -1) { - GST_DEBUG ("unexpected check_rate error"); - return FALSE; - } - gst_osselement_rate_add_range (ranges, probe->min + 1, probe->max - 1); - - while ((range = g_queue_pop_head (ranges))) { - int min1; - int max1; - int mid; - int mid_ret; - - GST_DEBUG ("checking [%d,%d]", range->min, range->max); - - mid = (range->min + range->max) / 2; - mid_ret = gst_osselement_rate_check_rate (probe, mid); - if (mid_ret == -1) { - /* FIXME ioctl returned an error. do something */ - GST_DEBUG ("unexpected check_rate error"); - } - n_checks++; - - if (mid == mid_ret && checking_exact_rates) { - int max_exact_matches = 20; - - exact_rates++; - if (exact_rates > max_exact_matches) { - GST_DEBUG ("got %d exact rates, assuming all are exact", - max_exact_matches); - result = FALSE; - g_free (range); - break; - } - } else { - checking_exact_rates = FALSE; - } - - /* Assume that the rate is arithmetically rounded to the nearest - * supported rate. */ - if (mid == mid_ret) { - min1 = mid - 1; - max1 = mid + 1; - } else { - if (mid < mid_ret) { - min1 = mid - (mid_ret - mid); - max1 = mid_ret + 1; - } else { - min1 = mid_ret - 1; - max1 = mid + (mid - mid_ret); - } - } - - gst_osselement_rate_add_range (ranges, range->min, min1); - gst_osselement_rate_add_range (ranges, max1, range->max); - - g_free (range); - } - - while ((range = g_queue_pop_head (ranges))) { - g_free (range); - } - g_queue_free (ranges); - - return result; -} - -static void -gst_osselement_rate_add_range (GQueue * queue, int min, int max) -{ - if (min <= max) { - GstOssRange *range = g_new0 (GstOssRange, 1); - - range->min = min; - range->max = max; - - g_queue_push_tail (queue, range); - /* push_head also works, but has different probing behavior */ - /*g_queue_push_head (queue, range); */ - } -} - -static int -gst_osselement_rate_check_rate (GstOssProbe * probe, int irate) -{ - int rate; - int format; - int n_channels; - int ret; - - rate = irate; - format = probe->format; - n_channels = probe->n_channels; - - GST_LOG ("checking format %d, channels %d, rate %d", - format, n_channels, rate); - ret = ioctl (probe->fd, SNDCTL_DSP_SETFMT, &format); - if (ret < 0) - return -1; - ret = ioctl (probe->fd, SNDCTL_DSP_CHANNELS, &n_channels); - if (ret < 0) - return -1; - ret = ioctl (probe->fd, SNDCTL_DSP_SPEED, &rate); - if (ret < 0) - return -1; - - GST_DEBUG ("rate %d -> %d", irate, rate); - - if (rate == irate - 1 || rate == irate + 1) { - rate = irate; - } - gst_osselement_rate_add_rate (probe->rates, rate); - return rate; -} - -static void -gst_osselement_rate_add_rate (GArray * array, int rate) -{ - int i; - int val; - - for (i = 0; i < array->len; i++) { - val = g_array_index (array, int, i); - - if (val == rate) - return; - } - GST_DEBUG ("supported rate: %d", rate); - g_array_append_val (array, rate); -} - -static int -gst_osselement_rate_int_compare (gconstpointer a, gconstpointer b) -{ - const int *va = (const int *) a; - const int *vb = (const int *) b; - - if (*va < *vb) - return -1; - if (*va > *vb) - return 1; - return 0; -} diff --git a/sys/oss/gstosselement.h b/sys/oss/gstosselement.h deleted file mode 100644 index b895d42b..00000000 --- a/sys/oss/gstosselement.h +++ /dev/null @@ -1,122 +0,0 @@ -/* 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 -#include - -#include "gstosshelper.h" - -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)) -#define GST_OSSELEMENT_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_OSSELEMENT, GstOssElementClass)) - -typedef struct _GstOssElement GstOssElement; -typedef struct _GstOssElementClass GstOssElementClass; - -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; - GstCaps *probed_caps; - - /* stats bytes per *second* */ - guint bps; - - /* sample width in bytes */ - guint sample_width; - - /* parameters */ - gint law; - gint endianness; - gboolean sign; - gint width; - gint depth; - gint channels; - gint rate; - gint mode; - - /* mixer stuff */ - GList *tracklist; - guint32 stereomask, - recdevs, - recmask, - mixcaps; - gint mixer_fd; - gchar *device_name; -}; - -struct _GstOssElementClass { - GstElementClass klass; - - GList *device_combinations; -}; - -GType gst_osselement_get_type (void); - -/* some useful functions */ -gboolean gst_osselement_parse_caps (GstOssElement *oss, - const GstCaps *caps); -gboolean gst_osselement_merge_fixed_caps (GstOssElement *oss, - GstCaps *caps); - -gboolean gst_osselement_open_audio (GstOssElement *oss, GstOssOpenMode mode); -gboolean gst_osselement_sync_parms (GstOssElement *oss); -void gst_osselement_reset (GstOssElement *oss); -void gst_osselement_close_audio (GstOssElement *oss); - - - -gboolean gst_osselement_convert (GstOssElement *oss, - GstFormat src_format, - gint64 src_value, - GstFormat *dest_format, - gint64 *dest_value); -void gst_osselement_probe_caps (GstOssElement *oss); - -G_END_DECLS - -#endif /* __GST_OSS_ELEMENT_H__ */ diff --git a/sys/oss/gstosshelper.c b/sys/oss/gstosshelper.c index dfd503e4..987047a9 100644 --- a/sys/oss/gstosshelper.c +++ b/sys/oss/gstosshelper.c @@ -2,8 +2,7 @@ * Copyright (C) 1999,2000 Erik Walthinsen * 2000 Wim Taymans * - * gstosshelper.c: helper functions for easy OSS device handling. - * See gstosshelper.h for details. + * gstosshelper.c: OSS helper routines * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -33,6 +32,7 @@ #include #include #include + #include #include @@ -40,822 +40,6 @@ #include "gstosshelper.h" #include "gstossmixer.h" -static void gst_ossprobe_interface_init (GstPropertyProbeInterface * iface); - -static GList *device_combinations = NULL; - -void -gst_oss_add_mixer_type (GType type) -{ - static const GInterfaceInfo ossiface_info = { - (GInterfaceInitFunc) gst_oss_interface_init, - NULL, - NULL - }; - static const GInterfaceInfo ossmixer_info = { - (GInterfaceInitFunc) gst_ossmixer_interface_init, - NULL, - NULL - }; - static const GInterfaceInfo ossprobe_info = { - (GInterfaceInitFunc) gst_ossprobe_interface_init, - NULL, - NULL - }; - - g_type_add_interface_static (type, - GST_TYPE_IMPLEMENTS_INTERFACE, &ossiface_info); - g_type_add_interface_static (type, GST_TYPE_MIXER, &ossmixer_info); - g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE, &ossprobe_info); -} - -void -gst_oss_add_device_properties (GstElementClass * klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - g_object_class_install_property (gobject_class, OSS_ARG_DEVICE, - g_param_spec_string ("device", "Device", "OSS device (/dev/dspN usually)", - "default", G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, OSS_ARG_MIXER_DEVICE, - g_param_spec_string ("mixerdev", "Mixer device", - "OSS mixer device (/dev/mixerN usually)", - "default", G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, OSS_ARG_DEVICE_NAME, - g_param_spec_string ("device_name", "Device name", "Name of the device", - NULL, G_PARAM_READABLE)); -} - -void -gst_oss_set_device_property (GstElement * element, - GstOssDeviceCombination * c, GstOssDevice * oss, - guint prop_id, GParamSpec * pspec, const GValue * value) -{ - switch (prop_id) { - case OSS_ARG_DEVICE: - /* disallow changing the device while it is opened - get_property("device") should return the right one */ - if (oss->fd == -1) { - g_free (c->dsp); - c->dsp = g_strdup (g_value_get_string (value)); - - /* let's assume that if we have a device map for the mixer, - * we're allowed to do all that automagically here */ - if (device_combinations != NULL) { - GList *list = device_combinations; - - while (list) { - GstOssDeviceCombination *combi = list->data; - - if (!strcmp (combi->dsp, c->dsp)) { - g_free (c->mixer); - c->mixer = g_strdup (combi->mixer); - break; - } - - list = list->next; - } - } - } - break; - case OSS_ARG_MIXER_DEVICE: - /* disallow changing the device while it is opened - get_property("mixerdev") should return the right one */ - if (oss->fd == -1) { - g_free (c->mixer); - c->mixer = g_strdup (g_value_get_string (value)); - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (element, prop_id, pspec); - break; - } -} - -void -gst_oss_get_device_property (GstElement * element, GstOssDeviceCombination * c, - GstOssDevice * oss, guint prop_id, GParamSpec * pspec, GValue * value) -{ - switch (prop_id) { - case OSS_ARG_DEVICE: - g_value_set_string (value, c->dsp); - break; - case OSS_ARG_MIXER_DEVICE: - g_value_set_string (value, c->mixer); - break; - case OSS_ARG_DEVICE_NAME: - g_value_set_string (value, oss->device_name); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (element, prop_id, pspec); - break; - } -} - -static const GList * -gst_oss_probe_get_properties (GstPropertyProbe * probe) -{ - GObjectClass *klass = G_OBJECT_GET_CLASS (probe); - static GList *list = NULL; - - if (!list) { - list = g_list_append (NULL, g_object_class_find_property (klass, "device")); - } - - return list; -} - -/* OSS (without devfs) allows at max. 16 devices */ -#define MAX_OSS_DEVICES 16 - -static void -gst_oss_do_probe (gchar * device_base, - gint device_num, gchar ** name, dev_t * devno) -{ - gchar *device = NULL; - struct stat s; - - if ((name == NULL) || (devno == NULL)) { - goto end; - } - - *name = NULL; - *devno = 0; - - if (device_num == -1) - device = g_strdup (device_base); - else if ((device_num >= -1) && (device_num <= MAX_OSS_DEVICES)) { - device = g_strdup_printf ("%s%d", device_base, device_num); - } else { - goto end; - } - - if (stat (device, &s) || !S_ISCHR (s.st_mode)) - goto end; - - *name = device; - *devno = s.st_rdev; - return; - -end: - g_free (device); -} - -static GList * -device_combination_append (GList * device_combinations, - GstOssDeviceCombination * combi) -{ - GList *it; - - for (it = device_combinations; it != NULL; it = it->next) { - GstOssDeviceCombination *cur; - - cur = (GstOssDeviceCombination *) it->data; - if (cur->dev == combi->dev) { - return device_combinations; - } - } - - return g_list_append (device_combinations, combi); -} - -static gboolean -gst_oss_probe_devices (GstOssOpenMode mode, gboolean check) -{ - static gboolean init = FALSE; - gint openmode = (mode == GST_OSS_MODE_WRITE) ? O_WRONLY : O_RDONLY; - gboolean do_mixer = (mode == GST_OSS_MODE_VOLUME); - - if (!init && !check) { -#define MIXER 0 -#define DSP 1 - gchar *dev_base[][2] = { {"/dev/mixer", "/dev/dsp"} - , - {"/dev/sound/mixer", "/dev/sound/dsp"} - , - {NULL, NULL} - }; - gint n; - gint base; - - while (device_combinations) { - GList *item = device_combinations; - GstOssDeviceCombination *combi = item->data; - - device_combinations = g_list_remove (device_combinations, item); - - g_free (combi->dsp); - g_free (combi->mixer); - g_free (combi); - } - - /* probe for all /dev entries */ - for (base = 0; dev_base[base][DSP] != NULL; base++) { - gint fd; - - for (n = -1; n < MAX_OSS_DEVICES; n++) { - gchar *dsp = NULL; - gchar *mixer = NULL; - dev_t dsp_dev; - dev_t mixer_dev; - - gst_oss_do_probe (dev_base[base][DSP], n, &dsp, &dsp_dev); - if (dsp == NULL) { - continue; - } - gst_oss_do_probe (dev_base[base][MIXER], n, &mixer, &mixer_dev); - /* does the device exist (can we open them)? */ - - /* we just check the dsp. we assume the mixer always works. - * we don't need a mixer anyway (says OSS)... If we are a - * mixer element, we use the mixer anyway. */ - if ((fd = open (do_mixer ? mixer : - dsp, openmode | O_NONBLOCK)) > 0 || errno == EBUSY) { - GstOssDeviceCombination *combi; - - if (fd > 0) - close (fd); - - /* yay! \o/ */ - combi = g_new0 (GstOssDeviceCombination, 1); - combi->dsp = dsp; - combi->mixer = mixer; - combi->dev = do_mixer ? mixer_dev : dsp_dev; - device_combinations = device_combination_append (device_combinations, - combi); - } else { - g_free (dsp); - g_free (mixer); - } - } - } - - init = TRUE; - } - - return init; -} - -static GValueArray * -gst_oss_probe_list_devices (void) -{ - GValueArray *array; - GValue value = { 0 }; - GList *item; - - if (!device_combinations) - return NULL; - - array = g_value_array_new (g_list_length (device_combinations)); - item = device_combinations; - g_value_init (&value, G_TYPE_STRING); - while (item) { - GstOssDeviceCombination *combi = item->data; - - g_value_set_string (&value, combi->dsp); - g_value_array_append (array, &value); - - item = item->next; - } - g_value_unset (&value); - - return array; -} - -static void -gst_oss_probe_property (GstPropertyProbe * probe, - guint prop_id, const GParamSpec * pspec) -{ - GstOssDevice *oss = g_object_get_data (G_OBJECT (probe), "oss-data"); - - switch (prop_id) { - case OSS_ARG_DEVICE: - gst_oss_probe_devices (oss ? oss->mode : GST_OSS_MODE_READ, FALSE); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); - break; - } -} - -static gboolean -gst_oss_needs_probe (GstPropertyProbe * probe, - guint prop_id, const GParamSpec * pspec) -{ - GstOssDevice *oss = g_object_get_data (G_OBJECT (probe), "oss-data"); - gboolean ret = FALSE; - - switch (prop_id) { - case OSS_ARG_DEVICE: - ret = !gst_oss_probe_devices (oss ? oss->mode : GST_OSS_MODE_READ, TRUE); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); - break; - } - - return ret; -} - -static GValueArray * -gst_oss_probe_get_values (GstPropertyProbe * probe, - guint prop_id, const GParamSpec * pspec) -{ - GValueArray *array = NULL; - - switch (prop_id) { - case OSS_ARG_DEVICE: - array = gst_oss_probe_list_devices (); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); - break; - } - - return array; -} - -static void -gst_ossprobe_interface_init (GstPropertyProbeInterface * iface) -{ - iface->get_properties = gst_oss_probe_get_properties; - iface->probe_property = gst_oss_probe_property; - iface->needs_probe = gst_oss_needs_probe; - iface->get_values = gst_oss_probe_get_values; -} - -void -gst_oss_init (GObject * obj, GstOssDeviceCombination * c, GstOssDevice * oss, - GstOssOpenMode mode) -{ - g_object_set_data (obj, "oss-data", oss); - - c->dsp = g_strdup ("/dev/dsp"); - c->mixer = g_strdup ("/dev/mixer"); - - oss->fd = -1; - oss->mixer_fd = -1; - oss->mode = mode; - - gst_oss_reset (oss); -} - -void -gst_oss_dispose (GstOssDeviceCombination * c, GstOssDevice * oss) -{ - g_free (c->dsp); - c->dsp = NULL; - g_free (c->mixer); - c->mixer = NULL; -} - -void -gst_oss_reset (GstOssDevice * 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 = 0; - oss->bps = 0; - oss->sample_width = 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_oss_parse_caps (GstOssDevice * oss, const GstCaps * caps) -{ - gint bps, format; - GstStructure *structure; - gboolean res; - - structure = gst_caps_get_structure (caps, 0); - - res = gst_structure_get_int (structure, "width", &oss->width); - res &= gst_structure_get_int (structure, "depth", &oss->depth); - - if (!res || oss->width != oss->depth) - return FALSE; - - res = gst_structure_get_int (structure, "law", &oss->law); - res &= gst_structure_get_int (structure, "endianness", &oss->endianness); - res &= gst_structure_get_boolean (structure, "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_structure_get_int (structure, "channels", &oss->channels); - gst_structure_get_int (structure, "rate", &oss->rate); - - oss->sample_width = bps * oss->channels; - 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_structure_get_int (structure, name, dest); \ -} G_STMT_END -#define GET_FIXED_BOOLEAN(caps, name, dest) \ -G_STMT_START { \ - if (gst_caps_has_fixed_property (caps, name)) \ - gst_structure_get_boolean (structure, name, dest); \ -} G_STMT_END - -gboolean -gst_oss_merge_fixed_caps (GstOssDevice * oss, GstCaps * caps) -{ - gint bps, format; - GstStructure *structure; - - structure = gst_caps_get_structure (caps, 0); - - /* peel off fixed stuff from the caps */ - gst_structure_get_int (structure, "law", &oss->law); - gst_structure_get_int (structure, "endianness", &oss->endianness); - gst_structure_get_boolean (structure, "signed", &oss->sign); - gst_structure_get_int (structure, "width", &oss->width); - gst_structure_get_int (structure, "depth", &oss->depth); - - if (!gst_ossformat_get (oss->law, oss->endianness, oss->sign, - oss->width, oss->depth, &format, &bps)) { - return FALSE; - } - - gst_structure_get_int (structure, "rate", &oss->rate); - gst_structure_get_int (structure, "channels", &oss->channels); - - oss->bps = bps * oss->channels * oss->rate; - oss->format = format; - - return TRUE; -} - -gboolean -gst_oss_sync_parms (GstOssDevice * 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 & 0xFFFF) == 0) { - frag = 0; - } else if (oss->fragment >> 16) { - frag = oss->fragment; - } else { - frag = 0x7FFF0000 | oss->fragment; - } - - GST_INFO - ("oss: setting sound card to %dHz %d format %s (%08x fragment)", - oss->rate, oss->format, (oss->channels == 2) ? "stereo" : "mono", frag); - - if (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_OSS_MODE_WRITE) { - ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &space); - } else { - ioctl (oss->fd, SNDCTL_DSP_GETISPACE, &space); - } - -#if 0 - /* FIXME: make the current fragment info available somehow - * the current way overrides preset values and that sucks */ - /* 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; -#endif - - GST_INFO ("oss: 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, - oss->bps, oss->fragment_time); - - if (target_format != oss->format || - target_channels != oss->channels || target_rate != oss->rate) { - if (target_channels != oss->channels) - g_warning - ("couldn't set the right number of channels (wanted %d, got %d), enjoy the tone difference", - target_channels, oss->channels); - if (target_rate < oss->rate - 1 || target_rate > oss->rate + 1) - g_warning - ("couldn't set the right sample rate (wanted %d, got %d), enjoy the speed difference", - target_rate, oss->rate); - if (target_format != oss->format) - g_warning ("couldn't set requested OSS format, 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_oss_open (GstElement * element, - GstOssDeviceCombination * c, GstOssDevice * oss) -{ - gint caps; - - g_return_val_if_fail (oss->fd == -1, FALSE); - GST_INFO ("oss: attempting to open sound device"); - - /* first try to open the sound card */ - if (oss->mode == GST_OSS_MODE_VOLUME) { - goto do_mixer; - } else if (oss->mode == GST_OSS_MODE_WRITE) { - /* open non blocking first so that it returns immediatly with an error - * when we cannot get to the device */ - oss->fd = open (c->dsp, O_WRONLY | O_NONBLOCK); - - if (oss->fd >= 0) { - close (oss->fd); - - /* re-open the sound device in blocking mode */ - oss->fd = open (c->dsp, O_WRONLY); - } - } else { - oss->fd = open (c->dsp, O_RDONLY); - } - - if (oss->fd < 0) { - switch (errno) { - case EBUSY: - GST_ELEMENT_ERROR (element, RESOURCE, BUSY, - (_("OSS device \"%s\" is already in use by another program."), - c->dsp), (NULL)); - break; - case EACCES: - case ETXTBSY: - if (oss->mode == GST_OSS_MODE_WRITE) - GST_ELEMENT_ERROR (element, RESOURCE, OPEN_WRITE, - (_("Could not access device \"%s\", check its permissions."), - c->dsp), GST_ERROR_SYSTEM); - else - GST_ELEMENT_ERROR (element, RESOURCE, OPEN_READ, - (_("Could not access device \"%s\", check its permissions."), - c->dsp), GST_ERROR_SYSTEM); - break; - case ENXIO: - case ENODEV: - case ENOENT: - GST_ELEMENT_ERROR (element, RESOURCE, NOT_FOUND, - (_("Device \"%s\" does not exist."), c->dsp), GST_ERROR_SYSTEM); - break; - default: - if (oss->mode == GST_OSS_MODE_WRITE) - GST_ELEMENT_ERROR (element, RESOURCE, OPEN_WRITE, - (_("Could not open device \"%s\" for writing."), c->dsp), - GST_ERROR_SYSTEM); - else - GST_ELEMENT_ERROR (element, RESOURCE, OPEN_READ, - (_("Could not open device \"%s\" for reading."), c->dsp), - GST_ERROR_SYSTEM); - break; - } - return FALSE; - } - - /* we have it, set the default parameters and go have fun */ - /* set card state */ - ioctl (oss->fd, SNDCTL_DSP_GETCAPS, &caps); - - GST_INFO ("oss: Capabilities %08x", caps); - - if (caps & DSP_CAP_DUPLEX) - GST_INFO ("oss: Full duplex"); - if (caps & DSP_CAP_REALTIME) - GST_INFO ("oss: Realtime"); - if (caps & DSP_CAP_BATCH) - GST_INFO ("oss: Batch"); - if (caps & DSP_CAP_COPROC) - GST_INFO ("oss: Has coprocessor"); - if (caps & DSP_CAP_TRIGGER) - GST_INFO ("oss: Trigger"); - if (caps & DSP_CAP_MMAP) - GST_INFO ("oss: Direct access"); - -#ifdef DSP_CAP_MULTI - if (caps & DSP_CAP_MULTI) - GST_INFO ("oss: Multiple open"); -#endif /* DSP_CAP_MULTI */ - -#ifdef DSP_CAP_BIND - if (caps & DSP_CAP_BIND) - GST_INFO ("oss: Channel binding"); -#endif /* DSP_CAP_BIND */ - - ioctl (oss->fd, SNDCTL_DSP_GETFMTS, &caps); - - GST_INFO ("oss: Formats %08x", caps); - if (caps & AFMT_MU_LAW) - GST_INFO ("oss: MU_LAW"); - if (caps & AFMT_A_LAW) - GST_INFO ("oss: A_LAW"); - if (caps & AFMT_IMA_ADPCM) - GST_INFO ("oss: IMA_ADPCM"); - if (caps & AFMT_U8) - GST_INFO ("oss: U8"); - if (caps & AFMT_S16_LE) - GST_INFO ("oss: S16_LE"); - if (caps & AFMT_S16_BE) - GST_INFO ("oss: S16_BE"); - if (caps & AFMT_S8) - GST_INFO ("oss: S8"); - if (caps & AFMT_U16_LE) - GST_INFO ("oss: U16_LE"); - if (caps & AFMT_U16_BE) - GST_INFO ("oss: U16_BE"); - if (caps & AFMT_MPEG) - GST_INFO ("oss: MPEG"); -#ifdef AFMT_AC3 - if (caps & AFMT_AC3) - GST_INFO ("oss: AC3"); -#endif - - GST_INFO ("oss: opened audio (%s) with fd=%d", c->dsp, oss->fd); - - oss->caps = caps; - -do_mixer: - gst_ossmixer_build_list (c, oss); - - return TRUE; -} - -void -gst_oss_close (GstOssDevice * oss) -{ - gst_ossmixer_free_list (oss); - - if (oss->probed_caps) { - gst_caps_unref (oss->probed_caps); - oss->probed_caps = NULL; - } - - if (oss->fd < 0) - return; - - close (oss->fd); - oss->fd = -1; -} - -gboolean -gst_oss_convert (GstOssDevice * 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->width * oss->channels / 8); - 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->width * oss->channels / 8; - break; - default: - res = FALSE; - } - break; - default: - res = FALSE; - } - - return res; -} - -/* rate probing code */ - - #if 0 #ifdef HAVE_OSS_INCLUDE_IN_SYS @@ -878,7 +62,7 @@ gst_oss_convert (GstOssDevice * oss, #include #include #include -#endif +#endif /* 0 */ typedef struct _GstOssProbe GstOssProbe; struct _GstOssProbe @@ -898,15 +82,16 @@ struct _GstOssRange int max; }; -static GstStructure *gst_oss_get_format_structure (unsigned int format_bit); -static gboolean gst_oss_rate_probe_check (GstOssProbe * probe); -static int gst_oss_rate_check_rate (GstOssProbe * probe, int irate); -static void gst_oss_rate_add_range (GQueue * queue, int min, int max); -static void gst_oss_rate_add_rate (GArray * array, int rate); -static int gst_oss_rate_int_compare (gconstpointer a, gconstpointer b); +static GstStructure *gst_oss_helper_get_format_structure (unsigned int + format_bit); +static gboolean gst_oss_helper_rate_probe_check (GstOssProbe * probe); +static int gst_oss_helper_rate_check_rate (GstOssProbe * probe, int irate); +static void gst_oss_helper_rate_add_range (GQueue * queue, int min, int max); +static void gst_oss_helper_rate_add_rate (GArray * array, int rate); +static int gst_oss_helper_rate_int_compare (gconstpointer a, gconstpointer b); -void -gst_oss_probe_caps (GstOssDevice * oss) +GstCaps * +gst_oss_helper_probe_caps (gint fd) { GstOssProbe *probe; int i; @@ -916,31 +101,29 @@ gst_oss_probe_caps (GstOssDevice * oss) unsigned int format_mask; GstCaps *caps; - if (oss->probed_caps != NULL) - return; - if (oss->fd == -1) - return; - /* FIXME test make sure we're not currently playing */ /* FIXME test both mono and stereo */ - format_mask = AFMT_U8 | AFMT_S16_LE | AFMT_S16_BE | AFMT_S8 | - AFMT_U16_LE | AFMT_U16_BE; - format_mask &= oss->caps; + format_mask = AFMT_U8 | AFMT_S8; + + if (G_BYTE_ORDER == G_LITTLE_ENDIAN) + format_mask |= AFMT_S16_LE | AFMT_U16_LE; + else + format_mask |= AFMT_S16_BE | AFMT_U16_BE; caps = gst_caps_new_empty (); /* assume that the most significant bit of format_mask is 0 */ - for (format_bit = 1; format_bit <= format_mask; format_bit <<= 1) { + for (format_bit = 1 << 31; format_bit > 0; format_bit >>= 1) { if (format_bit & format_mask) { GValue rate_value = { 0 }; probe = g_new0 (GstOssProbe, 1); - probe->fd = oss->fd; + probe->fd = fd; probe->format = format_bit; probe->n_channels = 2; - ret = gst_oss_rate_probe_check (probe); + ret = gst_oss_helper_rate_probe_check (probe); if (probe->min == -1 || probe->max == -1) { g_array_free (probe->rates, TRUE); g_free (probe); @@ -950,7 +133,7 @@ gst_oss_probe_caps (GstOssDevice * oss) if (ret) { GValue value = { 0 }; - g_array_sort (probe->rates, gst_oss_rate_int_compare); + g_array_sort (probe->rates, gst_oss_helper_rate_int_compare); g_value_init (&rate_value, GST_TYPE_LIST); g_value_init (&value, G_TYPE_INT); @@ -971,7 +154,7 @@ gst_oss_probe_caps (GstOssDevice * oss) g_array_free (probe->rates, TRUE); g_free (probe); - structure = gst_oss_get_format_structure (format_bit); + structure = gst_oss_helper_get_format_structure (format_bit); gst_structure_set (structure, "channels", GST_TYPE_INT_RANGE, 1, 2, NULL); gst_structure_set_value (structure, "rate", &rate_value); g_value_unset (&rate_value); @@ -980,17 +163,17 @@ gst_oss_probe_caps (GstOssDevice * oss) } } - if (gst_caps_is_empty (caps)) { - GST_ELEMENT_ERROR (oss, RESOURCE, SETTINGS, - (_("Your OSS device could not be probed correctly")), (NULL)); - return; - } + if (gst_caps_is_empty (caps)) + /* fixme: make user-visible */ + g_critical ("Your OSS device could not be probed correctly"); + GST_DEBUG ("probed caps: %" GST_PTR_FORMAT, caps); - oss->probed_caps = caps; + + return caps; } static GstStructure * -gst_oss_get_format_structure (unsigned int format_bit) +gst_oss_helper_get_format_structure (unsigned int format_bit) { GstStructure *structure; int endianness; @@ -1045,7 +228,7 @@ gst_oss_get_format_structure (unsigned int format_bit) } static gboolean -gst_oss_rate_probe_check (GstOssProbe * probe) +gst_oss_helper_rate_probe_check (GstOssProbe * probe) { GstOssRange *range; GQueue *ranges; @@ -1058,14 +241,14 @@ gst_oss_rate_probe_check (GstOssProbe * probe) probe->rates = g_array_new (FALSE, FALSE, sizeof (int)); - probe->min = gst_oss_rate_check_rate (probe, 1000); + probe->min = gst_oss_helper_rate_check_rate (probe, 1000); n_checks++; - probe->max = gst_oss_rate_check_rate (probe, 100000); + probe->max = gst_oss_helper_rate_check_rate (probe, 100000); /* a little bug workaround */ { int max; - max = gst_oss_rate_check_rate (probe, 48000); + max = gst_oss_helper_rate_check_rate (probe, 48000); if (max > probe->max) { GST_ERROR ("Driver bug recognized (driver does not round rates correctly). Please file a bug report."); @@ -1078,14 +261,14 @@ gst_oss_rate_probe_check (GstOssProbe * probe) * error) for rates outside of [8000,48000]. If this fails, the * driver is seriously buggy, and probably doesn't work with other * media libraries/apps. */ - probe->min = gst_oss_rate_check_rate (probe, 8000); - probe->max = gst_oss_rate_check_rate (probe, 48000); + probe->min = gst_oss_helper_rate_check_rate (probe, 8000); + probe->max = gst_oss_helper_rate_check_rate (probe, 48000); } if (probe->min == -1 || probe->max == -1) { GST_DEBUG ("unexpected check_rate error"); return FALSE; } - gst_oss_rate_add_range (ranges, probe->min + 1, probe->max - 1); + gst_oss_helper_rate_add_range (ranges, probe->min + 1, probe->max - 1); while ((range = g_queue_pop_head (ranges))) { int min1; @@ -1096,7 +279,7 @@ gst_oss_rate_probe_check (GstOssProbe * probe) GST_DEBUG ("checking [%d,%d]", range->min, range->max); mid = (range->min + range->max) / 2; - mid_ret = gst_oss_rate_check_rate (probe, mid); + mid_ret = gst_oss_helper_rate_check_rate (probe, mid); if (mid_ret == -1) { /* FIXME ioctl returned an error. do something */ GST_DEBUG ("unexpected check_rate error"); @@ -1133,8 +316,8 @@ gst_oss_rate_probe_check (GstOssProbe * probe) } } - gst_oss_rate_add_range (ranges, range->min, min1); - gst_oss_rate_add_range (ranges, max1, range->max); + gst_oss_helper_rate_add_range (ranges, range->min, min1); + gst_oss_helper_rate_add_range (ranges, max1, range->max); g_free (range); } @@ -1148,7 +331,7 @@ gst_oss_rate_probe_check (GstOssProbe * probe) } static void -gst_oss_rate_add_range (GQueue * queue, int min, int max) +gst_oss_helper_rate_add_range (GQueue * queue, int min, int max) { if (min <= max) { GstOssRange *range = g_new0 (GstOssRange, 1); @@ -1163,7 +346,7 @@ gst_oss_rate_add_range (GQueue * queue, int min, int max) } static int -gst_oss_rate_check_rate (GstOssProbe * probe, int irate) +gst_oss_helper_rate_check_rate (GstOssProbe * probe, int irate) { int rate; int format; @@ -1191,12 +374,12 @@ gst_oss_rate_check_rate (GstOssProbe * probe, int irate) if (rate == irate - 1 || rate == irate + 1) { rate = irate; } - gst_oss_rate_add_rate (probe->rates, rate); + gst_oss_helper_rate_add_rate (probe->rates, rate); return rate; } static void -gst_oss_rate_add_rate (GArray * array, int rate) +gst_oss_helper_rate_add_rate (GArray * array, int rate) { int i; int val; @@ -1212,7 +395,7 @@ gst_oss_rate_add_rate (GArray * array, int rate) } static int -gst_oss_rate_int_compare (gconstpointer a, gconstpointer b) +gst_oss_helper_rate_int_compare (gconstpointer a, gconstpointer b) { const int *va = (const int *) a; const int *vb = (const int *) b; diff --git a/sys/oss/gstosshelper.h b/sys/oss/gstosshelper.h index 9b7eebd5..1593fe39 100644 --- a/sys/oss/gstosshelper.h +++ b/sys/oss/gstosshelper.h @@ -2,11 +2,7 @@ * Copyright (C) 1999,2000 Erik Walthinsen * 2000 Wim Taymans * - * gstosshelper.h: helper functions for OSS Device handling. This - * set of functions takes care of device setting/getting, - * opening/closing devices, parsing caps to OSS formats/settings - * or the other way around, device probing, supported format - * probing and mixer integration. + * gstosshelper.h: OSS helper routines. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -24,128 +20,24 @@ * Boston, MA 02111-1307, USA. */ + #ifndef __GST_OSS_HELPER_H__ #define __GST_OSS_HELPER_H__ + #include #include -/* debugging category */ -GST_DEBUG_CATEGORY_EXTERN (oss_debug); -#define GST_CAT_DEFAULT oss_debug - -G_BEGIN_DECLS - -enum { - ARG_0, - OSS_ARG_DEVICE, - OSS_ARG_MIXER_DEVICE, - OSS_ARG_DEVICE_NAME, - OSS_ARG_0 -}; - -typedef enum { - GST_OSS_MODE_READ, - GST_OSS_MODE_WRITE, - GST_OSS_MODE_VOLUME, - GST_OSS_MODE_MIXER -} GstOssOpenMode; - -/* - * Embed those two in whatever object you're creating. - */ - -typedef struct _GstOssDeviceCombination { - gchar *dsp, *mixer; - dev_t dev; -} GstOssDeviceCombination; - -typedef struct _GstOssDevice { - /* device state */ - int fd; - int caps; /* the capabilities */ - gint format; - gint fragment; - guint64 fragment_time; - gint fragment_size; - GstOssOpenMode mode; - GstCaps *probed_caps; +#include "gstosshelper.h" - /* stats bytes per *second* */ - guint bps; - /* sample width in bytes */ - guint sample_width; - - /* parameters */ - gint law; - gint endianness; - gboolean sign; - gint width; - gint depth; - gint channels; - gint rate; - - /* mixer stuff */ - GList *tracklist; - guint32 stereomask, - recdevs, - recmask, - mixcaps; - gint mixer_fd; - gchar *device_name; -} GstOssDevice; - -/* - * class/type/interface handling for mixer/device handling. - */ -void gst_oss_add_mixer_type (GType type); -void gst_oss_add_device_properties (GstElementClass * klass); -void gst_oss_set_device_property (GstElement * element, - GstOssDeviceCombination * c, - GstOssDevice * dev, - guint prop_id, - GParamSpec * pspec, - const GValue * value); -void gst_oss_get_device_property (GstElement * element, - GstOssDeviceCombination * c, - GstOssDevice * d, - guint prop_id, - GParamSpec * pspec, - GValue * value); - -/* - * device open/close. - */ -void gst_oss_init (GObject * obj, - GstOssDeviceCombination * c, - GstOssDevice * dev, - GstOssOpenMode mode); -void gst_oss_dispose (GstOssDeviceCombination * c, - GstOssDevice * dev); -gboolean gst_oss_open (GstElement * element, - GstOssDeviceCombination * c, - GstOssDevice * dev); -void gst_oss_close (GstOssDevice * dev); +G_BEGIN_DECLS -/* - * caps parsing/probing. - */ -gboolean gst_oss_parse_caps (GstOssDevice * dev, - const GstCaps * caps); -gboolean gst_oss_merge_fixed_caps (GstOssDevice * dev, - GstCaps * caps); -gboolean gst_oss_sync_parms (GstOssDevice * dev); -void gst_oss_reset (GstOssDevice * dev); +GstCaps* gst_oss_helper_probe_caps (gint fd); -gboolean gst_oss_convert (GstOssDevice * dev, - GstFormat src_format, - gint64 src_value, - GstFormat * dest_format, - gint64 * dest_value); -void gst_oss_probe_caps (GstOssDevice * dev); G_END_DECLS + #endif /* __GST_OSS_HELPER_H__ */ diff --git a/sys/oss/gstossmixer.c b/sys/oss/gstossmixer.c index 1d462908..1e972568 100644 --- a/sys/oss/gstossmixer.c +++ b/sys/oss/gstossmixer.c @@ -35,257 +35,186 @@ #include #include "gstossmixer.h" +#include "gstossmixertrack.h" #define MASK_BIT_IS_SET(mask, bit) \ (mask & (1 << bit)) -static void gst_ossmixer_track_class_init (GstOssMixerTrackClass * klass); -static void gst_ossmixer_track_init (GstOssMixerTrack * track); +static gboolean +gst_ossmixer_open (GstOssMixer * mixer) +{ +#ifdef SOUND_MIXER_INFO + struct mixer_info minfo; +#endif -static gboolean gst_ossmixer_supported (GstImplementsInterface * iface, - GType iface_type); -static const GList *gst_ossmixer_list_tracks (GstMixer * ossmixer); + g_return_val_if_fail (mixer->mixer_fd == -1, FALSE); -static void gst_ossmixer_set_volume (GstMixer * ossmixer, - GstMixerTrack * track, gint * volumes); -static void gst_ossmixer_get_volume (GstMixer * ossmixer, - GstMixerTrack * track, gint * volumes); + mixer->mixer_fd = open (mixer->device, O_RDWR); + if (mixer->mixer_fd == -1) { + /* this is valid. OSS devices don't need to expose a mixer */ + GST_DEBUG ("Failed to open mixer device %s, mixing disabled: %s", + mixer->device, strerror (errno)); + return FALSE; + } -static void gst_ossmixer_set_record (GstMixer * ossmixer, - GstMixerTrack * track, gboolean record); -static void gst_ossmixer_set_mute (GstMixer * ossmixer, - GstMixerTrack * track, gboolean mute); + /* get masks */ + if (ioctl (mixer->mixer_fd, SOUND_MIXER_READ_RECMASK, &mixer->recmask) < 0 + || ioctl (mixer->mixer_fd, SOUND_MIXER_READ_RECSRC, &mixer->recdevs) < 0 + || ioctl (mixer->mixer_fd, SOUND_MIXER_READ_STEREODEVS, + &mixer->stereomask) < 0 + || ioctl (mixer->mixer_fd, SOUND_MIXER_READ_DEVMASK, &mixer->devmask) < 0 + || ioctl (mixer->mixer_fd, SOUND_MIXER_READ_CAPS, &mixer->mixcaps) < 0) { + GST_DEBUG ("Failed to get device masks"); + close (mixer->mixer_fd); + mixer->mixer_fd = -1; + return FALSE; + } -static const gchar **labels = NULL; -static GstMixerTrackClass *parent_class = NULL; + /* get name */ +#ifdef SOUND_MIXER_INFO + if (ioctl (mixer->mixer_fd, SOUND_MIXER_INFO, &minfo) == 0) { + mixer->cardname = g_strdup (minfo.name); + } +#else + oss->cardname = g_strdup ("Unknown"); +#endif -/* three functions: firstly, OSS has the nasty habit of inserting - * spaces in the labels, we want to get rid of them. Secondly, - * i18n is impossible with OSS' way of providing us with mixer - * labels, so we make a 'given' list of i18n'ed labels. Thirdly, I - * personally don't like the "1337" names that OSS gives to their - * labels ("Vol", "Mic", "Rec"), I'd rather see full names. */ + return TRUE; +} static void -fill_labels (void) +gst_ossmixer_ensure_track_list (GstOssMixer * mixer) { - gint i, pos; - gchar *origs[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_LABELS; - struct - { - gchar *given, *wanted; - } - cases[] = { - /* Note: this list is simply ripped from soundcard.h. For - * some people, some values might be missing (3D surround, - * etc.) - feel free to add them. That's the reason why - * I'm doing this in such a horribly complicated way. */ - { - "Vol ", _("Volume")} - , { - "Bass ", _("Bass")} - , { - "Trebl", _("Treble")} - , { - "Synth", _("Synth")} - , { - "Pcm ", _("PCM")} - , { - "Spkr ", _("Speaker")} - , { - "Line ", _("Line-in")} - , { - "Mic ", _("Microphone")} - , { - "CD ", _("CD")} - , { - "Mix ", _("Mixer")} - , { - "Pcm2 ", _("PCM-2")} - , { - "Rec ", _("Record")} - , { - "IGain", _("In-gain")} - , { - "OGain", _("Out-gain")} - , { - "Line1", _("Line-1")} - , { - "Line2", _("Line-2")} - , { - "Line3", _("Line-3")} - , { - "Digital1", _("Digital-1")} - , { - "Digital2", _("Digital-2")} - , { - "Digital3", _("Digital-3")} - , { - "PhoneIn", _("Phone-in")} - , { - "PhoneOut", _("Phone-out")} - , { - "Video", _("Video")} - , { - "Radio", _("Radio")} - , { - "Monitor", _("Monitor")} - , { - NULL, NULL} - }; - - labels = g_malloc (sizeof (gchar *) * SOUND_MIXER_NRDEVICES); + gint i, master = -1; + + g_return_if_fail (mixer->mixer_fd != -1); + if (mixer->tracklist) + return; + + /* find master volume */ + if (mixer->devmask & SOUND_MASK_VOLUME) + master = SOUND_MIXER_VOLUME; + else if (mixer->devmask & SOUND_MASK_PCM) + master = SOUND_MIXER_PCM; + else if (mixer->devmask & SOUND_MASK_SPEAKER) + master = SOUND_MIXER_SPEAKER; /* doubtful... */ + /* else: no master, so we won't set any */ + + /* build track list */ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { - for (pos = 0; cases[pos].given != NULL; pos++) { - if (!strcmp (cases[pos].given, origs[i])) { - labels[i] = g_strdup (cases[pos].wanted); - break; - } + if (mixer->devmask & (1 << i)) { + GstMixerTrack *track; + gboolean input = FALSE, stereo = FALSE, record = FALSE; + + /* track exists, make up capabilities */ + if (MASK_BIT_IS_SET (mixer->stereomask, i)) + stereo = TRUE; + if (MASK_BIT_IS_SET (mixer->recmask, i)) + input = TRUE; + if (MASK_BIT_IS_SET (mixer->recdevs, i)) + record = TRUE; + + /* do we want this in our list? */ + if (!((mixer->dir & GST_OSS_MIXER_CAPTURE && input == TRUE) || + (mixer->dir & GST_OSS_MIXER_PLAYBACK && i != SOUND_MIXER_PCM))) + /* the PLAYBACK case seems hacky, but that's how 0.8 had it */ + continue; + + /* add track to list */ + track = gst_ossmixer_track_new (mixer->mixer_fd, i, stereo ? 2 : 1, + (record ? GST_MIXER_TRACK_RECORD : 0) | + (input ? GST_MIXER_TRACK_INPUT : + GST_MIXER_TRACK_OUTPUT) | + ((master != i) ? 0 : GST_MIXER_TRACK_MASTER)); + mixer->tracklist = g_list_append (mixer->tracklist, track); } - if (cases[pos].given == NULL) - labels[i] = g_strdup (origs[i]); } } -GType -gst_ossmixer_track_get_type (void) +GstOssMixer * +gst_ossmixer_new (const char *device, GstOssMixerDirection dir) { - static GType gst_ossmixer_track_type = 0; - - if (!gst_ossmixer_track_type) { - static const GTypeInfo ossmixer_track_info = { - sizeof (GstOssMixerTrackClass), - NULL, - NULL, - (GClassInitFunc) gst_ossmixer_track_class_init, - NULL, - NULL, - sizeof (GstOssMixerTrack), - 0, - (GInstanceInitFunc) gst_ossmixer_track_init, - NULL - }; - - gst_ossmixer_track_type = - g_type_register_static (GST_TYPE_MIXER_TRACK, - "GstOssMixerTrack", &ossmixer_track_info, 0); - } + GstOssMixer *ret = NULL; - return gst_ossmixer_track_type; -} + g_return_val_if_fail (device != NULL, NULL); -static void -gst_ossmixer_track_class_init (GstOssMixerTrackClass * klass) -{ - parent_class = g_type_class_ref (GST_TYPE_MIXER_TRACK); -} + ret = g_new0 (GstOssMixer, 1); -static void -gst_ossmixer_track_init (GstOssMixerTrack * track) -{ - track->lvol = track->rvol = 0; - track->track_num = 0; -} + ret->device = g_strdup (device); + ret->dir = dir; -GstMixerTrack * -gst_ossmixer_track_new (GstOssDevice * oss, - gint track_num, gint max_chans, gint flags) -{ - GstOssMixerTrack *osstrack; - GstMixerTrack *track; - gint volume; + if (!gst_ossmixer_open (ret)) + goto error; - if (!labels) - fill_labels (); - - osstrack = g_object_new (GST_TYPE_OSSMIXER_TRACK, NULL); - track = GST_MIXER_TRACK (osstrack); - track->label = g_strdup (labels[track_num]); - track->num_channels = max_chans; - track->flags = flags; - track->min_volume = 0; - track->max_volume = 100; - osstrack->track_num = track_num; - - /* volume */ - if (ioctl (oss->mixer_fd, MIXER_READ (osstrack->track_num), &volume) < 0) { - g_warning ("Error getting device (%d) volume: %s", - osstrack->track_num, strerror (errno)); - volume = 0; - } - osstrack->lvol = (volume & 0xff); - if (track->num_channels == 2) { - osstrack->rvol = ((volume >> 8) & 0xff); - } + return ret; - return track; -} +error: + if (ret) + gst_ossmixer_free (ret); -void -gst_oss_interface_init (GstImplementsInterfaceClass * klass) -{ - /* default virtual functions */ - klass->supported = gst_ossmixer_supported; + return NULL; } void -gst_ossmixer_interface_init (GstMixerClass * klass) +gst_ossmixer_free (GstOssMixer * mixer) { - GST_MIXER_TYPE (klass) = GST_MIXER_HARDWARE; - - /* default virtual functions */ - klass->list_tracks = gst_ossmixer_list_tracks; - 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; -} + g_return_if_fail (mixer != NULL); -static gboolean -gst_ossmixer_supported (GstImplementsInterface * iface, GType iface_type) -{ - GstOssDevice *oss = g_object_get_data (G_OBJECT (iface), "oss-data"); + if (mixer->device) { + g_free (mixer->device); + mixer->device = NULL; + } + + if (mixer->cardname) { + g_free (mixer->cardname); + mixer->cardname = NULL; + } + + if (mixer->tracklist) { + g_list_foreach (mixer->tracklist, (GFunc) g_object_unref, NULL); + g_list_free (mixer->tracklist); + mixer->tracklist = NULL; + } - g_return_val_if_fail (oss != NULL, FALSE); - g_assert (iface_type == GST_TYPE_MIXER); + if (mixer->mixer_fd != -1) { + close (mixer->mixer_fd); + mixer->mixer_fd = -1; + } - return (oss->mixer_fd != -1); + g_free (mixer); } /* unused with G_DISABLE_* */ static G_GNUC_UNUSED gboolean -gst_ossmixer_contains_track (GstOssDevice * oss, GstOssMixerTrack * osstrack) +gst_ossmixer_contains_track (GstOssMixer * mixer, GstOssMixerTrack * osstrack) { const GList *item; - for (item = oss->tracklist; item != NULL; item = item->next) + for (item = mixer->tracklist; item != NULL; item = item->next) if (item->data == osstrack) return TRUE; return FALSE; } -static const GList * -gst_ossmixer_list_tracks (GstMixer * mixer) +const GList * +gst_ossmixer_list_tracks (GstOssMixer * mixer) { - GstOssDevice *oss = g_object_get_data (G_OBJECT (mixer), "oss-data"); + gst_ossmixer_ensure_track_list (mixer); - return (const GList *) oss->tracklist; + return (const GList *) mixer->tracklist; } -static void -gst_ossmixer_get_volume (GstMixer * mixer, +void +gst_ossmixer_get_volume (GstOssMixer * mixer, GstMixerTrack * track, gint * volumes) { gint volume; - GstOssDevice *oss = g_object_get_data (G_OBJECT (mixer), "oss-data"); GstOssMixerTrack *osstrack = GST_OSSMIXER_TRACK (track); - /* assert that we're opened and that we're using a known item */ - g_return_if_fail (oss != NULL); - g_return_if_fail (oss->mixer_fd != -1); - g_return_if_fail (gst_ossmixer_contains_track (oss, osstrack)); + g_return_if_fail (mixer->mixer_fd != -1); + g_return_if_fail (gst_ossmixer_contains_track (mixer, osstrack)); if (track->flags & GST_MIXER_TRACK_MUTE) { volumes[0] = osstrack->lvol; @@ -294,7 +223,7 @@ gst_ossmixer_get_volume (GstMixer * mixer, } } else { /* get */ - if (ioctl (oss->mixer_fd, MIXER_READ (osstrack->track_num), &volume) < 0) { + if (ioctl (mixer->mixer_fd, MIXER_READ (osstrack->track_num), &volume) < 0) { g_warning ("Error getting recording device (%d) volume: %s", osstrack->track_num, strerror (errno)); volume = 0; @@ -307,18 +236,15 @@ gst_ossmixer_get_volume (GstMixer * mixer, } } -static void -gst_ossmixer_set_volume (GstMixer * mixer, +void +gst_ossmixer_set_volume (GstOssMixer * mixer, GstMixerTrack * track, gint * volumes) { gint volume; - GstOssDevice *oss = g_object_get_data (G_OBJECT (mixer), "oss-data"); GstOssMixerTrack *osstrack = GST_OSSMIXER_TRACK (track); - /* assert that we're opened and that we're using a known item */ - g_return_if_fail (oss != NULL); - g_return_if_fail (oss->mixer_fd != -1); - g_return_if_fail (gst_ossmixer_contains_track (oss, osstrack)); + g_return_if_fail (mixer->mixer_fd != -1); + g_return_if_fail (gst_ossmixer_contains_track (mixer, osstrack)); /* prepare the value for ioctl() */ if (!(track->flags & GST_MIXER_TRACK_MUTE)) { @@ -328,7 +254,7 @@ gst_ossmixer_set_volume (GstMixer * mixer, } /* set */ - if (ioctl (oss->mixer_fd, MIXER_WRITE (osstrack->track_num), &volume) < 0) { + if (ioctl (mixer->mixer_fd, MIXER_WRITE (osstrack->track_num), &volume) < 0) { g_warning ("Error setting recording device (%d) volume (0x%x): %s", osstrack->track_num, volume, strerror (errno)); return; @@ -341,28 +267,26 @@ gst_ossmixer_set_volume (GstMixer * mixer, } } -static void -gst_ossmixer_set_mute (GstMixer * mixer, GstMixerTrack * track, gboolean mute) +void +gst_ossmixer_set_mute (GstOssMixer * mixer, GstMixerTrack * track, + gboolean mute) { int volume; - GstOssDevice *oss = g_object_get_data (G_OBJECT (mixer), "oss-data"); GstOssMixerTrack *osstrack = GST_OSSMIXER_TRACK (track); - /* assert that we're opened and that we're using a known item */ - g_return_if_fail (oss != NULL); - g_return_if_fail (oss->mixer_fd != -1); - g_return_if_fail (gst_ossmixer_contains_track (oss, osstrack)); + g_return_if_fail (mixer->mixer_fd != -1); + g_return_if_fail (gst_ossmixer_contains_track (mixer, osstrack)); if (mute) { volume = 0; } else { volume = (osstrack->lvol & 0xff); - if (MASK_BIT_IS_SET (oss->stereomask, osstrack->track_num)) { + if (MASK_BIT_IS_SET (mixer->stereomask, osstrack->track_num)) { volume |= ((osstrack->rvol & 0xff) << 8); } } - if (ioctl (oss->mixer_fd, MIXER_WRITE (osstrack->track_num), &volume) < 0) { + if (ioctl (mixer->mixer_fd, MIXER_WRITE (osstrack->track_num), &volume) < 0) { g_warning ("Error setting mixer recording device volume (0x%x): %s", volume, strerror (errno)); return; @@ -375,17 +299,14 @@ gst_ossmixer_set_mute (GstMixer * mixer, GstMixerTrack * track, gboolean mute) } } -static void -gst_ossmixer_set_record (GstMixer * mixer, +void +gst_ossmixer_set_record (GstOssMixer * mixer, GstMixerTrack * track, gboolean record) { - GstOssDevice *oss = g_object_get_data (G_OBJECT (mixer), "oss-data"); GstOssMixerTrack *osstrack = GST_OSSMIXER_TRACK (track); - /* assert that we're opened and that we're using a known item */ - g_return_if_fail (oss != NULL); - g_return_if_fail (oss->mixer_fd != -1); - g_return_if_fail (gst_ossmixer_contains_track (oss, osstrack)); + g_return_if_fail (mixer->mixer_fd != -1); + g_return_if_fail (gst_ossmixer_contains_track (mixer, osstrack)); /* if there's nothing to do... */ if ((record && GST_MIXER_TRACK_HAS_FLAG (track, GST_MIXER_TRACK_RECORD)) || @@ -393,28 +314,28 @@ gst_ossmixer_set_record (GstMixer * mixer, return; /* if we're exclusive, then we need to unset the current one(s) */ - if (oss->mixcaps & SOUND_CAP_EXCL_INPUT) { + if (mixer->mixcaps & SOUND_CAP_EXCL_INPUT) { GList *track; - for (track = oss->tracklist; track != NULL; track = track->next) { + for (track = mixer->tracklist; track != NULL; track = track->next) { GstMixerTrack *turn = (GstMixerTrack *) track->data; turn->flags &= ~GST_MIXER_TRACK_RECORD; } - oss->recdevs = 0; + mixer->recdevs = 0; } /* set new record bit, if needed */ if (record) { - oss->recdevs |= (1 << osstrack->track_num); + mixer->recdevs |= (1 << osstrack->track_num); } else { - oss->recdevs &= ~(1 << osstrack->track_num); + mixer->recdevs &= ~(1 << osstrack->track_num); } /* set it to the device */ - if (ioctl (oss->mixer_fd, SOUND_MIXER_WRITE_RECSRC, &oss->recdevs) < 0) { + if (ioctl (mixer->mixer_fd, SOUND_MIXER_WRITE_RECSRC, &mixer->recdevs) < 0) { g_warning ("Error setting mixer recording devices (0x%x): %s", - oss->recdevs, strerror (errno)); + mixer->recdevs, strerror (errno)); return; } @@ -424,101 +345,3 @@ gst_ossmixer_set_record (GstMixer * mixer, track->flags &= ~GST_MIXER_TRACK_RECORD; } } - -void -gst_ossmixer_build_list (GstOssDeviceCombination * c, GstOssDevice * oss) -{ - gint i, devmask, master = -1; - -#ifdef SOUND_MIXER_INFO - struct mixer_info minfo; -#endif - - g_return_if_fail (oss->mixer_fd == -1); - - oss->mixer_fd = open (c->mixer, O_RDWR); - if (oss->mixer_fd == -1) { - /* this is valid. OSS devices don't need to expose a mixer */ - GST_DEBUG ("Failed to open mixer device %s, mixing disabled: %s", - c->mixer, strerror (errno)); - return; - } - - /* get masks */ - if (ioctl (oss->mixer_fd, SOUND_MIXER_READ_RECMASK, &oss->recmask) < 0 || - ioctl (oss->mixer_fd, SOUND_MIXER_READ_RECSRC, &oss->recdevs) < 0 || - ioctl (oss->mixer_fd, SOUND_MIXER_READ_STEREODEVS, &oss->stereomask) < 0 - || ioctl (oss->mixer_fd, SOUND_MIXER_READ_DEVMASK, &devmask) < 0 - || ioctl (oss->mixer_fd, SOUND_MIXER_READ_CAPS, &oss->mixcaps) < 0) { - GST_DEBUG ("Failed to get device masks - disabling mixer"); - close (oss->mixer_fd); - oss->mixer_fd = -1; - return; - } - - /* get name */ -#ifdef SOUND_MIXER_INFO - if (ioctl (oss->mixer_fd, SOUND_MIXER_INFO, &minfo) == 0) { - oss->device_name = g_strdup (minfo.name); - } -#else - oss->device_name = g_strdup ("Unknown"); -#endif - - /* find master volume */ - if (devmask & SOUND_MASK_VOLUME) - master = SOUND_MIXER_VOLUME; - else if (devmask & SOUND_MASK_PCM) - master = SOUND_MIXER_PCM; - else if (devmask & SOUND_MASK_SPEAKER) - master = SOUND_MIXER_SPEAKER; /* doubtful... */ - /* else: no master, so we won't set any */ - - /* build track list */ - for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { - if (devmask & (1 << i)) { - GstMixerTrack *track; - gboolean input = FALSE, stereo = FALSE, record = FALSE; - - /* track 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; - - /* do we want this in our list? */ - if ((oss->mode == GST_OSS_MODE_READ && input == FALSE) || - (oss->mode == GST_OSS_MODE_WRITE && i != SOUND_MIXER_PCM)) - continue; - - /* add track to list */ - track = gst_ossmixer_track_new (oss, i, stereo ? 2 : 1, - (record ? GST_MIXER_TRACK_RECORD : 0) | - (input ? GST_MIXER_TRACK_INPUT : - GST_MIXER_TRACK_OUTPUT) | - ((master != i) ? 0 : GST_MIXER_TRACK_MASTER)); - oss->tracklist = g_list_append (oss->tracklist, track); - } - } -} - -void -gst_ossmixer_free_list (GstOssDevice * oss) -{ - if (oss->mixer_fd == -1) - return; - - g_list_foreach (oss->tracklist, (GFunc) g_object_unref, NULL); - g_list_free (oss->tracklist); - oss->tracklist = NULL; - - if (oss->device_name) { - g_free (oss->device_name); - oss->device_name = NULL; - } - - close (oss->mixer_fd); - oss->mixer_fd = -1; -} diff --git a/sys/oss/gstossmixer.h b/sys/oss/gstossmixer.h index 2eede0ed..c5a8f325 100644 --- a/sys/oss/gstossmixer.h +++ b/sys/oss/gstossmixer.h @@ -19,48 +19,153 @@ * Boston, MA 02111-1307, USA. */ + #ifndef __GST_OSS_MIXER_H__ #define __GST_OSS_MIXER_H__ + #include #include #include "gstosshelper.h" + G_BEGIN_DECLS -#define GST_TYPE_OSSMIXER_TRACK \ - (gst_ossmixer_track_get_type ()) -#define GST_OSSMIXER_TRACK(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_OSSMIXER_TRACK, \ - GstOssMixerTrack)) -#define GST_OSSMIXER_TRACK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_OSSMIXER_TRACK, \ - GstOssMixerTrackClass)) -#define GST_IS_OSSMIXER_TRACK(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_OSSMIXER_TRACK)) -#define GST_IS_OSSMIXER_TRACK_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_OSSMIXER_TRACK)) - -typedef struct _GstOssMixerTrack { - GstMixerTrack parent; - - gint lvol, rvol; - gint track_num; -} GstOssMixerTrack; - -typedef struct _GstOssMixerTrackClass { - GstMixerTrackClass parent; -} GstOssMixerTrackClass; - -GType gst_ossmixer_track_get_type (void); - -void gst_ossmixer_interface_init (GstMixerClass *klass); -void gst_oss_interface_init (GstImplementsInterfaceClass *klass); -void gst_ossmixer_build_list (GstOssDeviceCombination * c, - GstOssDevice *oss); -void gst_ossmixer_free_list (GstOssDevice *oss); + +#define GST_OSS_MIXER(obj) ((GstOssMixer*)(obj)) + + +typedef enum { + GST_OSS_MIXER_CAPTURE = 1<<0, + GST_OSS_MIXER_PLAYBACK = 1<<1, + GST_OSS_MIXER_ALL = GST_OSS_MIXER_CAPTURE | GST_OSS_MIXER_PLAYBACK +} GstOssMixerDirection; + + +typedef struct _GstOssMixer GstOssMixer; + + +struct _GstOssMixer { + GList * tracklist; /* list of available tracks */ + + gint mixer_fd; + + gchar * device; + gchar * cardname; + + gint recmask; + gint recdevs; + gint stereomask; + gint devmask; + gint mixcaps; + + GstOssMixerDirection dir; +}; + + +GstOssMixer* gst_ossmixer_new (const gchar *device, + GstOssMixerDirection dir); +void gst_ossmixer_free (GstOssMixer *mixer); + +const GList* gst_ossmixer_list_tracks (GstOssMixer * mixer); +void gst_ossmixer_set_volume (GstOssMixer * mixer, + GstMixerTrack * track, + gint * volumes); +void gst_ossmixer_get_volume (GstOssMixer * mixer, + GstMixerTrack * track, + gint * volumes); +void gst_ossmixer_set_record (GstOssMixer * mixer, + GstMixerTrack * track, + gboolean record); +void gst_ossmixer_set_mute (GstOssMixer * mixer, + GstMixerTrack * track, + gboolean mute); + + +#define GST_IMPLEMENT_OSS_MIXER_METHODS(Type, interface_as_function) \ +static gboolean \ +interface_as_function ## _supported (Type *this, GType iface_type) \ +{ \ + g_assert (iface_type == GST_TYPE_MIXER); \ + \ + return (this->mixer != NULL); \ +} \ + \ +static const GList* \ +interface_as_function ## _list_tracks (GstMixer * mixer) \ +{ \ + Type *this = (Type*) mixer; \ + \ + g_return_val_if_fail (this != NULL, NULL); \ + g_return_val_if_fail (this->mixer != NULL, NULL); \ + \ + return gst_ossmixer_list_tracks (this->mixer); \ +} \ + \ +static void \ +interface_as_function ## _set_volume (GstMixer * mixer, GstMixerTrack * track, \ + gint * volumes) \ +{ \ + Type *this = (Type*) mixer; \ + \ + g_return_if_fail (this != NULL); \ + g_return_if_fail (this->mixer != NULL); \ + \ + gst_ossmixer_set_volume (this->mixer, track, volumes); \ +} \ + \ +static void \ +interface_as_function ## _get_volume (GstMixer * mixer, GstMixerTrack * track, \ + gint * volumes) \ +{ \ + Type *this = (Type*) mixer; \ + \ + g_return_if_fail (this != NULL); \ + g_return_if_fail (this->mixer != NULL); \ + \ + gst_ossmixer_get_volume (this->mixer, track, volumes); \ +} \ + \ +static void \ +interface_as_function ## _set_record (GstMixer * mixer, GstMixerTrack * track, \ + gboolean record) \ +{ \ + Type *this = (Type*) mixer; \ + \ + g_return_if_fail (this != NULL); \ + g_return_if_fail (this->mixer != NULL); \ + \ + gst_ossmixer_set_record (this->mixer, track, record); \ +} \ + \ +static void \ +interface_as_function ## _set_mute (GstMixer * mixer, GstMixerTrack * track, \ + gboolean mute) \ +{ \ + Type *this = (Type*) mixer; \ + \ + g_return_if_fail (this != NULL); \ + g_return_if_fail (this->mixer != NULL); \ + \ + gst_ossmixer_set_mute (this->mixer, track, mute); \ +} \ + \ +static void \ +interface_as_function ## _interface_init (GstMixerClass * klass) \ +{ \ + GST_MIXER_TYPE (klass) = GST_MIXER_HARDWARE; \ + \ + /* set up the interface hooks */ \ + klass->list_tracks = interface_as_function ## _list_tracks; \ + klass->set_volume = interface_as_function ## _set_volume; \ + klass->get_volume = interface_as_function ## _get_volume; \ + klass->set_mute = interface_as_function ## _set_mute; \ + klass->set_record = interface_as_function ## _set_record; \ +} + G_END_DECLS + #endif /* __GST_OSS_MIXER_H__ */ diff --git a/sys/oss/gstossmixertrack.c b/sys/oss/gstossmixertrack.c new file mode 100644 index 00000000..48e4a9d6 --- /dev/null +++ b/sys/oss/gstossmixertrack.c @@ -0,0 +1,180 @@ +/* GStreamer OSS Mixer implementation + * Copyright (C) 2003 Ronald Bultje + * + * gstossmixer.c: 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 + +#include "gstossmixertrack.h" + +#define MASK_BIT_IS_SET(mask, bit) \ + (mask & (1 << bit)) + +G_DEFINE_TYPE (GstOssMixerTrack, gst_ossmixer_track, GST_TYPE_MIXER_TRACK); + +static void +gst_ossmixer_track_class_init (GstOssMixerTrackClass * klass) +{ + /* nop */ +} + +static void +gst_ossmixer_track_init (GstOssMixerTrack * track) +{ + track->lvol = track->rvol = 0; + track->track_num = 0; +} + +static const gchar **labels = NULL; + +/* three functions: firstly, OSS has the nasty habit of inserting + * spaces in the labels, we want to get rid of them. Secondly, + * i18n is impossible with OSS' way of providing us with mixer + * labels, so we make a 'given' list of i18n'ed labels. Thirdly, I + * personally don't like the "1337" names that OSS gives to their + * labels ("Vol", "Mic", "Rec"), I'd rather see full names. */ + +static void +fill_labels (void) +{ + gint i, pos; + gchar *origs[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_LABELS; + struct + { + gchar *given, *wanted; + } + cases[] = { + /* Note: this list is simply ripped from soundcard.h. For + * some people, some values might be missing (3D surround, + * etc.) - feel free to add them. That's the reason why + * I'm doing this in such a horribly complicated way. */ + { + "Vol ", _("Volume")} + , { + "Bass ", _("Bass")} + , { + "Trebl", _("Treble")} + , { + "Synth", _("Synth")} + , { + "Pcm ", _("PCM")} + , { + "Spkr ", _("Speaker")} + , { + "Line ", _("Line-in")} + , { + "Mic ", _("Microphone")} + , { + "CD ", _("CD")} + , { + "Mix ", _("Mixer")} + , { + "Pcm2 ", _("PCM-2")} + , { + "Rec ", _("Record")} + , { + "IGain", _("In-gain")} + , { + "OGain", _("Out-gain")} + , { + "Line1", _("Line-1")} + , { + "Line2", _("Line-2")} + , { + "Line3", _("Line-3")} + , { + "Digital1", _("Digital-1")} + , { + "Digital2", _("Digital-2")} + , { + "Digital3", _("Digital-3")} + , { + "PhoneIn", _("Phone-in")} + , { + "PhoneOut", _("Phone-out")} + , { + "Video", _("Video")} + , { + "Radio", _("Radio")} + , { + "Monitor", _("Monitor")} + , { + NULL, NULL} + }; + + labels = g_malloc (sizeof (gchar *) * SOUND_MIXER_NRDEVICES); + + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) { + for (pos = 0; cases[pos].given != NULL; pos++) { + if (!strcmp (cases[pos].given, origs[i])) { + labels[i] = g_strdup (cases[pos].wanted); + break; + } + } + if (cases[pos].given == NULL) + labels[i] = g_strdup (origs[i]); + } +} + +GstMixerTrack * +gst_ossmixer_track_new (gint mixer_fd, + gint track_num, gint max_chans, gint flags) +{ + GstOssMixerTrack *osstrack; + GstMixerTrack *track; + gint volume; + + if (!labels) + fill_labels (); + + osstrack = g_object_new (GST_TYPE_OSSMIXER_TRACK, NULL); + track = GST_MIXER_TRACK (osstrack); + track->label = g_strdup (labels[track_num]); + track->num_channels = max_chans; + track->flags = flags; + track->min_volume = 0; + track->max_volume = 100; + osstrack->track_num = track_num; + + /* volume */ + if (ioctl (mixer_fd, MIXER_READ (osstrack->track_num), &volume) < 0) { + g_warning ("Error getting device (%d) volume: %s", + osstrack->track_num, strerror (errno)); + volume = 0; + } + osstrack->lvol = (volume & 0xff); + if (track->num_channels == 2) { + osstrack->rvol = ((volume >> 8) & 0xff); + } + + return track; +} diff --git a/sys/oss/gstossmixertrack.h b/sys/oss/gstossmixertrack.h new file mode 100644 index 00000000..1350a026 --- /dev/null +++ b/sys/oss/gstossmixertrack.h @@ -0,0 +1,62 @@ +/* GStreamer OSS Mixer implementation + * Copyright (C) 2003 Ronald Bultje + * + * gstossmixertrack.h: OSS mixer tracks + * + * 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_TRACK_H__ +#define __GST_OSS_MIXER_TRACK_H__ + +#include +#include + +#include "gstosshelper.h" + +G_BEGIN_DECLS + +#define GST_TYPE_OSSMIXER_TRACK \ + (gst_ossmixer_track_get_type ()) +#define GST_OSSMIXER_TRACK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_OSSMIXER_TRACK, \ + GstOssMixerTrack)) +#define GST_OSSMIXER_TRACK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_OSSMIXER_TRACK, \ + GstOssMixerTrackClass)) +#define GST_IS_OSSMIXER_TRACK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_OSSMIXER_TRACK)) +#define GST_IS_OSSMIXER_TRACK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_OSSMIXER_TRACK)) + +typedef struct _GstOssMixerTrack { + GstMixerTrack parent; + + gint lvol, rvol; + gint track_num; +} GstOssMixerTrack; + +typedef struct _GstOssMixerTrackClass { + GstMixerTrackClass parent; +} GstOssMixerTrackClass; + +GType gst_ossmixer_track_get_type (void); +GstMixerTrack* gst_ossmixer_track_new (gint mixer_fd, + gint track_num, gint max_chans, gint flags); + +G_END_DECLS + +#endif /* __GST_OSS_MIXER_TRACK_H__ */ diff --git a/sys/oss/gstosssink.c b/sys/oss/gstosssink.c index efef1ba0..a98efab1 100644 --- a/sys/oss/gstosssink.c +++ b/sys/oss/gstosssink.c @@ -162,27 +162,22 @@ gst_oss_sink_init (GstOssSink * osssink) { GST_DEBUG ("initializing osssink"); - osssink->element = g_object_new (GST_TYPE_OSSELEMENT, NULL); + osssink->fd = -1; } static GstCaps * gst_oss_sink_getcaps (GstBaseSink * bsink) { GstOssSink *osssink; - GstOssElement *element; GstCaps *caps; osssink = GST_OSSSINK (bsink); - element = osssink->element; - gst_osselement_probe_caps (element); - - if (element->probed_caps == NULL) { - caps = - gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD + if (osssink->fd == -1) { + caps = gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (bsink))); } else { - caps = gst_caps_ref (element->probed_caps); + caps = gst_oss_helper_probe_caps (osssink->fd); } return caps; diff --git a/sys/oss/gstosssink.h b/sys/oss/gstosssink.h index 7f488117..3cede595 100644 --- a/sys/oss/gstosssink.h +++ b/sys/oss/gstosssink.h @@ -28,7 +28,7 @@ #include #include -#include "gstosselement.h" +#include "gstosshelper.h" G_BEGIN_DECLS @@ -44,8 +44,6 @@ typedef struct _GstOssSinkClass GstOssSinkClass; struct _GstOssSink { GstAudioSink sink; - GstOssElement *element; - gint fd; gint bytes_per_sample; }; diff --git a/sys/oss/gstosssrc.c b/sys/oss/gstosssrc.c index e7a5cda1..2c413657 100644 --- a/sys/oss/gstosssrc.c +++ b/sys/oss/gstosssrc.c @@ -192,27 +192,23 @@ gst_oss_src_init (GstOssSrc * osssrc) { GST_DEBUG ("initializing osssrc"); + osssrc->fd = -1; osssrc->device = g_strdup ("/dev/dsp"); - osssrc->element = g_object_new (GST_TYPE_OSSELEMENT, NULL); } static GstCaps * gst_oss_src_getcaps (GstBaseSrc * bsrc) { GstOssSrc *osssrc; - GstOssElement *element; GstCaps *caps; osssrc = GST_OSS_SRC (bsrc); - element = osssrc->element; - gst_osselement_probe_caps (element); - - if (element->probed_caps == NULL) { - caps = - gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD (bsrc))); + if (osssrc->fd == -1) { + caps = gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD + (bsrc))); } else { - caps = gst_caps_ref (element->probed_caps); + caps = gst_oss_helper_probe_caps (osssrc->fd); } return caps; diff --git a/sys/oss/gstosssrc.h b/sys/oss/gstosssrc.h index f787524f..23f7c389 100644 --- a/sys/oss/gstosssrc.h +++ b/sys/oss/gstosssrc.h @@ -28,7 +28,7 @@ #include #include -#include "gstosselement.h" +#include "gstosshelper.h" G_BEGIN_DECLS @@ -44,8 +44,6 @@ typedef struct _GstOssSrcClass GstOssSrcClass; struct _GstOssSrc { GstAudioSrc src; - GstOssElement *element; - gint fd; gint bytes_per_sample; -- cgit