2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3 * 2000 Wim Taymans <wim.taymans@chello.be>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
27 #include "gst/gst-i18n-plugin.h"
28 #include <sys/types.h>
30 #include <sys/ioctl.h>
32 #include <sys/soundcard.h>
37 #include <gst/propertyprobe/propertyprobe.h>
39 #include "gstosselement.h"
40 #include "gstossmixer.h"
49 /* elementfactory information */
50 static GstElementDetails gst_osselement_details = GST_ELEMENT_DETAILS (
53 "OSS-based mixer element",
54 "Ronald Bultje <rbultje@ronald.bitfreak.net>"
57 static void gst_osselement_base_init (GstOssElementClass *klass);
58 static void gst_osselement_class_init (GstOssElementClass *klass);
60 static void gst_ossprobe_interface_init (GstPropertyProbeInterface *iface);
61 static void gst_osselement_init (GstOssElement *oss);
62 static void gst_osselement_dispose (GObject *object);
64 static void gst_osselement_set_property (GObject *object,
68 static void gst_osselement_get_property (GObject *object,
72 static GstElementStateReturn gst_osselement_change_state (GstElement *element);
74 static GstElementClass *parent_class = NULL;
75 /*static guint gst_osssrc_signals[LAST_SIGNAL] = { 0 }; */
78 gst_osselement_get_type (void)
80 static GType osselement_type = 0;
82 if (!osselement_type) {
83 static const GTypeInfo osselement_info = {
84 sizeof(GstOssElementClass),
85 (GBaseInitFunc)gst_osselement_base_init,
87 (GClassInitFunc)gst_osselement_class_init,
90 sizeof(GstOssElement),
92 (GInstanceInitFunc)gst_osselement_init
94 static const GInterfaceInfo ossiface_info = {
95 (GInterfaceInitFunc) gst_oss_interface_init,
99 static const GInterfaceInfo ossmixer_info = {
100 (GInterfaceInitFunc) gst_ossmixer_interface_init,
104 static const GInterfaceInfo ossprobe_info = {
105 (GInterfaceInitFunc) gst_ossprobe_interface_init,
110 osselement_type = g_type_register_static (GST_TYPE_ELEMENT,
112 &osselement_info, 0);
113 g_type_add_interface_static (osselement_type,
114 GST_TYPE_IMPLEMENTS_INTERFACE,
116 g_type_add_interface_static (osselement_type,
119 g_type_add_interface_static (osselement_type,
120 GST_TYPE_PROPERTY_PROBE,
124 return osselement_type;
128 gst_osselement_base_init (GstOssElementClass *klass)
130 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
132 klass->device_combinations = NULL;
134 gst_element_class_set_details (element_class, &gst_osselement_details);
138 gst_osselement_class_init (GstOssElementClass *klass)
140 GObjectClass *gobject_class;
141 GstElementClass *gstelement_class;
143 gobject_class = (GObjectClass*)klass;
144 gstelement_class = (GstElementClass*)klass;
146 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
148 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE,
149 g_param_spec_string ("device", "Device", "OSS device (/dev/dspN usually)",
150 "default", G_PARAM_READWRITE));
151 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_MIXERDEV,
152 g_param_spec_string ("mixerdev", "Mixer device",
153 "OSS mixer device (/dev/mixerN usually)",
154 "default", G_PARAM_READWRITE));
155 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE_NAME,
156 g_param_spec_string ("device_name", "Device name", "Name of the device",
157 NULL, G_PARAM_READABLE));
159 gobject_class->set_property = gst_osselement_set_property;
160 gobject_class->get_property = gst_osselement_get_property;
161 gobject_class->dispose = gst_osselement_dispose;
163 gstelement_class->change_state = gst_osselement_change_state;
167 gst_ossprobe_get_properties (GstPropertyProbe *probe)
169 GObjectClass *klass = G_OBJECT_GET_CLASS (probe);
170 static GList *list = NULL;
173 list = g_list_append (NULL, g_object_class_find_property (klass, "device"));
179 /* OSS (without devfs) allows at max. 16 devices */
180 #define MAX_OSS_DEVICES 16
183 gst_osselement_probe (gchar *device_base,
188 gchar *device = NULL;
191 if ((name == NULL) || (devno == NULL)) {
198 if (device_num == -1)
199 device = g_strdup (device_base);
200 else if ((device_num >= -1) && (device_num <= MAX_OSS_DEVICES)) {
201 device = g_strdup_printf ("%s%d", device_base, device_num);
206 if (lstat (device, &s) || !S_ISCHR (s.st_mode))
218 device_combination_append (GList *device_combinations,
219 GstOssDeviceCombination *combi)
223 for (it = device_combinations; it != NULL; it = it->next) {
224 GstOssDeviceCombination *cur;
226 cur = (GstOssDeviceCombination*)it->data;
227 if (cur->dev == combi->dev) {
228 return device_combinations;
232 return g_list_append (device_combinations, combi);
236 gst_osselement_class_probe_devices (GstOssElementClass *klass,
239 GstElementClass *eklass = GST_ELEMENT_CLASS (klass);
240 static gboolean init = FALSE;
241 static GList *device_combinations;
243 gint openmode = O_RDONLY;
244 gboolean mixer = FALSE;
246 /* Ok, so how do we open the device? We assume that we have (max.) one
247 * pad, and if this is a sinkpad, we're osssink (w). else, we're osssrc
249 padtempllist = gst_element_class_get_pad_template_list (eklass);
250 if (padtempllist != NULL) {
251 GstPadTemplate *firstpadtempl = padtempllist->data;
252 if (GST_PAD_TEMPLATE_DIRECTION (firstpadtempl) == GST_PAD_SINK) {
258 if (!init && !check) {
261 gchar *dev_base[][2] = { {"/dev/mixer", "/dev/dsp"},
262 {"/dev/sound/mixer", "/dev/sound/dsp"},
267 while (device_combinations) {
268 GList *item = device_combinations;
269 GstOssDeviceCombination *combi = item->data;
271 device_combinations = g_list_remove (device_combinations, item);
274 g_free (combi->mixer);
278 /* probe for all /dev entries */
279 for (base = 0; dev_base[base][DSP] != NULL; base++) {
282 for (n = -1; n < MAX_OSS_DEVICES; n++) {
288 gst_osselement_probe (dev_base[base][DSP], n, &dsp, &dsp_dev);
292 gst_osselement_probe (dev_base[base][MIXER], n, &mixer, &mixer_dev);
293 /* does the device exist (can we open them)? */
295 /* we just check the dsp. we assume the mixer always works.
296 * we don't need a mixer anyway (says OSS)... If we are a
297 * mixer element, we use the mixer anyway. */
298 if ((fd = open (mixer ? mixer :
299 dsp, openmode | O_NONBLOCK)) > 0 || errno == EBUSY) {
300 GstOssDeviceCombination *combi;
306 combi = g_new0 (GstOssDeviceCombination, 1);
308 combi->mixer = mixer;
309 device_combinations = device_combination_append (device_combinations,
321 klass->device_combinations = device_combinations;
327 gst_osselement_class_list_devices (GstOssElementClass *klass)
330 GValue value = { 0 };
333 if (!klass->device_combinations)
336 array = g_value_array_new (g_list_length (klass->device_combinations));
337 item = klass->device_combinations;
338 g_value_init (&value, G_TYPE_STRING);
340 GstOssDeviceCombination *combi = item->data;
342 g_value_set_string (&value, combi->dsp);
343 g_value_array_append (array, &value);
347 g_value_unset (&value);
353 gst_ossprobe_probe_property (GstPropertyProbe *probe,
355 const GParamSpec *pspec)
357 GstOssElementClass *klass = GST_OSSELEMENT_GET_CLASS (probe);
361 gst_osselement_class_probe_devices (klass, FALSE);
364 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
370 gst_ossprobe_needs_probe (GstPropertyProbe *probe,
372 const GParamSpec *pspec)
374 GstOssElementClass *klass = GST_OSSELEMENT_GET_CLASS (probe);
375 gboolean ret = FALSE;
379 ret = !gst_osselement_class_probe_devices (klass, TRUE);
382 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
390 gst_ossprobe_get_values (GstPropertyProbe *probe,
392 const GParamSpec *pspec)
394 GstOssElementClass *klass = GST_OSSELEMENT_GET_CLASS (probe);
395 GValueArray *array = NULL;
399 array = gst_osselement_class_list_devices (klass);
402 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec);
410 gst_ossprobe_interface_init (GstPropertyProbeInterface *iface)
412 iface->get_properties = gst_ossprobe_get_properties;
413 iface->probe_property = gst_ossprobe_probe_property;
414 iface->needs_probe = gst_ossprobe_needs_probe;
415 iface->get_values = gst_ossprobe_get_values;
419 gst_osselement_init (GstOssElement *oss)
421 oss->device = g_strdup ("/dev/dsp");
422 oss->mixer_dev = g_strdup ("/dev/mixer");
425 oss->tracklist = NULL;
426 oss->device_name = NULL;
428 gst_osselement_reset (oss);
432 gst_osselement_dispose (GObject *object)
434 GstOssElement *oss = (GstOssElement *) object;
436 g_free (oss->device);
437 g_free (oss->mixer_dev);
439 G_OBJECT_CLASS (parent_class)->dispose (object);
443 gst_osselement_reset (GstOssElement *oss)
446 oss->endianness = G_BYTE_ORDER;
455 /* AFMT_*_BE not available on all OSS includes (e.g. FBSD) */
456 #ifdef WORDS_BIGENDIAN
457 oss->format = AFMT_S16_BE;
459 oss->format = AFMT_S16_LE;
460 #endif /* WORDS_BIGENDIAN */
464 gst_ossformat_get (gint law, gint endianness, gboolean sign, gint width, gint depth,
465 gint *format, gint *bps)
475 if (endianness == G_LITTLE_ENDIAN) {
476 *format = AFMT_S16_LE;
478 "16 bit signed LE, no law (%d)", *format);
480 else if (endianness == G_BIG_ENDIAN) {
481 *format = AFMT_S16_BE;
483 "16 bit signed BE, no law (%d)", *format);
487 if (endianness == G_LITTLE_ENDIAN) {
488 *format = AFMT_U16_LE;
490 "16 bit unsigned LE, no law (%d)", *format);
492 else if (endianness == G_BIG_ENDIAN) {
493 *format = AFMT_U16_BE;
495 "16 bit unsigned BE, no law (%d)", *format);
500 else if (width == 8) {
504 "8 bit signed, no law (%d)", *format);
509 "8 bit unsigned, no law (%d)", *format);
513 } else if (law == 1) {
514 *format = AFMT_MU_LAW;
516 "mu law (%d)", *format);
517 } else if (law == 2) {
518 *format = AFMT_A_LAW;
520 "a law (%d)", *format);
522 g_critical ("unknown law");
530 gst_osselement_parse_caps (GstOssElement *oss, const GstCaps *caps)
533 GstStructure *structure;
535 structure = gst_caps_get_structure (caps, 0);
537 gst_structure_get_int (structure, "width", &oss->width);
538 gst_structure_get_int (structure, "depth", &oss->depth);
540 if (oss->width != oss->depth)
543 gst_structure_get_int (structure, "law", &oss->law);
544 gst_structure_get_int (structure, "endianness", &oss->endianness);
545 gst_structure_get_boolean (structure, "signed", &oss->sign);
547 if (!gst_ossformat_get (oss->law, oss->endianness, oss->sign,
548 oss->width, oss->depth, &format, &bps))
550 GST_DEBUG ("could not get format");
554 gst_structure_get_int (structure, "channels", &oss->channels);
555 gst_structure_get_int (structure, "rate", &oss->rate);
557 oss->bps = bps * oss->channels * oss->rate;
558 oss->format = format;
563 #define GET_FIXED_INT(caps, name, dest) \
565 if (gst_caps_has_fixed_property (caps, name)) \
566 gst_structure_get_int (structure, name, dest); \
568 #define GET_FIXED_BOOLEAN(caps, name, dest) \
570 if (gst_caps_has_fixed_property (caps, name)) \
571 gst_structure_get_boolean (structure, name, dest); \
575 gst_osselement_merge_fixed_caps (GstOssElement *oss, GstCaps *caps)
578 GstStructure *structure;
580 structure = gst_caps_get_structure (caps, 0);
582 /* peel off fixed stuff from the caps */
583 gst_structure_get_int (structure, "law", &oss->law);
584 gst_structure_get_int (structure, "endianness", &oss->endianness);
585 gst_structure_get_boolean (structure, "signed", &oss->sign);
586 gst_structure_get_int (structure, "width", &oss->width);
587 gst_structure_get_int (structure, "depth", &oss->depth);
589 if (!gst_ossformat_get (oss->law, oss->endianness, oss->sign,
590 oss->width, oss->depth, &format, &bps))
595 gst_structure_get_int (structure, "rate", &oss->rate);
596 gst_structure_get_int (structure, "channels", &oss->channels);
598 oss->bps = bps * oss->channels * oss->rate;
599 oss->format = format;
605 gst_osselement_sync_parms (GstOssElement *oss)
607 audio_buf_info space;
610 gint target_channels;
612 gint fragscale, frag_ln;
617 if (oss->fragment >> 16)
618 frag = oss->fragment;
620 frag = 0x7FFF0000 | oss->fragment;
622 GST_INFO ("osselement: setting sound card to %dHz %d format %s (%08x fragment)",
623 oss->rate, oss->format,
624 (oss->channels == 2) ? "stereo" : "mono", frag);
626 ioctl (oss->fd, SNDCTL_DSP_SETFRAGMENT, &frag);
627 ioctl (oss->fd, SNDCTL_DSP_RESET, 0);
629 target_format = oss->format;
630 target_channels = oss->channels;
631 target_rate = oss->rate;
633 ioctl (oss->fd, SNDCTL_DSP_SETFMT, &oss->format);
634 ioctl (oss->fd, SNDCTL_DSP_CHANNELS, &oss->channels);
635 ioctl (oss->fd, SNDCTL_DSP_SPEED, &oss->rate);
637 ioctl (oss->fd, SNDCTL_DSP_GETBLKSIZE, &oss->fragment_size);
639 if (oss->mode == GST_OSSELEMENT_WRITE) {
640 ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &space);
643 ioctl (oss->fd, SNDCTL_DSP_GETISPACE, &space);
646 /* calculate new fragment using a poor man's logarithm function */
649 while (fragscale < space.fragsize) {
653 oss->fragment = space.fragstotal << 16 | frag_ln;
655 GST_INFO ("osselement: set sound card to %dHz, %d format, %s "
656 "(%d bytes buffer, %08x fragment)",
657 oss->rate, oss->format,
658 (oss->channels == 2) ? "stereo" : "mono",
659 space.bytes, oss->fragment);
661 oss->fragment_time = (GST_SECOND * oss->fragment_size) / oss->bps;
662 GST_INFO ("fragment time %u %" G_GUINT64_FORMAT "\n",
663 oss->bps, oss->fragment_time);
665 if (target_format != oss->format ||
666 target_channels != oss->channels ||
667 target_rate != oss->rate)
669 if (target_channels != oss->channels)
670 g_warning ("couldn't set the right number of channels (wanted %d, got %d), enjoy the tone difference", target_channels, oss->channels);
671 if (target_rate != oss->rate)
672 g_warning ("couldn't set the right sample rate (wanted %d, got %d), enjoy the speed difference", target_rate, oss->rate);
673 if (target_format != oss->format)
674 g_warning ("couldn't set requested OSS format, enjoy the noise :)");
675 /* we could eventually return FALSE here, or just do some additional tests
676 * to see that the frequencies don't differ too much etc.. */
682 gst_osselement_open_audio (GstOssElement *oss)
685 GstOssOpenMode mode = GST_OSSELEMENT_READ;
686 const GList *padlist;
688 g_return_val_if_fail (oss->fd == -1, FALSE);
689 GST_INFO ("osselement: attempting to open sound device");
691 /* Ok, so how do we open the device? We assume that we have (max.) one
692 * pad, and if this is a sinkpad, we're osssink (w). else, we're osssrc (r) */
693 padlist = gst_element_get_pad_list (GST_ELEMENT (oss));
694 if (padlist != NULL) {
695 GstPad *firstpad = padlist->data;
696 if (GST_PAD_IS_SINK (firstpad)) {
697 mode = GST_OSSELEMENT_WRITE;
703 /* first try to open the sound card */
704 if (mode == GST_OSSELEMENT_WRITE) {
705 /* open non blocking first so that it returns immediatly with an error
706 * when we cannot get to the device */
707 oss->fd = open (oss->device, O_WRONLY | O_NONBLOCK);
712 /* re-open the sound device in blocking mode */
713 oss->fd = open (oss->device, O_WRONLY);
717 oss->fd = open (oss->device, O_RDONLY);
723 GST_ELEMENT_ERROR (oss, RESOURCE, BUSY,
724 (_("OSS device \"%s\" is already in use by another program."), oss->device),
729 if (mode == GST_OSSELEMENT_WRITE)
730 GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_WRITE,
731 (_("Could not access device \"%s\", check its permissions."), oss->device),
734 GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_READ,
735 (_("Could not access device \"%s\", check its permissions."), oss->device),
741 GST_ELEMENT_ERROR (oss, RESOURCE, NOT_FOUND,
742 (_("Device \"%s\" does not exist."), oss->device),
746 /* FIXME: strerror is not threadsafe */
747 if (mode == GST_OSSELEMENT_WRITE)
748 GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_WRITE,
749 (_("Could not open device \"%s\" for writing."), oss->device),
752 GST_ELEMENT_ERROR (oss, RESOURCE, OPEN_READ,
753 (_("Could not open device \"%s\" for reading."), oss->device),
762 /* we have it, set the default parameters and go have fun */
764 ioctl (oss->fd, SNDCTL_DSP_GETCAPS, &caps);
766 GST_INFO ("osselement: Capabilities %08x", caps);
768 if (caps & DSP_CAP_DUPLEX) GST_INFO ( "osselement: Full duplex");
769 if (caps & DSP_CAP_REALTIME) GST_INFO ( "osselement: Realtime");
770 if (caps & DSP_CAP_BATCH) GST_INFO ( "osselement: Batch");
771 if (caps & DSP_CAP_COPROC) GST_INFO ( "osselement: Has coprocessor");
772 if (caps & DSP_CAP_TRIGGER) GST_INFO ( "osselement: Trigger");
773 if (caps & DSP_CAP_MMAP) GST_INFO ( "osselement: Direct access");
776 if (caps & DSP_CAP_MULTI) GST_INFO ( "osselement: Multiple open");
777 #endif /* DSP_CAP_MULTI */
780 if (caps & DSP_CAP_BIND) GST_INFO ( "osselement: Channel binding");
781 #endif /* DSP_CAP_BIND */
783 ioctl(oss->fd, SNDCTL_DSP_GETFMTS, &caps);
785 GST_INFO ( "osselement: Formats %08x", caps);
786 if (caps & AFMT_MU_LAW) GST_INFO ( "osselement: MU_LAW");
787 if (caps & AFMT_A_LAW) GST_INFO ( "osselement: A_LAW");
788 if (caps & AFMT_IMA_ADPCM) GST_INFO ( "osselement: IMA_ADPCM");
789 if (caps & AFMT_U8) GST_INFO ( "osselement: U8");
790 if (caps & AFMT_S16_LE) GST_INFO ( "osselement: S16_LE");
791 if (caps & AFMT_S16_BE) GST_INFO ( "osselement: S16_BE");
792 if (caps & AFMT_S8) GST_INFO ( "osselement: S8");
793 if (caps & AFMT_U16_LE) GST_INFO ( "osselement: U16_LE");
794 if (caps & AFMT_U16_BE) GST_INFO ( "osselement: U16_BE");
795 if (caps & AFMT_MPEG) GST_INFO ( "osselement: MPEG");
797 if (caps & AFMT_AC3) GST_INFO ( "osselement: AC3");
800 GST_INFO ("osselement: opened audio (%s) with fd=%d",
801 oss->device, oss->fd);
806 gst_ossmixer_build_list (oss);
812 gst_osselement_close_audio (GstOssElement *oss)
814 gst_ossmixer_free_list (oss);
824 gst_osselement_convert (GstOssElement *oss,
825 GstFormat src_format,
827 GstFormat *dest_format,
832 if (src_format == *dest_format) {
833 *dest_value = src_value;
837 if (oss->bps == 0 || oss->channels == 0 || oss->width == 0)
840 switch (src_format) {
841 case GST_FORMAT_BYTES:
842 switch (*dest_format) {
843 case GST_FORMAT_TIME:
844 *dest_value = src_value * GST_SECOND / oss->bps;
846 case GST_FORMAT_DEFAULT:
847 *dest_value = src_value / (oss->width * oss->channels / 8);
853 case GST_FORMAT_TIME:
854 switch (*dest_format) {
855 case GST_FORMAT_BYTES:
856 *dest_value = src_value * oss->bps / GST_SECOND;
858 case GST_FORMAT_DEFAULT:
859 *dest_value = src_value * oss->rate / GST_SECOND;
865 case GST_FORMAT_DEFAULT:
866 switch (*dest_format) {
867 case GST_FORMAT_TIME:
868 *dest_value = src_value * GST_SECOND / oss->rate;
870 case GST_FORMAT_BYTES:
871 *dest_value = src_value * oss->width * oss->channels / 8;
885 gst_osselement_set_property (GObject *object,
890 GstOssElement *oss = GST_OSSELEMENT (object);
894 /* disallow changing the device while it is opened
895 get_property("device") should return the right one */
896 if (gst_element_get_state (GST_ELEMENT (oss)) == GST_STATE_NULL) {
897 g_free (oss->device);
898 oss->device = g_strdup (g_value_get_string (value));
900 /* let's assume that if we have a device map for the mixer,
901 * we're allowed to do all that automagically here */
902 if (GST_OSSELEMENT_GET_CLASS (oss)->device_combinations != NULL) {
903 GList *list = GST_OSSELEMENT_GET_CLASS (oss)->device_combinations;
906 GstOssDeviceCombination *combi = list->data;
908 if (!strcmp (combi->dsp, oss->device)) {
909 g_free (oss->mixer_dev);
910 oss->mixer_dev = g_strdup (combi->mixer);
920 /* disallow changing the device while it is opened
921 get_property("mixerdev") should return the right one */
922 if (gst_element_get_state (GST_ELEMENT (oss)) == GST_STATE_NULL) {
923 g_free (oss->mixer_dev);
924 oss->mixer_dev = g_strdup (g_value_get_string (value));
933 gst_osselement_get_property (GObject *object,
938 GstOssElement *oss = GST_OSSELEMENT (object);
942 g_value_set_string (value, oss->device);
945 g_value_set_string (value, oss->mixer_dev);
947 case ARG_DEVICE_NAME:
948 g_value_set_string (value, oss->device_name);
951 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
956 static GstElementStateReturn
957 gst_osselement_change_state (GstElement *element)
959 GstOssElement *oss = GST_OSSELEMENT (element);
961 switch (GST_STATE_TRANSITION (element)) {
962 case GST_STATE_NULL_TO_READY:
963 if (!gst_osselement_open_audio (oss)) {
964 return GST_STATE_FAILURE;
966 GST_INFO ("osselement: opened sound device");
968 case GST_STATE_READY_TO_NULL:
969 gst_osselement_close_audio (oss);
970 gst_osselement_reset (oss);
971 GST_INFO ("osselement: closed sound device");
977 if (GST_ELEMENT_CLASS (parent_class)->change_state)
978 return GST_ELEMENT_CLASS (parent_class)->change_state (element);
980 return GST_STATE_SUCCESS;