diff options
Diffstat (limited to 'sys/oss/gstosselement.c')
-rw-r--r-- | sys/oss/gstosselement.c | 1319 |
1 files changed, 0 insertions, 1319 deletions
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 <omega@cse.ogi.edu> - * 2000 Wim Taymans <wim.taymans@chello.be> - * - * 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 <sys/types.h> -#include <sys/stat.h> -#include <sys/ioctl.h> -#include <fcntl.h> -#include <unistd.h> -#include <errno.h> -#include <string.h> - -#include <sys/soundcard.h> - -#include <gst/interfaces/propertyprobe.h> - -#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 <rbultje@ronald.bitfreak.net>"); - -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 <sys/soundcard.h> -#else - -#ifdef HAVE_OSS_INCLUDE_IN_ROOT -#include <soundcard.h> -#else - -#include <machine/soundcard.h> - -#endif /* HAVE_OSS_INCLUDE_IN_ROOT */ - -#endif /* HAVE_OSS_INCLUDE_IN_SYS */ - -#include <unistd.h> -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/ioctl.h> -#include <glib.h> -#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; -} |