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.
24 #include <sys/types.h>
26 #include <sys/ioctl.h>
28 #include <sys/soundcard.h>
32 #include <gstosssink.h>
34 /* elementfactory information */
35 static GstElementDetails gst_osssink_details = {
39 "Output to a sound card via OSS",
41 "Erik Walthinsen <omega@cse.ogi.edu>, "
42 "Wim Taymans <wim.taymans@chello.be>",
46 static void gst_osssink_class_init (GstOssSinkClass *klass);
47 static void gst_osssink_init (GstOssSink *osssink);
48 static void gst_osssink_finalize (GObject *object);
50 static gboolean gst_osssink_open_audio (GstOssSink *sink);
51 static void gst_osssink_close_audio (GstOssSink *sink);
52 static gboolean gst_osssink_sync_parms (GstOssSink *osssink);
53 static GstElementStateReturn gst_osssink_change_state (GstElement *element);
54 static void gst_osssink_set_clock (GstElement *element, GstClock *clock);
55 static GstClock* gst_osssink_get_clock (GstElement *element);
56 static GstClockTime gst_osssink_get_time (GstClock *clock, gpointer data);
58 static const GstFormat* gst_osssink_get_formats (GstPad *pad);
59 static gboolean gst_osssink_convert (GstPad *pad, GstFormat src_format, gint64 src_value,
60 GstFormat *dest_format, gint64 *dest_value);
61 static const GstPadQueryType* gst_osssink_get_query_types (GstPad *pad);
62 static gboolean gst_osssink_query (GstElement *element, GstPadQueryType type,
63 GstFormat *format, gint64 *value);
64 static gboolean gst_osssink_sink_query (GstPad *pad, GstPadQueryType type,
65 GstFormat *format, gint64 *value);
67 static GstPadConnectReturn gst_osssink_sinkconnect (GstPad *pad, GstCaps *caps);
69 static void gst_osssink_set_property (GObject *object, guint prop_id, const GValue *value,
71 static void gst_osssink_get_property (GObject *object, guint prop_id, GValue *value,
74 static void gst_osssink_chain (GstPad *pad,GstBuffer *buf);
76 /* OssSink signals and args */
92 GST_PAD_TEMPLATE_FACTORY (osssink_sink_factory,
99 "format", GST_PROPS_STRING ("int"), /* hack */
100 "law", GST_PROPS_INT (0),
101 "endianness", GST_PROPS_INT (G_BYTE_ORDER),
102 "signed", GST_PROPS_LIST (
103 GST_PROPS_BOOLEAN (FALSE),
104 GST_PROPS_BOOLEAN (TRUE)
106 "width", GST_PROPS_LIST (
110 "depth", GST_PROPS_LIST (
114 "rate", GST_PROPS_INT_RANGE (1000, 48000),
115 "channels", GST_PROPS_INT_RANGE (1, 2)
119 static GstElementClass *parent_class = NULL;
120 static guint gst_osssink_signals[LAST_SIGNAL] = { 0 };
123 gst_osssink_get_type (void)
125 static GType osssink_type = 0;
128 static const GTypeInfo osssink_info = {
129 sizeof(GstOssSinkClass),
132 (GClassInitFunc)gst_osssink_class_init,
137 (GInstanceInitFunc)gst_osssink_init,
139 osssink_type = g_type_register_static (GST_TYPE_ELEMENT, "GstOssSink", &osssink_info, 0);
145 static GstBufferPool*
146 gst_osssink_get_bufferpool (GstPad *pad)
150 oss = GST_OSSSINK (gst_pad_get_parent(pad));
152 /* 6 buffers per chunk by default */
154 oss->sinkpool = gst_buffer_pool_get_default (oss->bufsize, 6);
156 return oss->sinkpool;
160 gst_osssink_finalize (GObject *object)
162 GstOssSink *osssink = (GstOssSink *) object;
164 g_free (osssink->device);
166 G_OBJECT_CLASS (parent_class)->finalize (object);
170 gst_osssink_class_init (GstOssSinkClass *klass)
172 GObjectClass *gobject_class;
173 GstElementClass *gstelement_class;
175 gobject_class = (GObjectClass*)klass;
176 gstelement_class = (GstElementClass*)klass;
178 parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
180 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DEVICE,
181 g_param_spec_string ("device", "Device", "The device to use for output",
182 "/dev/dsp", G_PARAM_READWRITE)); /* CHECKME! */
183 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MUTE,
184 g_param_spec_boolean ("mute", "Mute", "Mute the audio",
185 TRUE, G_PARAM_READWRITE));
186 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SYNC,
187 g_param_spec_boolean ("sync", "Sync", "If syncing on timestamps should be enabled",
188 TRUE, G_PARAM_READWRITE));
189 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FRAGMENT,
190 g_param_spec_int ("fragment", "Fragment",
191 "The fragment as 0xMMMMSSSS (MMMM = total fragments, 2^SSSS = fragment size)",
192 0, G_MAXINT, 6, G_PARAM_READWRITE));
193 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BUFFER_SIZE,
194 g_param_spec_int ("buffer_size", "Buffer size", "The buffer size",
195 0, G_MAXINT, 4096, G_PARAM_READWRITE));
197 gst_osssink_signals[SIGNAL_HANDOFF] =
198 g_signal_new ("handoff", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
199 G_STRUCT_OFFSET (GstOssSinkClass, handoff), NULL, NULL,
200 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
202 gobject_class->set_property = gst_osssink_set_property;
203 gobject_class->get_property = gst_osssink_get_property;
204 gobject_class->finalize = gst_osssink_finalize;
206 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_osssink_change_state);
207 gstelement_class->query = GST_DEBUG_FUNCPTR (gst_osssink_query);
211 gst_osssink_init (GstOssSink *osssink)
213 osssink->sinkpad = gst_pad_new_from_template (
214 GST_PAD_TEMPLATE_GET (osssink_sink_factory), "sink");
215 gst_element_add_pad (GST_ELEMENT (osssink), osssink->sinkpad);
216 gst_pad_set_connect_function (osssink->sinkpad, gst_osssink_sinkconnect);
217 gst_pad_set_bufferpool_function (osssink->sinkpad, gst_osssink_get_bufferpool);
218 gst_pad_set_convert_function (osssink->sinkpad, gst_osssink_convert);
219 gst_pad_set_query_function (osssink->sinkpad, gst_osssink_sink_query);
220 gst_pad_set_query_type_function (osssink->sinkpad, gst_osssink_get_query_types);
221 gst_pad_set_formats_function (osssink->sinkpad, gst_osssink_get_formats);
223 gst_pad_set_chain_function (osssink->sinkpad, gst_osssink_chain);
225 osssink->device = g_strdup ("/dev/dsp");
227 osssink->channels = 1;
228 osssink->frequency = 11025;
229 osssink->fragment = 6;
230 /* AFMT_*_BE not available on all OSS includes (e.g. FBSD) */
231 #ifdef WORDS_BIGENDIAN
232 osssink->format = AFMT_S16_BE;
234 osssink->format = AFMT_S16_LE;
235 #endif /* WORDS_BIGENDIAN */
236 osssink->bufsize = 4096;
238 osssink->resync = FALSE;
239 osssink->sync = TRUE;
240 osssink->sinkpool = NULL;
241 osssink->provided_clock = GST_CLOCK (gst_oss_clock_new ("ossclock", gst_osssink_get_time, osssink));
242 osssink->handled = 0;
244 GST_ELEMENT (osssink)->setclockfunc = gst_osssink_set_clock;
245 GST_ELEMENT (osssink)->getclockfunc = gst_osssink_get_clock;
247 GST_FLAG_SET (osssink, GST_ELEMENT_THREAD_SUGGESTED);
248 GST_FLAG_SET (osssink, GST_ELEMENT_EVENT_AWARE);
252 static GstPadConnectReturn
253 gst_osssink_sinkconnect (GstPad *pad, GstCaps *caps)
255 gint law, endianness, depth;
258 GstOssSink *osssink = GST_OSSSINK (gst_pad_get_parent (pad));
260 if (!GST_CAPS_IS_FIXED (caps))
261 return GST_PAD_CONNECT_DELAYED;
263 gst_caps_get_int (caps, "width", &osssink->width);
264 gst_caps_get_int (caps, "depth", &depth);
266 if (osssink->width != depth)
267 return GST_PAD_CONNECT_REFUSED;
269 /* laws 1 and 2 are 1 bps anyway */
272 gst_caps_get_int (caps, "law", &law);
273 gst_caps_get_int (caps, "endianness", &endianness);
274 gst_caps_get_boolean (caps, "signed", &sign);
277 if (osssink->width == 16) {
279 if (endianness == G_LITTLE_ENDIAN)
281 format = AFMT_S16_LE;
282 GST_DEBUG (GST_CAT_PLUGIN_INFO,
283 "gst_osssink_sinkconnect: 16 bit signed LE, no law (%d)",
286 else if (endianness == G_BIG_ENDIAN)
288 format = AFMT_S16_BE;
289 GST_DEBUG (GST_CAT_PLUGIN_INFO,
290 "gst_osssink_sinkconnect: 16 bit signed BE, no law (%d)",
295 if (endianness == G_LITTLE_ENDIAN)
297 format = AFMT_U16_LE;
298 GST_DEBUG (GST_CAT_PLUGIN_INFO,
299 "gst_osssink_sinkconnect: 16 bit unsigned LE, no law (%d)",
302 else if (endianness == G_BIG_ENDIAN)
304 format = AFMT_U16_BE;
305 GST_DEBUG (GST_CAT_PLUGIN_INFO,
306 "gst_osssink_sinkconnect: 16 bit unsigned BE, no law (%d)",
312 else if (osssink->width == 8) {
315 GST_DEBUG (GST_CAT_PLUGIN_INFO,
316 "gst_osssink_sinkconnect: 8 bit signed, no law (%d)",
321 GST_DEBUG (GST_CAT_PLUGIN_INFO,
322 "gst_osssink_sinkconnect: 8 bit unsigned, no law (%d)",
327 } else if (law == 1) {
328 format = AFMT_MU_LAW;
329 GST_DEBUG (GST_CAT_PLUGIN_INFO,
330 "gst_osssink_sinkconnect: mu law (%d)",
332 } else if (law == 2) {
334 GST_DEBUG (GST_CAT_PLUGIN_INFO,
335 "gst_osssink_sinkconnect: a law (%d)",
338 g_critical ("unknown law");
339 return GST_PAD_CONNECT_REFUSED;
343 return GST_PAD_CONNECT_REFUSED;
345 osssink->format = format;
346 gst_caps_get_int (caps, "channels", &osssink->channels);
347 gst_caps_get_int (caps, "rate", &osssink->frequency);
349 osssink->bps *= osssink->channels;
350 osssink->bps *= osssink->frequency;
352 if (!gst_osssink_sync_parms (osssink)) {
353 return GST_PAD_CONNECT_REFUSED;
356 return GST_PAD_CONNECT_OK;
360 gst_osssink_sync_parms (GstOssSink *osssink)
362 audio_buf_info ospace;
365 gint target_channels;
366 gint target_frequency;
368 gint fragscale, frag_ln;
370 g_return_val_if_fail (osssink != NULL, FALSE);
371 g_return_val_if_fail (GST_IS_OSSSINK (osssink), FALSE);
373 if (osssink->fd == -1)
376 if (osssink->fragment >> 16)
377 frag = osssink->fragment;
379 frag = 0x7FFF0000 | osssink->fragment;
381 GST_INFO (GST_CAT_PLUGIN_INFO,
382 "osssink: setting sound card to %dHz %d format %s (%08x fragment)",
383 osssink->frequency, osssink->format,
384 (osssink->channels == 2) ? "stereo" : "mono", frag);
386 ioctl (osssink->fd, SNDCTL_DSP_SETFRAGMENT, &frag);
388 ioctl (osssink->fd, SNDCTL_DSP_RESET, 0);
390 target_format = osssink->format;
391 target_channels = osssink->channels;
392 target_frequency = osssink->frequency;
394 ioctl (osssink->fd, SNDCTL_DSP_SETFMT, &osssink->format);
395 ioctl (osssink->fd, SNDCTL_DSP_CHANNELS, &osssink->channels);
396 ioctl (osssink->fd, SNDCTL_DSP_SPEED, &osssink->frequency);
398 ioctl (osssink->fd, SNDCTL_DSP_GETBLKSIZE, &osssink->fragment_size);
399 ioctl (osssink->fd, SNDCTL_DSP_GETOSPACE, &ospace);
401 /* calculate new fragment using a poor man's logarithm function */
404 while (fragscale < ospace.fragsize) {
408 osssink->fragment = ospace.fragstotal << 16 | frag_ln;
410 GST_INFO (GST_CAT_PLUGIN_INFO,
411 "osssink: set sound card to %dHz %d format %s "
412 "(%d bytes buffer, %08x fragment)",
413 osssink->frequency, osssink->format,
414 (osssink->channels == 2) ? "stereo" : "mono",
415 ospace.bytes, osssink->fragment);
417 object = G_OBJECT (osssink);
418 g_object_freeze_notify (object);
419 g_object_notify (object, "fragment");
420 g_object_thaw_notify (object);
422 osssink->fragment_time = (GST_SECOND * osssink->fragment_size) / osssink->bps;
423 GST_INFO (GST_CAT_PLUGIN_INFO, "fragment time %u %llu\n",
424 osssink->bps, osssink->fragment_time);
426 if (target_format != osssink->format ||
427 target_channels != osssink->channels ||
428 target_frequency != osssink->frequency)
430 g_warning ("couldn't set requested OSS parameters, enjoy the noise :)");
431 /* we could eventually return FALSE here, or just do some additional tests
432 * to see that the frequencies don't differ too much etc.. */
438 gst_osssink_get_delay (GstOssSink *osssink)
442 if (osssink->fd == -1)
445 if (ioctl (osssink->fd, SNDCTL_DSP_GETODELAY, &delay) < 0) {
447 if (ioctl (osssink->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
451 delay = (info.fragstotal * info.fragsize) - info.bytes;
458 gst_osssink_get_time (GstClock *clock, gpointer data)
460 GstOssSink *osssink = GST_OSSSINK (data);
467 delay = gst_osssink_get_delay (osssink);
469 /* sometimes delay is bigger than the number of bytes sent to the device,
470 * which screws up this calculation, we assume that everything is still
471 * in the device then */
472 if (((guint64)delay) > osssink->handled) {
473 delay = osssink->handled;
475 res = (osssink->handled - delay) * GST_SECOND / osssink->bps;
481 gst_osssink_get_clock (GstElement *element)
485 osssink = GST_OSSSINK (element);
487 return GST_CLOCK (osssink->provided_clock);
491 gst_osssink_set_clock (GstElement *element, GstClock *clock)
495 osssink = GST_OSSSINK (element);
497 osssink->clock = clock;
501 gst_osssink_chain (GstPad *pad, GstBuffer *buf)
504 GstClockTime buftime;
506 /* this has to be an audio buffer */
507 osssink = GST_OSSSINK (gst_pad_get_parent (pad));
509 if (GST_IS_EVENT (buf)) {
510 GstEvent *event = GST_EVENT (buf);
512 switch (GST_EVENT_TYPE (event)) {
514 ioctl (osssink->fd, SNDCTL_DSP_SYNC);
515 gst_oss_clock_set_active (osssink->provided_clock, FALSE);
516 gst_pad_event_default (pad, event);
518 case GST_EVENT_NEW_MEDIA:
519 g_print ("new media\n");
521 case GST_EVENT_DISCONTINUOUS:
525 ioctl (osssink->fd, SNDCTL_DSP_RESET);
526 if (gst_event_discont_get_value (event, GST_FORMAT_TIME, &value)) {
527 if (!gst_clock_handle_discont (osssink->clock, value))
528 gst_oss_clock_set_active (osssink->provided_clock, FALSE);
529 osssink->handled = 0;
531 osssink->resync = TRUE;
535 gst_pad_event_default (pad, event);
538 gst_event_unref (event);
543 gst_buffer_unref (buf);
544 gst_element_error (GST_ELEMENT (osssink), "capsnego was never performed, unknown data type");
548 buftime = GST_BUFFER_TIMESTAMP (buf);
550 if (osssink->fd >= 0) {
551 if (!osssink->mute) {
552 guchar *data = GST_BUFFER_DATA (buf);
553 gint size = GST_BUFFER_SIZE (buf);
555 if (osssink->clock) {
558 GstClockTimeDiff jitter;
560 delay = gst_osssink_get_delay (osssink);
561 queued = delay * GST_SECOND / osssink->bps;
563 if (osssink->resync && osssink->sync) {
564 gst_element_clock_wait (GST_ELEMENT (osssink), osssink->clock,
565 buftime - queued, &jitter);
568 gst_clock_handle_discont (osssink->clock, buftime - queued + jitter);
569 write (osssink->fd, data, size);
570 gst_oss_clock_set_active (osssink->provided_clock, TRUE);
571 osssink->resync = FALSE;
572 osssink->handled += size;
576 write (osssink->fd, data, size);
577 osssink->handled += size;
580 /* no clock, try to be as fast as possible */
582 audio_buf_info ospace;
584 ioctl (osssink->fd, SNDCTL_DSP_GETOSPACE, &ospace);
586 if (ospace.bytes >= size) {
587 write (osssink->fd, data, size);
592 gst_buffer_unref (buf);
595 static const GstFormat*
596 gst_osssink_get_formats (GstPad *pad)
598 static const GstFormat formats[] = {
608 gst_osssink_convert (GstPad *pad, GstFormat src_format, gint64 src_value,
609 GstFormat *dest_format, gint64 *dest_value)
615 if (src_format == *dest_format) {
616 *dest_value = src_value;
620 osssink = GST_OSSSINK (gst_pad_get_parent (pad));
622 if (osssink->bps == 0 || osssink->channels == 0 || osssink->width == 0)
625 switch (src_format) {
626 case GST_FORMAT_BYTES:
627 switch (*dest_format) {
628 case GST_FORMAT_DEFAULT:
629 *dest_format = GST_FORMAT_TIME;
630 case GST_FORMAT_TIME:
631 *dest_value = src_value * GST_SECOND / osssink->bps;
633 case GST_FORMAT_UNITS:
634 *dest_value = src_value / (osssink->channels * osssink->width);
640 case GST_FORMAT_TIME:
641 switch (*dest_format) {
642 case GST_FORMAT_DEFAULT:
643 *dest_format = GST_FORMAT_BYTES;
644 case GST_FORMAT_BYTES:
645 *dest_value = src_value * osssink->bps / GST_SECOND;
647 case GST_FORMAT_UNITS:
648 *dest_value = src_value * osssink->frequency / GST_SECOND;
654 case GST_FORMAT_UNITS:
655 switch (*dest_format) {
656 case GST_FORMAT_DEFAULT:
657 *dest_format = GST_FORMAT_TIME;
658 case GST_FORMAT_TIME:
659 *dest_value = src_value * GST_SECOND / osssink->frequency;
661 case GST_FORMAT_BYTES:
662 *dest_value = src_value * osssink->channels * osssink->width;
675 static const GstPadQueryType*
676 gst_osssink_get_query_types (GstPad *pad)
678 static const GstPadQueryType query_types[] = {
679 GST_PAD_QUERY_LATENCY,
680 GST_PAD_QUERY_POSITION,
687 gst_osssink_sink_query (GstPad *pad, GstPadQueryType type, GstFormat *format, gint64 *value)
692 osssink = GST_OSSSINK (gst_pad_get_parent (pad));
695 case GST_PAD_QUERY_LATENCY:
696 if (!gst_osssink_convert (pad,
697 GST_FORMAT_BYTES, gst_osssink_get_delay (osssink),
703 case GST_PAD_QUERY_POSITION:
704 if (!gst_osssink_convert (pad,
705 GST_FORMAT_TIME, gst_clock_get_time (osssink->provided_clock),
712 res = gst_pad_query (gst_pad_get_peer (osssink->sinkpad), type, format, value);
720 gst_osssink_query (GstElement *element, GstPadQueryType type, GstFormat *format, gint64 *value)
722 GstOssSink *osssink = GST_OSSSINK (element);
724 return gst_osssink_sink_query (osssink->sinkpad, type, format, value);
728 gst_osssink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
732 /* it's not null if we got it, but it might not be ours */
733 g_return_if_fail (GST_IS_OSSSINK (object));
735 osssink = GST_OSSSINK (object);
739 /* disallow changing the device while it is opened
740 get_property("device") should return the right one */
741 if (!GST_FLAG_IS_SET (osssink, GST_OSSSINK_OPEN))
743 g_free (osssink->device);
744 osssink->device = g_strdup (g_value_get_string (value));
745 g_object_notify (object, "device");
749 osssink->mute = g_value_get_boolean (value);
750 g_object_notify (G_OBJECT (osssink), "mute");
753 osssink->fragment = g_value_get_int (value);
754 gst_osssink_sync_parms (osssink);
756 case ARG_BUFFER_SIZE:
757 if (osssink->bufsize == g_value_get_int (value)) break;
758 osssink->bufsize = g_value_get_int (value);
759 osssink->sinkpool = gst_buffer_pool_get_default (osssink->bufsize, 6);
760 g_object_notify (object, "buffer_size");
763 osssink->sync = g_value_get_boolean (value);
764 g_object_notify (G_OBJECT (osssink), "sync");
767 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
773 gst_osssink_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
777 /* it's not null if we got it, but it might not be ours */
778 g_return_if_fail (GST_IS_OSSSINK (object));
780 osssink = GST_OSSSINK (object);
784 g_value_set_string (value, osssink->device);
787 g_value_set_boolean (value, osssink->mute);
790 g_value_set_int (value, osssink->fragment);
792 case ARG_BUFFER_SIZE:
793 g_value_set_int (value, osssink->bufsize);
796 g_value_set_boolean (value, osssink->sync);
799 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
805 gst_osssink_open_audio (GstOssSink *sink)
808 g_return_val_if_fail (sink->fd == -1, FALSE);
810 GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: attempting to open sound device");
812 /* first try to open the sound card */
813 sink->fd = open (sink->device, O_WRONLY | O_NONBLOCK);
814 if (errno == EBUSY) {
815 g_warning ("osssink: unable to open the sound device (in use ?)\n");
821 /* re-open the sound device in blocking mode */
822 sink->fd = open (sink->device, O_WRONLY);
825 g_warning ("osssink: unable to open the sound device (errno=%d)\n", errno);
829 /* we have it, set the default parameters and go have fun */
831 ioctl (sink->fd, SNDCTL_DSP_GETCAPS, &caps);
833 GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Capabilities %08x", caps);
835 if (caps & DSP_CAP_DUPLEX) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Full duplex");
836 if (caps & DSP_CAP_REALTIME) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Realtime");
837 if (caps & DSP_CAP_BATCH) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Batch");
838 if (caps & DSP_CAP_COPROC) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Has coprocessor");
839 if (caps & DSP_CAP_TRIGGER) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Trigger");
840 if (caps & DSP_CAP_MMAP) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Direct access");
843 if (caps & DSP_CAP_MULTI) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Multiple open");
844 #endif /* DSP_CAP_MULTI */
847 if (caps & DSP_CAP_BIND) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Channel binding");
848 #endif /* DSP_CAP_BIND */
850 ioctl(sink->fd, SNDCTL_DSP_GETFMTS, &caps);
852 GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Formats %08x", caps);
853 if (caps & AFMT_MU_LAW) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: MU_LAW");
854 if (caps & AFMT_A_LAW) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: A_LAW");
855 if (caps & AFMT_IMA_ADPCM) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: IMA_ADPCM");
856 if (caps & AFMT_U8) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: U8");
857 if (caps & AFMT_S16_LE) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: S16_LE");
858 if (caps & AFMT_S16_BE) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: S16_BE");
859 if (caps & AFMT_S8) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: S8");
860 if (caps & AFMT_U16_LE) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: U16_LE");
861 if (caps & AFMT_U16_BE) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: U16_BE");
862 if (caps & AFMT_MPEG) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: MPEG");
864 if (caps & AFMT_AC3) GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: AC3");
867 GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: opened audio (%s) with fd=%d", sink->device, sink->fd);
868 GST_FLAG_SET (sink, GST_OSSSINK_OPEN);
874 gst_osssink_close_audio (GstOssSink *sink)
876 if (sink->fd < 0) return;
881 GST_FLAG_UNSET (sink, GST_OSSSINK_OPEN);
883 GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: closed sound device");
886 static GstElementStateReturn
887 gst_osssink_change_state (GstElement *element)
891 g_return_val_if_fail (GST_IS_OSSSINK (element), FALSE);
893 osssink = GST_OSSSINK (element);
895 switch (GST_STATE_TRANSITION (element)) {
896 case GST_STATE_NULL_TO_READY:
897 if (!GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN)) {
898 if (!gst_osssink_open_audio (osssink)) {
899 return GST_STATE_FAILURE;
903 case GST_STATE_READY_TO_PAUSED:
905 case GST_STATE_PAUSED_TO_PLAYING:
906 osssink->resync = TRUE;
908 case GST_STATE_PLAYING_TO_PAUSED:
910 if (GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN))
911 ioctl (osssink->fd, SNDCTL_DSP_RESET, 0);
912 gst_oss_clock_set_active (osssink->provided_clock, FALSE);
913 osssink->resync = TRUE;
916 case GST_STATE_PAUSED_TO_READY:
917 if (GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN))
918 ioctl (osssink->fd, SNDCTL_DSP_RESET, 0);
920 case GST_STATE_READY_TO_NULL:
921 if (GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN))
922 gst_osssink_close_audio (osssink);
926 if (GST_ELEMENT_CLASS (parent_class)->change_state)
927 return GST_ELEMENT_CLASS (parent_class)->change_state (element);
929 return GST_STATE_SUCCESS;
933 gst_osssink_factory_init (GstPlugin *plugin)
935 GstElementFactory *factory;
937 factory = gst_element_factory_new ("osssink", GST_TYPE_OSSSINK, &gst_osssink_details);
938 g_return_val_if_fail (factory != NULL, FALSE);
940 gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (osssink_sink_factory));
942 gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));