change NULL to (NULL) for GST_ELEMENT_ERROR
[platform/upstream/gst-plugins-base.git] / ext / alsa / gstalsasink.c
1 /*
2  * Copyright (C) 2001 CodeFactory AB
3  * Copyright (C) 2001 Thomas Nyberg <thomas@codefactory.se>
4  * Copyright (C) 2001-2002 Andy Wingo <apwingo@eos.ncsu.edu>
5  * Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
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 Free
19  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "gstalsasink.h"
27 #include "gstalsaclock.h"
28
29 /* elementfactory information */
30 static GstElementDetails gst_alsa_sink_details = GST_ELEMENT_DETAILS (
31   "Alsa Sink",
32   "Sink/Audio",
33   "Output to a sound card via ALSA",
34   "Thomas Nyberg <thomas@codefactory.se>, "
35   "Andy Wingo <apwingo@eos.ncsu.edu>, "
36   "Benjamin Otte <in7y118@public.uni-hamburg.de>"
37 );
38
39 static GstPadTemplate *         gst_alsa_sink_pad_factory       (void);
40 static GstPadTemplate *         gst_alsa_sink_request_pad_factory(void);
41 static void                     gst_alsa_sink_base_init         (gpointer               g_class);
42 static void                     gst_alsa_sink_class_init        (gpointer               g_klass,
43                                                                  gpointer               class_data);
44 static void                     gst_alsa_sink_init              (GstAlsaSink *          this);
45 static inline void              gst_alsa_sink_flush_one_pad     (GstAlsaSink *          sink,
46                                                                  gint                   i);
47 static void                     gst_alsa_sink_flush_pads        (GstAlsaSink *          sink);
48 static int                      gst_alsa_sink_mmap              (GstAlsa *              this,
49                                                                  snd_pcm_sframes_t *    avail);
50 static int                      gst_alsa_sink_write             (GstAlsa *              this,
51                                                                  snd_pcm_sframes_t *    avail);
52 static void                     gst_alsa_sink_loop              (GstElement *           element);
53 static gboolean                 gst_alsa_sink_check_event       (GstAlsaSink *          sink, 
54                                                                  gint                   pad_nr);
55 static GstElementStateReturn    gst_alsa_sink_change_state      (GstElement *           element);
56
57 static GstClockTime             gst_alsa_sink_get_time          (GstAlsa *              this);
58
59 static GstAlsa *sink_parent_class = NULL;
60
61 static GstPadTemplate *
62 gst_alsa_sink_pad_factory (void)
63 {
64   static GstPadTemplate *template = NULL;
65
66   if (!template)
67     template = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
68                                      gst_alsa_caps (SND_PCM_FORMAT_UNKNOWN, -1, -1));
69
70   return template;
71 }
72 static GstPadTemplate *
73 gst_alsa_sink_request_pad_factory (void)
74 {
75   static GstPadTemplate *template = NULL;
76
77   if (!template)
78     template =
79       gst_pad_template_new ("sink%d", GST_PAD_SINK, GST_PAD_REQUEST,
80                                      gst_alsa_caps (SND_PCM_FORMAT_UNKNOWN, -1, 1));
81
82   return template;
83 }
84 GType
85 gst_alsa_sink_get_type (void)
86 {
87   static GType alsa_sink_type = 0;
88
89   if (!alsa_sink_type) {
90     static const GTypeInfo alsa_sink_info = {
91       sizeof (GstAlsaSinkClass),
92       gst_alsa_sink_base_init,
93       NULL,
94       gst_alsa_sink_class_init,
95       NULL,
96       NULL,
97       sizeof (GstAlsaSink),
98       0,
99       (GInstanceInitFunc) gst_alsa_sink_init,
100     };
101
102     alsa_sink_type = g_type_register_static (GST_TYPE_ALSA, "GstAlsaSink", &alsa_sink_info, 0);
103   }
104   return alsa_sink_type;
105 }
106
107 static void
108 gst_alsa_sink_base_init (gpointer g_class)
109 {
110   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
111  
112   gst_element_class_add_pad_template (element_class, gst_alsa_sink_pad_factory ());
113   gst_element_class_add_pad_template (element_class, gst_alsa_sink_request_pad_factory ());
114
115   gst_element_class_set_details (element_class, &gst_alsa_sink_details);
116 }
117
118 static void
119 gst_alsa_sink_class_init (gpointer g_class, gpointer class_data)
120 {
121   GObjectClass *object_class;
122   GstElementClass *element_class;
123   GstAlsaClass *alsa_class;
124   GstAlsaSinkClass *klass;
125
126   klass = (GstAlsaSinkClass *) g_class;
127   object_class = (GObjectClass *) klass;
128   element_class = (GstElementClass *) klass;
129   alsa_class = (GstAlsaClass *) klass;
130
131   if (sink_parent_class == NULL)
132     sink_parent_class = g_type_class_ref (GST_TYPE_ALSA);
133   
134   alsa_class->stream            = SND_PCM_STREAM_PLAYBACK;
135   alsa_class->transmit_mmap     = gst_alsa_sink_mmap;
136   alsa_class->transmit_rw       = gst_alsa_sink_write;
137
138   element_class->change_state   = gst_alsa_sink_change_state;
139 }
140 static void
141 gst_alsa_sink_init (GstAlsaSink *sink)
142 {
143   GstAlsa *this = GST_ALSA (sink);
144
145   this->pad[0] = gst_pad_new_from_template (gst_alsa_sink_pad_factory (), "sink");
146   gst_pad_set_link_function (this->pad[0], gst_alsa_link);
147   gst_pad_set_getcaps_function (this->pad[0], gst_alsa_get_caps);
148   gst_element_add_pad (GST_ELEMENT (this), this->pad[0]);
149   
150   this->clock = gst_alsa_clock_new ("alsasinkclock", gst_alsa_sink_get_time, this);
151   /* we hold a ref to our clock until we're disposed */
152   gst_object_ref (GST_OBJECT (this->clock));
153   gst_object_sink (GST_OBJECT (this->clock));
154
155   gst_element_set_loop_function (GST_ELEMENT (this), gst_alsa_sink_loop);
156 }
157
158 static inline void
159 gst_alsa_sink_flush_one_pad (GstAlsaSink *sink, gint i)
160 {
161   switch (sink->behaviour[i]) {
162   case 0:
163     if (sink->buf[i])
164       gst_data_unref (GST_DATA (sink->buf[i]));
165     sink->buf[i] = NULL;  
166     sink->data[i] = NULL;
167     sink->behaviour[i] = 0;
168     sink->size[i] = 0;
169     break;
170   case 1:
171     g_free (sink->data[i]);
172     sink->data[i] = NULL;
173     sink->behaviour[i] = 0;
174     sink->size[i] = 0;
175     break;
176   default:
177     g_assert_not_reached ();
178   }
179 }
180 static void
181 gst_alsa_sink_flush_pads (GstAlsaSink *sink)
182 {
183   gint i;
184
185   for (i = 0; i < GST_ELEMENT (sink)->numpads; i++) {
186     /* flush twice to unref buffer when behaviour == 1 */
187     gst_alsa_sink_flush_one_pad (sink, i);
188     gst_alsa_sink_flush_one_pad (sink, i);
189   }
190 }
191 /* TRUE, if everything should continue */
192 static gboolean
193 gst_alsa_sink_check_event (GstAlsaSink *sink, gint pad_nr)
194 {
195   gboolean cont = TRUE;
196   GstEvent *event = GST_EVENT (sink->buf[pad_nr]);
197   GstAlsa *this = GST_ALSA (sink);
198
199   if (event) {
200     switch (GST_EVENT_TYPE (event)) {
201       case GST_EVENT_EOS:
202         gst_alsa_set_eos (this);
203         cont = FALSE;
204         break;
205       case GST_EVENT_INTERRUPT:
206         cont = FALSE;
207         break;
208       case GST_EVENT_DISCONTINUOUS: 
209         {
210           GstClockTime value;
211
212           /* only the first pad my seek */
213           if (pad_nr != 0) {
214             break;          
215           }
216           if (gst_event_discont_get_value (event, GST_FORMAT_TIME, &value)) {
217             gst_element_set_time (GST_ELEMENT (this), value);
218           } else if (gst_event_discont_get_value (event, GST_FORMAT_DEFAULT, &value)) {
219             value = gst_alsa_samples_to_timestamp (this, value); 
220             gst_element_set_time (GST_ELEMENT (this), value);
221           } else if (gst_event_discont_get_value (event, GST_FORMAT_BYTES, &value)) {
222             value = gst_alsa_bytes_to_timestamp (this, value); 
223             gst_element_set_time (GST_ELEMENT (this), value);
224           } else {
225             GST_ERROR_OBJECT (this, "couldn't extract time from discont event. Bad things might happen!");
226           }
227
228
229           break;
230         }
231       default:
232         GST_INFO_OBJECT (this, "got an unknown event (Type: %d)", GST_EVENT_TYPE (event));
233         break;
234     }
235     gst_event_unref (event);
236     sink->buf[pad_nr] = NULL;
237   } else {
238     /* the element at the top of the chain did not emit an event. */
239     g_assert_not_reached ();
240   }
241   return cont;
242 }
243 static int
244 gst_alsa_sink_mmap (GstAlsa *this, snd_pcm_sframes_t *avail)
245 {
246   snd_pcm_uframes_t offset;
247   const snd_pcm_channel_area_t *dst;
248   snd_pcm_channel_area_t *src;
249   GstAlsaSink *sink = GST_ALSA_SINK (this);
250   int i, err, width = snd_pcm_format_physical_width (this->format->format);
251
252   /* areas points to the memory areas that belong to gstreamer. */
253   src = g_malloc0 (this->format->channels * sizeof(snd_pcm_channel_area_t));
254
255   if (((GstElement *) this)->numpads == 1) {
256     /* interleaved */
257     for (i = 0; i < this->format->channels; i++) {
258       src[i].addr = sink->data[0];
259       src[i].first = i * width;
260       src[i].step = this->format->channels * width;
261     }
262   } else {
263     /* noninterleaved */
264     for (i = 0; i < this->format->channels; i++) {
265       src[i].addr = sink->data[i];
266       src[i].first = 0;
267       src[i].step = width;
268     }
269   }
270
271   if ((err = snd_pcm_mmap_begin (this->handle, &dst, &offset, avail)) < 0) {
272     GST_ERROR_OBJECT (this, "mmap failed: %s", snd_strerror (err));
273     return -1;
274   }
275
276   if ((err = snd_pcm_areas_copy (dst, offset, src, 0, this->format->channels, *avail, this->format->format)) < 0) {
277     snd_pcm_mmap_commit (this->handle, offset, 0);
278     GST_ERROR_OBJECT (this, "data copy failed: %s", snd_strerror (err));
279     return -1;
280   }
281   if ((err = snd_pcm_mmap_commit (this->handle, offset, *avail)) < 0) {
282     GST_ERROR_OBJECT (this, "mmap commit failed: %s", snd_strerror (err));
283     return -1;
284   }
285
286   return err;
287 }
288 static int
289 gst_alsa_sink_write (GstAlsa *this, snd_pcm_sframes_t *avail)
290 {
291   GstAlsaSink *sink = GST_ALSA_SINK (this);
292   void *channels[this->format->channels];
293   int err, i;
294
295   if (((GstElement *) this)->numpads == 1) {
296     /* interleaved */
297     err = snd_pcm_writei (this->handle, sink->data[0], *avail);
298   } else {
299     /* noninterleaved */
300     for (i = 0; i < this->format->channels; i++) {
301       channels[i] = sink->data[i];
302     }
303     err = snd_pcm_writen (this->handle, channels, *avail);
304   }
305   /* error handling */
306   if (err < 0) {
307     if (err == -EPIPE) {
308       gst_alsa_xrun_recovery (this);
309       return 0;
310     }
311     GST_ERROR_OBJECT (this, "error on data access: %s", snd_strerror (err));
312   }
313   return err;
314 }
315 static void
316 gst_alsa_sink_loop (GstElement *element)
317 {
318   snd_pcm_sframes_t avail, avail2, copied, sample_diff, max_discont;
319   snd_pcm_uframes_t samplestamp, time_sample;
320   gint i;
321   guint bytes; /* per channel */
322   GstAlsa *this = GST_ALSA (element);
323   GstAlsaSink *sink = GST_ALSA_SINK (element);
324
325   g_return_if_fail (sink != NULL);
326
327 sink_restart:
328
329   avail = gst_alsa_update_avail (this);
330   if (avail == -EPIPE) goto sink_restart;
331   if (avail < 0) return;
332   if (avail > 0) {
333
334   /* Not enough space. We grab data nonetheless and sleep afterwards */
335     if (avail < this->period_size) {
336       avail = this->period_size;
337     }
338     
339     /* check how many bytes we still have in all our bytestreams */
340     /* initialize this value to a somewhat sane state, we might alloc this much data below (which would be a bug, but who knows)... */
341     bytes = this->period_size * this->period_count * element->numpads * 8; /* must be > max sample size in bytes */
342     for (i = 0; i < element->numpads; i++) {
343       g_assert (this->pad[i] != NULL);
344       while (sink->size[i] == 0) {
345         if (!sink->buf[i])
346           sink->buf[i] = GST_BUFFER (gst_pad_pull (this->pad[i]));
347         if (GST_IS_EVENT (sink->buf[i])) {
348           if (gst_alsa_sink_check_event (sink, i))
349             continue;
350           return;
351         }
352         /* caps nego failed somewhere */
353         if (this->format == NULL) {
354           GST_ELEMENT_ERROR (this, CORE, NEGOTIATION, (NULL),
355                              ("ALSA format not negotiated"));
356         }
357         samplestamp = gst_alsa_timestamp_to_samples (this, GST_BUFFER_TIMESTAMP (sink->buf[i]));
358         max_discont = gst_alsa_timestamp_to_samples (this, this->max_discont);
359         time_sample = gst_alsa_timestamp_to_samples (this, gst_element_get_time (GST_ELEMENT (this)));
360         snd_pcm_delay (this->handle, &sample_diff);
361         /* actual diff = buffer samplestamp - played - to_play */
362         sample_diff = samplestamp - time_sample - sample_diff;
363
364         if ((!GST_BUFFER_TIMESTAMP_IS_VALID (sink->buf[i])) ||
365             (-max_discont <= sample_diff && sample_diff <= max_discont)) {
366
367           /* difference between expected and current is < GST_ALSA_DEVIATION */
368 no_difference:
369           sink->size[i] = sink->buf[i]->size;
370           sink->data[i] = sink->buf[i]->data;
371           sink->behaviour[i] = 0;
372         } else if (sample_diff > 0) {
373           /* there are empty samples in front of us, fill them with silence */
374           int samples = MIN (bytes, sample_diff) *
375                      (element->numpads == 1 ? this->format->channels : 1);
376           int size = samples * snd_pcm_format_physical_width (this->format->format) / 8;
377           GST_INFO_OBJECT (this, "Allocating %d bytes (%ld samples) now to resync: sample %ld expected, but got %ld", 
378                            size, MIN (bytes, sample_diff), time_sample, samplestamp);
379           sink->data[i] = g_try_malloc (size);
380           if (!sink->data[i]) {
381             GST_WARNING_OBJECT (this, "error allocating %d bytes, buffers unsynced now.", size);
382             goto no_difference;
383           }
384           sink->size[i] = size;
385           if (0 != snd_pcm_format_set_silence (this->format->format, sink->data[i], samples)) {
386             GST_WARNING_OBJECT (this, "error silencing buffer, enjoy the noise.");
387           }
388           sink->behaviour[i] = 1;
389         } else if (gst_alsa_samples_to_bytes (this, -sample_diff) >= sink->buf[i]->size) {
390           GST_INFO_OBJECT (this, "Skipping %lu samples to resync (complete buffer): sample %ld expected, but got %ld", 
391                            gst_alsa_bytes_to_samples (this, sink->buf[i]->size), time_sample, samplestamp);                   
392           /* this buffer is way behind */
393           gst_buffer_unref (sink->buf[i]);
394           sink->buf[i] = NULL;
395           continue;
396         } else if (sample_diff < 0) {
397           gint difference = gst_alsa_samples_to_bytes (this, -samplestamp);
398           GST_INFO_OBJECT (this, "Skipping %lu samples to resync: sample %ld expected, but got %ld",
399                            (gulong) -sample_diff, time_sample, samplestamp);
400           /* this buffer is only a bit behind */
401           sink->size[i] = sink->buf[i]->size - difference;
402           sink->data[i] = sink->buf[i]->data + difference;
403           sink->behaviour[i] = 0;
404         } else {
405           g_assert_not_reached ();
406         }
407       }
408       bytes = MIN (bytes, sink->size[i]);
409     }
410
411     avail = MIN (avail, gst_alsa_bytes_to_samples (this, bytes));
412
413     /* wait until the hw buffer has enough space */
414     while (gst_element_get_state (element) == GST_STATE_PLAYING && (avail2 = gst_alsa_update_avail (this)) < avail) {
415       if (avail2 <= -EPIPE) goto sink_restart;
416       if (avail2 < 0) return;
417       if (avail2 < avail && snd_pcm_state(this->handle) != SND_PCM_STATE_RUNNING)
418         if (!gst_alsa_start (this)) return;
419       if (gst_alsa_pcm_wait (this) == FALSE)
420         return;
421     }
422
423     /* FIXME: lotsa stuff can have happened while fetching data. Do we need to check something? */
424   
425     /* put this data into alsa */
426     if ((copied = this->transmit (this, &avail)) < 0)
427       return;
428     /* update our clock */
429     this->transmitted += copied;
430     /* flush the data */
431     bytes = gst_alsa_samples_to_bytes (this, copied);
432     for (i = 0; i < element->numpads; i++) {
433       if ((sink->size[i] -= bytes) == 0) {
434         gst_alsa_sink_flush_one_pad (sink, i);
435         continue;
436       }
437       g_assert (sink->size[i] > 0);
438       if (sink->behaviour[i] != 1)
439         sink->data[i] += bytes;
440     }
441   }
442
443   if (snd_pcm_state(this->handle) != SND_PCM_STATE_RUNNING && snd_pcm_avail_update (this->handle) == 0) {
444     gst_alsa_start (this);
445   }
446
447 }
448
449 static GstElementStateReturn
450 gst_alsa_sink_change_state (GstElement *element)
451 {
452   GstAlsaSink *sink;
453
454   g_return_val_if_fail (element != NULL, FALSE);
455   sink = GST_ALSA_SINK (element);
456
457   switch (GST_STATE_TRANSITION (element)) {
458   case GST_STATE_NULL_TO_READY:
459   case GST_STATE_READY_TO_PAUSED:
460   case GST_STATE_PAUSED_TO_PLAYING:
461   case GST_STATE_PLAYING_TO_PAUSED:
462     break;
463   case GST_STATE_PAUSED_TO_READY:
464     gst_alsa_sink_flush_pads (sink);
465     break;
466   case GST_STATE_READY_TO_NULL:
467     break;
468   default:
469     g_assert_not_reached();
470   }
471
472   if (GST_ELEMENT_CLASS (sink_parent_class)->change_state)
473     return GST_ELEMENT_CLASS (sink_parent_class)->change_state (element);
474
475   return GST_STATE_SUCCESS;
476 }
477
478 static GstClockTime
479 gst_alsa_sink_get_time (GstAlsa *this)
480 {
481   snd_pcm_sframes_t delay;
482   
483   if (snd_pcm_delay (this->handle, &delay) == 0 && this->format) {
484     return GST_SECOND * (GstClockTime) (this->transmitted > delay ? this->transmitted - delay : 0) / this->format->rate;
485   } else {
486     return 0;
487   }
488 }
489