This is a megapatch with the following changes:
[platform/upstream/gstreamer.git] / gst / elements / gstaudiosink.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gstaudiosink.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 //#define DEBUG_ENABLED
33
34 #include <gstaudiosink.h>
35 #include <gst/meta/audioraw.h>
36
37
38 GstElementDetails gst_audiosink_details = {  
39   "Audio Sink (OSS)",
40   "Sink/Audio",
41   "Output to a sound card via OSS",
42   VERSION,
43   "Erik Walthinsen <omega@cse.ogi.edu>",
44   "(C) 1999",
45 };
46
47 static void                     gst_audiosink_class_init        (GstAudioSinkClass *klass);
48 static void                     gst_audiosink_init              (GstAudioSink *audiosink);
49
50 static gboolean                 gst_audiosink_open_audio        (GstAudioSink *sink);
51 static void                     gst_audiosink_close_audio       (GstAudioSink *sink);
52 static GstElementStateReturn    gst_audiosink_change_state      (GstElement *element);
53
54 static void                     gst_audiosink_set_arg           (GtkObject *object, GtkArg *arg, guint id);
55 static void                     gst_audiosink_get_arg           (GtkObject *object, GtkArg *arg, guint id);
56
57 static void                     gst_audiosink_chain             (GstPad *pad,GstBuffer *buf);
58
59 /* AudioSink signals and args */
60 enum {
61   SIGNAL_HANDOFF,
62   LAST_SIGNAL
63 };
64
65 enum {
66   ARG_0,
67   ARG_MUTE,
68   ARG_FORMAT,
69   ARG_CHANNELS,
70   ARG_FREQUENCY,
71   /* FILL ME */
72 };
73
74 static GstPadFactory audiosink_sink_factory = {
75   "sink",
76   GST_PAD_FACTORY_SINK,
77   GST_PAD_FACTORY_ALWAYS,
78   GST_PAD_FACTORY_CAPS (
79   "audiosink_sink",
80     "audio/raw",
81     "format",   GST_PROPS_INT (AFMT_S16_LE),
82     "depth",    GST_PROPS_LIST (
83                   GST_PROPS_INT (8),
84                   GST_PROPS_INT (16)
85                 ),
86     "rate",     GST_PROPS_INT_RANGE (8000, 48000),
87     "channels", GST_PROPS_INT_RANGE (1, 2)
88   ),
89   NULL
90 };
91
92 #define GST_TYPE_AUDIOSINK_FORMATS (gst_audiosink_formats_get_type())
93
94 static GtkType 
95 gst_audiosink_formats_get_type(void) {
96   static GtkType audiosink_formats_type = 0;
97   static GtkEnumValue audiosink_formats[] = {
98     {8, "8", "8 Bits"},
99     {16, "16", "16 Bits"},
100     {0, NULL, NULL},
101   };
102   if (!audiosink_formats_type) {
103     audiosink_formats_type = gtk_type_register_enum("GstAudiosinkFormats", audiosink_formats);
104   }
105   return audiosink_formats_type;
106 }
107
108 #define GST_TYPE_AUDIOSINK_CHANNELS (gst_audiosink_channels_get_type())
109
110 static GtkType 
111 gst_audiosink_channels_get_type(void) {
112   static GtkType audiosink_channels_type = 0;
113   static GtkEnumValue audiosink_channels[] = {
114     {1, "1", "Mono"},
115     {2, "2", "Stereo"},
116     {0, NULL, NULL},
117   };
118   if (!audiosink_channels_type) {
119     audiosink_channels_type = gtk_type_register_enum("GstAudiosinkChannels", audiosink_channels);
120   }
121   return audiosink_channels_type;
122 }
123
124
125 static GstElementClass *parent_class = NULL;
126 static guint gst_audiosink_signals[LAST_SIGNAL] = { 0 };
127
128 static GstPadTemplate *gst_audiosink_sink_template;
129
130 GtkType
131 gst_audiosink_get_type (void) 
132 {
133   static GtkType audiosink_type = 0;
134
135   if (!audiosink_type) {
136     static const GtkTypeInfo audiosink_info = {
137       "GstAudioSink",
138       sizeof(GstAudioSink),
139       sizeof(GstAudioSinkClass),
140       (GtkClassInitFunc)gst_audiosink_class_init,
141       (GtkObjectInitFunc)gst_audiosink_init,
142       (GtkArgSetFunc)NULL,
143       (GtkArgGetFunc)NULL,
144       (GtkClassInitFunc)NULL,
145     };
146     audiosink_type = gtk_type_unique (GST_TYPE_ELEMENT, &audiosink_info);
147   }
148
149   return audiosink_type;
150 }
151
152 static void
153 gst_audiosink_class_init (GstAudioSinkClass *klass) 
154 {
155   GtkObjectClass *gtkobject_class;
156   GstElementClass *gstelement_class;
157
158   gtkobject_class = (GtkObjectClass*)klass;
159   gstelement_class = (GstElementClass*)klass;
160
161   parent_class = gtk_type_class(GST_TYPE_ELEMENT);
162
163   gtk_object_add_arg_type ("GstAudioSink::mute", GTK_TYPE_BOOL,
164                            GTK_ARG_READWRITE, ARG_MUTE);
165   gtk_object_add_arg_type ("GstAudioSink::format", GST_TYPE_AUDIOSINK_FORMATS,
166                            GTK_ARG_READWRITE, ARG_FORMAT);
167   gtk_object_add_arg_type ("GstAudioSink::channels", GST_TYPE_AUDIOSINK_CHANNELS,
168                            GTK_ARG_READWRITE, ARG_CHANNELS);
169   gtk_object_add_arg_type ("GstAudioSink::frequency", GTK_TYPE_INT,
170                            GTK_ARG_READWRITE, ARG_FREQUENCY);
171
172   gtkobject_class->set_arg = gst_audiosink_set_arg;
173   gtkobject_class->get_arg = gst_audiosink_get_arg;
174
175   gst_audiosink_signals[SIGNAL_HANDOFF] =
176     gtk_signal_new("handoff",GTK_RUN_LAST,gtkobject_class->type,
177                    GTK_SIGNAL_OFFSET(GstAudioSinkClass,handoff),
178                    gtk_marshal_NONE__NONE,GTK_TYPE_NONE,0);
179   
180   gtk_object_class_add_signals(gtkobject_class,gst_audiosink_signals,
181                                LAST_SIGNAL);
182
183   gstelement_class->change_state = gst_audiosink_change_state;
184 }
185
186 static void 
187 gst_audiosink_init (GstAudioSink *audiosink) 
188 {
189   audiosink->sinkpad = gst_pad_new_from_template (gst_audiosink_sink_template, "sink");
190   gst_element_add_pad (GST_ELEMENT (audiosink), audiosink->sinkpad);
191
192   gst_pad_set_chain_function (audiosink->sinkpad, gst_audiosink_chain);
193
194   audiosink->fd = -1;
195   audiosink->clock = gst_clock_get_system();
196   audiosink->format = 16;
197   audiosink->channels = 2;
198   audiosink->frequency = 44100;
199   
200   gst_clock_register (audiosink->clock, GST_OBJECT (audiosink));
201
202   GST_FLAG_SET (audiosink, GST_ELEMENT_THREAD_SUGGESTED);
203 }
204
205 static void 
206 gst_audiosink_sync_parms (GstAudioSink *audiosink) 
207 {
208   audio_buf_info ospace;
209   int frag;
210
211   g_return_if_fail (audiosink != NULL);
212   g_return_if_fail (GST_IS_AUDIOSINK (audiosink));
213
214   if (audiosink->fd == -1) return;
215
216   ioctl (audiosink->fd, SNDCTL_DSP_RESET, 0);
217
218   ioctl (audiosink->fd, SNDCTL_DSP_SETFMT, &audiosink->format);
219   ioctl (audiosink->fd, SNDCTL_DSP_CHANNELS, &audiosink->channels);
220   ioctl (audiosink->fd, SNDCTL_DSP_SPEED, &audiosink->frequency);
221   ioctl (audiosink->fd, SNDCTL_DSP_GETBLKSIZE, &frag);
222
223   ioctl (audiosink->fd, SNDCTL_DSP_GETOSPACE, &ospace);
224
225   g_print("audiosink: setting sound card to %dKHz %d bit %s (%d bytes buffer, %d fragment)\n",
226           audiosink->frequency, audiosink->format,
227           (audiosink->channels == 2) ? "stereo" : "mono", ospace.bytes, frag);
228
229 }
230
231 static void 
232 gst_audiosink_chain (GstPad *pad, GstBuffer *buf) 
233 {
234   GstAudioSink *audiosink;
235   MetaAudioRaw *meta;
236   gboolean in_flush;
237   audio_buf_info ospace;
238
239   g_return_if_fail (pad != NULL);
240   g_return_if_fail (GST_IS_PAD (pad));
241   g_return_if_fail (buf != NULL);
242
243
244   /* this has to be an audio buffer */
245 //  g_return_if_fail(((GstMeta *)buf->meta)->type !=
246 //gst_audiosink_type_audio);
247   audiosink = GST_AUDIOSINK (gst_pad_get_parent (pad));
248 //  g_return_if_fail(GST_FLAG_IS_SET(audiosink,GST_STATE_RUNNING));
249
250   if ((in_flush = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLUSH))) {
251     GST_DEBUG (0,"audiosink: flush\n");
252     ioctl (audiosink->fd, SNDCTL_DSP_RESET, 0);
253   }
254
255
256   meta = (MetaAudioRaw *)gst_buffer_get_first_meta (buf);
257   if (meta != NULL) {
258     if ((meta->format != audiosink->format) ||
259         (meta->channels != audiosink->channels) ||
260         (meta->frequency != audiosink->frequency)) 
261     {
262       audiosink->format    = meta->format;
263       audiosink->channels  = meta->channels;
264       audiosink->frequency = meta->frequency;
265       gst_audiosink_sync_parms (audiosink);
266       g_print("audiosink: sound device set to format %d, %d channels, %dHz\n",
267               audiosink->format, audiosink->channels, audiosink->frequency);
268     }
269   }
270
271   gtk_signal_emit (GTK_OBJECT (audiosink), gst_audiosink_signals[SIGNAL_HANDOFF],
272                   audiosink);
273
274   if (GST_BUFFER_DATA (buf) != NULL) {
275     gst_trace_add_entry(NULL, 0, buf, "audiosink: writing to soundcard");
276     //g_print("audiosink: writing to soundcard\n");
277     if (audiosink->fd >= 0) {
278       if (!audiosink->mute) {
279         gst_clock_wait (audiosink->clock, GST_BUFFER_TIMESTAMP (buf), GST_OBJECT (audiosink));
280         ioctl (audiosink->fd, SNDCTL_DSP_GETOSPACE, &ospace);
281         GST_DEBUG (0,"audiosink: (%d bytes buffer) %d %p %d\n", ospace.bytes, 
282                         audiosink->fd, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
283         write (audiosink->fd, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
284         //write(STDOUT_FILENO,GST_BUFFER_DATA(buf),GST_BUFFER_SIZE(buf));
285       }
286     }
287   }
288   gst_buffer_unref (buf);
289 }
290
291 static void 
292 gst_audiosink_set_arg (GtkObject *object, GtkArg *arg, guint id) 
293 {
294   GstAudioSink *audiosink;
295
296   /* it's not null if we got it, but it might not be ours */
297   g_return_if_fail (GST_IS_AUDIOSINK (object));
298   
299   audiosink = GST_AUDIOSINK (object);
300
301   switch(id) {
302     case ARG_MUTE:
303       audiosink->mute = GTK_VALUE_BOOL (*arg);
304       break;
305     case ARG_FORMAT:
306       audiosink->format = GTK_VALUE_ENUM (*arg);
307       gst_audiosink_sync_parms (audiosink);
308       break;
309     case ARG_CHANNELS:
310       audiosink->channels = GTK_VALUE_ENUM (*arg);
311       gst_audiosink_sync_parms (audiosink);
312       break;
313     case ARG_FREQUENCY:
314       audiosink->frequency = GTK_VALUE_INT (*arg);
315       gst_audiosink_sync_parms (audiosink);
316       break;
317     default:
318       break;
319   }
320 }
321
322 static void 
323 gst_audiosink_get_arg (GtkObject *object, GtkArg *arg, guint id) 
324 {
325   GstAudioSink *audiosink;
326
327   /* it's not null if we got it, but it might not be ours */
328   g_return_if_fail (GST_IS_AUDIOSINK (object));
329   
330   audiosink = GST_AUDIOSINK (object);
331
332   switch(id) {
333     case ARG_MUTE:
334       GTK_VALUE_BOOL (*arg) = audiosink->mute;
335       break;
336     case ARG_FORMAT:
337       GTK_VALUE_ENUM (*arg) = audiosink->format;
338       break;
339     case ARG_CHANNELS:
340       GTK_VALUE_ENUM (*arg) = audiosink->channels;
341       break;
342     case ARG_FREQUENCY:
343       GTK_VALUE_INT (*arg) = audiosink->frequency;
344       break;
345     default:
346       break;
347   }
348 }
349
350 static gboolean
351 gst_audiosink_open_audio (GstAudioSink *sink)
352 {
353   g_return_val_if_fail (sink->fd == -1, FALSE);
354
355   g_print ("audiosink: attempting to open sound device\n");
356
357   /* first try to open the sound card */
358   sink->fd = open("/dev/dsp", O_WRONLY | O_NONBLOCK);
359   if (errno == EBUSY) {
360     g_print ("audiosink: unable to open the sound device (in use ?)\n");
361     return FALSE;
362   }
363
364   /* re-open the sound device in blocking mode */
365   close(sink->fd);
366   sink->fd = open("/dev/dsp", O_WRONLY);
367
368   /* if we have it, set the default parameters and go have fun */
369   if (sink->fd >= 0) {
370     /* set card state */
371     sink->format = AFMT_S16_LE;
372     sink->channels = 2; /* stereo */
373     sink->frequency = 44100;
374     gst_audiosink_sync_parms (sink);
375     ioctl(sink->fd, SNDCTL_DSP_GETCAPS, &sink->caps);
376
377     g_print("audiosink: Capabilities\n");
378
379     if (sink->caps & DSP_CAP_DUPLEX)   g_print("audiosink:   Full duplex\n");
380     if (sink->caps & DSP_CAP_REALTIME) g_print("audiosink:   Realtime\n");
381     if (sink->caps & DSP_CAP_BATCH)    g_print("audiosink:   Batch\n");
382     if (sink->caps & DSP_CAP_COPROC)   g_print("audiosink:   Has coprocessor\n");
383     if (sink->caps & DSP_CAP_TRIGGER)  g_print("audiosink:   Trigger\n");
384     if (sink->caps & DSP_CAP_MMAP)     g_print("audiosink:   Direct access\n");
385
386     g_print("audiosink: opened audio with fd=%d\n", sink->fd);
387     GST_FLAG_SET (sink, GST_AUDIOSINK_OPEN);
388
389     return TRUE;
390   }
391
392   return FALSE;
393 }
394
395 static void
396 gst_audiosink_close_audio (GstAudioSink *sink)
397 {
398   if (sink->fd < 0) return;
399
400   close(sink->fd);
401   sink->fd = -1;
402
403   GST_FLAG_UNSET (sink, GST_AUDIOSINK_OPEN);
404
405   g_print("audiosink: closed sound device\n");
406 }
407
408 static GstElementStateReturn 
409 gst_audiosink_change_state (GstElement *element) 
410 {
411   g_return_val_if_fail (GST_IS_AUDIOSINK (element), FALSE);
412
413   /* if going down into NULL state, close the file if it's open */ 
414   if (GST_STATE_PENDING (element) == GST_STATE_NULL) {
415     if (GST_FLAG_IS_SET (element, GST_AUDIOSINK_OPEN))
416       gst_audiosink_close_audio (GST_AUDIOSINK (element));
417   /* otherwise (READY or higher) we need to open the sound card */
418   } else {
419     if (!GST_FLAG_IS_SET (element, GST_AUDIOSINK_OPEN)) {
420       if (!gst_audiosink_open_audio (GST_AUDIOSINK (element)))
421         return GST_STATE_FAILURE;
422     }
423   }
424       
425   if (GST_ELEMENT_CLASS (parent_class)->change_state)
426     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
427   return GST_STATE_SUCCESS;
428 }
429
430 gboolean 
431 gst_audiosink_factory_init (GstElementFactory *factory) 
432
433   gst_audiosink_sink_template = gst_padtemplate_new (&audiosink_sink_factory);
434   gst_elementfactory_add_padtemplate (factory, gst_audiosink_sink_template);
435
436   return TRUE;
437 }
438