gst-libs/gst/audio/gstbaseaudiosink.*: Make the clock sync code more accurate wrt...
[platform/upstream/gstreamer.git] / gst-libs / gst / audio / gstbaseaudiosink.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2005 Wim Taymans <wim@fluendo.com>
4  *
5  * gstbaseaudiosink.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  * SECTION:gstbaseaudiosink
25  * @short_description: Base class for audio sinks
26  * @see_also: #GstAudioSink, #GstRingBuffer.
27  *
28  * This is the base class for audio sinks. Subclasses need to implement the
29  * ::create_ringbuffer vmethod. This base class will then take care of
30  * writing samples to the ringbuffer, synchronisation, clipping and flushing.
31  *
32  * Last reviewed on 2006-09-27 (0.10.12)
33  */
34
35 #include <string.h>
36
37 #include "gstbaseaudiosink.h"
38
39 GST_DEBUG_CATEGORY_STATIC (gst_base_audio_sink_debug);
40 #define GST_CAT_DEFAULT gst_base_audio_sink_debug
41
42 /* BaseAudioSink signals and args */
43 enum
44 {
45   /* FILL ME */
46   LAST_SIGNAL
47 };
48
49 /* we tollerate half a second diff before we start resyncing. This
50  * should be enough to compensate for various rounding errors in the timestamp
51  * and sample offset position. 
52  * This is an emergency resync fallback since buffers marked as DISCONT will
53  * always lock to the correct timestamp immediatly and buffers not marked as
54  * DISCONT are contiguous by definition.
55  */
56 #define DIFF_TOLERANCE  2
57
58 /* FIXME: 0.11, store the buffer_time and latency_time in nanoseconds */
59 #define DEFAULT_BUFFER_TIME     ((200 * GST_MSECOND) / GST_USECOND)
60 #define DEFAULT_LATENCY_TIME    ((10 * GST_MSECOND) / GST_USECOND)
61 #define DEFAULT_PROVIDE_CLOCK   TRUE
62
63 enum
64 {
65   PROP_0,
66   PROP_BUFFER_TIME,
67   PROP_LATENCY_TIME,
68   PROP_PROVIDE_CLOCK,
69 };
70
71 #define _do_init(bla) \
72     GST_DEBUG_CATEGORY_INIT (gst_base_audio_sink_debug, "baseaudiosink", 0, "baseaudiosink element");
73
74 GST_BOILERPLATE_FULL (GstBaseAudioSink, gst_base_audio_sink, GstBaseSink,
75     GST_TYPE_BASE_SINK, _do_init);
76
77 static void gst_base_audio_sink_dispose (GObject * object);
78
79 static void gst_base_audio_sink_set_property (GObject * object, guint prop_id,
80     const GValue * value, GParamSpec * pspec);
81 static void gst_base_audio_sink_get_property (GObject * object, guint prop_id,
82     GValue * value, GParamSpec * pspec);
83
84 static GstStateChangeReturn gst_base_audio_sink_async_play (GstBaseSink *
85     basesink);
86 static GstStateChangeReturn gst_base_audio_sink_change_state (GstElement *
87     element, GstStateChange transition);
88
89 static GstClock *gst_base_audio_sink_provide_clock (GstElement * elem);
90 static GstClockTime gst_base_audio_sink_get_time (GstClock * clock,
91     GstBaseAudioSink * sink);
92 static void gst_base_audio_sink_callback (GstRingBuffer * rbuf, guint8 * data,
93     guint len, gpointer user_data);
94
95 static GstFlowReturn gst_base_audio_sink_preroll (GstBaseSink * bsink,
96     GstBuffer * buffer);
97 static GstFlowReturn gst_base_audio_sink_render (GstBaseSink * bsink,
98     GstBuffer * buffer);
99 static gboolean gst_base_audio_sink_event (GstBaseSink * bsink,
100     GstEvent * event);
101 static void gst_base_audio_sink_get_times (GstBaseSink * bsink,
102     GstBuffer * buffer, GstClockTime * start, GstClockTime * end);
103 static gboolean gst_base_audio_sink_setcaps (GstBaseSink * bsink,
104     GstCaps * caps);
105
106 /* static guint gst_base_audio_sink_signals[LAST_SIGNAL] = { 0 }; */
107
108 static void
109 gst_base_audio_sink_base_init (gpointer g_class)
110 {
111 }
112
113 static void
114 gst_base_audio_sink_class_init (GstBaseAudioSinkClass * klass)
115 {
116   GObjectClass *gobject_class;
117   GstElementClass *gstelement_class;
118   GstBaseSinkClass *gstbasesink_class;
119
120   gobject_class = (GObjectClass *) klass;
121   gstelement_class = (GstElementClass *) klass;
122   gstbasesink_class = (GstBaseSinkClass *) klass;
123
124   gobject_class->set_property =
125       GST_DEBUG_FUNCPTR (gst_base_audio_sink_set_property);
126   gobject_class->get_property =
127       GST_DEBUG_FUNCPTR (gst_base_audio_sink_get_property);
128   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_base_audio_sink_dispose);
129
130   g_object_class_install_property (gobject_class, PROP_BUFFER_TIME,
131       g_param_spec_int64 ("buffer-time", "Buffer Time",
132           "Size of audio buffer in microseconds", 1,
133           G_MAXINT64, DEFAULT_BUFFER_TIME, G_PARAM_READWRITE));
134
135   g_object_class_install_property (gobject_class, PROP_LATENCY_TIME,
136       g_param_spec_int64 ("latency-time", "Latency Time",
137           "Audio latency in microseconds", 1,
138           G_MAXINT64, DEFAULT_LATENCY_TIME, G_PARAM_READWRITE));
139
140   g_object_class_install_property (gobject_class, PROP_PROVIDE_CLOCK,
141       g_param_spec_boolean ("provide-clock", "Provide Clock",
142           "Provide a clock to be used as the global pipeline clock",
143           DEFAULT_PROVIDE_CLOCK, G_PARAM_READWRITE));
144
145   gstelement_class->change_state =
146       GST_DEBUG_FUNCPTR (gst_base_audio_sink_change_state);
147   gstelement_class->provide_clock =
148       GST_DEBUG_FUNCPTR (gst_base_audio_sink_provide_clock);
149
150   gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_base_audio_sink_event);
151   gstbasesink_class->preroll = GST_DEBUG_FUNCPTR (gst_base_audio_sink_preroll);
152   gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_base_audio_sink_render);
153   gstbasesink_class->get_times =
154       GST_DEBUG_FUNCPTR (gst_base_audio_sink_get_times);
155   gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_base_audio_sink_setcaps);
156   gstbasesink_class->async_play =
157       GST_DEBUG_FUNCPTR (gst_base_audio_sink_async_play);
158 }
159
160 static void
161 gst_base_audio_sink_init (GstBaseAudioSink * baseaudiosink,
162     GstBaseAudioSinkClass * g_class)
163 {
164   baseaudiosink->buffer_time = DEFAULT_BUFFER_TIME;
165   baseaudiosink->latency_time = DEFAULT_LATENCY_TIME;
166   baseaudiosink->provide_clock = DEFAULT_PROVIDE_CLOCK;
167
168   baseaudiosink->provided_clock = gst_audio_clock_new ("clock",
169       (GstAudioClockGetTimeFunc) gst_base_audio_sink_get_time, baseaudiosink);
170 }
171
172 static void
173 gst_base_audio_sink_dispose (GObject * object)
174 {
175   GstBaseAudioSink *sink;
176
177   sink = GST_BASE_AUDIO_SINK (object);
178
179   if (sink->provided_clock)
180     gst_object_unref (sink->provided_clock);
181   sink->provided_clock = NULL;
182
183   if (sink->ringbuffer) {
184     gst_object_unparent (GST_OBJECT_CAST (sink->ringbuffer));
185     sink->ringbuffer = NULL;
186   }
187
188   G_OBJECT_CLASS (parent_class)->dispose (object);
189 }
190
191 static GstClock *
192 gst_base_audio_sink_provide_clock (GstElement * elem)
193 {
194   GstBaseAudioSink *sink;
195   GstClock *clock;
196
197   sink = GST_BASE_AUDIO_SINK (elem);
198
199   /* we have no ringbuffer (must be NULL state) */
200   if (sink->ringbuffer == NULL)
201     goto wrong_state;
202
203   if (!gst_ring_buffer_is_acquired (sink->ringbuffer))
204     goto wrong_state;
205
206   GST_OBJECT_LOCK (sink);
207   if (!sink->provide_clock)
208     goto clock_disabled;
209
210   clock = GST_CLOCK_CAST (gst_object_ref (sink->provided_clock));
211   GST_OBJECT_UNLOCK (sink);
212
213   return clock;
214
215   /* ERRORS */
216 wrong_state:
217   {
218     GST_DEBUG_OBJECT (sink, "ringbuffer not acquired");
219     return NULL;
220   }
221 clock_disabled:
222   {
223     GST_DEBUG_OBJECT (sink, "clock provide disabled");
224     GST_OBJECT_UNLOCK (sink);
225     return NULL;
226   }
227 }
228
229 static GstClockTime
230 gst_base_audio_sink_get_time (GstClock * clock, GstBaseAudioSink * sink)
231 {
232   guint64 raw, samples;
233   guint delay;
234   GstClockTime result;
235
236   if (sink->ringbuffer == NULL || sink->ringbuffer->spec.rate == 0)
237     return GST_CLOCK_TIME_NONE;
238
239   /* our processed samples are always increasing */
240   raw = samples = gst_ring_buffer_samples_done (sink->ringbuffer);
241
242   /* the number of samples not yet processed, this is still queued in the
243    * device (not played for playback). */
244   delay = gst_ring_buffer_delay (sink->ringbuffer);
245
246   if (G_LIKELY (samples >= delay))
247     samples -= delay;
248   else
249     samples = 0;
250
251   result = gst_util_uint64_scale_int (samples, GST_SECOND,
252       sink->ringbuffer->spec.rate);
253
254   GST_DEBUG_OBJECT (sink,
255       "processed samples: raw %llu, delay %u, real %llu, time %"
256       GST_TIME_FORMAT, raw, delay, samples, GST_TIME_ARGS (result));
257
258   return result;
259 }
260
261 static void
262 gst_base_audio_sink_set_property (GObject * object, guint prop_id,
263     const GValue * value, GParamSpec * pspec)
264 {
265   GstBaseAudioSink *sink;
266
267   sink = GST_BASE_AUDIO_SINK (object);
268
269   switch (prop_id) {
270     case PROP_BUFFER_TIME:
271       sink->buffer_time = g_value_get_int64 (value);
272       break;
273     case PROP_LATENCY_TIME:
274       sink->latency_time = g_value_get_int64 (value);
275       break;
276     case PROP_PROVIDE_CLOCK:
277       GST_OBJECT_LOCK (sink);
278       sink->provide_clock = g_value_get_boolean (value);
279       GST_OBJECT_UNLOCK (sink);
280       break;
281     default:
282       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
283       break;
284   }
285 }
286
287 static void
288 gst_base_audio_sink_get_property (GObject * object, guint prop_id,
289     GValue * value, GParamSpec * pspec)
290 {
291   GstBaseAudioSink *sink;
292
293   sink = GST_BASE_AUDIO_SINK (object);
294
295   switch (prop_id) {
296     case PROP_BUFFER_TIME:
297       g_value_set_int64 (value, sink->buffer_time);
298       break;
299     case PROP_LATENCY_TIME:
300       g_value_set_int64 (value, sink->latency_time);
301       break;
302     case PROP_PROVIDE_CLOCK:
303       GST_OBJECT_LOCK (sink);
304       g_value_set_boolean (value, sink->provide_clock);
305       GST_OBJECT_UNLOCK (sink);
306       break;
307     default:
308       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
309       break;
310   }
311 }
312
313 static gboolean
314 gst_base_audio_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
315 {
316   GstBaseAudioSink *sink = GST_BASE_AUDIO_SINK (bsink);
317   GstRingBufferSpec *spec;
318
319   if (!sink->ringbuffer)
320     return FALSE;
321
322   spec = &sink->ringbuffer->spec;
323
324   GST_DEBUG_OBJECT (sink, "release old ringbuffer");
325
326   /* release old ringbuffer */
327   gst_ring_buffer_release (sink->ringbuffer);
328
329   GST_DEBUG_OBJECT (sink, "parse caps");
330
331   spec->buffer_time = sink->buffer_time;
332   spec->latency_time = sink->latency_time;
333
334   /* parse new caps */
335   if (!gst_ring_buffer_parse_caps (spec, caps))
336     goto parse_error;
337
338   gst_ring_buffer_debug_spec_buff (spec);
339
340   GST_DEBUG_OBJECT (sink, "acquire new ringbuffer");
341
342   if (!gst_ring_buffer_acquire (sink->ringbuffer, spec))
343     goto acquire_error;
344
345   /* calculate actual latency and buffer times. 
346    * FIXME: In 0.11, store the latency_time internally in ns */
347   spec->latency_time = gst_util_uint64_scale (spec->segsize,
348       (GST_SECOND / GST_USECOND), spec->rate * spec->bytes_per_sample);
349
350   spec->buffer_time = spec->segtotal * spec->latency_time;
351
352   gst_ring_buffer_debug_spec_buff (spec);
353
354   return TRUE;
355
356   /* ERRORS */
357 parse_error:
358   {
359     GST_DEBUG_OBJECT (sink, "could not parse caps");
360     GST_ELEMENT_ERROR (sink, STREAM, FORMAT,
361         (NULL), ("cannot parse audio format."));
362     return FALSE;
363   }
364 acquire_error:
365   {
366     GST_DEBUG_OBJECT (sink, "could not acquire ringbuffer");
367     return FALSE;
368   }
369 }
370
371 static void
372 gst_base_audio_sink_get_times (GstBaseSink * bsink, GstBuffer * buffer,
373     GstClockTime * start, GstClockTime * end)
374 {
375   /* our clock sync is a bit too much for the base class to handle so
376    * we implement it ourselves. */
377   *start = GST_CLOCK_TIME_NONE;
378   *end = GST_CLOCK_TIME_NONE;
379 }
380
381 /* FIXME, this waits for the drain to happen but it cannot be
382  * canceled.
383  */
384 static gboolean
385 gst_base_audio_sink_drain (GstBaseAudioSink * sink)
386 {
387   if (!sink->ringbuffer)
388     return TRUE;
389   if (!sink->ringbuffer->spec.rate)
390     return TRUE;
391
392   /* need to start playback before we can drain, but only when
393    * we have successfully negotiated a format and thus aqcuired the
394    * ringbuffer. */
395   if (gst_ring_buffer_is_acquired (sink->ringbuffer))
396     gst_ring_buffer_start (sink->ringbuffer);
397
398   if (sink->next_sample != -1) {
399     GstClockTime time;
400     GstClock *clock;
401
402     time =
403         gst_util_uint64_scale_int (sink->next_sample, GST_SECOND,
404         sink->ringbuffer->spec.rate);
405
406     GST_OBJECT_LOCK (sink);
407     if ((clock = GST_ELEMENT_CLOCK (sink)) != NULL) {
408       GstClockID id = gst_clock_new_single_shot_id (clock, time);
409
410       GST_OBJECT_UNLOCK (sink);
411
412       GST_DEBUG_OBJECT (sink, "waiting for last sample to play");
413       gst_clock_id_wait (id, NULL);
414
415       gst_clock_id_unref (id);
416       sink->next_sample = -1;
417     } else {
418       GST_OBJECT_UNLOCK (sink);
419     }
420   }
421   return TRUE;
422 }
423
424 static gboolean
425 gst_base_audio_sink_event (GstBaseSink * bsink, GstEvent * event)
426 {
427   GstBaseAudioSink *sink = GST_BASE_AUDIO_SINK (bsink);
428
429   switch (GST_EVENT_TYPE (event)) {
430     case GST_EVENT_FLUSH_START:
431       if (sink->ringbuffer)
432         gst_ring_buffer_set_flushing (sink->ringbuffer, TRUE);
433       break;
434     case GST_EVENT_FLUSH_STOP:
435       /* always resync on sample after a flush */
436       sink->next_sample = -1;
437       if (sink->ringbuffer)
438         gst_ring_buffer_set_flushing (sink->ringbuffer, FALSE);
439       break;
440     case GST_EVENT_EOS:
441       /* now wait till we played everything */
442       gst_base_audio_sink_drain (sink);
443       break;
444     case GST_EVENT_NEWSEGMENT:
445     {
446       gdouble rate;
447
448       /* we only need the rate */
449       gst_event_parse_new_segment_full (event, NULL, &rate, NULL, NULL,
450           NULL, NULL, NULL);
451
452       GST_DEBUG_OBJECT (sink, "new rate of %f", rate);
453       break;
454     }
455     default:
456       break;
457   }
458   return TRUE;
459 }
460
461 static GstFlowReturn
462 gst_base_audio_sink_preroll (GstBaseSink * bsink, GstBuffer * buffer)
463 {
464   GstBaseAudioSink *sink = GST_BASE_AUDIO_SINK (bsink);
465
466   if (!gst_ring_buffer_is_acquired (sink->ringbuffer))
467     goto wrong_state;
468
469   /* we don't really do anything when prerolling. We could make a
470    * property to play this buffer to have some sort of scrubbing
471    * support. */
472   return GST_FLOW_OK;
473
474 wrong_state:
475   {
476     GST_DEBUG_OBJECT (sink, "ringbuffer in wrong state");
477     GST_ELEMENT_ERROR (sink, STREAM, FORMAT, (NULL), ("sink not negotiated."));
478     return GST_FLOW_NOT_NEGOTIATED;
479   }
480 }
481
482 static guint64
483 gst_base_audio_sink_get_offset (GstBaseAudioSink * sink)
484 {
485   guint64 sample;
486   gint writeseg, segdone, sps;
487   gint diff;
488
489   /* assume we can append to the previous sample */
490   sample = sink->next_sample;
491   /* no previous sample, try to insert at position 0 */
492   if (sample == -1)
493     sample = 0;
494
495   sps = sink->ringbuffer->samples_per_seg;
496
497   /* figure out the segment and the offset inside the segment where
498    * the sample should be written. */
499   writeseg = sample / sps;
500
501   /* get the currently processed segment */
502   segdone = g_atomic_int_get (&sink->ringbuffer->segdone)
503       - sink->ringbuffer->segbase;
504
505   /* see how far away it is from the write segment */
506   diff = writeseg - segdone;
507   if (diff < 0) {
508     /* sample would be dropped, position to next playable position */
509     sample = (segdone + 1) * sps;
510   }
511
512   return sample;
513 }
514
515 static GstFlowReturn
516 gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
517 {
518   guint64 in_offset, clock_offset;
519   GstClockTime time, stop, render_start, render_stop, sample_offset;
520   GstBaseAudioSink *sink;
521   GstRingBuffer *ringbuf;
522   gint64 diff, align, ctime, cstop;
523   guint8 *data;
524   guint size;
525   guint samples, written;
526   gint bps;
527   gint accum;
528   GstClockTime crate_num;
529   GstClockTime crate_denom;
530   gint out_samples;
531   GstClockTime cinternal, cexternal;
532   GstClock *clock;
533   gboolean sync;
534
535   sink = GST_BASE_AUDIO_SINK (bsink);
536
537   ringbuf = sink->ringbuffer;
538
539   /* can't do anything when we don't have the device */
540   if (G_UNLIKELY (!gst_ring_buffer_is_acquired (ringbuf)))
541     goto wrong_state;
542
543   bps = ringbuf->spec.bytes_per_sample;
544
545   size = GST_BUFFER_SIZE (buf);
546   if (G_UNLIKELY (size % bps) != 0)
547     goto wrong_size;
548
549   samples = size / bps;
550   out_samples = samples;
551
552   in_offset = GST_BUFFER_OFFSET (buf);
553   time = GST_BUFFER_TIMESTAMP (buf);
554   stop = time + gst_util_uint64_scale_int (samples, GST_SECOND,
555       ringbuf->spec.rate);
556
557   GST_DEBUG_OBJECT (sink,
558       "time %" GST_TIME_FORMAT ", offset %llu, start %" GST_TIME_FORMAT
559       ", samples %u", GST_TIME_ARGS (time), in_offset,
560       GST_TIME_ARGS (bsink->segment.start), samples);
561
562   data = GST_BUFFER_DATA (buf);
563
564   /* if not valid timestamp or we can't clip or sync, try to play
565    * sample ASAP */
566   if (!GST_CLOCK_TIME_IS_VALID (time)) {
567     render_start = gst_base_audio_sink_get_offset (sink);
568     render_stop = render_start + samples;
569     GST_DEBUG_OBJECT (sink,
570         "Buffer of size %u has no time. Using render_start=%" G_GUINT64_FORMAT,
571         GST_BUFFER_SIZE (buf), render_start);
572     goto no_sync;
573   }
574
575   /* samples should be rendered based on their timestamp. All samples
576    * arriving before the segment.start or after segment.stop are to be 
577    * thrown away. All samples should also be clipped to the segment 
578    * boundaries */
579   /* let's calc stop based on the number of samples in the buffer instead
580    * of trusting the DURATION */
581   if (!gst_segment_clip (&bsink->segment, GST_FORMAT_TIME, time, stop, &ctime,
582           &cstop))
583     goto out_of_segment;
584
585   /* see if some clipping happened */
586   diff = ctime - time;
587   if (diff > 0) {
588     /* bring clipped time to samples */
589     diff = gst_util_uint64_scale_int (diff, ringbuf->spec.rate, GST_SECOND);
590     GST_DEBUG_OBJECT (sink, "clipping start to %" GST_TIME_FORMAT " %"
591         G_GUINT64_FORMAT " samples", GST_TIME_ARGS (ctime), diff);
592     samples -= diff;
593     data += diff * bps;
594     time = ctime;
595   }
596   diff = stop - cstop;
597   if (diff > 0) {
598     /* bring clipped time to samples */
599     diff = gst_util_uint64_scale_int (diff, ringbuf->spec.rate, GST_SECOND);
600     GST_DEBUG_OBJECT (sink, "clipping stop to %" GST_TIME_FORMAT " %"
601         G_GUINT64_FORMAT " samples", GST_TIME_ARGS (cstop), diff);
602     samples -= diff;
603     stop = cstop;
604   }
605
606   /* figure out how to sync */
607   if ((clock = GST_ELEMENT_CLOCK (bsink)))
608     sync = bsink->sync;
609   else
610     sync = FALSE;
611
612   if (!sync) {
613     /* no sync needed, play sample ASAP */
614     render_start = gst_base_audio_sink_get_offset (sink);
615     render_stop = render_start + samples;
616     GST_DEBUG_OBJECT (sink,
617         "no sync needed. Using render_start=%" G_GUINT64_FORMAT, render_start);
618     goto no_sync;
619   }
620
621   /* bring buffer start and stop times to running time */
622   render_start =
623       gst_segment_to_running_time (&bsink->segment, GST_FORMAT_TIME, time);
624   render_stop =
625       gst_segment_to_running_time (&bsink->segment, GST_FORMAT_TIME, stop);
626
627   GST_DEBUG_OBJECT (sink,
628       "running: start %" GST_TIME_FORMAT " - stop %" GST_TIME_FORMAT,
629       GST_TIME_ARGS (render_start), GST_TIME_ARGS (render_stop));
630
631   /* get calibration parameters to compensate for speed and offset differences
632    * when we are slaved */
633   gst_clock_get_calibration (sink->provided_clock, &cinternal, &cexternal,
634       &crate_num, &crate_denom);
635
636   clock_offset =
637       (gst_element_get_base_time (GST_ELEMENT_CAST (bsink)) - cexternal) +
638       cinternal;
639
640   GST_DEBUG_OBJECT (sink, "clock offset %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
641       "/%" G_GUINT64_FORMAT, GST_TIME_ARGS (clock_offset), crate_num,
642       crate_denom);
643
644   /* and bring the time to the rate corrected offset in the buffer */
645   render_start = gst_util_uint64_scale_int (render_start + clock_offset,
646       ringbuf->spec.rate, GST_SECOND);
647   render_stop = gst_util_uint64_scale_int (render_stop + clock_offset,
648       ringbuf->spec.rate, GST_SECOND);
649
650   GST_DEBUG_OBJECT (sink,
651       "render: start %" GST_TIME_FORMAT " - stop %" GST_TIME_FORMAT,
652       GST_TIME_ARGS (render_start), GST_TIME_ARGS (render_stop));
653
654   /* always resync after a discont */
655   if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT))) {
656     GST_DEBUG_OBJECT (sink, "resync after discont");
657     goto no_align;
658   }
659
660   if (G_UNLIKELY (sink->next_sample == -1)) {
661     GST_DEBUG_OBJECT (sink,
662         "no align possible: no previous sample position known");
663     goto no_align;
664   }
665
666   if (bsink->segment.rate >= 1.0)
667     sample_offset = render_start;
668   else
669     sample_offset = render_stop;
670
671   /* now try to align the sample to the previous one */
672   if (sample_offset >= sink->next_sample)
673     diff = sample_offset - sink->next_sample;
674   else
675     diff = sink->next_sample - sample_offset;
676
677   /* we tollerate half a second diff before we start resyncing. This
678    * should be enough to compensate for various rounding errors in the timestamp
679    * and sample offset position. We always resync if we got a discont anyway and
680    * non-discont should be aligned by definition. */
681   if (G_LIKELY (diff < ringbuf->spec.rate / DIFF_TOLERANCE)) {
682     GST_DEBUG_OBJECT (sink,
683         "align with prev sample, %" G_GINT64_FORMAT " < %d", diff,
684         ringbuf->spec.rate / DIFF_TOLERANCE);
685     /* calc align with previous sample */
686     align = sink->next_sample - sample_offset;
687   } else {
688     /* bring sample diff to seconds for error message */
689     diff = gst_util_uint64_scale_int (diff, GST_SECOND, ringbuf->spec.rate);
690     /* timestamps drifted apart from previous samples too much, we need to
691      * resync. We log this as an element warning. */
692     GST_ELEMENT_WARNING (sink, CORE, CLOCK,
693         ("Compensating for audio synchronisation problems"),
694         ("Unexpected discontinuity in audio timestamps of more "
695             "than half a second (%" GST_TIME_FORMAT "), resyncing",
696             GST_TIME_ARGS (diff)));
697     align = 0;
698   }
699
700   /* apply alignment */
701   render_start += align;
702
703   /* only align stop if we are not slaved */
704   if (clock != sink->provided_clock) {
705     GST_DEBUG_OBJECT (sink, "no stop time align needed: we are slaved");
706     goto no_align;
707   }
708   render_stop += align;
709
710 no_align:
711   /* number of target samples is difference between start and stop */
712   out_samples = render_stop - render_start;
713
714 no_sync:
715   GST_DEBUG_OBJECT (sink, "rendering at %" G_GUINT64_FORMAT " %d/%d",
716       sink->next_sample, samples, out_samples);
717
718   /* we render the first or last sample first, depending on the rate */
719   if (bsink->segment.rate >= 1.0)
720     sample_offset = render_start;
721   else
722     sample_offset = render_stop;
723
724   /* we need to accumulate over different runs for when we get interrupted */
725   accum = 0;
726   do {
727     written =
728         gst_ring_buffer_commit_full (ringbuf, &sample_offset, data, samples,
729         out_samples, &accum);
730
731     GST_DEBUG_OBJECT (sink, "wrote %u of %u", written, samples);
732     /* if we wrote all, we're done */
733     if (written == samples)
734       break;
735
736     /* else something interrupted us and we wait for preroll. */
737     if (gst_base_sink_wait_preroll (bsink) != GST_FLOW_OK)
738       goto stopping;
739
740     samples -= written;
741     data += written * bps;
742   } while (TRUE);
743
744   sink->next_sample = sample_offset;
745
746   GST_DEBUG_OBJECT (sink, "next sample expected at %" G_GUINT64_FORMAT,
747       sink->next_sample);
748
749   if (GST_CLOCK_TIME_IS_VALID (stop) && stop >= bsink->segment.stop) {
750     GST_DEBUG_OBJECT (sink,
751         "start playback because we are at the end of segment");
752     gst_ring_buffer_start (ringbuf);
753   }
754
755   return GST_FLOW_OK;
756
757   /* SPECIAL cases */
758 out_of_segment:
759   {
760     GST_DEBUG_OBJECT (sink,
761         "dropping sample out of segment time %" GST_TIME_FORMAT ", start %"
762         GST_TIME_FORMAT, GST_TIME_ARGS (time),
763         GST_TIME_ARGS (bsink->segment.start));
764     return GST_FLOW_OK;
765   }
766   /* ERRORS */
767 wrong_state:
768   {
769     GST_DEBUG_OBJECT (sink, "ringbuffer not negotiated");
770     GST_ELEMENT_ERROR (sink, STREAM, FORMAT, (NULL), ("sink not negotiated."));
771     return GST_FLOW_NOT_NEGOTIATED;
772   }
773 wrong_size:
774   {
775     GST_DEBUG_OBJECT (sink, "wrong size");
776     GST_ELEMENT_ERROR (sink, STREAM, WRONG_TYPE,
777         (NULL), ("sink received buffer of wrong size."));
778     return GST_FLOW_ERROR;
779   }
780 stopping:
781   {
782     GST_DEBUG_OBJECT (sink, "ringbuffer is stopping");
783     return GST_FLOW_WRONG_STATE;
784   }
785 }
786
787 /**
788  * gst_base_audio_sink_create_ringbuffer:
789  * @sink: a #GstBaseAudioSink.
790  *
791  * Create and return the #GstRingBuffer for @sink. This function will call the
792  * ::create_ringbuffer vmethod and will set @sink as the parent of the returned
793  * buffer (see gst_object_set_parent()).
794  *
795  * Returns: The new ringbuffer of @sink.
796  */
797 GstRingBuffer *
798 gst_base_audio_sink_create_ringbuffer (GstBaseAudioSink * sink)
799 {
800   GstBaseAudioSinkClass *bclass;
801   GstRingBuffer *buffer = NULL;
802
803   bclass = GST_BASE_AUDIO_SINK_GET_CLASS (sink);
804   if (bclass->create_ringbuffer)
805     buffer = bclass->create_ringbuffer (sink);
806
807   if (buffer)
808     gst_object_set_parent (GST_OBJECT (buffer), GST_OBJECT (sink));
809
810   return buffer;
811 }
812
813 static void
814 gst_base_audio_sink_callback (GstRingBuffer * rbuf, guint8 * data, guint len,
815     gpointer user_data)
816 {
817   /* GstBaseAudioSink *sink = GST_BASE_AUDIO_SINK (data); */
818 }
819
820 /* should be called with the LOCK */
821 static GstStateChangeReturn
822 gst_base_audio_sink_async_play (GstBaseSink * basesink)
823 {
824   GstClock *clock;
825   GstClockTime time, base;
826   GstBaseAudioSink *sink;
827
828   sink = GST_BASE_AUDIO_SINK (basesink);
829
830   GST_DEBUG_OBJECT (sink, "ringbuffer may start now");
831   gst_ring_buffer_may_start (sink->ringbuffer, TRUE);
832
833   clock = GST_ELEMENT_CLOCK (sink);
834   if (clock == NULL)
835     goto no_clock;
836
837   /* FIXME, only start slaving when we really start the ringbuffer */
838   /* if we are slaved to a clock, we need to set the initial
839    * calibration */
840   if (clock != sink->provided_clock) {
841     GstClockTime rate_num, rate_denom;
842
843     base = GST_ELEMENT_CAST (sink)->base_time;
844     time = gst_clock_get_internal_time (sink->provided_clock);
845
846     GST_DEBUG_OBJECT (sink,
847         "time: %" GST_TIME_FORMAT " base: %" GST_TIME_FORMAT,
848         GST_TIME_ARGS (time), GST_TIME_ARGS (base));
849
850     /* FIXME, this is not yet accurate enough for smooth playback */
851     gst_clock_get_calibration (sink->provided_clock, NULL, NULL, &rate_num,
852         &rate_denom);
853     /* Does not work yet. */
854     gst_clock_set_calibration (sink->provided_clock, time, base,
855         rate_num, rate_denom);
856
857     gst_clock_set_master (sink->provided_clock, clock);
858   }
859
860 no_clock:
861   return GST_STATE_CHANGE_SUCCESS;
862 }
863
864 static GstStateChangeReturn
865 gst_base_audio_sink_do_play (GstBaseAudioSink * sink)
866 {
867   GstStateChangeReturn ret;
868
869   GST_OBJECT_LOCK (sink);
870   ret = gst_base_audio_sink_async_play (GST_BASE_SINK_CAST (sink));
871   GST_OBJECT_UNLOCK (sink);
872
873   return ret;
874 }
875
876 static GstStateChangeReturn
877 gst_base_audio_sink_change_state (GstElement * element,
878     GstStateChange transition)
879 {
880   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
881   GstBaseAudioSink *sink = GST_BASE_AUDIO_SINK (element);
882
883   switch (transition) {
884     case GST_STATE_CHANGE_NULL_TO_READY:
885       if (sink->ringbuffer == NULL) {
886         sink->ringbuffer = gst_base_audio_sink_create_ringbuffer (sink);
887         gst_ring_buffer_set_callback (sink->ringbuffer,
888             gst_base_audio_sink_callback, sink);
889       }
890       if (!gst_ring_buffer_open_device (sink->ringbuffer))
891         goto open_failed;
892       break;
893     case GST_STATE_CHANGE_READY_TO_PAUSED:
894       sink->next_sample = -1;
895       gst_ring_buffer_set_flushing (sink->ringbuffer, FALSE);
896       gst_ring_buffer_may_start (sink->ringbuffer, FALSE);
897       break;
898     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
899       gst_base_audio_sink_do_play (sink);
900       break;
901     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
902       /* need to take the lock so we don't interfere with an
903        * async play */
904       GST_OBJECT_LOCK (sink);
905       /* ringbuffer cannot start anymore */
906       gst_ring_buffer_may_start (sink->ringbuffer, FALSE);
907       gst_ring_buffer_pause (sink->ringbuffer);
908       GST_OBJECT_UNLOCK (sink);
909       break;
910     case GST_STATE_CHANGE_PAUSED_TO_READY:
911       /* make sure we unblock before calling the parent state change
912        * so it can grab the STREAM_LOCK */
913       gst_ring_buffer_set_flushing (sink->ringbuffer, TRUE);
914       break;
915     default:
916       break;
917   }
918
919   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
920
921   switch (transition) {
922     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
923       /* slop slaving ourselves to the master, if any */
924       gst_clock_set_master (sink->provided_clock, NULL);
925       break;
926     case GST_STATE_CHANGE_PAUSED_TO_READY:
927       gst_ring_buffer_release (sink->ringbuffer);
928       gst_pad_set_caps (GST_BASE_SINK_PAD (sink), NULL);
929       break;
930     case GST_STATE_CHANGE_READY_TO_NULL:
931       gst_ring_buffer_close_device (sink->ringbuffer);
932       break;
933     default:
934       break;
935   }
936
937   return ret;
938
939   /* ERRORS */
940 open_failed:
941   {
942     /* subclass must post a meaningfull error message */
943     GST_DEBUG_OBJECT (sink, "open failed");
944     return GST_STATE_CHANGE_FAILURE;
945   }
946 }