"pardon begg'd, Sir, I do think that my backside's not a sync"
[platform/upstream/gst-plugins-good.git] / sys / oss / gstosssink.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wim.taymans@chello.be>
4  *
5  * gstosssink.c: 
6  *
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.
11  *
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.
16  *
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.
21  */
22
23
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <sys/ioctl.h>
27 #include <fcntl.h>
28 #include <sys/soundcard.h>
29 #include <unistd.h>
30 #include <errno.h>
31
32 #include <gstosssink.h>
33
34 static GstElementDetails gst_osssink_details = {  
35   "Audio Sink (OSS)",
36   "Sink/Audio",
37   "Output to a sound card via OSS",
38   VERSION,
39   "Erik Walthinsen <omega@cse.ogi.edu>, "
40   "Wim Taymans <wim.taymans@chello.be>",
41   "(C) 1999",
42 };
43
44 static void                     gst_osssink_class_init          (GstOssSinkClass *klass);
45 static void                     gst_osssink_init                (GstOssSink *osssink);
46 static void                     gst_osssink_finalize            (GObject *object);
47
48 static gboolean                 gst_osssink_open_audio          (GstOssSink *sink);
49 static void                     gst_osssink_close_audio         (GstOssSink *sink);
50 static gboolean                 gst_osssink_sync_parms          (GstOssSink *osssink);
51 static GstElementStateReturn    gst_osssink_change_state        (GstElement *element);
52 static void                     gst_osssink_set_clock           (GstElement *element, GstClock *clock);
53 //static GstClock*              gst_osssink_get_clock           (GstElement *element);
54
55 static GstPadConnectReturn      gst_osssink_sinkconnect         (GstPad *pad, GstCaps *caps);
56
57 static void                     gst_osssink_set_property        (GObject *object, guint prop_id, const GValue *value, 
58                                                                  GParamSpec *pspec);
59 static void                     gst_osssink_get_property        (GObject *object, guint prop_id, GValue *value, 
60                                                                  GParamSpec *pspec);
61
62 static void                     gst_osssink_chain               (GstPad *pad,GstBuffer *buf);
63
64 /* OssSink signals and args */
65 enum {
66   SIGNAL_HANDOFF,
67   LAST_SIGNAL
68 };
69
70 enum {
71   ARG_0,
72   ARG_DEVICE,
73   ARG_MUTE,
74   ARG_FORMAT,
75   ARG_CHANNELS,
76   ARG_FREQUENCY,
77   ARG_FRAGMENT,
78   ARG_BUFFER_SIZE,
79   ARG_SYNC
80   /* FILL ME */
81 };
82
83 GST_PAD_TEMPLATE_FACTORY (osssink_sink_factory,
84   "sink",
85   GST_PAD_SINK,
86   GST_PAD_ALWAYS,
87   GST_CAPS_NEW (
88     "osssink_sink",
89     "audio/raw",
90       "format",     GST_PROPS_STRING ("int"),   /* hack */
91       "law",        GST_PROPS_INT (0),
92       "endianness", GST_PROPS_INT (G_BYTE_ORDER),
93       "signed",     GST_PROPS_LIST (
94                       GST_PROPS_BOOLEAN (FALSE),
95                       GST_PROPS_BOOLEAN (TRUE)
96                     ),
97       "width",      GST_PROPS_LIST (
98                       GST_PROPS_INT (8),
99                       GST_PROPS_INT (16)
100                     ),
101       "depth",      GST_PROPS_LIST (
102                       GST_PROPS_INT (8),
103                       GST_PROPS_INT (16)
104                     ),
105       "rate",       GST_PROPS_INT_RANGE (1000, 48000),
106       "channels",   GST_PROPS_INT_RANGE (1, 2)
107   )
108 );
109
110 #define GST_TYPE_OSSSINK_CHANNELS (gst_osssink_channels_get_type())
111 static GType 
112 gst_osssink_channels_get_type(void) {
113   static GType osssink_channels_type = 0;
114   static GEnumValue osssink_channels[] = {
115     {0, "0", "Silence"},
116     {1, "1", "Mono"},
117     {2, "2", "Stereo"},
118     {0, NULL, NULL},
119   };
120   if (!osssink_channels_type) {
121     osssink_channels_type = g_enum_register_static("GstAudiosinkChannels", osssink_channels);
122   }
123   return osssink_channels_type;
124 }
125
126
127 static GstElementClass *parent_class = NULL;
128 static guint gst_osssink_signals[LAST_SIGNAL] = { 0 };
129
130 GType
131 gst_osssink_get_type (void) 
132 {
133   static GType osssink_type = 0;
134
135   if (!osssink_type) {
136     static const GTypeInfo osssink_info = {
137       sizeof(GstOssSinkClass),
138       NULL,
139       NULL,
140       (GClassInitFunc)gst_osssink_class_init,
141       NULL,
142       NULL,
143       sizeof(GstOssSink),
144       0,
145       (GInstanceInitFunc)gst_osssink_init,
146     };
147     osssink_type = g_type_register_static (GST_TYPE_ELEMENT, "GstOssSink", &osssink_info, 0);
148   }
149
150   return osssink_type;
151 }
152
153 static GstBufferPool*
154 gst_osssink_get_bufferpool (GstPad *pad)
155 {
156   GstOssSink *oss;
157   
158   oss = GST_OSSSINK (gst_pad_get_parent(pad));
159
160   return oss->sinkpool;
161 }
162
163 static void
164 gst_osssink_finalize (GObject *object)
165 {
166   GstOssSink *osssink = (GstOssSink *) object;
167
168   g_free (osssink->device);
169
170   G_OBJECT_CLASS (parent_class)->finalize (object);
171 }
172
173 static void
174 gst_osssink_class_init (GstOssSinkClass *klass) 
175 {
176   GObjectClass *gobject_class;
177   GstElementClass *gstelement_class;
178
179   gobject_class = (GObjectClass*)klass;
180   gstelement_class = (GstElementClass*)klass;
181
182   parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
183
184   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE,
185     g_param_spec_string("device","device","device",
186                         "/dev/dsp",G_PARAM_READWRITE)); /* CHECKME! */
187   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_MUTE,
188     g_param_spec_boolean("mute","mute","mute",
189                          TRUE,G_PARAM_READWRITE)); 
190   g_object_class_install_property (G_OBJECT_CLASS(klass), ARG_SYNC,
191     g_param_spec_boolean("sync","Sync","If syncing on timestamps should be enabled",
192                          TRUE, G_PARAM_READWRITE)); 
193
194   /* it would be nice to show format in symbolic form, oh well */
195   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_FORMAT,
196     g_param_spec_int ("format","format","format",
197                       0, G_MAXINT, AFMT_S16_LE, G_PARAM_READWRITE)); 
198
199   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_CHANNELS,
200     g_param_spec_enum("channels","channels","channels",
201                       GST_TYPE_OSSSINK_CHANNELS,2,G_PARAM_READWRITE)); 
202   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_FREQUENCY,
203     g_param_spec_int("frequency","frequency","frequency",
204                      0,G_MAXINT,44100,G_PARAM_READWRITE));
205   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_FRAGMENT,
206     g_param_spec_int("fragment","fragment","fragment",
207                      0,G_MAXINT,6,G_PARAM_READWRITE));
208   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BUFFER_SIZE,
209     g_param_spec_int("buffer_size","buffer_size","buffer_size",
210                      0,G_MAXINT,4096,G_PARAM_READWRITE));
211
212   gst_osssink_signals[SIGNAL_HANDOFF] =
213     g_signal_new("handoff",G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
214                    G_STRUCT_OFFSET(GstOssSinkClass,handoff), NULL, NULL,
215                    g_cclosure_marshal_VOID__VOID,G_TYPE_NONE,0);
216   
217   gobject_class->set_property = gst_osssink_set_property;
218   gobject_class->get_property = gst_osssink_get_property;
219   gobject_class->finalize     = gst_osssink_finalize;
220   
221   gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_osssink_change_state);
222 }
223
224 static void 
225 gst_osssink_init (GstOssSink *osssink) 
226 {
227   osssink->sinkpad = gst_pad_new_from_template (
228                   GST_PAD_TEMPLATE_GET (osssink_sink_factory), "sink");
229   gst_element_add_pad (GST_ELEMENT (osssink), osssink->sinkpad);
230   gst_pad_set_connect_function (osssink->sinkpad, gst_osssink_sinkconnect);
231   gst_pad_set_bufferpool_function (osssink->sinkpad, gst_osssink_get_bufferpool);
232
233   gst_pad_set_chain_function (osssink->sinkpad, gst_osssink_chain);
234
235   osssink->device = g_strdup ("/dev/dsp");
236   osssink->fd = -1;
237   osssink->channels = 1;
238   osssink->frequency = 11025;
239   osssink->fragment = 6;
240 /* AFMT_*_BE not available on all OSS includes (e.g. FBSD) */
241 #ifdef WORDS_BIGENDIAN
242   osssink->format = AFMT_S16_BE;
243 #else
244   osssink->format = AFMT_S16_LE;
245 #endif /* WORDS_BIGENDIAN */  
246   osssink->bufsize = 4096;
247   osssink->bps = 0;
248   osssink->resync = FALSE;
249   osssink->sync = TRUE;
250   /* 6 buffers per chunk by default */
251   osssink->sinkpool = gst_buffer_pool_get_default (osssink->bufsize, 6);
252
253   GST_ELEMENT (osssink)->setclockfunc    = gst_osssink_set_clock;
254   
255   GST_FLAG_SET (osssink, GST_ELEMENT_THREAD_SUGGESTED);
256   GST_FLAG_SET (osssink, GST_ELEMENT_EVENT_AWARE);
257 }
258
259 static GstPadConnectReturn 
260 gst_osssink_sinkconnect (GstPad *pad, GstCaps *caps) 
261 {
262   gint law, endianness, width, depth;
263   gboolean sign;
264   gint format = -1;
265   GstOssSink *osssink = GST_OSSSINK (gst_pad_get_parent (pad));
266
267   if (!GST_CAPS_IS_FIXED (caps))
268     return GST_PAD_CONNECT_DELAYED;
269   
270   gst_caps_get_int (caps, "width", &width);
271   gst_caps_get_int (caps, "depth", &depth);
272
273   if (width != depth) 
274     return GST_PAD_CONNECT_REFUSED;
275
276   /* laws 1 and 2 are 1 bps anyway */
277   osssink->bps = 1;
278
279   gst_caps_get_int (caps, "law", &law);
280   gst_caps_get_int (caps, "endianness", &endianness);
281   gst_caps_get_boolean (caps, "signed", &sign);
282
283   if (law == 0) {
284     if (width == 16) {
285       if (sign == TRUE) {
286         if (endianness == G_LITTLE_ENDIAN)
287           format = AFMT_S16_LE;
288         else if (endianness == G_BIG_ENDIAN)
289           format = AFMT_S16_BE;
290       }
291       else {
292         if (endianness == G_LITTLE_ENDIAN)
293           format = AFMT_U16_LE;
294         else if (endianness == G_BIG_ENDIAN)
295           format = AFMT_U16_BE;
296       }
297       osssink->bps = 2;
298     }
299     else if (width == 8) {
300       if (sign == TRUE) {
301         format = AFMT_S8;
302       }
303       else {
304         format = AFMT_U8;
305       }
306       osssink->bps = 1;
307     }
308   } else if (law == 1) {
309     format = AFMT_MU_LAW;
310   } else if (law == 2) {
311     format = AFMT_A_LAW;
312   } else {
313     g_critical ("unknown law");
314     return GST_PAD_CONNECT_REFUSED;
315   }
316
317   if (format == -1) 
318     return GST_PAD_CONNECT_REFUSED;
319
320   osssink->format = format;
321   gst_caps_get_int (caps, "channels", &osssink->channels);
322   gst_caps_get_int (caps, "rate", &osssink->frequency);
323
324   osssink->bps *= osssink->channels;
325   osssink->bps *= osssink->frequency;
326
327   if (!gst_osssink_sync_parms (osssink)) {
328     return GST_PAD_CONNECT_REFUSED;
329   }
330
331   return GST_PAD_CONNECT_OK;
332 }
333
334 static gboolean 
335 gst_osssink_sync_parms (GstOssSink *osssink) 
336 {
337   audio_buf_info ospace;
338   int frag;
339   gint target_format;
340   gint target_channels;
341   gint target_frequency;
342   GObject *object;
343
344   g_return_val_if_fail (osssink != NULL, FALSE);
345   g_return_val_if_fail (GST_IS_OSSSINK (osssink), FALSE);
346
347   if (osssink->fd == -1)
348     return FALSE;
349   
350   if (osssink->fragment >> 16)
351     frag = osssink->fragment;
352   else
353     frag = 0x7FFF0000 | osssink->fragment;
354   
355   GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: trying to set sound card to %dHz %d bit %s (%08x fragment)",
356            osssink->frequency, osssink->format,
357            (osssink->channels == 2) ? "stereo" : "mono",frag);
358
359   ioctl (osssink->fd, SNDCTL_DSP_SETFRAGMENT, &frag);
360
361   ioctl (osssink->fd, SNDCTL_DSP_RESET, 0);
362
363   target_format = osssink->format;
364   target_channels = osssink->channels;
365   target_frequency = osssink->frequency;
366
367   ioctl (osssink->fd, SNDCTL_DSP_SETFMT, &osssink->format);
368   ioctl (osssink->fd, SNDCTL_DSP_CHANNELS, &osssink->channels);
369   ioctl (osssink->fd, SNDCTL_DSP_SPEED, &osssink->frequency);
370
371   ioctl (osssink->fd, SNDCTL_DSP_GETBLKSIZE, &osssink->fragment);
372   ioctl (osssink->fd, SNDCTL_DSP_GETOSPACE, &ospace);
373
374   GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: set sound card to %dHz %d bit %s (%d bytes buffer, %08x fragment)",
375            osssink->frequency, osssink->format,
376            (osssink->channels == 2) ? "stereo" : "mono", ospace.bytes, osssink->fragment);
377
378   object = G_OBJECT (osssink);
379   g_object_freeze_notify (object);
380   g_object_notify (object, "channels");
381   g_object_notify (object, "frequency");
382   g_object_notify (object, "fragment");
383   g_object_notify (object, "format");
384   g_object_thaw_notify (object);
385
386   osssink->fragment_time = (1000000 * osssink->fragment) / osssink->bps;
387   GST_INFO (GST_CAT_PLUGIN_INFO, "fragment time %u %llu\n", osssink->bps, osssink->fragment_time);
388
389   if (target_format != osssink->format ||
390       target_channels != osssink->channels ||
391       target_frequency != osssink->frequency) 
392   {
393     g_warning ("could not configure oss with required parameters, enjoy the noise :)");
394     /* we could eventually return FALSE here, or just do some additional tests
395      * to see that the frequencies don't differ too much etc.. */
396   }
397   return TRUE;
398 }
399
400 static void
401 gst_osssink_set_clock (GstElement *element, GstClock *clock)
402 {
403   GstOssSink *osssink;
404   
405   osssink = GST_OSSSINK (element);
406
407   osssink->clock = clock;  
408 }
409
410 static void 
411 gst_osssink_chain (GstPad *pad, GstBuffer *buf) 
412 {
413   GstOssSink *osssink;
414   GstClockTime buftime;
415
416   /* this has to be an audio buffer */
417   osssink = GST_OSSSINK (gst_pad_get_parent (pad));
418
419   if (GST_IS_EVENT (buf)) {
420     GstEvent *event = GST_EVENT (buf);
421     //gint64 offset;
422
423     switch (GST_EVENT_TYPE (event)) {
424       case GST_EVENT_EOS:
425         ioctl (osssink->fd, SNDCTL_DSP_SYNC);
426         gst_pad_event_default (pad, event);
427         return;
428       case GST_EVENT_NEW_MEDIA:
429         g_print ("new media\n");
430         return;
431       case GST_EVENT_DISCONTINUOUS:
432       {
433         gint64 value;
434         
435         ioctl (osssink->fd, SNDCTL_DSP_RESET);
436         if (gst_event_discont_get_value (event, GST_FORMAT_TIME, &value)) {
437           gst_clock_handle_discont (osssink->clock, value);
438         }
439         osssink->resync = TRUE;
440         return;
441       }
442       default:
443         gst_pad_event_default (pad, event);
444         return;
445     }
446     gst_event_free (event);
447   }
448
449   if (!osssink->bps) {
450     gst_buffer_unref (buf);
451     gst_element_error (GST_ELEMENT (osssink), "capsnego was never performed, unknown data type");
452     return;
453   }
454
455   buftime = GST_BUFFER_TIMESTAMP (buf);
456
457   if (osssink->fd >= 0) {
458     if (!osssink->mute) {
459       guchar *data = GST_BUFFER_DATA (buf);
460       gint size = GST_BUFFER_SIZE (buf);
461
462       if (osssink->clock) {
463         gint delay = 0;
464         gint64 queued;
465         GstClockTimeDiff jitter;
466     
467         if (ioctl (osssink->fd, SNDCTL_DSP_GETODELAY, &delay) < 0) {
468           audio_buf_info info;
469           if (ioctl (osssink->fd, SNDCTL_DSP_GETOSPACE, &info) < 0) {
470             delay = 0;
471           }
472           else {
473             delay = (info.fragstotal * info.fragsize) - info.bytes;       
474           }
475         }
476         queued = delay * GST_SECOND / osssink->bps;
477
478         if  (osssink->resync && osssink->sync) {
479           gst_element_clock_wait (GST_ELEMENT (osssink), osssink->clock, 
480                                 buftime - queued, &jitter);
481
482           if (jitter > 0) {
483             write (osssink->fd, data, size);
484             osssink->resync = FALSE;
485           }
486         }
487         else {
488           write (osssink->fd, data, size);
489         }
490       }
491       /* no clock, try to be as fast as possible */
492       else {
493         audio_buf_info ospace;
494
495         ioctl (osssink->fd, SNDCTL_DSP_GETOSPACE, &ospace);
496
497         if (ospace.bytes >= size) {
498           write (osssink->fd, data, size);
499         }
500       }
501     }
502   }
503   gst_buffer_unref (buf);
504 }
505
506 static void 
507 gst_osssink_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) 
508 {
509   GstOssSink *osssink;
510
511   /* it's not null if we got it, but it might not be ours */
512   g_return_if_fail (GST_IS_OSSSINK (object));
513   
514   osssink = GST_OSSSINK (object);
515
516   switch (prop_id) {
517     case ARG_DEVICE:
518       /* disallow changing the device while it is opened
519          get_property("device") should return the right one */
520       if (!GST_FLAG_IS_SET (osssink, GST_OSSSINK_OPEN))
521       {
522         g_free (osssink->device);
523         osssink->device = g_strdup (g_value_get_string (value));
524         g_object_notify (object, "device");
525       }
526       break;
527     case ARG_MUTE:
528       osssink->mute = g_value_get_boolean (value);
529       g_object_notify (G_OBJECT (osssink), "mute");
530       break;
531     case ARG_FORMAT:
532       osssink->format = g_value_get_int (value);
533       gst_osssink_sync_parms (osssink);
534       break;
535     case ARG_CHANNELS:
536       osssink->channels = g_value_get_enum (value);
537       gst_osssink_sync_parms (osssink);
538       break;
539     case ARG_FREQUENCY:
540       osssink->frequency = g_value_get_int (value);
541       gst_osssink_sync_parms (osssink);
542       break;
543     case ARG_FRAGMENT:
544       osssink->fragment = g_value_get_int (value);
545       gst_osssink_sync_parms (osssink);
546       break;
547     case ARG_BUFFER_SIZE:
548       if (osssink->bufsize == g_value_get_int (value)) break;
549       osssink->bufsize = g_value_get_int (value);
550       osssink->sinkpool = gst_buffer_pool_get_default (osssink->bufsize, 6);
551       g_object_notify (object, "buffer_size");
552       break;
553     case ARG_SYNC:
554       osssink->sync = g_value_get_boolean (value);
555       g_object_notify (G_OBJECT (osssink), "sync");
556     default:
557       break;
558   }
559 }
560
561 static void 
562 gst_osssink_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) 
563 {
564   GstOssSink *osssink;
565
566   /* it's not null if we got it, but it might not be ours */
567   g_return_if_fail (GST_IS_OSSSINK (object));
568   
569   osssink = GST_OSSSINK (object);
570
571   switch (prop_id) {
572     case ARG_DEVICE:
573       g_value_set_string (value, osssink->device);
574       break;
575     case ARG_MUTE:
576       g_value_set_boolean (value, osssink->mute);
577       break;
578     case ARG_FORMAT:
579       g_value_set_int (value, osssink->format);
580       break;
581     case ARG_CHANNELS:
582       g_value_set_enum (value, osssink->channels);
583       break;
584     case ARG_FREQUENCY:
585       g_value_set_int (value, osssink->frequency);
586       break;
587     case ARG_FRAGMENT:
588       g_value_set_int (value, osssink->fragment);
589       break;
590     case ARG_BUFFER_SIZE:
591       g_value_set_int (value, osssink->bufsize);
592       break;
593     case ARG_SYNC:
594       g_value_set_boolean (value, osssink->sync);
595       break;
596     default:
597       break;
598   }
599 }
600
601 static gboolean
602 gst_osssink_open_audio (GstOssSink *sink)
603 {
604   gint caps;
605   g_return_val_if_fail (sink->fd == -1, FALSE);
606
607   GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: attempting to open sound device");
608
609   /* first try to open the sound card */
610   sink->fd = open(sink->device, O_WRONLY | O_NONBLOCK);
611   if (errno == EBUSY) {
612     g_warning ("osssink: unable to open the sound device (in use ?)\n");
613     return FALSE;
614   }
615
616   /* re-open the sound device in blocking mode */
617   close(sink->fd);
618   sink->fd = open(sink->device, O_WRONLY);
619
620   /* if we have it, set the default parameters and go have fun */
621   if (sink->fd >= 0) {
622     /* set card state */
623     ioctl(sink->fd, SNDCTL_DSP_GETCAPS, &caps);
624
625     GST_INFO(GST_CAT_PLUGIN_INFO, "osssink: Capabilities %08x", caps);
626
627     if (caps & DSP_CAP_DUPLEX)          GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   Full duplex");
628     if (caps & DSP_CAP_REALTIME)        GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   Realtime");
629     if (caps & DSP_CAP_BATCH)           GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   Batch");
630     if (caps & DSP_CAP_COPROC)          GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   Has coprocessor");
631     if (caps & DSP_CAP_TRIGGER)         GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   Trigger");
632     if (caps & DSP_CAP_MMAP)            GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   Direct access");
633
634 #ifdef DSP_CAP_MULTI
635     if (caps & DSP_CAP_MULTI)           GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   Multiple open");
636 #endif /* DSP_CAP_MULTI */
637
638 #ifdef DSP_CAP_BIND
639     if (caps & DSP_CAP_BIND)            GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   Channel binding");
640 #endif /* DSP_CAP_BIND */
641
642     ioctl(sink->fd, SNDCTL_DSP_GETFMTS, &caps);
643
644     GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: Formats %08x", caps);
645     if (caps & AFMT_MU_LAW)             GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   MU_LAW");
646     if (caps & AFMT_A_LAW)              GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   A_LAW");
647     if (caps & AFMT_IMA_ADPCM)          GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   IMA_ADPCM");
648     if (caps & AFMT_U8)                 GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   U8");
649     if (caps & AFMT_S16_LE)             GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   S16_LE");
650     if (caps & AFMT_S16_BE)             GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   S16_BE");
651     if (caps & AFMT_S8)                 GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   S8");
652     if (caps & AFMT_U16_LE)             GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   U16_LE");
653     if (caps & AFMT_U16_BE)             GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   U16_BE");
654     if (caps & AFMT_MPEG)               GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   MPEG");
655 #ifdef AFMT_AC3
656     if (caps & AFMT_AC3)                GST_INFO (GST_CAT_PLUGIN_INFO, "osssink:   AC3");
657 #endif
658
659     GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: opened audio (%s) with fd=%d", sink->device, sink->fd);
660     GST_FLAG_SET (sink, GST_OSSSINK_OPEN);
661
662     return TRUE;
663   }
664
665   return FALSE;
666 }
667
668 static void
669 gst_osssink_close_audio (GstOssSink *sink)
670 {
671   if (sink->fd < 0) return;
672
673   close(sink->fd);
674   sink->fd = -1;
675
676   GST_FLAG_UNSET (sink, GST_OSSSINK_OPEN);
677
678   GST_INFO (GST_CAT_PLUGIN_INFO, "osssink: closed sound device");
679 }
680
681 static GstElementStateReturn 
682 gst_osssink_change_state (GstElement *element) 
683 {
684   GstOssSink *osssink;
685
686   g_return_val_if_fail (GST_IS_OSSSINK (element), FALSE);
687
688   osssink = GST_OSSSINK (element);
689
690   switch (GST_STATE_TRANSITION (element)) {
691     case GST_STATE_NULL_TO_READY:
692       if (!GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN)) {
693         if (!gst_osssink_open_audio (osssink)) {
694           return GST_STATE_FAILURE;
695         }
696       }
697       break;
698     case GST_STATE_READY_TO_PAUSED:
699     case GST_STATE_PAUSED_TO_PLAYING:
700       osssink->resync = TRUE;
701       break;
702     case GST_STATE_PLAYING_TO_PAUSED:
703     {
704       if (GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN)) 
705         ioctl (osssink->fd, SNDCTL_DSP_RESET, 0);
706       break;
707     }
708     case GST_STATE_PAUSED_TO_READY:
709       if (GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN))
710         ioctl (osssink->fd, SNDCTL_DSP_RESET, 0);
711       break;
712     case GST_STATE_READY_TO_NULL:
713       if (GST_FLAG_IS_SET (element, GST_OSSSINK_OPEN))
714         gst_osssink_close_audio (osssink);
715       break;
716   }
717       
718   if (GST_ELEMENT_CLASS (parent_class)->change_state)
719     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
720
721   return GST_STATE_SUCCESS;
722 }
723
724 gboolean 
725 gst_osssink_factory_init (GstPlugin *plugin) 
726
727   GstElementFactory *factory;
728
729   factory = gst_element_factory_new ("osssink", GST_TYPE_OSSSINK, &gst_osssink_details);
730   g_return_val_if_fail (factory != NULL, FALSE);
731
732   gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (osssink_sink_factory));
733
734   gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
735
736   return TRUE;
737 }
738