Brought standard elements in line with new state management system.
[platform/upstream/gstreamer.git] / gst / elements / gstaudiosink.c
1 /* Gnome-Streamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <sys/ioctl.h>
24 #include <fcntl.h>
25 #include <sys/soundcard.h>
26 #include <unistd.h>
27
28 #include <gstaudiosink.h>
29 #include <gst/meta/audioraw.h>
30
31
32 GstElementDetails gst_audiosink_details = {  
33   "Audio Sink (OSS)",
34   "Sink/Audio",
35   "Output to a sound card via OSS",
36   VERSION,
37   "Erik Walthinsen <omega@cse.ogi.edu>",
38   "(C) 1999",
39 };
40
41
42 static gboolean gst_audiosink_open_audio(GstAudioSink *sink);
43 static void gst_audiosink_close_audio(GstAudioSink *sink);
44 static GstElementStateReturn gst_audiosink_change_state(GstElement *element);
45
46 static void gst_audiosink_set_arg(GtkObject *object,GtkArg *arg,guint id);
47 static void gst_audiosink_get_arg(GtkObject *object,GtkArg *arg,guint id);
48
49 void gst_audiosink_chain(GstPad *pad,GstBuffer *buf);
50
51 /* AudioSink signals and args */
52 enum {
53   SIGNAL_HANDOFF,
54   LAST_SIGNAL
55 };
56
57 enum {
58   ARG_0,
59   ARG_MUTE,
60   ARG_FORMAT,
61   ARG_CHANNELS,
62   ARG_FREQUENCY,
63   /* FILL ME */
64 };
65
66
67 static void gst_audiosink_class_init(GstAudioSinkClass *klass);
68 static void gst_audiosink_init(GstAudioSink *audiosink);
69
70
71 static GstSinkClass *parent_class = NULL;
72 static guint gst_audiosink_signals[LAST_SIGNAL] = { 0 };
73
74 static guint16 gst_audiosink_type_audio = 0;
75
76 GtkType
77 gst_audiosink_get_type(void) {
78   static GtkType audiosink_type = 0;
79
80   if (!audiosink_type) {
81     static const GtkTypeInfo audiosink_info = {
82       "GstAudioSink",
83       sizeof(GstAudioSink),
84       sizeof(GstAudioSinkClass),
85       (GtkClassInitFunc)gst_audiosink_class_init,
86       (GtkObjectInitFunc)gst_audiosink_init,
87       (GtkArgSetFunc)NULL,
88       (GtkArgGetFunc)NULL,
89       (GtkClassInitFunc)NULL,
90     };
91     audiosink_type = gtk_type_unique(GST_TYPE_SINK,&audiosink_info);
92   }
93
94   if (!gst_audiosink_type_audio)
95     gst_audiosink_type_audio = gst_type_find_by_mime("audio/raw");
96
97   return audiosink_type;
98 }
99
100 static void
101 gst_audiosink_class_init(GstAudioSinkClass *klass) {
102   GtkObjectClass *gtkobject_class;
103   GstElementClass *gstelement_class;
104
105   gtkobject_class = (GtkObjectClass*)klass;
106   gstelement_class = (GstElementClass*)klass;
107
108   parent_class = gtk_type_class(GST_TYPE_FILTER);
109
110   gtk_object_add_arg_type("GstAudioSink::mute", GTK_TYPE_BOOL,
111                            GTK_ARG_READWRITE, ARG_MUTE);
112   gtk_object_add_arg_type("GstAudioSink::format", GTK_TYPE_INT,
113                            GTK_ARG_READWRITE, ARG_FORMAT);
114   gtk_object_add_arg_type("GstAudioSink::channels", GTK_TYPE_INT,
115                            GTK_ARG_READWRITE, ARG_CHANNELS);
116   gtk_object_add_arg_type("GstAudioSink::frequency", GTK_TYPE_INT,
117                            GTK_ARG_READWRITE, ARG_FREQUENCY);
118
119   gtkobject_class->set_arg = gst_audiosink_set_arg;
120   gtkobject_class->get_arg = gst_audiosink_get_arg;
121
122   gst_audiosink_signals[SIGNAL_HANDOFF] =
123     gtk_signal_new("handoff",GTK_RUN_LAST,gtkobject_class->type,
124                    GTK_SIGNAL_OFFSET(GstAudioSinkClass,handoff),
125                    gtk_marshal_NONE__POINTER,GTK_TYPE_NONE,1,
126                    GST_TYPE_AUDIOSINK);
127   gtk_object_class_add_signals(gtkobject_class,gst_audiosink_signals,
128                                LAST_SIGNAL);
129
130   gstelement_class->change_state = gst_audiosink_change_state;
131 }
132
133 static void gst_audiosink_init(GstAudioSink *audiosink) {
134   audiosink->sinkpad = gst_pad_new("sink",GST_PAD_SINK);
135   gst_element_add_pad(GST_ELEMENT(audiosink),audiosink->sinkpad);
136   if (!gst_audiosink_type_audio)
137     gst_audiosink_type_audio = gst_type_find_by_mime("audio/raw");
138   gst_pad_set_type_id(audiosink->sinkpad,gst_audiosink_type_audio);
139   gst_pad_set_chain_function(audiosink->sinkpad,gst_audiosink_chain);
140
141   audiosink->fd = -1;
142   audiosink->clock = gst_clock_get_system();
143   gst_clock_register(audiosink->clock, GST_OBJECT(audiosink));
144   //audiosink->clocktime = 0LL;
145
146 }
147
148 void gst_audiosink_sync_parms(GstAudioSink *audiosink) {
149   audio_buf_info ospace;
150   int frag;
151
152   g_return_if_fail(audiosink != NULL);
153   g_return_if_fail(GST_IS_AUDIOSINK(audiosink));
154   g_return_if_fail(audiosink->fd > 0);
155
156   ioctl(audiosink->fd,SNDCTL_DSP_RESET,0);
157
158   ioctl(audiosink->fd,SNDCTL_DSP_SETFMT,&audiosink->format);
159   ioctl(audiosink->fd,SNDCTL_DSP_CHANNELS,&audiosink->channels);
160   ioctl(audiosink->fd,SNDCTL_DSP_SPEED,&audiosink->frequency);
161   ioctl(audiosink->fd,SNDCTL_DSP_GETBLKSIZE, &frag);
162
163   ioctl(audiosink->fd,SNDCTL_DSP_GETOSPACE,&ospace);
164
165   g_print("audiosink: setting sound card to %dKHz %d bit %s (%d bytes buffer, %d fragment)\n",
166           audiosink->frequency,audiosink->format,
167           (audiosink->channels == 2) ? "stereo" : "mono",ospace.bytes, frag);
168
169 }
170
171 GstElement *gst_audiosink_new(gchar *name) {
172   GstElement *audiosink = GST_ELEMENT(gtk_type_new(GST_TYPE_AUDIOSINK));
173   gst_element_set_name(GST_ELEMENT(audiosink),name);
174   return audiosink;
175 }
176
177 void gst_audiosink_chain(GstPad *pad,GstBuffer *buf) {
178   GstAudioSink *audiosink;
179   MetaAudioRaw *meta;
180   gboolean in_flush;
181   audio_buf_info ospace;
182
183   g_return_if_fail(pad != NULL);
184   g_return_if_fail(GST_IS_PAD(pad));
185   g_return_if_fail(buf != NULL);
186
187   /* this has to be an audio buffer */
188 //  g_return_if_fail(((GstMeta *)buf->meta)->type !=
189 //gst_audiosink_type_audio);
190   audiosink = GST_AUDIOSINK(pad->parent);
191 //  g_return_if_fail(GST_FLAG_IS_SET(audiosink,GST_STATE_RUNNING));
192
193   if (in_flush = GST_BUFFER_FLAG_IS_SET(buf, GST_BUFFER_FLUSH)) {
194     DEBUG("audiosink: flush\n");
195     ioctl(audiosink->fd,SNDCTL_DSP_RESET,0);
196   }
197
198
199   meta = (MetaAudioRaw *)gst_buffer_get_first_meta(buf);
200   if (meta != NULL) {
201     if ((meta->format != audiosink->format) ||
202         (meta->channels != audiosink->channels) ||
203         (meta->frequency != audiosink->frequency)) {
204       audiosink->format = meta->format;
205       audiosink->channels = meta->channels;
206       audiosink->frequency = meta->frequency;
207       gst_audiosink_sync_parms(audiosink);
208       g_print("audiosink: sound device set to format %d, %d channels, %dHz\n",
209               audiosink->format,audiosink->channels,audiosink->frequency);
210     }
211   }
212
213   gtk_signal_emit(GTK_OBJECT(audiosink),gst_audiosink_signals[SIGNAL_HANDOFF],
214                   audiosink);
215   if (GST_BUFFER_DATA(buf) != NULL) {
216     gst_trace_add_entry(NULL,0,buf,"audiosink: writing to soundcard");
217     //g_print("audiosink: writing to soundcard\n");
218     if (audiosink->fd > 2) {
219       if (!audiosink->mute) {
220         //if (gst_clock_current_diff(audiosink->clock, GST_BUFFER_TIMESTAMP(buf)) > 500000) {
221         //}
222         //else {
223           gst_clock_wait(audiosink->clock, GST_BUFFER_TIMESTAMP(buf), GST_OBJECT(audiosink));
224           ioctl(audiosink->fd,SNDCTL_DSP_GETOSPACE,&ospace);
225           DEBUG("audiosink: (%d bytes buffer)\n", ospace.bytes);
226           write(audiosink->fd,GST_BUFFER_DATA(buf),GST_BUFFER_SIZE(buf));
227         //}
228           //gst_clock_set(audiosink->clock, GST_BUFFER_TIMESTAMP(buf));
229         //}
230       }
231     }
232   }
233 end:
234   //g_print("a unref\n");
235   gst_buffer_unref(buf);
236   //g_print("a done\n");
237 }
238
239 static void gst_audiosink_set_arg(GtkObject *object,GtkArg *arg,guint id) {
240   GstAudioSink *audiosink;
241
242   /* it's not null if we got it, but it might not be ours */
243   g_return_if_fail(GST_IS_AUDIOSINK(object));
244   audiosink = GST_AUDIOSINK(object);
245
246   switch(id) {
247     case ARG_MUTE:
248       audiosink->mute = GTK_VALUE_BOOL(*arg);
249       break;
250     case ARG_FORMAT:
251       audiosink->format = GTK_VALUE_INT(*arg);
252       gst_audiosink_sync_parms(audiosink);
253       break;
254     case ARG_CHANNELS:
255       audiosink->channels = GTK_VALUE_INT(*arg);
256       gst_audiosink_sync_parms(audiosink);
257       break;
258     case ARG_FREQUENCY:
259       audiosink->frequency = GTK_VALUE_INT(*arg);
260       gst_audiosink_sync_parms(audiosink);
261       break;
262     default:
263       break;
264   }
265 }
266
267 static void gst_audiosink_get_arg(GtkObject *object,GtkArg *arg,guint id) {
268   GstAudioSink *audiosink;
269
270   /* it's not null if we got it, but it might not be ours */
271   g_return_if_fail(GST_IS_AUDIOSINK(object));
272   audiosink = GST_AUDIOSINK(object);
273
274   switch(id) {
275     case ARG_MUTE:
276       GTK_VALUE_BOOL(*arg) = audiosink->mute;
277       break;
278     case ARG_FORMAT:
279       GTK_VALUE_INT(*arg) = audiosink->format;
280       break;
281     case ARG_CHANNELS:
282       GTK_VALUE_INT(*arg) = audiosink->channels;
283       break;
284     case ARG_FREQUENCY:
285       GTK_VALUE_INT(*arg) = audiosink->frequency;
286       break;
287     default:
288       break;
289   }
290 }
291
292 static gboolean gst_audiosink_open_audio(GstAudioSink *sink) {
293   g_return_val_if_fail(sink->fd == -1, FALSE);
294
295   g_print("audiosink: attempting to open sound device\n");
296
297   /* first try to open the sound card */
298   sink->fd = open("/dev/dsp",O_RDWR);
299
300   /* if we have it, set the default parameters and go have fun */
301   if (sink->fd > 0) {
302     /* set card state */
303     sink->format = AFMT_S16_LE;
304     sink->channels = 2; /* stereo */
305     sink->frequency = 44100;
306     gst_audiosink_sync_parms(sink);
307     ioctl(sink->fd,SNDCTL_DSP_GETCAPS,&sink->caps);
308
309     g_print("audiosink: Capabilities\n");
310     if (sink->caps & DSP_CAP_DUPLEX)   g_print("audiosink:   Full duplex\n");
311     if (sink->caps & DSP_CAP_REALTIME) g_print("audiosink:   Realtime\n");
312     if (sink->caps & DSP_CAP_BATCH)    g_print("audiosink:   Batch\n");
313     if (sink->caps & DSP_CAP_COPROC)   g_print("audiosink:   Has coprocessor\n");
314     if (sink->caps & DSP_CAP_TRIGGER)  g_print("audiosink:   Trigger\n");
315     if (sink->caps & DSP_CAP_MMAP)     g_print("audiosink:   Direct access\n");
316     g_print("audiosink: opened audio\n");
317     return TRUE;
318   }
319
320   return FALSE;
321 }
322
323 static void gst_audiosink_close_audio(GstAudioSink *sink) {
324   if (sink->fd < 0) return;
325
326   close(sink->fd);
327   sink->fd = -1;
328   g_print("audiosink: closed sound device\n");
329 }
330
331
332 static GstElementStateReturn gst_audiosink_change_state(GstElement *element) {
333   g_return_val_if_fail(GST_IS_AUDIOSINK(element), FALSE);
334
335   /* if going down into NULL state, close the file if it's open */ 
336   if (GST_STATE_PENDING(element) == GST_STATE_NULL) {
337     if (GST_FLAG_IS_SET(element,GST_AUDIOSINK_OPEN))
338       gst_audiosink_close_audio(GST_AUDIOSINK(element));
339   /* otherwise (READY or higher) we need to open the sound card */
340   } else {
341     if (!GST_FLAG_IS_SET(element,GST_AUDIOSINK_OPEN)) {
342       if (!gst_audiosink_open_audio(GST_AUDIOSINK(element)))
343         return GST_STATE_FAILURE;
344     }
345   }
346       
347   if (GST_ELEMENT_CLASS(parent_class)->change_state)
348     return GST_ELEMENT_CLASS(parent_class)->change_state(element);
349   return TRUE;
350 }