• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2005 Wim Taymans <wim@fluendo.com>
4  *
5  * gstaudiobasesink.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., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22 
23 /**
24  * SECTION:gstaudiobasesink
25  * @title: GstAudioBaseSink
26  * @short_description: Base class for audio sinks
27  * @see_also: #GstAudioSink, #GstAudioRingBuffer.
28  *
29  * This is the base class for audio sinks. Subclasses need to implement the
30  * ::create_ringbuffer vmethod. This base class will then take care of
31  * writing samples to the ringbuffer, synchronisation, clipping and flushing.
32  */
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36 
37 #include <string.h>
38 
39 #include <gst/audio/audio.h>
40 #include "gstaudiobasesink.h"
41 
42 GST_DEBUG_CATEGORY_STATIC (gst_audio_base_sink_debug);
43 #define GST_CAT_DEFAULT gst_audio_base_sink_debug
44 
45 struct _GstAudioBaseSinkPrivate
46 {
47   /* upstream latency */
48   GstClockTime us_latency;
49   /* the clock slaving algorithm in use */
50   GstAudioBaseSinkSlaveMethod slave_method;
51   /* running average of clock skew */
52   GstClockTimeDiff avg_skew;
53   /* the number of samples we aligned last time */
54   gint64 last_align;
55 
56   gboolean sync_latency;
57 
58   GstClockTime eos_time;
59 
60   /* number of microseconds we allow clock slaving to drift
61    * before resyncing */
62   guint64 drift_tolerance;
63 
64   /* number of nanoseconds we allow timestamps to drift
65    * before resyncing */
66   GstClockTime alignment_threshold;
67 
68   /* time of the previous detected discont candidate */
69   GstClockTime discont_time;
70 
71   /* number of nanoseconds to wait until creating a discontinuity */
72   GstClockTime discont_wait;
73 
74   /* custom slaving algorithm callback */
75   GstAudioBaseSinkCustomSlavingCallback custom_slaving_callback;
76   gpointer custom_slaving_cb_data;
77   GDestroyNotify custom_slaving_cb_notify;
78 };
79 
80 /* BaseAudioSink signals and args */
81 enum
82 {
83   /* FILL ME */
84   LAST_SIGNAL
85 };
86 
87 /* FIXME: 2.0, store the buffer_time and latency_time in nanoseconds */
88 #define DEFAULT_BUFFER_TIME     ((200 * GST_MSECOND) / GST_USECOND)
89 #define DEFAULT_LATENCY_TIME    ((10 * GST_MSECOND) / GST_USECOND)
90 #define DEFAULT_PROVIDE_CLOCK   TRUE
91 #define DEFAULT_SLAVE_METHOD    GST_AUDIO_BASE_SINK_SLAVE_SKEW
92 
93 /* FIXME, enable pull mode when clock slaving and trick modes are figured out */
94 #define DEFAULT_CAN_ACTIVATE_PULL FALSE
95 
96 /* when timestamps drift for more than 40ms we resync. This should
97  * be enough to compensate for timestamp rounding errors. */
98 #define DEFAULT_ALIGNMENT_THRESHOLD   (40 * GST_MSECOND)
99 
100 /* when clock slaving drift for more than 40ms we resync. This is
101  * a reasonable default */
102 #define DEFAULT_DRIFT_TOLERANCE   ((40 * GST_MSECOND) / GST_USECOND)
103 
104 /* allow for one second before resyncing to see if the timestamps drift will
105  * fix itself, or is a permanent offset */
106 #define DEFAULT_DISCONT_WAIT        (1 * GST_SECOND)
107 
108 enum
109 {
110   PROP_0,
111 
112   PROP_BUFFER_TIME,
113   PROP_LATENCY_TIME,
114   PROP_PROVIDE_CLOCK,
115   PROP_SLAVE_METHOD,
116   PROP_CAN_ACTIVATE_PULL,
117   PROP_ALIGNMENT_THRESHOLD,
118   PROP_DRIFT_TOLERANCE,
119   PROP_DISCONT_WAIT,
120 
121   PROP_LAST
122 };
123 
124 #define _do_init \
125     GST_DEBUG_CATEGORY_INIT (gst_audio_base_sink_debug, "audiobasesink", 0, "audiobasesink element");
126 #define gst_audio_base_sink_parent_class parent_class
127 G_DEFINE_TYPE_WITH_CODE (GstAudioBaseSink, gst_audio_base_sink,
128     GST_TYPE_BASE_SINK, G_ADD_PRIVATE (GstAudioBaseSink) _do_init);
129 
130 static void gst_audio_base_sink_dispose (GObject * object);
131 
132 static void gst_audio_base_sink_set_property (GObject * object, guint prop_id,
133     const GValue * value, GParamSpec * pspec);
134 static void gst_audio_base_sink_get_property (GObject * object, guint prop_id,
135     GValue * value, GParamSpec * pspec);
136 
137 static GstStateChangeReturn gst_audio_base_sink_change_state (GstElement *
138     element, GstStateChange transition);
139 static gboolean gst_audio_base_sink_activate_pull (GstBaseSink * basesink,
140     gboolean active);
141 static gboolean gst_audio_base_sink_query (GstElement * element, GstQuery *
142     query);
143 
144 static GstClock *gst_audio_base_sink_provide_clock (GstElement * elem);
145 static inline void gst_audio_base_sink_reset_sync (GstAudioBaseSink * sink);
146 static GstClockTime gst_audio_base_sink_get_time (GstClock * clock,
147     GstAudioBaseSink * sink);
148 static void gst_audio_base_sink_callback (GstAudioRingBuffer * rbuf,
149     guint8 * data, guint len, gpointer user_data);
150 
151 static GstFlowReturn gst_audio_base_sink_preroll (GstBaseSink * bsink,
152     GstBuffer * buffer);
153 static GstFlowReturn gst_audio_base_sink_render (GstBaseSink * bsink,
154     GstBuffer * buffer);
155 static gboolean gst_audio_base_sink_event (GstBaseSink * bsink,
156     GstEvent * event);
157 static GstFlowReturn gst_audio_base_sink_wait_event (GstBaseSink * bsink,
158     GstEvent * event);
159 static void gst_audio_base_sink_get_times (GstBaseSink * bsink,
160     GstBuffer * buffer, GstClockTime * start, GstClockTime * end);
161 static gboolean gst_audio_base_sink_setcaps (GstBaseSink * bsink,
162     GstCaps * caps);
163 static GstCaps *gst_audio_base_sink_fixate (GstBaseSink * bsink,
164     GstCaps * caps);
165 
166 static gboolean gst_audio_base_sink_query_pad (GstBaseSink * bsink,
167     GstQuery * query);
168 
169 
170 /* static guint gst_audio_base_sink_signals[LAST_SIGNAL] = { 0 }; */
171 
172 static void
gst_audio_base_sink_class_init(GstAudioBaseSinkClass * klass)173 gst_audio_base_sink_class_init (GstAudioBaseSinkClass * klass)
174 {
175   GObjectClass *gobject_class;
176   GstElementClass *gstelement_class;
177   GstBaseSinkClass *gstbasesink_class;
178 
179   gobject_class = (GObjectClass *) klass;
180   gstelement_class = (GstElementClass *) klass;
181   gstbasesink_class = (GstBaseSinkClass *) klass;
182 
183   gobject_class->set_property = gst_audio_base_sink_set_property;
184   gobject_class->get_property = gst_audio_base_sink_get_property;
185   gobject_class->dispose = gst_audio_base_sink_dispose;
186 
187   g_object_class_install_property (gobject_class, PROP_BUFFER_TIME,
188       g_param_spec_int64 ("buffer-time", "Buffer Time",
189           "Size of audio buffer in microseconds, this is the minimum "
190           "latency that the sink reports", 1, G_MAXINT64, DEFAULT_BUFFER_TIME,
191           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
192 
193   g_object_class_install_property (gobject_class, PROP_LATENCY_TIME,
194       g_param_spec_int64 ("latency-time", "Latency Time",
195           "The minimum amount of data to write in each iteration "
196           "in microseconds", 1, G_MAXINT64, DEFAULT_LATENCY_TIME,
197           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
198 
199   g_object_class_install_property (gobject_class, PROP_PROVIDE_CLOCK,
200       g_param_spec_boolean ("provide-clock", "Provide Clock",
201           "Provide a clock to be used as the global pipeline clock",
202           DEFAULT_PROVIDE_CLOCK, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
203 
204   g_object_class_install_property (gobject_class, PROP_SLAVE_METHOD,
205       g_param_spec_enum ("slave-method", "Slave Method",
206           "Algorithm used to match the rate of the masterclock",
207           GST_TYPE_AUDIO_BASE_SINK_SLAVE_METHOD, DEFAULT_SLAVE_METHOD,
208           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
209 
210   g_object_class_install_property (gobject_class, PROP_CAN_ACTIVATE_PULL,
211       g_param_spec_boolean ("can-activate-pull", "Allow Pull Scheduling",
212           "Allow pull-based scheduling", DEFAULT_CAN_ACTIVATE_PULL,
213           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
214   /**
215    * GstAudioBaseSink:drift-tolerance:
216    *
217    * Controls the amount of time in microseconds that clocks are allowed
218    * to drift before resynchronisation happens.
219    */
220   g_object_class_install_property (gobject_class, PROP_DRIFT_TOLERANCE,
221       g_param_spec_int64 ("drift-tolerance", "Drift Tolerance",
222           "Tolerance for clock drift in microseconds", 1,
223           G_MAXINT64, DEFAULT_DRIFT_TOLERANCE,
224           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
225   /**
226    * GstAudioBaseSink:alignment_threshold:
227    *
228    * Controls the amount of time in nanoseconds that timestamps are allowed
229    * to drift from their ideal time before choosing not to align them.
230    */
231   g_object_class_install_property (gobject_class, PROP_ALIGNMENT_THRESHOLD,
232       g_param_spec_uint64 ("alignment-threshold", "Alignment Threshold",
233           "Timestamp alignment threshold in nanoseconds", 1,
234           G_MAXUINT64 - 1, DEFAULT_ALIGNMENT_THRESHOLD,
235           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
236 
237   /**
238    * GstAudioBaseSink:discont-wait:
239    *
240    * A window of time in nanoseconds to wait before creating a discontinuity as
241    * a result of breaching the drift-tolerance.
242    */
243   g_object_class_install_property (gobject_class, PROP_DISCONT_WAIT,
244       g_param_spec_uint64 ("discont-wait", "Discont Wait",
245           "Window of time in nanoseconds to wait before "
246           "creating a discontinuity", 0,
247           G_MAXUINT64 - 1, DEFAULT_DISCONT_WAIT,
248           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
249 
250   gstelement_class->change_state =
251       GST_DEBUG_FUNCPTR (gst_audio_base_sink_change_state);
252   gstelement_class->provide_clock =
253       GST_DEBUG_FUNCPTR (gst_audio_base_sink_provide_clock);
254   gstelement_class->query = GST_DEBUG_FUNCPTR (gst_audio_base_sink_query);
255 
256   gstbasesink_class->fixate = GST_DEBUG_FUNCPTR (gst_audio_base_sink_fixate);
257   gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_audio_base_sink_setcaps);
258   gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_audio_base_sink_event);
259   gstbasesink_class->wait_event =
260       GST_DEBUG_FUNCPTR (gst_audio_base_sink_wait_event);
261   gstbasesink_class->get_times =
262       GST_DEBUG_FUNCPTR (gst_audio_base_sink_get_times);
263   gstbasesink_class->preroll = GST_DEBUG_FUNCPTR (gst_audio_base_sink_preroll);
264   gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_audio_base_sink_render);
265   gstbasesink_class->query = GST_DEBUG_FUNCPTR (gst_audio_base_sink_query_pad);
266   gstbasesink_class->activate_pull =
267       GST_DEBUG_FUNCPTR (gst_audio_base_sink_activate_pull);
268 
269   /* ref class from a thread-safe context to work around missing bit of
270    * thread-safety in GObject */
271   g_type_class_ref (GST_TYPE_AUDIO_CLOCK);
272   g_type_class_ref (GST_TYPE_AUDIO_RING_BUFFER);
273 
274 }
275 
276 static void
gst_audio_base_sink_init(GstAudioBaseSink * audiobasesink)277 gst_audio_base_sink_init (GstAudioBaseSink * audiobasesink)
278 {
279   GstBaseSink *basesink = GST_BASE_SINK_CAST (audiobasesink);
280 
281   audiobasesink->priv =
282       gst_audio_base_sink_get_instance_private (audiobasesink);
283 
284   audiobasesink->buffer_time = DEFAULT_BUFFER_TIME;
285   audiobasesink->latency_time = DEFAULT_LATENCY_TIME;
286   audiobasesink->priv->slave_method = DEFAULT_SLAVE_METHOD;
287   audiobasesink->priv->drift_tolerance = DEFAULT_DRIFT_TOLERANCE;
288   audiobasesink->priv->alignment_threshold = DEFAULT_ALIGNMENT_THRESHOLD;
289   audiobasesink->priv->discont_wait = DEFAULT_DISCONT_WAIT;
290   audiobasesink->priv->custom_slaving_callback = NULL;
291   audiobasesink->priv->custom_slaving_cb_data = NULL;
292   audiobasesink->priv->custom_slaving_cb_notify = NULL;
293 
294   audiobasesink->provided_clock = gst_audio_clock_new ("GstAudioSinkClock",
295       (GstAudioClockGetTimeFunc) gst_audio_base_sink_get_time, audiobasesink,
296       NULL);
297 
298   basesink->can_activate_push = TRUE;
299   basesink->can_activate_pull = DEFAULT_CAN_ACTIVATE_PULL;
300 
301   gst_base_sink_set_last_sample_enabled (basesink, FALSE);
302   if (DEFAULT_PROVIDE_CLOCK)
303     GST_OBJECT_FLAG_SET (basesink, GST_ELEMENT_FLAG_PROVIDE_CLOCK);
304   else
305     GST_OBJECT_FLAG_UNSET (basesink, GST_ELEMENT_FLAG_PROVIDE_CLOCK);
306 }
307 
308 static void
gst_audio_base_sink_dispose(GObject * object)309 gst_audio_base_sink_dispose (GObject * object)
310 {
311   GstAudioBaseSink *sink;
312 
313   sink = GST_AUDIO_BASE_SINK (object);
314 
315   if (sink->priv->custom_slaving_cb_notify)
316     sink->priv->custom_slaving_cb_notify (sink->priv->custom_slaving_cb_data);
317 
318   if (sink->provided_clock) {
319     gst_audio_clock_invalidate (GST_AUDIO_CLOCK (sink->provided_clock));
320     gst_object_unref (sink->provided_clock);
321     sink->provided_clock = NULL;
322   }
323 
324   if (sink->ringbuffer) {
325     gst_object_unparent (GST_OBJECT_CAST (sink->ringbuffer));
326     sink->ringbuffer = NULL;
327   }
328 
329   G_OBJECT_CLASS (parent_class)->dispose (object);
330 }
331 
332 
333 static GstClock *
gst_audio_base_sink_provide_clock(GstElement * elem)334 gst_audio_base_sink_provide_clock (GstElement * elem)
335 {
336   GstAudioBaseSink *sink;
337   GstClock *clock;
338 
339   sink = GST_AUDIO_BASE_SINK (elem);
340 
341   /* we have no ringbuffer (must be NULL state) */
342   if (sink->ringbuffer == NULL)
343     goto wrong_state;
344 
345   if (!gst_audio_ring_buffer_is_acquired (sink->ringbuffer))
346     goto wrong_state;
347 
348   GST_OBJECT_LOCK (sink);
349   if (!GST_OBJECT_FLAG_IS_SET (sink, GST_ELEMENT_FLAG_PROVIDE_CLOCK))
350     goto clock_disabled;
351 
352   clock = GST_CLOCK_CAST (gst_object_ref (sink->provided_clock));
353   GST_OBJECT_UNLOCK (sink);
354 
355   return clock;
356 
357   /* ERRORS */
358 wrong_state:
359   {
360     GST_DEBUG_OBJECT (sink, "ringbuffer not acquired");
361     return NULL;
362   }
363 clock_disabled:
364   {
365     GST_DEBUG_OBJECT (sink, "clock provide disabled");
366     GST_OBJECT_UNLOCK (sink);
367     return NULL;
368   }
369 }
370 
371 static gboolean
gst_audio_base_sink_is_self_provided_clock(GstAudioBaseSink * sink)372 gst_audio_base_sink_is_self_provided_clock (GstAudioBaseSink * sink)
373 {
374   return (sink->provided_clock && GST_IS_AUDIO_CLOCK (sink->provided_clock) &&
375       GST_AUDIO_CLOCK_CAST (sink->provided_clock)->func ==
376       (GstAudioClockGetTimeFunc) gst_audio_base_sink_get_time);
377 }
378 
379 static gboolean
gst_audio_base_sink_query_pad(GstBaseSink * bsink,GstQuery * query)380 gst_audio_base_sink_query_pad (GstBaseSink * bsink, GstQuery * query)
381 {
382   gboolean res = FALSE;
383   GstAudioBaseSink *basesink;
384 
385   basesink = GST_AUDIO_BASE_SINK (bsink);
386 
387   switch (GST_QUERY_TYPE (query)) {
388     case GST_QUERY_CONVERT:
389     {
390       GstFormat src_fmt, dest_fmt;
391       gint64 src_val, dest_val;
392 
393       GST_LOG_OBJECT (basesink, "query convert");
394 
395       if (basesink->ringbuffer) {
396         gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, NULL);
397         res =
398             gst_audio_ring_buffer_convert (basesink->ringbuffer, src_fmt,
399             src_val, dest_fmt, &dest_val);
400         if (res) {
401           gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
402         }
403       }
404       break;
405     }
406     default:
407       res = GST_BASE_SINK_CLASS (parent_class)->query (bsink, query);
408       break;
409   }
410   return res;
411 }
412 
413 static gboolean
gst_audio_base_sink_query(GstElement * element,GstQuery * query)414 gst_audio_base_sink_query (GstElement * element, GstQuery * query)
415 {
416   gboolean res = FALSE;
417   GstAudioBaseSink *basesink;
418 
419   basesink = GST_AUDIO_BASE_SINK (element);
420 
421   switch (GST_QUERY_TYPE (query)) {
422     case GST_QUERY_LATENCY:
423     {
424       gboolean live, us_live;
425       GstClockTime min_l, max_l;
426 
427       GST_DEBUG_OBJECT (basesink, "latency query");
428 
429       /* ask parent first, it will do an upstream query for us. */
430       if ((res =
431               gst_base_sink_query_latency (GST_BASE_SINK_CAST (basesink), &live,
432                   &us_live, &min_l, &max_l))) {
433         GstClockTime base_latency, min_latency, max_latency;
434 
435         /* we and upstream are both live, adjust the min_latency */
436         if (live && us_live) {
437           GstAudioRingBufferSpec *spec;
438 
439           GST_OBJECT_LOCK (basesink);
440           if (!basesink->ringbuffer || !basesink->ringbuffer->spec.info.rate) {
441             GST_OBJECT_UNLOCK (basesink);
442 
443             GST_DEBUG_OBJECT (basesink,
444                 "we are not negotiated, can't report latency yet");
445             res = FALSE;
446             goto done;
447           }
448           spec = &basesink->ringbuffer->spec;
449 
450           basesink->priv->us_latency = min_l;
451 
452           base_latency =
453               gst_util_uint64_scale_int (spec->seglatency * spec->segsize,
454               GST_SECOND, spec->info.rate * spec->info.bpf);
455           GST_OBJECT_UNLOCK (basesink);
456 
457           /* we cannot go lower than the buffer size and the min peer latency */
458           min_latency = base_latency + min_l;
459           /* the max latency is the max of the peer, we can delay an infinite
460            * amount of time. */
461           max_latency = (max_l == -1) ? -1 : (base_latency + max_l);
462 
463           GST_DEBUG_OBJECT (basesink,
464               "peer min %" GST_TIME_FORMAT ", our min latency: %"
465               GST_TIME_FORMAT, GST_TIME_ARGS (min_l),
466               GST_TIME_ARGS (min_latency));
467           GST_DEBUG_OBJECT (basesink,
468               "peer max %" GST_TIME_FORMAT ", our max latency: %"
469               GST_TIME_FORMAT, GST_TIME_ARGS (max_l),
470               GST_TIME_ARGS (max_latency));
471         } else {
472           GST_DEBUG_OBJECT (basesink,
473               "peer or we are not live, don't care about latency");
474           min_latency = min_l;
475           max_latency = max_l;
476         }
477         gst_query_set_latency (query, live, min_latency, max_latency);
478       }
479       break;
480     }
481     case GST_QUERY_CONVERT:
482     {
483       GstFormat src_fmt, dest_fmt;
484       gint64 src_val, dest_val;
485 
486       GST_LOG_OBJECT (basesink, "query convert");
487 
488       if (basesink->ringbuffer) {
489         gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, NULL);
490         res =
491             gst_audio_ring_buffer_convert (basesink->ringbuffer, src_fmt,
492             src_val, dest_fmt, &dest_val);
493         if (res) {
494           gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
495         }
496       }
497       break;
498     }
499     default:
500       res = GST_ELEMENT_CLASS (parent_class)->query (element, query);
501       break;
502   }
503 
504 done:
505   return res;
506 }
507 
508 
509 /* we call this function without holding the lock on sink for performance
510  * reasons. Try hard to not deal with and invalid ringbuffer and rate. */
511 static GstClockTime
gst_audio_base_sink_get_time(GstClock * clock,GstAudioBaseSink * sink)512 gst_audio_base_sink_get_time (GstClock * clock, GstAudioBaseSink * sink)
513 {
514   guint64 raw, samples;
515   guint delay;
516   GstClockTime result;
517   GstAudioRingBuffer *ringbuffer;
518   gint rate;
519 
520   if ((ringbuffer = sink->ringbuffer) == NULL)
521     return GST_CLOCK_TIME_NONE;
522 
523   if ((rate = ringbuffer->spec.info.rate) == 0)
524     return GST_CLOCK_TIME_NONE;
525 
526   /* our processed samples are always increasing */
527   raw = samples = gst_audio_ring_buffer_samples_done (ringbuffer);
528 
529   /* the number of samples not yet processed, this is still queued in the
530    * device (not played for playback). */
531   delay = gst_audio_ring_buffer_delay (ringbuffer);
532 
533   if (G_LIKELY (samples >= delay))
534     samples -= delay;
535   else
536     samples = 0;
537 
538   result = gst_util_uint64_scale_int (samples, GST_SECOND, rate);
539 
540   GST_DEBUG_OBJECT (sink,
541       "processed samples: raw %" G_GUINT64_FORMAT ", delay %u, real %"
542       G_GUINT64_FORMAT ", time %" GST_TIME_FORMAT,
543       raw, delay, samples, GST_TIME_ARGS (result));
544 
545   return result;
546 }
547 
548 /**
549  * gst_audio_base_sink_set_provide_clock:
550  * @sink: a #GstAudioBaseSink
551  * @provide: new state
552  *
553  * Controls whether @sink will provide a clock or not. If @provide is %TRUE,
554  * gst_element_provide_clock() will return a clock that reflects the datarate
555  * of @sink. If @provide is %FALSE, gst_element_provide_clock() will return
556  * NULL.
557  */
558 void
gst_audio_base_sink_set_provide_clock(GstAudioBaseSink * sink,gboolean provide)559 gst_audio_base_sink_set_provide_clock (GstAudioBaseSink * sink,
560     gboolean provide)
561 {
562   g_return_if_fail (GST_IS_AUDIO_BASE_SINK (sink));
563 
564   GST_OBJECT_LOCK (sink);
565   if (provide)
566     GST_OBJECT_FLAG_SET (sink, GST_ELEMENT_FLAG_PROVIDE_CLOCK);
567   else
568     GST_OBJECT_FLAG_UNSET (sink, GST_ELEMENT_FLAG_PROVIDE_CLOCK);
569   GST_OBJECT_UNLOCK (sink);
570 }
571 
572 /**
573  * gst_audio_base_sink_get_provide_clock:
574  * @sink: a #GstAudioBaseSink
575  *
576  * Queries whether @sink will provide a clock or not. See also
577  * gst_audio_base_sink_set_provide_clock.
578  *
579  * Returns: %TRUE if @sink will provide a clock.
580  */
581 gboolean
gst_audio_base_sink_get_provide_clock(GstAudioBaseSink * sink)582 gst_audio_base_sink_get_provide_clock (GstAudioBaseSink * sink)
583 {
584   gboolean result;
585 
586   g_return_val_if_fail (GST_IS_AUDIO_BASE_SINK (sink), FALSE);
587 
588   GST_OBJECT_LOCK (sink);
589   result = GST_OBJECT_FLAG_IS_SET (sink, GST_ELEMENT_FLAG_PROVIDE_CLOCK);
590   GST_OBJECT_UNLOCK (sink);
591 
592   return result;
593 }
594 
595 /**
596  * gst_audio_base_sink_set_slave_method:
597  * @sink: a #GstAudioBaseSink
598  * @method: the new slave method
599  *
600  * Controls how clock slaving will be performed in @sink.
601  */
602 void
gst_audio_base_sink_set_slave_method(GstAudioBaseSink * sink,GstAudioBaseSinkSlaveMethod method)603 gst_audio_base_sink_set_slave_method (GstAudioBaseSink * sink,
604     GstAudioBaseSinkSlaveMethod method)
605 {
606   g_return_if_fail (GST_IS_AUDIO_BASE_SINK (sink));
607 
608   GST_OBJECT_LOCK (sink);
609   sink->priv->slave_method = method;
610   GST_OBJECT_UNLOCK (sink);
611 }
612 
613 /**
614  * gst_audio_base_sink_get_slave_method:
615  * @sink: a #GstAudioBaseSink
616  *
617  * Get the current slave method used by @sink.
618  *
619  * Returns: The current slave method used by @sink.
620  */
621 GstAudioBaseSinkSlaveMethod
gst_audio_base_sink_get_slave_method(GstAudioBaseSink * sink)622 gst_audio_base_sink_get_slave_method (GstAudioBaseSink * sink)
623 {
624   GstAudioBaseSinkSlaveMethod result;
625 
626   g_return_val_if_fail (GST_IS_AUDIO_BASE_SINK (sink), -1);
627 
628   GST_OBJECT_LOCK (sink);
629   result = sink->priv->slave_method;
630   GST_OBJECT_UNLOCK (sink);
631 
632   return result;
633 }
634 
635 
636 /**
637  * gst_audio_base_sink_set_drift_tolerance:
638  * @sink: a #GstAudioBaseSink
639  * @drift_tolerance: the new drift tolerance in microseconds
640  *
641  * Controls the sink's drift tolerance.
642  */
643 void
gst_audio_base_sink_set_drift_tolerance(GstAudioBaseSink * sink,gint64 drift_tolerance)644 gst_audio_base_sink_set_drift_tolerance (GstAudioBaseSink * sink,
645     gint64 drift_tolerance)
646 {
647   g_return_if_fail (GST_IS_AUDIO_BASE_SINK (sink));
648 
649   GST_OBJECT_LOCK (sink);
650   sink->priv->drift_tolerance = drift_tolerance;
651   GST_OBJECT_UNLOCK (sink);
652 }
653 
654 /**
655  * gst_audio_base_sink_get_drift_tolerance:
656  * @sink: a #GstAudioBaseSink
657  *
658  * Get the current drift tolerance, in microseconds, used by @sink.
659  *
660  * Returns: The current drift tolerance used by @sink.
661  */
662 gint64
gst_audio_base_sink_get_drift_tolerance(GstAudioBaseSink * sink)663 gst_audio_base_sink_get_drift_tolerance (GstAudioBaseSink * sink)
664 {
665   gint64 result;
666 
667   g_return_val_if_fail (GST_IS_AUDIO_BASE_SINK (sink), -1);
668 
669   GST_OBJECT_LOCK (sink);
670   result = sink->priv->drift_tolerance;
671   GST_OBJECT_UNLOCK (sink);
672 
673   return result;
674 }
675 
676 /**
677  * gst_audio_base_sink_set_alignment_threshold:
678  * @sink: a #GstAudioBaseSink
679  * @alignment_threshold: the new alignment threshold in nanoseconds
680  *
681  * Controls the sink's alignment threshold.
682  */
683 void
gst_audio_base_sink_set_alignment_threshold(GstAudioBaseSink * sink,GstClockTime alignment_threshold)684 gst_audio_base_sink_set_alignment_threshold (GstAudioBaseSink * sink,
685     GstClockTime alignment_threshold)
686 {
687   g_return_if_fail (GST_IS_AUDIO_BASE_SINK (sink));
688   g_return_if_fail (GST_CLOCK_TIME_IS_VALID (alignment_threshold));
689 
690   GST_OBJECT_LOCK (sink);
691   sink->priv->alignment_threshold = alignment_threshold;
692   GST_OBJECT_UNLOCK (sink);
693 }
694 
695 /**
696  * gst_audio_base_sink_get_alignment_threshold:
697  * @sink: a #GstAudioBaseSink
698  *
699  * Get the current alignment threshold, in nanoseconds, used by @sink.
700  *
701  * Returns: The current alignment threshold used by @sink.
702  */
703 GstClockTime
gst_audio_base_sink_get_alignment_threshold(GstAudioBaseSink * sink)704 gst_audio_base_sink_get_alignment_threshold (GstAudioBaseSink * sink)
705 {
706   GstClockTime result;
707 
708   g_return_val_if_fail (GST_IS_AUDIO_BASE_SINK (sink), GST_CLOCK_TIME_NONE);
709 
710   GST_OBJECT_LOCK (sink);
711   result = sink->priv->alignment_threshold;
712   GST_OBJECT_UNLOCK (sink);
713 
714   return result;
715 }
716 
717 /**
718  * gst_audio_base_sink_set_discont_wait:
719  * @sink: a #GstAudioBaseSink
720  * @discont_wait: the new discont wait in nanoseconds
721  *
722  * Controls how long the sink will wait before creating a discontinuity.
723  */
724 void
gst_audio_base_sink_set_discont_wait(GstAudioBaseSink * sink,GstClockTime discont_wait)725 gst_audio_base_sink_set_discont_wait (GstAudioBaseSink * sink,
726     GstClockTime discont_wait)
727 {
728   g_return_if_fail (GST_IS_AUDIO_BASE_SINK (sink));
729   g_return_if_fail (GST_CLOCK_TIME_IS_VALID (discont_wait));
730 
731   GST_OBJECT_LOCK (sink);
732   sink->priv->discont_wait = discont_wait;
733   GST_OBJECT_UNLOCK (sink);
734 }
735 
736 /**
737  * gst_audio_base_sink_set_custom_slaving_callback:
738  * @sink: a #GstAudioBaseSink
739  * @callback: a #GstAudioBaseSinkCustomSlavingCallback
740  * @user_data: user data passed to the callback
741  * @notify : called when user_data becomes unused
742  *
743  * Sets the custom slaving callback. This callback will
744  * be invoked if the slave-method property is set to
745  * GST_AUDIO_BASE_SINK_SLAVE_CUSTOM and the audio sink
746  * receives and plays samples.
747  *
748  * Setting the callback to NULL causes the sink to
749  * behave as if the GST_AUDIO_BASE_SINK_SLAVE_NONE
750  * method were used.
751  *
752  * Since: 1.6
753  */
754 void
gst_audio_base_sink_set_custom_slaving_callback(GstAudioBaseSink * sink,GstAudioBaseSinkCustomSlavingCallback callback,gpointer user_data,GDestroyNotify notify)755 gst_audio_base_sink_set_custom_slaving_callback (GstAudioBaseSink * sink,
756     GstAudioBaseSinkCustomSlavingCallback callback,
757     gpointer user_data, GDestroyNotify notify)
758 {
759   g_return_if_fail (GST_IS_AUDIO_BASE_SINK (sink));
760 
761   GST_OBJECT_LOCK (sink);
762   sink->priv->custom_slaving_callback = callback;
763   sink->priv->custom_slaving_cb_data = user_data;
764   sink->priv->custom_slaving_cb_notify = notify;
765   GST_OBJECT_UNLOCK (sink);
766 }
767 
768 static void
gst_audio_base_sink_custom_cb_report_discont(GstAudioBaseSink * sink,GstAudioBaseSinkDiscontReason discont_reason)769 gst_audio_base_sink_custom_cb_report_discont (GstAudioBaseSink * sink,
770     GstAudioBaseSinkDiscontReason discont_reason)
771 {
772   if ((sink->priv->custom_slaving_callback != NULL) &&
773       (sink->priv->slave_method == GST_AUDIO_BASE_SINK_SLAVE_CUSTOM)) {
774     sink->priv->custom_slaving_callback (sink, GST_CLOCK_TIME_NONE,
775         GST_CLOCK_TIME_NONE, NULL, discont_reason,
776         sink->priv->custom_slaving_cb_data);
777   }
778 }
779 
780 /**
781  * gst_audio_base_sink_report_device_failure:
782  * @sink: a #GstAudioBaseSink
783  *
784  * Informs this base class that the audio output device has failed for
785  * some reason, causing a discontinuity (for example, because the device
786  * recovered from the error, but lost all contents of its ring buffer).
787  * This function is typically called by derived classes, and is useful
788  * for the custom slave method.
789  *
790  * Since: 1.6
791  */
792 void
gst_audio_base_sink_report_device_failure(GstAudioBaseSink * sink)793 gst_audio_base_sink_report_device_failure (GstAudioBaseSink * sink)
794 {
795   g_return_if_fail (GST_IS_AUDIO_BASE_SINK (sink));
796 
797   GST_OBJECT_LOCK (sink);
798   gst_audio_base_sink_custom_cb_report_discont (sink,
799       GST_AUDIO_BASE_SINK_DISCONT_REASON_DEVICE_FAILURE);
800   GST_OBJECT_UNLOCK (sink);
801 }
802 
803 /**
804  * gst_audio_base_sink_get_discont_wait:
805  * @sink: a #GstAudioBaseSink
806  *
807  * Get the current discont wait, in nanoseconds, used by @sink.
808  *
809  * Returns: The current discont wait used by @sink.
810  */
811 GstClockTime
gst_audio_base_sink_get_discont_wait(GstAudioBaseSink * sink)812 gst_audio_base_sink_get_discont_wait (GstAudioBaseSink * sink)
813 {
814   GstClockTime result;
815 
816   g_return_val_if_fail (GST_IS_AUDIO_BASE_SINK (sink), -1);
817 
818   GST_OBJECT_LOCK (sink);
819   result = sink->priv->discont_wait;
820   GST_OBJECT_UNLOCK (sink);
821 
822   return result;
823 }
824 
825 static void
gst_audio_base_sink_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)826 gst_audio_base_sink_set_property (GObject * object, guint prop_id,
827     const GValue * value, GParamSpec * pspec)
828 {
829   GstAudioBaseSink *sink;
830 
831   sink = GST_AUDIO_BASE_SINK (object);
832 
833   switch (prop_id) {
834     case PROP_BUFFER_TIME:
835       sink->buffer_time = g_value_get_int64 (value);
836       break;
837     case PROP_LATENCY_TIME:
838       sink->latency_time = g_value_get_int64 (value);
839       break;
840     case PROP_PROVIDE_CLOCK:
841       gst_audio_base_sink_set_provide_clock (sink, g_value_get_boolean (value));
842       break;
843     case PROP_SLAVE_METHOD:
844       gst_audio_base_sink_set_slave_method (sink, g_value_get_enum (value));
845       break;
846     case PROP_CAN_ACTIVATE_PULL:
847       GST_BASE_SINK (sink)->can_activate_pull = g_value_get_boolean (value);
848       break;
849     case PROP_DRIFT_TOLERANCE:
850       gst_audio_base_sink_set_drift_tolerance (sink, g_value_get_int64 (value));
851       break;
852     case PROP_ALIGNMENT_THRESHOLD:
853       gst_audio_base_sink_set_alignment_threshold (sink,
854           g_value_get_uint64 (value));
855       break;
856     case PROP_DISCONT_WAIT:
857       gst_audio_base_sink_set_discont_wait (sink, g_value_get_uint64 (value));
858       break;
859     default:
860       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
861       break;
862   }
863 }
864 
865 static void
gst_audio_base_sink_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)866 gst_audio_base_sink_get_property (GObject * object, guint prop_id,
867     GValue * value, GParamSpec * pspec)
868 {
869   GstAudioBaseSink *sink;
870 
871   sink = GST_AUDIO_BASE_SINK (object);
872 
873   switch (prop_id) {
874     case PROP_BUFFER_TIME:
875       g_value_set_int64 (value, sink->buffer_time);
876       break;
877     case PROP_LATENCY_TIME:
878       g_value_set_int64 (value, sink->latency_time);
879       break;
880     case PROP_PROVIDE_CLOCK:
881       g_value_set_boolean (value, gst_audio_base_sink_get_provide_clock (sink));
882       break;
883     case PROP_SLAVE_METHOD:
884       g_value_set_enum (value, gst_audio_base_sink_get_slave_method (sink));
885       break;
886     case PROP_CAN_ACTIVATE_PULL:
887       g_value_set_boolean (value, GST_BASE_SINK (sink)->can_activate_pull);
888       break;
889     case PROP_DRIFT_TOLERANCE:
890       g_value_set_int64 (value, gst_audio_base_sink_get_drift_tolerance (sink));
891       break;
892     case PROP_ALIGNMENT_THRESHOLD:
893       g_value_set_uint64 (value,
894           gst_audio_base_sink_get_alignment_threshold (sink));
895       break;
896     case PROP_DISCONT_WAIT:
897       g_value_set_uint64 (value, gst_audio_base_sink_get_discont_wait (sink));
898       break;
899     default:
900       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
901       break;
902   }
903 }
904 
905 static gboolean
gst_audio_base_sink_setcaps(GstBaseSink * bsink,GstCaps * caps)906 gst_audio_base_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
907 {
908   GstAudioBaseSink *sink = GST_AUDIO_BASE_SINK (bsink);
909   GstAudioRingBufferSpec *spec;
910   GstClockTime now, internal_time;
911   GstClockTime crate_num, crate_denom;
912 
913   if (!sink->ringbuffer)
914     return FALSE;
915 
916   spec = &sink->ringbuffer->spec;
917 
918   if (G_UNLIKELY (spec->caps && gst_caps_is_equal (spec->caps, caps))) {
919     GST_DEBUG_OBJECT (sink,
920         "Ringbuffer caps haven't changed, skipping reconfiguration");
921     return TRUE;
922   }
923 
924   GST_DEBUG_OBJECT (sink, "release old ringbuffer");
925 
926   /* get current time, updates the last_time. When the subclass has a clock that
927    * restarts from 0 when a new format is negotiated, it will call
928    * gst_audio_clock_reset() which will use this last_time to create an offset
929    * so that time from the clock keeps on increasing monotonically. */
930   now = gst_clock_get_time (sink->provided_clock);
931   internal_time = gst_clock_get_internal_time (sink->provided_clock);
932 
933   GST_DEBUG_OBJECT (sink, "time was %" GST_TIME_FORMAT, GST_TIME_ARGS (now));
934 
935   /* release old ringbuffer */
936   gst_audio_ring_buffer_pause (sink->ringbuffer);
937   gst_audio_ring_buffer_activate (sink->ringbuffer, FALSE);
938   gst_audio_ring_buffer_release (sink->ringbuffer);
939 
940   GST_DEBUG_OBJECT (sink, "parse caps");
941 
942   spec->buffer_time = sink->buffer_time;
943   spec->latency_time = sink->latency_time;
944 
945   /* parse new caps */
946   if (!gst_audio_ring_buffer_parse_caps (spec, caps))
947     goto parse_error;
948 
949   gst_audio_ring_buffer_debug_spec_buff (spec);
950 
951   GST_DEBUG_OBJECT (sink, "acquire ringbuffer");
952   if (!gst_audio_ring_buffer_acquire (sink->ringbuffer, spec))
953     goto acquire_error;
954 
955   /* If we use our own clock, we need to adjust the offset since it will now
956    * restart from zero */
957   if (gst_audio_base_sink_is_self_provided_clock (sink))
958     gst_audio_clock_reset (GST_AUDIO_CLOCK (sink->provided_clock), 0);
959 
960   /* We need to resync since the ringbuffer restarted */
961   gst_audio_base_sink_reset_sync (sink);
962 
963   gst_audio_base_sink_custom_cb_report_discont (sink,
964       GST_AUDIO_BASE_SINK_DISCONT_REASON_NEW_CAPS);
965 
966   if (bsink->pad_mode == GST_PAD_MODE_PUSH) {
967     GST_DEBUG_OBJECT (sink, "activate ringbuffer");
968     gst_audio_ring_buffer_activate (sink->ringbuffer, TRUE);
969   }
970 
971   /* due to possible changes in the spec file we should recalibrate the clock */
972   gst_clock_get_calibration (sink->provided_clock, NULL, NULL,
973       &crate_num, &crate_denom);
974   gst_clock_set_calibration (sink->provided_clock,
975       internal_time, now, crate_num, crate_denom);
976 
977   /* calculate actual latency and buffer times.
978    * FIXME: In 2.0, store the latency_time internally in ns */
979   spec->latency_time = gst_util_uint64_scale (spec->segsize,
980       (GST_SECOND / GST_USECOND), spec->info.rate * spec->info.bpf);
981 
982   spec->buffer_time = spec->segtotal * spec->latency_time;
983 
984   gst_audio_ring_buffer_debug_spec_buff (spec);
985 
986   gst_element_post_message (GST_ELEMENT_CAST (bsink),
987       gst_message_new_latency (GST_OBJECT (bsink)));
988 
989   return TRUE;
990 
991   /* ERRORS */
992 parse_error:
993   {
994     GST_DEBUG_OBJECT (sink, "could not parse caps");
995     GST_ELEMENT_ERROR (sink, STREAM, FORMAT,
996         (NULL), ("cannot parse audio format."));
997     return FALSE;
998   }
999 acquire_error:
1000   {
1001     GST_DEBUG_OBJECT (sink, "could not acquire ringbuffer");
1002     return FALSE;
1003   }
1004 }
1005 
1006 static GstCaps *
gst_audio_base_sink_fixate(GstBaseSink * bsink,GstCaps * caps)1007 gst_audio_base_sink_fixate (GstBaseSink * bsink, GstCaps * caps)
1008 {
1009   GstStructure *s;
1010   gint width, depth;
1011 
1012   caps = gst_caps_make_writable (caps);
1013 
1014   s = gst_caps_get_structure (caps, 0);
1015 
1016   /* fields for all formats */
1017   gst_structure_fixate_field_nearest_int (s, "rate", 44100);
1018   gst_structure_fixate_field_nearest_int (s, "channels", 2);
1019   gst_structure_fixate_field_nearest_int (s, "width", 16);
1020 
1021   /* fields for int */
1022   if (gst_structure_has_field (s, "depth")) {
1023     gst_structure_get_int (s, "width", &width);
1024     /* round width to nearest multiple of 8 for the depth */
1025     depth = GST_ROUND_UP_8 (width);
1026     gst_structure_fixate_field_nearest_int (s, "depth", depth);
1027   }
1028   if (gst_structure_has_field (s, "signed"))
1029     gst_structure_fixate_field_boolean (s, "signed", TRUE);
1030   if (gst_structure_has_field (s, "endianness"))
1031     gst_structure_fixate_field_nearest_int (s, "endianness", G_BYTE_ORDER);
1032 
1033   caps = GST_BASE_SINK_CLASS (parent_class)->fixate (bsink, caps);
1034 
1035   return caps;
1036 }
1037 
1038 static inline void
gst_audio_base_sink_reset_sync(GstAudioBaseSink * sink)1039 gst_audio_base_sink_reset_sync (GstAudioBaseSink * sink)
1040 {
1041   sink->next_sample = -1;
1042   sink->priv->eos_time = -1;
1043   sink->priv->discont_time = -1;
1044   sink->priv->avg_skew = -1;
1045   sink->priv->last_align = 0;
1046 }
1047 
1048 static void
gst_audio_base_sink_get_times(GstBaseSink * bsink,GstBuffer * buffer,GstClockTime * start,GstClockTime * end)1049 gst_audio_base_sink_get_times (GstBaseSink * bsink, GstBuffer * buffer,
1050     GstClockTime * start, GstClockTime * end)
1051 {
1052   /* our clock sync is a bit too much for the base class to handle so
1053    * we implement it ourselves. */
1054   *start = GST_CLOCK_TIME_NONE;
1055   *end = GST_CLOCK_TIME_NONE;
1056 }
1057 
1058 static void
gst_audio_base_sink_force_start(GstAudioBaseSink * sink)1059 gst_audio_base_sink_force_start (GstAudioBaseSink * sink)
1060 {
1061   /* Set the eos_rendering flag so sub-classes definitely start the clock.
1062    * FIXME 2.0: Pass this as a flag to gst_audio_ring_buffer_start() */
1063   g_atomic_int_set (&sink->eos_rendering, 1);
1064   gst_audio_ring_buffer_start (sink->ringbuffer);
1065   g_atomic_int_set (&sink->eos_rendering, 0);
1066 }
1067 
1068 /* This waits for the drain to happen and can be canceled */
1069 static GstFlowReturn
gst_audio_base_sink_drain(GstAudioBaseSink * sink)1070 gst_audio_base_sink_drain (GstAudioBaseSink * sink)
1071 {
1072   GstFlowReturn ret = GST_FLOW_OK;
1073   if (!sink->ringbuffer)
1074     return ret;
1075   if (!sink->ringbuffer->spec.info.rate)
1076     return ret;
1077 
1078   /* if PLAYING is interrupted,
1079    * arrange to have clock running when going to PLAYING again */
1080   g_atomic_int_set (&sink->eos_rendering, 1);
1081 
1082   /* need to start playback before we can drain, but only when
1083    * we have successfully negotiated a format and thus acquired the
1084    * ringbuffer. */
1085   if (gst_audio_ring_buffer_is_acquired (sink->ringbuffer))
1086     gst_audio_ring_buffer_start (sink->ringbuffer);
1087 
1088   if (sink->priv->eos_time != -1) {
1089     GST_DEBUG_OBJECT (sink,
1090         "last sample time %" GST_TIME_FORMAT,
1091         GST_TIME_ARGS (sink->priv->eos_time));
1092 
1093     /* wait for the EOS time to be reached, this is the time when the last
1094      * sample is played. */
1095     ret = gst_base_sink_wait (GST_BASE_SINK (sink), sink->priv->eos_time, NULL);
1096 
1097     GST_DEBUG_OBJECT (sink, "drained audio");
1098   }
1099   g_atomic_int_set (&sink->eos_rendering, 0);
1100   return ret;
1101 }
1102 
1103 static GstFlowReturn
gst_audio_base_sink_wait_event(GstBaseSink * bsink,GstEvent * event)1104 gst_audio_base_sink_wait_event (GstBaseSink * bsink, GstEvent * event)
1105 {
1106   GstAudioBaseSink *sink = GST_AUDIO_BASE_SINK (bsink);
1107   GstFlowReturn ret = GST_FLOW_OK;
1108   gboolean clear_force_start_flag = FALSE;
1109 
1110   /* For both gap and EOS events, make sure the ringbuffer is running
1111    * before trying to wait on the event! */
1112   switch (GST_EVENT_TYPE (event)) {
1113     case GST_EVENT_EOS:
1114     case GST_EVENT_GAP:
1115       /* We must have a negotiated format before starting the ringbuffer */
1116       if (G_UNLIKELY (!gst_audio_ring_buffer_is_acquired (sink->ringbuffer))) {
1117         GST_ELEMENT_ERROR (sink, STREAM, FORMAT, (NULL),
1118             ("Sink not negotiated before %s event.",
1119                 GST_EVENT_TYPE_NAME (event)));
1120         return GST_FLOW_ERROR;
1121       }
1122 
1123       gst_audio_base_sink_force_start (sink);
1124       /* Make sure the ringbuffer will start again if interrupted during event_wait() */
1125       g_atomic_int_set (&sink->eos_rendering, 1);
1126       clear_force_start_flag = TRUE;
1127       break;
1128     default:
1129       break;
1130   }
1131 
1132   ret = GST_BASE_SINK_CLASS (parent_class)->wait_event (bsink, event);
1133   if (ret != GST_FLOW_OK)
1134     goto done;
1135 
1136   switch (GST_EVENT_TYPE (event)) {
1137     case GST_EVENT_EOS:
1138       /* now wait till we played everything */
1139       ret = gst_audio_base_sink_drain (sink);
1140       break;
1141     default:
1142       break;
1143   }
1144 
1145 done:
1146   if (clear_force_start_flag)
1147     g_atomic_int_set (&sink->eos_rendering, 0);
1148   return ret;
1149 }
1150 
1151 static gboolean
gst_audio_base_sink_event(GstBaseSink * bsink,GstEvent * event)1152 gst_audio_base_sink_event (GstBaseSink * bsink, GstEvent * event)
1153 {
1154   GstAudioBaseSink *sink = GST_AUDIO_BASE_SINK (bsink);
1155 
1156   switch (GST_EVENT_TYPE (event)) {
1157     case GST_EVENT_FLUSH_START:
1158       if (sink->ringbuffer)
1159         gst_audio_ring_buffer_set_flushing (sink->ringbuffer, TRUE);
1160       break;
1161     case GST_EVENT_FLUSH_STOP:
1162       /* always resync on sample after a flush */
1163       gst_audio_base_sink_reset_sync (sink);
1164 
1165       gst_audio_base_sink_custom_cb_report_discont (sink,
1166           GST_AUDIO_BASE_SINK_DISCONT_REASON_FLUSH);
1167 
1168       if (sink->ringbuffer)
1169         gst_audio_ring_buffer_set_flushing (sink->ringbuffer, FALSE);
1170       break;
1171     default:
1172       break;
1173   }
1174   return GST_BASE_SINK_CLASS (parent_class)->event (bsink, event);
1175 }
1176 
1177 static GstFlowReturn
gst_audio_base_sink_preroll(GstBaseSink * bsink,GstBuffer * buffer)1178 gst_audio_base_sink_preroll (GstBaseSink * bsink, GstBuffer * buffer)
1179 {
1180   GstAudioBaseSink *sink = GST_AUDIO_BASE_SINK (bsink);
1181 
1182   if (!gst_audio_ring_buffer_is_acquired (sink->ringbuffer))
1183     goto wrong_state;
1184 
1185   /* we don't really do anything when prerolling. We could make a
1186    * property to play this buffer to have some sort of scrubbing
1187    * support. */
1188   return GST_FLOW_OK;
1189 
1190 wrong_state:
1191   {
1192     GST_DEBUG_OBJECT (sink, "ringbuffer in wrong state");
1193     GST_ELEMENT_ERROR (sink, STREAM, FORMAT, (NULL), ("sink not negotiated."));
1194     return GST_FLOW_NOT_NEGOTIATED;
1195   }
1196 }
1197 
1198 static guint64
gst_audio_base_sink_get_offset(GstAudioBaseSink * sink)1199 gst_audio_base_sink_get_offset (GstAudioBaseSink * sink)
1200 {
1201   guint64 sample, sps;
1202   gint writeseg, segdone;
1203   gint diff;
1204 
1205   /* assume we can append to the previous sample */
1206   sample = sink->next_sample;
1207   /* no previous sample, try to insert at position 0 */
1208   if (sample == -1)
1209     sample = 0;
1210 
1211   sps = sink->ringbuffer->samples_per_seg;
1212 
1213   /* figure out the segment and the offset inside the segment where
1214    * the sample should be written. */
1215   writeseg = sample / sps;
1216 
1217   /* get the currently processed segment */
1218   segdone = g_atomic_int_get (&sink->ringbuffer->segdone)
1219       - sink->ringbuffer->segbase;
1220 
1221   /* see how far away it is from the write segment */
1222   diff = writeseg - segdone;
1223   if (diff < 0) {
1224     /* sample would be dropped, position to next playable position */
1225     sample = (segdone + 1) * sps;
1226   }
1227 
1228   return sample;
1229 }
1230 
1231 static GstClockTime
clock_convert_external(GstClockTime external,GstClockTime cinternal,GstClockTime cexternal,GstClockTime crate_num,GstClockTime crate_denom)1232 clock_convert_external (GstClockTime external, GstClockTime cinternal,
1233     GstClockTime cexternal, GstClockTime crate_num, GstClockTime crate_denom)
1234 {
1235   /* adjust for rate and speed */
1236   if (external >= cexternal) {
1237     external =
1238         gst_util_uint64_scale (external - cexternal, crate_denom, crate_num);
1239     external += cinternal;
1240   } else {
1241     external =
1242         gst_util_uint64_scale (cexternal - external, crate_denom, crate_num);
1243     if (cinternal > external)
1244       external = cinternal - external;
1245     else
1246       external = 0;
1247   }
1248   return external;
1249 }
1250 
1251 
1252 /* apply the clock offset and invoke a custom callback
1253  * which might also request changes to the playout pointer
1254  *
1255  * this reuses code from the skewing algorithm, but leaves
1256  * decision on whether or not to skew (and how much to skew)
1257  * up to the callback */
1258 static void
gst_audio_base_sink_custom_slaving(GstAudioBaseSink * sink,GstClockTime render_start,GstClockTime render_stop,GstClockTime * srender_start,GstClockTime * srender_stop)1259 gst_audio_base_sink_custom_slaving (GstAudioBaseSink * sink,
1260     GstClockTime render_start, GstClockTime render_stop,
1261     GstClockTime * srender_start, GstClockTime * srender_stop)
1262 {
1263   GstClockTime cinternal, cexternal, crate_num, crate_denom;
1264   GstClockTime etime, itime;
1265   GstClockTimeDiff requested_skew;
1266   gint driftsamples;
1267   gint64 last_align;
1268 
1269   /* get calibration parameters to compensate for offsets */
1270   gst_clock_get_calibration (sink->provided_clock, &cinternal, &cexternal,
1271       &crate_num, &crate_denom);
1272 
1273   /* sample clocks and figure out clock skew */
1274   etime = gst_clock_get_time (GST_ELEMENT_CLOCK (sink));
1275   itime = gst_audio_clock_get_time (GST_AUDIO_CLOCK (sink->provided_clock));
1276   itime =
1277       gst_audio_clock_adjust (GST_AUDIO_CLOCK (sink->provided_clock), itime);
1278 
1279   GST_DEBUG_OBJECT (sink,
1280       "internal %" GST_TIME_FORMAT " external %" GST_TIME_FORMAT
1281       " cinternal %" GST_TIME_FORMAT " cexternal %" GST_TIME_FORMAT,
1282       GST_TIME_ARGS (itime), GST_TIME_ARGS (etime),
1283       GST_TIME_ARGS (cinternal), GST_TIME_ARGS (cexternal));
1284 
1285   /* make sure we never go below 0 */
1286   etime = etime > cexternal ? etime - cexternal : 0;
1287   itime = itime > cinternal ? itime - cinternal : 0;
1288 
1289   /* don't do any skewing unless the callback explicitly requests one */
1290   requested_skew = 0;
1291 
1292   if (sink->priv->custom_slaving_callback != NULL) {
1293     sink->priv->custom_slaving_callback (sink, etime, itime, &requested_skew,
1294         FALSE, sink->priv->custom_slaving_cb_data);
1295     GST_DEBUG_OBJECT (sink, "custom slaving requested skew %" GST_STIME_FORMAT,
1296         GST_STIME_ARGS (requested_skew));
1297   } else {
1298     GST_DEBUG_OBJECT (sink,
1299         "no custom slaving callback set - clock drift will not be compensated");
1300   }
1301 
1302   if (requested_skew > 0) {
1303     cexternal = (cexternal > requested_skew) ? (cexternal - requested_skew) : 0;
1304 
1305     driftsamples =
1306         (sink->ringbuffer->spec.info.rate * requested_skew) / GST_SECOND;
1307     last_align = sink->priv->last_align;
1308 
1309     /* if we were aligning in the wrong direction or we aligned more than what we
1310      * will correct, resync */
1311     if ((last_align < 0) || (last_align > driftsamples))
1312       sink->next_sample = -1;
1313 
1314     GST_DEBUG_OBJECT (sink,
1315         "last_align %" G_GINT64_FORMAT " driftsamples %u, next %"
1316         G_GUINT64_FORMAT, last_align, driftsamples, sink->next_sample);
1317 
1318     gst_clock_set_calibration (sink->provided_clock, cinternal, cexternal,
1319         crate_num, crate_denom);
1320   } else if (requested_skew < 0) {
1321     cexternal += ABS (requested_skew);
1322 
1323     driftsamples =
1324         (sink->ringbuffer->spec.info.rate * ABS (requested_skew)) / GST_SECOND;
1325     last_align = sink->priv->last_align;
1326 
1327     /* if we were aligning in the wrong direction or we aligned more than what we
1328      * will correct, resync */
1329     if ((last_align > 0) || (-last_align > driftsamples))
1330       sink->next_sample = -1;
1331 
1332     GST_DEBUG_OBJECT (sink,
1333         "last_align %" G_GINT64_FORMAT " driftsamples %u, next %"
1334         G_GUINT64_FORMAT, last_align, driftsamples, sink->next_sample);
1335 
1336     gst_clock_set_calibration (sink->provided_clock, cinternal, cexternal,
1337         crate_num, crate_denom);
1338   }
1339 
1340   /* convert, ignoring speed */
1341   render_start = clock_convert_external (render_start, cinternal, cexternal,
1342       crate_num, crate_denom);
1343   render_stop = clock_convert_external (render_stop, cinternal, cexternal,
1344       crate_num, crate_denom);
1345 
1346   *srender_start = render_start;
1347   *srender_stop = render_stop;
1348 }
1349 
1350 /* algorithm to calculate sample positions that will result in resampling to
1351  * match the clock rate of the master */
1352 static void
gst_audio_base_sink_resample_slaving(GstAudioBaseSink * sink,GstClockTime render_start,GstClockTime render_stop,GstClockTime * srender_start,GstClockTime * srender_stop)1353 gst_audio_base_sink_resample_slaving (GstAudioBaseSink * sink,
1354     GstClockTime render_start, GstClockTime render_stop,
1355     GstClockTime * srender_start, GstClockTime * srender_stop)
1356 {
1357   GstClockTime cinternal, cexternal;
1358   GstClockTime crate_num, crate_denom;
1359 
1360   /* FIXME, we can sample and add observations here or use the timeouts on the
1361    * clock. No idea which one is better or more stable. The timeout seems more
1362    * arbitrary but this one seems more demanding and does not work when there is
1363    * no data coming in to the sink. */
1364 #if 0
1365   GstClockTime etime, itime;
1366   gdouble r_squared;
1367 
1368   /* sample clocks and figure out clock skew */
1369   etime = gst_clock_get_time (GST_ELEMENT_CLOCK (sink));
1370   itime = gst_audio_clock_get_time (sink->provided_clock);
1371 
1372   /* add new observation */
1373   gst_clock_add_observation (sink->provided_clock, itime, etime, &r_squared);
1374 #endif
1375 
1376   /* get calibration parameters to compensate for speed and offset differences
1377    * when we are slaved */
1378   gst_clock_get_calibration (sink->provided_clock, &cinternal, &cexternal,
1379       &crate_num, &crate_denom);
1380 
1381   GST_DEBUG_OBJECT (sink, "internal %" GST_TIME_FORMAT " external %"
1382       GST_TIME_FORMAT " %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT " = %f",
1383       GST_TIME_ARGS (cinternal), GST_TIME_ARGS (cexternal), crate_num,
1384       crate_denom, gst_guint64_to_gdouble (crate_num) /
1385       gst_guint64_to_gdouble (crate_denom));
1386 
1387   if (crate_num == 0)
1388     crate_denom = crate_num = 1;
1389 
1390   /* bring external time to internal time */
1391   render_start = clock_convert_external (render_start, cinternal, cexternal,
1392       crate_num, crate_denom);
1393   render_stop = clock_convert_external (render_stop, cinternal, cexternal,
1394       crate_num, crate_denom);
1395 
1396   GST_DEBUG_OBJECT (sink,
1397       "after slaving: start %" GST_TIME_FORMAT " - stop %" GST_TIME_FORMAT,
1398       GST_TIME_ARGS (render_start), GST_TIME_ARGS (render_stop));
1399 
1400   *srender_start = render_start;
1401   *srender_stop = render_stop;
1402 }
1403 
1404 /* algorithm to calculate sample positions that will result in changing the
1405  * playout pointer to match the clock rate of the master */
1406 static void
gst_audio_base_sink_skew_slaving(GstAudioBaseSink * sink,GstClockTime render_start,GstClockTime render_stop,GstClockTime * srender_start,GstClockTime * srender_stop)1407 gst_audio_base_sink_skew_slaving (GstAudioBaseSink * sink,
1408     GstClockTime render_start, GstClockTime render_stop,
1409     GstClockTime * srender_start, GstClockTime * srender_stop)
1410 {
1411   GstClockTime cinternal, cexternal, crate_num, crate_denom;
1412   GstClockTime etime, itime;
1413   GstClockTimeDiff skew, drift, mdrift2;
1414   gint driftsamples;
1415   gint64 last_align;
1416 
1417   /* get calibration parameters to compensate for offsets */
1418   gst_clock_get_calibration (sink->provided_clock, &cinternal, &cexternal,
1419       &crate_num, &crate_denom);
1420 
1421   /* sample clocks and figure out clock skew */
1422   etime = gst_clock_get_time (GST_ELEMENT_CLOCK (sink));
1423   itime = gst_audio_clock_get_time (GST_AUDIO_CLOCK (sink->provided_clock));
1424   itime =
1425       gst_audio_clock_adjust (GST_AUDIO_CLOCK (sink->provided_clock), itime);
1426 
1427   GST_DEBUG_OBJECT (sink,
1428       "internal %" GST_TIME_FORMAT " external %" GST_TIME_FORMAT
1429       " cinternal %" GST_TIME_FORMAT " cexternal %" GST_TIME_FORMAT,
1430       GST_TIME_ARGS (itime), GST_TIME_ARGS (etime),
1431       GST_TIME_ARGS (cinternal), GST_TIME_ARGS (cexternal));
1432 
1433   /* make sure we never go below 0 */
1434   etime = etime > cexternal ? etime - cexternal : 0;
1435   itime = itime > cinternal ? itime - cinternal : 0;
1436 
1437   /* do itime - etime.
1438    * positive value means external clock goes slower
1439    * negative value means external clock goes faster */
1440   skew = GST_CLOCK_DIFF (etime, itime);
1441   if (sink->priv->avg_skew == -1) {
1442     /* first observation */
1443     sink->priv->avg_skew = skew;
1444   } else {
1445     /* next observations use a moving average */
1446     sink->priv->avg_skew = (31 * sink->priv->avg_skew + skew) / 32;
1447   }
1448 
1449   GST_DEBUG_OBJECT (sink, "internal %" GST_TIME_FORMAT " external %"
1450       GST_TIME_FORMAT " skew %" GST_STIME_FORMAT " avg %" GST_STIME_FORMAT,
1451       GST_TIME_ARGS (itime), GST_TIME_ARGS (etime), GST_STIME_ARGS (skew),
1452       GST_STIME_ARGS (sink->priv->avg_skew));
1453 
1454   /* the max drift we allow */
1455   mdrift2 = (sink->priv->drift_tolerance * 1000) / 2;
1456 
1457   /* adjust playout pointer based on skew */
1458   if (sink->priv->avg_skew > mdrift2) {
1459     /* master is running slower, move external time backwards */
1460     GST_WARNING_OBJECT (sink,
1461         "correct clock skew %" GST_STIME_FORMAT " > %" GST_STIME_FORMAT,
1462         GST_STIME_ARGS (sink->priv->avg_skew), GST_STIME_ARGS (mdrift2));
1463 
1464     /* Move the external time backward by the average skew, but don't ever
1465      * go negative.  Moving the average skew by the same distance defines
1466      * the new clock skew window center point.  This allows the clock to
1467      * drift equally into either direction after the correction. */
1468     if (G_LIKELY (cexternal > sink->priv->avg_skew))
1469       drift = sink->priv->avg_skew;
1470     else
1471       drift = cexternal;
1472     cexternal -= drift;
1473     sink->priv->avg_skew -= drift;
1474 
1475     driftsamples = (sink->ringbuffer->spec.info.rate * drift) / GST_SECOND;
1476     last_align = sink->priv->last_align;
1477 
1478     /* if we were aligning in the wrong direction or we aligned more than what
1479      * we will correct, resync */
1480     if (last_align < 0 || last_align > driftsamples)
1481       sink->next_sample = -1;
1482 
1483     GST_DEBUG_OBJECT (sink,
1484         "last_align %" G_GINT64_FORMAT " driftsamples %u, next %"
1485         G_GUINT64_FORMAT, last_align, driftsamples, sink->next_sample);
1486 
1487     gst_clock_set_calibration (sink->provided_clock, cinternal, cexternal,
1488         crate_num, crate_denom);
1489   } else if (sink->priv->avg_skew < -mdrift2) {
1490     /* master is running faster, move external time forwards */
1491     GST_WARNING_OBJECT (sink,
1492         "correct clock skew %" GST_STIME_FORMAT " < -%" GST_STIME_FORMAT,
1493         GST_STIME_ARGS (sink->priv->avg_skew), GST_STIME_ARGS (mdrift2));
1494 
1495     /* Move the external time forward by the average skew, and move the
1496      * average skew by the same distance (which equals a reset to 0). This
1497      * defines the new clock skew window center point.  This allows the
1498      * clock to drift equally into either direction after the correction. */
1499     drift = -sink->priv->avg_skew;
1500     cexternal += drift;
1501     sink->priv->avg_skew = 0;
1502 
1503     driftsamples = (sink->ringbuffer->spec.info.rate * drift) / GST_SECOND;
1504     last_align = sink->priv->last_align;
1505 
1506     /* if we were aligning in the wrong direction or we aligned more than what
1507      * we will correct, resync */
1508     if (last_align > 0 || -last_align > driftsamples)
1509       sink->next_sample = -1;
1510 
1511     GST_DEBUG_OBJECT (sink,
1512         "last_align %" G_GINT64_FORMAT " driftsamples %u, next %"
1513         G_GUINT64_FORMAT, last_align, driftsamples, sink->next_sample);
1514 
1515     gst_clock_set_calibration (sink->provided_clock, cinternal, cexternal,
1516         crate_num, crate_denom);
1517   }
1518 
1519   /* convert, ignoring speed */
1520   render_start = clock_convert_external (render_start, cinternal, cexternal,
1521       crate_num, crate_denom);
1522   render_stop = clock_convert_external (render_stop, cinternal, cexternal,
1523       crate_num, crate_denom);
1524 
1525   *srender_start = render_start;
1526   *srender_stop = render_stop;
1527 }
1528 
1529 /* apply the clock offset but do no slaving otherwise */
1530 static void
gst_audio_base_sink_none_slaving(GstAudioBaseSink * sink,GstClockTime render_start,GstClockTime render_stop,GstClockTime * srender_start,GstClockTime * srender_stop)1531 gst_audio_base_sink_none_slaving (GstAudioBaseSink * sink,
1532     GstClockTime render_start, GstClockTime render_stop,
1533     GstClockTime * srender_start, GstClockTime * srender_stop)
1534 {
1535   GstClockTime cinternal, cexternal, crate_num, crate_denom;
1536 
1537   /* get calibration parameters to compensate for offsets */
1538   gst_clock_get_calibration (sink->provided_clock, &cinternal, &cexternal,
1539       &crate_num, &crate_denom);
1540 
1541   /* convert, ignoring speed */
1542   render_start = clock_convert_external (render_start, cinternal, cexternal,
1543       crate_num, crate_denom);
1544   render_stop = clock_convert_external (render_stop, cinternal, cexternal,
1545       crate_num, crate_denom);
1546 
1547   *srender_start = render_start;
1548   *srender_stop = render_stop;
1549 }
1550 
1551 /* converts render_start and render_stop to their slaved values */
1552 static void
gst_audio_base_sink_handle_slaving(GstAudioBaseSink * sink,GstClockTime render_start,GstClockTime render_stop,GstClockTime * srender_start,GstClockTime * srender_stop)1553 gst_audio_base_sink_handle_slaving (GstAudioBaseSink * sink,
1554     GstClockTime render_start, GstClockTime render_stop,
1555     GstClockTime * srender_start, GstClockTime * srender_stop)
1556 {
1557   switch (sink->priv->slave_method) {
1558     case GST_AUDIO_BASE_SINK_SLAVE_RESAMPLE:
1559       gst_audio_base_sink_resample_slaving (sink, render_start, render_stop,
1560           srender_start, srender_stop);
1561       break;
1562     case GST_AUDIO_BASE_SINK_SLAVE_SKEW:
1563       gst_audio_base_sink_skew_slaving (sink, render_start, render_stop,
1564           srender_start, srender_stop);
1565       break;
1566     case GST_AUDIO_BASE_SINK_SLAVE_NONE:
1567       gst_audio_base_sink_none_slaving (sink, render_start, render_stop,
1568           srender_start, srender_stop);
1569       break;
1570     case GST_AUDIO_BASE_SINK_SLAVE_CUSTOM:
1571       gst_audio_base_sink_custom_slaving (sink, render_start, render_stop,
1572           srender_start, srender_stop);
1573       break;
1574     default:
1575       g_warning ("unknown slaving method %d", sink->priv->slave_method);
1576       break;
1577   }
1578 }
1579 
1580 /* must be called with LOCK */
1581 static GstFlowReturn
gst_audio_base_sink_sync_latency(GstBaseSink * bsink,GstMiniObject * obj)1582 gst_audio_base_sink_sync_latency (GstBaseSink * bsink, GstMiniObject * obj)
1583 {
1584   GstClock *clock;
1585   GstClockReturn status;
1586   GstClockTime time, render_delay;
1587   GstFlowReturn ret;
1588   GstAudioBaseSink *sink;
1589   GstClockTime itime, etime;
1590   GstClockTime rate_num, rate_denom;
1591   GstClockTimeDiff jitter;
1592 
1593   sink = GST_AUDIO_BASE_SINK (bsink);
1594 
1595   clock = GST_ELEMENT_CLOCK (sink);
1596   if (G_UNLIKELY (clock == NULL))
1597     goto no_clock;
1598 
1599   /* we provided the global clock, don't need to do anything special */
1600   if (clock == sink->provided_clock)
1601     goto no_slaving;
1602 
1603   GST_OBJECT_UNLOCK (sink);
1604 
1605   do {
1606     GST_DEBUG_OBJECT (sink, "checking preroll");
1607 
1608     ret = gst_base_sink_do_preroll (bsink, obj);
1609     if (ret != GST_FLOW_OK)
1610       goto flushing;
1611 
1612     GST_OBJECT_LOCK (sink);
1613     time = sink->priv->us_latency;
1614     GST_OBJECT_UNLOCK (sink);
1615 
1616     /* Renderdelay is added onto our own latency, and needs
1617      * to be subtracted as well */
1618     render_delay = gst_base_sink_get_render_delay (bsink);
1619 
1620     if (G_LIKELY (time > render_delay))
1621       time -= render_delay;
1622     else
1623       time = 0;
1624 
1625     /* preroll done, we can sync since we are in PLAYING now. */
1626     GST_DEBUG_OBJECT (sink, "possibly waiting for clock to reach %"
1627         GST_TIME_FORMAT, GST_TIME_ARGS (time));
1628 
1629     /* wait for the clock, this can be interrupted because we got shut down or
1630      * we PAUSED. */
1631     status = gst_base_sink_wait_clock (bsink, time, &jitter);
1632 
1633     GST_DEBUG_OBJECT (sink, "clock returned %d %" GST_TIME_FORMAT, status,
1634         GST_TIME_ARGS (jitter));
1635 
1636     /* invalid time, no clock or sync disabled, just continue then */
1637     if (status == GST_CLOCK_BADTIME)
1638       break;
1639 
1640     /* waiting could have been interrupted and we can be flushing now */
1641     if (G_UNLIKELY (bsink->flushing))
1642       goto flushing;
1643 
1644     /* retry if we got unscheduled, which means we did not reach the timeout
1645      * yet. if some other error occurs, we continue. */
1646   } while (status == GST_CLOCK_UNSCHEDULED);
1647 
1648   GST_DEBUG_OBJECT (sink, "latency synced");
1649 
1650   /* We might need to take the object lock within gst_audio_clock_get_time(),
1651    * so call that before we take it again */
1652   itime = gst_audio_clock_get_time (GST_AUDIO_CLOCK (sink->provided_clock));
1653   itime =
1654       gst_audio_clock_adjust (GST_AUDIO_CLOCK (sink->provided_clock), itime);
1655 
1656   GST_OBJECT_LOCK (sink);
1657 
1658   /* when we prerolled in time, we can accurately set the calibration,
1659    * our internal clock should exactly have been the latency (== the running
1660    * time of the external clock) */
1661   etime = GST_ELEMENT_CAST (sink)->base_time + time;
1662 
1663   if (status == GST_CLOCK_EARLY) {
1664     /* when we prerolled late, we have to take into account the lateness */
1665     GST_DEBUG_OBJECT (sink, "late preroll, adding jitter");
1666     etime += jitter;
1667   }
1668 
1669   /* start ringbuffer so we can start slaving right away when we need to */
1670   gst_audio_base_sink_force_start (sink);
1671 
1672   GST_DEBUG_OBJECT (sink,
1673       "internal time: %" GST_TIME_FORMAT " external time: %" GST_TIME_FORMAT,
1674       GST_TIME_ARGS (itime), GST_TIME_ARGS (etime));
1675 
1676   /* copy the original calibrated rate but update the internal and external
1677    * times. */
1678   gst_clock_get_calibration (sink->provided_clock, NULL, NULL, &rate_num,
1679       &rate_denom);
1680   gst_clock_set_calibration (sink->provided_clock, itime, etime,
1681       rate_num, rate_denom);
1682 
1683   switch (sink->priv->slave_method) {
1684     case GST_AUDIO_BASE_SINK_SLAVE_RESAMPLE:
1685       /* only set as master when we are resampling */
1686       GST_DEBUG_OBJECT (sink, "Setting clock as master");
1687       gst_clock_set_master (sink->provided_clock, clock);
1688       break;
1689     case GST_AUDIO_BASE_SINK_SLAVE_SKEW:
1690     case GST_AUDIO_BASE_SINK_SLAVE_NONE:
1691     case GST_AUDIO_BASE_SINK_SLAVE_CUSTOM:
1692     default:
1693       break;
1694   }
1695 
1696   gst_audio_base_sink_reset_sync (sink);
1697 
1698   gst_audio_base_sink_custom_cb_report_discont (sink,
1699       GST_AUDIO_BASE_SINK_DISCONT_REASON_SYNC_LATENCY);
1700 
1701   return GST_FLOW_OK;
1702 
1703   /* ERRORS */
1704 no_clock:
1705   {
1706     GST_DEBUG_OBJECT (sink, "we have no clock");
1707     return GST_FLOW_OK;
1708   }
1709 no_slaving:
1710   {
1711     GST_DEBUG_OBJECT (sink, "we are not slaved");
1712     return GST_FLOW_OK;
1713   }
1714 flushing:
1715   {
1716     GST_DEBUG_OBJECT (sink, "we are flushing");
1717     GST_OBJECT_LOCK (sink);
1718     return GST_FLOW_FLUSHING;
1719   }
1720 }
1721 
1722 static gint64
gst_audio_base_sink_get_alignment(GstAudioBaseSink * sink,GstClockTime sample_offset)1723 gst_audio_base_sink_get_alignment (GstAudioBaseSink * sink,
1724     GstClockTime sample_offset)
1725 {
1726   GstAudioRingBuffer *ringbuf = sink->ringbuffer;
1727   gint64 align;
1728   gint64 sample_diff;
1729   gint64 max_sample_diff;
1730   gint segdone = g_atomic_int_get (&ringbuf->segdone) - ringbuf->segbase;
1731   gint64 samples_done = segdone * (gint64) ringbuf->samples_per_seg;
1732   gint64 headroom = sample_offset - samples_done;
1733   gboolean allow_align = TRUE;
1734   gboolean discont = FALSE;
1735   gint rate;
1736 
1737   /* now try to align the sample to the previous one. */
1738 
1739   /* calc align with previous sample and determine how big the
1740    * difference is. */
1741   align = sink->next_sample - sample_offset;
1742   sample_diff = ABS (align);
1743 
1744   /* calculate the max allowed drift in units of samples. */
1745   rate = GST_AUDIO_INFO_RATE (&ringbuf->spec.info);
1746   max_sample_diff = gst_util_uint64_scale_int (sink->priv->alignment_threshold,
1747       rate, GST_SECOND);
1748 
1749   /* don't align if it means writing behind the read-segment */
1750   if (sample_diff > headroom && align < 0)
1751     allow_align = FALSE;
1752 
1753   if (G_UNLIKELY (sample_diff >= max_sample_diff)) {
1754     /* wait before deciding to make a discontinuity */
1755     if (sink->priv->discont_wait > 0) {
1756       GstClockTime time = gst_util_uint64_scale_int (sample_offset,
1757           GST_SECOND, rate);
1758       if (sink->priv->discont_time == -1) {
1759         /* discont candidate */
1760         sink->priv->discont_time = time;
1761       } else if (time - sink->priv->discont_time >= sink->priv->discont_wait) {
1762         /* discont_wait expired, discontinuity detected */
1763         discont = TRUE;
1764         sink->priv->discont_time = -1;
1765       }
1766     } else {
1767       discont = TRUE;
1768     }
1769   } else if (G_UNLIKELY (sink->priv->discont_time != -1)) {
1770     /* we have had a discont, but are now back on track! */
1771     sink->priv->discont_time = -1;
1772   }
1773 
1774   if (G_LIKELY (!discont && allow_align)) {
1775     GST_DEBUG_OBJECT (sink,
1776         "align with prev sample, ABS (%" G_GINT64_FORMAT ") < %"
1777         G_GINT64_FORMAT, align, max_sample_diff);
1778   } else {
1779     gint64 diff_s G_GNUC_UNUSED;
1780 
1781     /* calculate sample diff in seconds for error message */
1782     diff_s = gst_util_uint64_scale_int (sample_diff, GST_SECOND, rate);
1783 
1784     /* timestamps drifted apart from previous samples too much, we need to
1785      * resync. We log this as an element warning. */
1786     GST_WARNING_OBJECT (sink,
1787         "Unexpected discontinuity in audio timestamps of "
1788         "%s%" GST_TIME_FORMAT ", resyncing",
1789         sample_offset > sink->next_sample ? "+" : "-", GST_TIME_ARGS (diff_s));
1790     align = 0;
1791 
1792     gst_audio_base_sink_custom_cb_report_discont (sink,
1793         GST_AUDIO_BASE_SINK_DISCONT_REASON_ALIGNMENT);
1794   }
1795 
1796   return align;
1797 }
1798 
1799 static GstFlowReturn
gst_audio_base_sink_render(GstBaseSink * bsink,GstBuffer * buf)1800 gst_audio_base_sink_render (GstBaseSink * bsink, GstBuffer * buf)
1801 {
1802   GstClockTime time, stop, render_start, render_stop, sample_offset;
1803   GstClockTimeDiff sync_offset, ts_offset;
1804   GstAudioBaseSinkClass *bclass;
1805   GstAudioBaseSink *sink;
1806   GstAudioRingBuffer *ringbuf;
1807   gint64 diff, align;
1808   guint64 ctime, cstop;
1809   gsize offset;
1810   GstMapInfo info;
1811   gsize size;
1812   guint samples, written;
1813   gint bpf, rate;
1814   gint accum;
1815   gint out_samples;
1816   GstClockTime base_time, render_delay, latency;
1817   GstClock *clock;
1818   gboolean sync, slaved, align_next;
1819   GstFlowReturn ret;
1820   GstSegment clip_seg;
1821   gint64 time_offset;
1822   GstBuffer *out = NULL;
1823 
1824   sink = GST_AUDIO_BASE_SINK (bsink);
1825   bclass = GST_AUDIO_BASE_SINK_GET_CLASS (sink);
1826 
1827   ringbuf = sink->ringbuffer;
1828 
1829   /* can't do anything when we don't have the device */
1830   if (G_UNLIKELY (!gst_audio_ring_buffer_is_acquired (ringbuf)))
1831     goto wrong_state;
1832 
1833   /* Wait for upstream latency before starting the ringbuffer, we do this so
1834    * that we can align the first sample of the ringbuffer to the base_time +
1835    * latency. */
1836   GST_OBJECT_LOCK (sink);
1837   base_time = GST_ELEMENT_CAST (sink)->base_time;
1838   if (G_UNLIKELY (sink->priv->sync_latency)) {
1839     ret = gst_audio_base_sink_sync_latency (bsink, GST_MINI_OBJECT_CAST (buf));
1840     GST_OBJECT_UNLOCK (sink);
1841     if (G_UNLIKELY (ret != GST_FLOW_OK))
1842       goto sync_latency_failed;
1843     /* only do this once until we are set back to PLAYING */
1844     sink->priv->sync_latency = FALSE;
1845   } else {
1846     GST_OBJECT_UNLOCK (sink);
1847   }
1848 
1849   /* Before we go on, let's see if we need to payload the data. If yes, we also
1850    * need to unref the output buffer before leaving. */
1851   if (bclass->payload) {
1852     out = bclass->payload (sink, buf);
1853 
1854     if (!out)
1855       goto payload_failed;
1856 
1857     buf = out;
1858   }
1859 
1860   bpf = GST_AUDIO_INFO_BPF (&ringbuf->spec.info);
1861   rate = GST_AUDIO_INFO_RATE (&ringbuf->spec.info);
1862 
1863   size = gst_buffer_get_size (buf);
1864   if (G_UNLIKELY (size % bpf) != 0)
1865     goto wrong_size;
1866 
1867   samples = size / bpf;
1868 
1869   time = GST_BUFFER_PTS (buf);
1870 
1871   /* Last ditch attempt to ensure that we only play silence if
1872    * we are in trickmode no-audio mode (or if a buffer is marked as a GAP)
1873    * by dropping the buffer contents and rendering as a gap event instead */
1874   if (G_UNLIKELY ((bsink->segment.flags & GST_SEGMENT_FLAG_TRICKMODE_NO_AUDIO)
1875           || (buf && GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_GAP)))) {
1876     GstClockTime duration;
1877     GstEvent *event;
1878     GstBaseSinkClass *bclass;
1879     GST_DEBUG_OBJECT (bsink,
1880         "Received GAP or ignoring audio for trickplay. Dropping contents");
1881 
1882     duration = gst_util_uint64_scale_int (samples, GST_SECOND, rate);
1883     event = gst_event_new_gap (time, duration);
1884 
1885     bclass = GST_BASE_SINK_GET_CLASS (bsink);
1886     ret = bclass->wait_event (bsink, event);
1887     gst_event_unref (event);
1888 
1889     /* Ensure we'll resync on the next buffer as if discont */
1890     sink->next_sample = -1;
1891     goto done;
1892   }
1893 
1894   GST_DEBUG_OBJECT (sink,
1895       "time %" GST_TIME_FORMAT ", start %"
1896       GST_TIME_FORMAT ", samples %u", GST_TIME_ARGS (time),
1897       GST_TIME_ARGS (bsink->segment.start), samples);
1898 
1899   offset = 0;
1900 
1901   /* if not valid timestamp or we can't clip or sync, try to play
1902    * sample ASAP */
1903   if (!GST_CLOCK_TIME_IS_VALID (time)) {
1904     render_start = gst_audio_base_sink_get_offset (sink);
1905     render_stop = render_start + samples;
1906     GST_DEBUG_OBJECT (sink, "Buffer of size %" G_GSIZE_FORMAT " has no time."
1907         " Using render_start=%" G_GUINT64_FORMAT, size, render_start);
1908     /* we don't have a start so we don't know stop either */
1909     stop = -1;
1910     goto no_align;
1911   }
1912 
1913   /* let's calc stop based on the number of samples in the buffer instead
1914    * of trusting the DURATION */
1915   stop = time + gst_util_uint64_scale_int (samples, GST_SECOND, rate);
1916 
1917   /* prepare the clipping segment. Since we will be subtracting ts-offset and
1918    * device-delay later we scale the start and stop with those values so that we
1919    * can correctly clip them */
1920   clip_seg.format = GST_FORMAT_TIME;
1921   clip_seg.start = bsink->segment.start;
1922   clip_seg.stop = bsink->segment.stop;
1923   clip_seg.duration = -1;
1924 
1925   /* the sync offset is the combination of ts-offset and device-delay */
1926   latency = gst_base_sink_get_latency (bsink);
1927   ts_offset = gst_base_sink_get_ts_offset (bsink);
1928   render_delay = gst_base_sink_get_render_delay (bsink);
1929   sync_offset = ts_offset - render_delay + latency;
1930 
1931   GST_DEBUG_OBJECT (sink,
1932       "sync-offset %" GST_STIME_FORMAT ", render-delay %" GST_TIME_FORMAT
1933       ", ts-offset %" GST_STIME_FORMAT, GST_STIME_ARGS (sync_offset),
1934       GST_TIME_ARGS (render_delay), GST_STIME_ARGS (ts_offset));
1935 
1936   /* compensate for ts-offset and device-delay when negative we need to
1937    * clip. */
1938   if (G_UNLIKELY (sync_offset < 0)) {
1939     clip_seg.start += -sync_offset;
1940     if (clip_seg.stop != -1)
1941       clip_seg.stop += -sync_offset;
1942   }
1943 
1944   /* samples should be rendered based on their timestamp. All samples
1945    * arriving before the segment.start or after segment.stop are to be
1946    * thrown away. All samples should also be clipped to the segment
1947    * boundaries */
1948   if (G_UNLIKELY (!gst_segment_clip (&clip_seg, GST_FORMAT_TIME, time, stop,
1949               &ctime, &cstop)))
1950     goto out_of_segment;
1951 
1952   /* see if some clipping happened */
1953   diff = ctime - time;
1954   if (G_UNLIKELY (diff > 0)) {
1955     /* bring clipped time to samples */
1956     diff = gst_util_uint64_scale_int (diff, rate, GST_SECOND);
1957     GST_DEBUG_OBJECT (sink, "clipping start to %" GST_TIME_FORMAT " %"
1958         G_GUINT64_FORMAT " samples", GST_TIME_ARGS (ctime), diff);
1959     samples -= diff;
1960     offset += diff * bpf;
1961     time = ctime;
1962   }
1963   diff = stop - cstop;
1964   if (G_UNLIKELY (diff > 0)) {
1965     /* bring clipped time to samples */
1966     diff = gst_util_uint64_scale_int (diff, rate, GST_SECOND);
1967     GST_DEBUG_OBJECT (sink, "clipping stop to %" GST_TIME_FORMAT " %"
1968         G_GUINT64_FORMAT " samples", GST_TIME_ARGS (cstop), diff);
1969     samples -= diff;
1970     stop = cstop;
1971   }
1972 
1973   /* figure out how to sync */
1974   if (G_LIKELY ((clock = GST_ELEMENT_CLOCK (bsink))))
1975     sync = bsink->sync;
1976   else
1977     sync = FALSE;
1978 
1979   if (G_UNLIKELY (!sync)) {
1980     /* no sync needed, play sample ASAP */
1981     render_start = gst_audio_base_sink_get_offset (sink);
1982     render_stop = render_start + samples;
1983     GST_DEBUG_OBJECT (sink,
1984         "no sync needed. Using render_start=%" G_GUINT64_FORMAT, render_start);
1985     goto no_align;
1986   }
1987 
1988   /* bring buffer start and stop times to running time */
1989   render_start =
1990       gst_segment_to_running_time (&bsink->segment, GST_FORMAT_TIME, time);
1991   render_stop =
1992       gst_segment_to_running_time (&bsink->segment, GST_FORMAT_TIME, stop);
1993 
1994   if (render_start == GST_CLOCK_TIME_NONE || render_stop == GST_CLOCK_TIME_NONE)
1995     goto too_late;
1996 
1997   GST_DEBUG_OBJECT (sink,
1998       "running: start %" GST_TIME_FORMAT " - stop %" GST_TIME_FORMAT,
1999       GST_TIME_ARGS (render_start), GST_TIME_ARGS (render_stop));
2000 
2001   /* store the time of the last sample, we'll use this to perform sync on the
2002    * last sample when draining the buffer */
2003   if (G_LIKELY (bsink->segment.rate >= 0.0)) {
2004     sink->priv->eos_time = render_stop;
2005   } else {
2006     sink->priv->eos_time = render_start;
2007   }
2008 
2009   if (G_UNLIKELY (sync_offset != 0)) {
2010     /* compensate for ts-offset and delay. We know this will not underflow
2011      * because we clipped above. */
2012     GST_DEBUG_OBJECT (sink,
2013         "compensating for sync-offset %" GST_TIME_FORMAT,
2014         GST_TIME_ARGS (sync_offset));
2015     render_start += sync_offset;
2016     render_stop += sync_offset;
2017   }
2018 
2019   if (base_time != 0) {
2020     GST_DEBUG_OBJECT (sink, "adding base_time %" GST_TIME_FORMAT,
2021         GST_TIME_ARGS (base_time));
2022 
2023     /* add base time to sync against the clock */
2024     render_start += base_time;
2025     render_stop += base_time;
2026   }
2027 
2028   if (G_UNLIKELY ((slaved = (clock != sink->provided_clock)))) {
2029     /* handle clock slaving */
2030     gst_audio_base_sink_handle_slaving (sink, render_start, render_stop,
2031         &render_start, &render_stop);
2032   } else {
2033     /* no slaving needed but we need to adapt to the clock calibration
2034      * parameters */
2035     gst_audio_base_sink_none_slaving (sink, render_start, render_stop,
2036         &render_start, &render_stop);
2037   }
2038 
2039   GST_DEBUG_OBJECT (sink,
2040       "final timestamps: start %" GST_TIME_FORMAT " - stop %" GST_TIME_FORMAT,
2041       GST_TIME_ARGS (render_start), GST_TIME_ARGS (render_stop));
2042 
2043   /* bring to position in the ringbuffer */
2044   time_offset = GST_AUDIO_CLOCK_CAST (sink->provided_clock)->time_offset;
2045 
2046   if (G_UNLIKELY (time_offset != 0)) {
2047     GST_DEBUG_OBJECT (sink,
2048         "apply time offset %" GST_STIME_FORMAT, GST_STIME_ARGS (time_offset));
2049 
2050     if (render_start > time_offset)
2051       render_start -= time_offset;
2052     else
2053       render_start = 0;
2054     if (render_stop > time_offset)
2055       render_stop -= time_offset;
2056     else
2057       render_stop = 0;
2058   }
2059 
2060   /* in some clock slaving cases, all late samples end up at 0 first,
2061    * and subsequent ones align with that until threshold exceeded,
2062    * and then sync back to 0 and so on, so avoid that altogether */
2063   if (G_UNLIKELY (render_start == 0 && render_stop == 0))
2064     goto too_late;
2065 
2066   /* and bring the time to the rate corrected offset in the buffer */
2067   render_start = gst_util_uint64_scale_int (render_start, rate, GST_SECOND);
2068   render_stop = gst_util_uint64_scale_int (render_stop, rate, GST_SECOND);
2069 
2070   /* If the slaving got us an interval spanning 0, render_start will
2071      have been set to 0. So if render_start is 0, we check whether
2072      render_stop is set to contain all samples. If not, we need to
2073      drop samples to match. */
2074   if (render_start == 0) {
2075     guint nsamples = render_stop - render_start;
2076     if (nsamples < samples) {
2077       guint diff;
2078 
2079       diff = samples - nsamples;
2080       GST_DEBUG_OBJECT (bsink, "Clipped start: %u/%u samples", nsamples,
2081           samples);
2082       samples -= diff;
2083       offset += diff * bpf;
2084     }
2085   }
2086 
2087   /* positive playback rate, first sample is render_start, negative rate, first
2088    * sample is render_stop. When no rate conversion is active, render exactly
2089    * the amount of input samples to avoid aligning to rounding errors. */
2090   if (G_LIKELY (bsink->segment.rate >= 0.0)) {
2091     sample_offset = render_start;
2092     if (G_LIKELY (bsink->segment.rate == 1.0))
2093       render_stop = sample_offset + samples;
2094   } else {
2095     sample_offset = render_stop;
2096     if (bsink->segment.rate == -1.0)
2097       render_start = sample_offset + samples;
2098   }
2099 
2100   /* always resync after a discont */
2101   if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT) ||
2102           GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_RESYNC))) {
2103     GST_DEBUG_OBJECT (sink, "resync after discont/resync");
2104     goto no_align;
2105   }
2106 
2107   /* resync when we don't know what to align the sample with */
2108   if (G_UNLIKELY (sink->next_sample == -1)) {
2109     GST_DEBUG_OBJECT (sink,
2110         "no align possible: no previous sample position known");
2111     goto no_align;
2112   }
2113 
2114   align = gst_audio_base_sink_get_alignment (sink, sample_offset);
2115   sink->priv->last_align = align;
2116 
2117   /* apply alignment */
2118   render_start += align;
2119 
2120   /* only align stop if we are not slaved to resample */
2121   if (G_UNLIKELY (slaved
2122           && sink->priv->slave_method == GST_AUDIO_BASE_SINK_SLAVE_RESAMPLE)) {
2123     GST_DEBUG_OBJECT (sink, "no stop time align needed: we are slaved");
2124     goto no_align;
2125   }
2126   render_stop += align;
2127 
2128 no_align:
2129   /* number of target samples is difference between start and stop */
2130   out_samples = render_stop - render_start;
2131 
2132   /* we render the first or last sample first, depending on the rate */
2133   if (G_LIKELY (bsink->segment.rate >= 0.0))
2134     sample_offset = render_start;
2135   else
2136     sample_offset = render_stop;
2137 
2138   GST_DEBUG_OBJECT (sink, "rendering at %" G_GUINT64_FORMAT " %d/%d",
2139       sample_offset, samples, out_samples);
2140 
2141   /* we need to accumulate over different runs for when we get interrupted */
2142   accum = 0;
2143   align_next = TRUE;
2144   gst_buffer_map (buf, &info, GST_MAP_READ);
2145   do {
2146     written =
2147         gst_audio_ring_buffer_commit (ringbuf, &sample_offset,
2148         info.data + offset, samples, out_samples, &accum);
2149 
2150     GST_DEBUG_OBJECT (sink, "wrote %u of %u", written, samples);
2151     /* if we wrote all, we're done */
2152     if (G_LIKELY (written == samples))
2153       break;
2154 
2155     /* else something interrupted us and we wait for preroll. */
2156     if ((ret = gst_base_sink_wait_preroll (bsink)) != GST_FLOW_OK)
2157       goto stopping;
2158 
2159     /* if we got interrupted, we cannot assume that the next sample should
2160      * be aligned to this one */
2161     align_next = FALSE;
2162 
2163     /* update the output samples. FIXME, this will just skip them when pausing
2164      * during trick mode */
2165     if (out_samples > written) {
2166       out_samples -= written;
2167       accum = 0;
2168     } else
2169       break;
2170 
2171     samples -= written;
2172     offset += written * bpf;
2173   } while (TRUE);
2174   gst_buffer_unmap (buf, &info);
2175 
2176   if (G_LIKELY (align_next))
2177     sink->next_sample = sample_offset;
2178   else
2179     sink->next_sample = -1;
2180 
2181   GST_DEBUG_OBJECT (sink, "next sample expected at %" G_GUINT64_FORMAT,
2182       sink->next_sample);
2183 
2184   if (G_UNLIKELY (GST_CLOCK_TIME_IS_VALID (stop)
2185           && stop >= bsink->segment.stop)) {
2186     GST_DEBUG_OBJECT (sink,
2187         "start playback because we are at the end of segment");
2188     gst_audio_base_sink_force_start (sink);
2189   }
2190 
2191   ret = GST_FLOW_OK;
2192 
2193 done:
2194   if (out)
2195     gst_buffer_unref (out);
2196 
2197   return ret;
2198 
2199   /* SPECIAL cases */
2200 out_of_segment:
2201   {
2202     GST_DEBUG_OBJECT (sink,
2203         "dropping sample out of segment time %" GST_TIME_FORMAT ", start %"
2204         GST_TIME_FORMAT, GST_TIME_ARGS (time),
2205         GST_TIME_ARGS (bsink->segment.start));
2206     ret = GST_FLOW_OK;
2207     goto done;
2208   }
2209 too_late:
2210   {
2211     GST_DEBUG_OBJECT (sink, "dropping late sample");
2212     ret = GST_FLOW_OK;
2213     goto done;
2214   }
2215   /* ERRORS */
2216 payload_failed:
2217   {
2218     GST_ELEMENT_ERROR (sink, STREAM, FORMAT, (NULL), ("failed to payload."));
2219     ret = GST_FLOW_ERROR;
2220     goto done;
2221   }
2222 wrong_state:
2223   {
2224     GST_DEBUG_OBJECT (sink, "ringbuffer not negotiated");
2225     GST_ELEMENT_ERROR (sink, STREAM, FORMAT, (NULL), ("sink not negotiated."));
2226     ret = GST_FLOW_NOT_NEGOTIATED;
2227     goto done;
2228   }
2229 wrong_size:
2230   {
2231     GST_DEBUG_OBJECT (sink, "wrong size");
2232     GST_ELEMENT_ERROR (sink, STREAM, WRONG_TYPE,
2233         (NULL), ("sink received buffer of wrong size."));
2234     ret = GST_FLOW_ERROR;
2235     goto done;
2236   }
2237 stopping:
2238   {
2239     GST_DEBUG_OBJECT (sink, "preroll got interrupted: %d (%s)", ret,
2240         gst_flow_get_name (ret));
2241     gst_buffer_unmap (buf, &info);
2242     goto done;
2243   }
2244 sync_latency_failed:
2245   {
2246     GST_DEBUG_OBJECT (sink, "failed waiting for latency");
2247     goto done;
2248   }
2249 }
2250 
2251 /**
2252  * gst_audio_base_sink_create_ringbuffer:
2253  * @sink: a #GstAudioBaseSink.
2254  *
2255  * Create and return the #GstAudioRingBuffer for @sink. This function will
2256  * call the ::create_ringbuffer vmethod and will set @sink as the parent of
2257  * the returned buffer (see gst_object_set_parent()).
2258  *
2259  * Returns: (transfer none): The new ringbuffer of @sink.
2260  */
2261 GstAudioRingBuffer *
gst_audio_base_sink_create_ringbuffer(GstAudioBaseSink * sink)2262 gst_audio_base_sink_create_ringbuffer (GstAudioBaseSink * sink)
2263 {
2264   GstAudioBaseSinkClass *bclass;
2265   GstAudioRingBuffer *buffer = NULL;
2266 
2267   bclass = GST_AUDIO_BASE_SINK_GET_CLASS (sink);
2268   if (bclass->create_ringbuffer)
2269     buffer = bclass->create_ringbuffer (sink);
2270 
2271   if (buffer)
2272     gst_object_set_parent (GST_OBJECT (buffer), GST_OBJECT (sink));
2273 
2274   return buffer;
2275 }
2276 
2277 static void
gst_audio_base_sink_callback(GstAudioRingBuffer * rbuf,guint8 * data,guint len,gpointer user_data)2278 gst_audio_base_sink_callback (GstAudioRingBuffer * rbuf, guint8 * data,
2279     guint len, gpointer user_data)
2280 {
2281   GstBaseSink *basesink;
2282   GstAudioBaseSink *sink;
2283   GstBuffer *buf = NULL;
2284   GstFlowReturn ret;
2285   gsize size;
2286 
2287   basesink = GST_BASE_SINK (user_data);
2288   sink = GST_AUDIO_BASE_SINK (user_data);
2289 
2290   GST_PAD_STREAM_LOCK (basesink->sinkpad);
2291 
2292   /* would be nice to arrange for pad_alloc_buffer to return data -- as it is we
2293    * will copy twice, once into data, once into DMA */
2294   GST_LOG_OBJECT (basesink, "pulling %u bytes offset %" G_GUINT64_FORMAT
2295       " to fill audio buffer", len, basesink->offset);
2296   ret =
2297       gst_pad_pull_range (basesink->sinkpad, basesink->segment.position, len,
2298       &buf);
2299 
2300   if (ret != GST_FLOW_OK) {
2301     if (ret == GST_FLOW_EOS)
2302       goto eos;
2303     else
2304       goto error;
2305   }
2306 
2307   GST_BASE_SINK_PREROLL_LOCK (basesink);
2308   if (basesink->flushing)
2309     goto flushing;
2310 
2311   /* complete preroll and wait for PLAYING */
2312   ret = gst_base_sink_do_preroll (basesink, GST_MINI_OBJECT_CAST (buf));
2313   if (ret != GST_FLOW_OK)
2314     goto preroll_error;
2315 
2316   size = gst_buffer_get_size (buf);
2317 
2318   if (len != size) {
2319     GST_INFO_OBJECT (basesink,
2320         "got different size than requested from sink pad: %u"
2321         " != %" G_GSIZE_FORMAT, len, size);
2322     len = MIN (size, len);
2323   }
2324 
2325   basesink->segment.position += len;
2326 
2327   gst_buffer_extract (buf, 0, data, len);
2328   GST_BASE_SINK_PREROLL_UNLOCK (basesink);
2329 
2330   GST_PAD_STREAM_UNLOCK (basesink->sinkpad);
2331 
2332   return;
2333 
2334 error:
2335   {
2336     GST_WARNING_OBJECT (basesink, "Got flow '%s' but can't return it: %d",
2337         gst_flow_get_name (ret), ret);
2338     gst_audio_ring_buffer_pause (rbuf);
2339     GST_PAD_STREAM_UNLOCK (basesink->sinkpad);
2340     return;
2341   }
2342 eos:
2343   {
2344     /* FIXME: this is not quite correct; we'll be called endlessly until
2345      * the sink gets shut down; maybe we should set a flag somewhere, or
2346      * set segment.stop and segment.duration to the last sample or so */
2347     GST_DEBUG_OBJECT (sink, "EOS");
2348     gst_audio_base_sink_drain (sink);
2349     gst_audio_ring_buffer_pause (rbuf);
2350     gst_element_post_message (GST_ELEMENT_CAST (sink),
2351         gst_message_new_eos (GST_OBJECT_CAST (sink)));
2352     GST_PAD_STREAM_UNLOCK (basesink->sinkpad);
2353     return;
2354   }
2355 flushing:
2356   {
2357     GST_DEBUG_OBJECT (sink, "we are flushing");
2358     gst_audio_ring_buffer_pause (rbuf);
2359     GST_BASE_SINK_PREROLL_UNLOCK (basesink);
2360     GST_PAD_STREAM_UNLOCK (basesink->sinkpad);
2361     return;
2362   }
2363 preroll_error:
2364   {
2365     GST_DEBUG_OBJECT (sink, "error %s", gst_flow_get_name (ret));
2366     gst_audio_ring_buffer_pause (rbuf);
2367     GST_BASE_SINK_PREROLL_UNLOCK (basesink);
2368     GST_PAD_STREAM_UNLOCK (basesink->sinkpad);
2369     return;
2370   }
2371 }
2372 
2373 static gboolean
gst_audio_base_sink_activate_pull(GstBaseSink * basesink,gboolean active)2374 gst_audio_base_sink_activate_pull (GstBaseSink * basesink, gboolean active)
2375 {
2376   gboolean ret;
2377   GstAudioBaseSink *sink = GST_AUDIO_BASE_SINK (basesink);
2378 
2379   if (active) {
2380     GST_DEBUG_OBJECT (basesink, "activating pull");
2381 
2382     gst_audio_ring_buffer_set_callback (sink->ringbuffer,
2383         gst_audio_base_sink_callback, sink);
2384 
2385     ret = gst_audio_ring_buffer_activate (sink->ringbuffer, TRUE);
2386   } else {
2387     GST_DEBUG_OBJECT (basesink, "deactivating pull");
2388     gst_audio_ring_buffer_set_callback (sink->ringbuffer, NULL, NULL);
2389     ret = gst_audio_ring_buffer_activate (sink->ringbuffer, FALSE);
2390   }
2391 
2392   return ret;
2393 }
2394 
2395 static GstStateChangeReturn
gst_audio_base_sink_change_state(GstElement * element,GstStateChange transition)2396 gst_audio_base_sink_change_state (GstElement * element,
2397     GstStateChange transition)
2398 {
2399   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
2400   GstAudioBaseSink *sink = GST_AUDIO_BASE_SINK (element);
2401 
2402   switch (transition) {
2403     case GST_STATE_CHANGE_NULL_TO_READY:{
2404       GstAudioRingBuffer *rb;
2405 
2406       gst_audio_clock_reset (GST_AUDIO_CLOCK (sink->provided_clock), 0);
2407       rb = gst_audio_base_sink_create_ringbuffer (sink);
2408       if (rb == NULL)
2409         goto create_failed;
2410 
2411       GST_OBJECT_LOCK (sink);
2412       sink->ringbuffer = rb;
2413       GST_OBJECT_UNLOCK (sink);
2414 
2415       if (!gst_audio_ring_buffer_open_device (sink->ringbuffer)) {
2416         GST_OBJECT_LOCK (sink);
2417         gst_object_unparent (GST_OBJECT_CAST (sink->ringbuffer));
2418         sink->ringbuffer = NULL;
2419         GST_OBJECT_UNLOCK (sink);
2420         goto open_failed;
2421       }
2422       break;
2423     }
2424     case GST_STATE_CHANGE_READY_TO_PAUSED:
2425       gst_audio_base_sink_reset_sync (sink);
2426       gst_audio_ring_buffer_set_flushing (sink->ringbuffer, FALSE);
2427       gst_audio_ring_buffer_may_start (sink->ringbuffer, FALSE);
2428 
2429       /* Only post clock-provide messages if this is the clock that
2430        * we've created. If the subclass has overridden it the subclass
2431        * should post this messages whenever necessary */
2432       if (gst_audio_base_sink_is_self_provided_clock (sink))
2433         gst_element_post_message (element,
2434             gst_message_new_clock_provide (GST_OBJECT_CAST (element),
2435                 sink->provided_clock, TRUE));
2436       break;
2437     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
2438     {
2439       gboolean eos;
2440 
2441       GST_OBJECT_LOCK (sink);
2442       GST_DEBUG_OBJECT (sink, "ringbuffer may start now");
2443       sink->priv->sync_latency = TRUE;
2444       eos = GST_BASE_SINK (sink)->eos;
2445       GST_OBJECT_UNLOCK (sink);
2446 
2447       gst_audio_ring_buffer_may_start (sink->ringbuffer, TRUE);
2448       if (GST_BASE_SINK_CAST (sink)->pad_mode == GST_PAD_MODE_PULL ||
2449           g_atomic_int_get (&sink->eos_rendering) || eos) {
2450         /* we always start the ringbuffer in pull mode immediately */
2451         /* sync rendering on eos needs running clock,
2452          * and others need running clock when finished rendering eos */
2453         gst_audio_ring_buffer_start (sink->ringbuffer);
2454       }
2455       break;
2456     }
2457     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
2458       /* ringbuffer cannot start anymore */
2459       gst_audio_ring_buffer_may_start (sink->ringbuffer, FALSE);
2460       gst_audio_ring_buffer_pause (sink->ringbuffer);
2461 
2462       GST_OBJECT_LOCK (sink);
2463       sink->priv->sync_latency = FALSE;
2464       GST_OBJECT_UNLOCK (sink);
2465       break;
2466     case GST_STATE_CHANGE_PAUSED_TO_READY:
2467       /* Only post clock-lost messages if this is the clock that
2468        * we've created. If the subclass has overridden it the subclass
2469        * should post this messages whenever necessary */
2470       if (gst_audio_base_sink_is_self_provided_clock (sink))
2471         gst_element_post_message (element,
2472             gst_message_new_clock_lost (GST_OBJECT_CAST (element),
2473                 sink->provided_clock));
2474 
2475       /* make sure we unblock before calling the parent state change
2476        * so it can grab the STREAM_LOCK */
2477       gst_audio_ring_buffer_set_flushing (sink->ringbuffer, TRUE);
2478       break;
2479     default:
2480       break;
2481   }
2482 
2483   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
2484 
2485   switch (transition) {
2486     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
2487       /* stop slaving ourselves to the master, if any */
2488       gst_clock_set_master (sink->provided_clock, NULL);
2489       break;
2490     case GST_STATE_CHANGE_PAUSED_TO_READY:
2491       gst_audio_ring_buffer_activate (sink->ringbuffer, FALSE);
2492       gst_audio_ring_buffer_release (sink->ringbuffer);
2493       break;
2494     case GST_STATE_CHANGE_READY_TO_NULL:
2495       /* we release again here because the acquire happens when setting the
2496        * caps, which happens before we commit the state to PAUSED and thus the
2497        * PAUSED->READY state change (see above, where we release the ringbuffer)
2498        * might not be called when we get here. */
2499       gst_audio_ring_buffer_activate (sink->ringbuffer, FALSE);
2500       gst_audio_ring_buffer_release (sink->ringbuffer);
2501       gst_audio_ring_buffer_close_device (sink->ringbuffer);
2502       GST_OBJECT_LOCK (sink);
2503       gst_object_unparent (GST_OBJECT_CAST (sink->ringbuffer));
2504       sink->ringbuffer = NULL;
2505       GST_OBJECT_UNLOCK (sink);
2506       break;
2507     default:
2508       break;
2509   }
2510 
2511   return ret;
2512 
2513   /* ERRORS */
2514 create_failed:
2515   {
2516     /* subclass must post a meaningful error message */
2517     GST_DEBUG_OBJECT (sink, "create failed");
2518     return GST_STATE_CHANGE_FAILURE;
2519   }
2520 open_failed:
2521   {
2522     /* subclass must post a meaningful error message */
2523     GST_DEBUG_OBJECT (sink, "open failed");
2524     return GST_STATE_CHANGE_FAILURE;
2525   }
2526 }
2527