2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3 * 2005 Wim Taymans <wim@fluendo.com>
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.
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.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
25 #include "gstbaseaudiosink.h"
27 GST_DEBUG_CATEGORY_STATIC (gst_base_audio_sink_debug);
28 #define GST_CAT_DEFAULT gst_base_audio_sink_debug
30 /* BaseAudioSink signals and args */
37 /* we tollerate a 10th of a second diff before we start resyncing. This
38 * should be enough to compensate for various rounding errors in the timestamp
39 * and sample offset position. */
40 #define DIFF_TOLERANCE 10
42 #define DEFAULT_BUFFER_TIME 500 * GST_USECOND
43 #define DEFAULT_LATENCY_TIME 10 * GST_USECOND
44 #define DEFAULT_PROVIDE_CLOCK TRUE
54 #define _do_init(bla) \
55 GST_DEBUG_CATEGORY_INIT (gst_base_audio_sink_debug, "baseaudiosink", 0, "baseaudiosink element");
57 GST_BOILERPLATE_FULL (GstBaseAudioSink, gst_base_audio_sink, GstBaseSink,
58 GST_TYPE_BASE_SINK, _do_init);
60 static void gst_base_audio_sink_dispose (GObject * object);
62 static void gst_base_audio_sink_set_property (GObject * object, guint prop_id,
63 const GValue * value, GParamSpec * pspec);
64 static void gst_base_audio_sink_get_property (GObject * object, guint prop_id,
65 GValue * value, GParamSpec * pspec);
67 static GstStateChangeReturn gst_base_audio_sink_change_state (GstElement *
68 element, GstStateChange transition);
70 static GstClock *gst_base_audio_sink_provide_clock (GstElement * elem);
71 static GstClockTime gst_base_audio_sink_get_time (GstClock * clock,
72 GstBaseAudioSink * sink);
73 static void gst_base_audio_sink_callback (GstRingBuffer * rbuf, guint8 * data,
74 guint len, gpointer user_data);
76 static GstFlowReturn gst_base_audio_sink_preroll (GstBaseSink * bsink,
78 static GstFlowReturn gst_base_audio_sink_render (GstBaseSink * bsink,
80 static gboolean gst_base_audio_sink_event (GstBaseSink * bsink,
82 static void gst_base_audio_sink_get_times (GstBaseSink * bsink,
83 GstBuffer * buffer, GstClockTime * start, GstClockTime * end);
84 static gboolean gst_base_audio_sink_setcaps (GstBaseSink * bsink,
87 //static guint gst_base_audio_sink_signals[LAST_SIGNAL] = { 0 };
90 gst_base_audio_sink_base_init (gpointer g_class)
95 gst_base_audio_sink_class_init (GstBaseAudioSinkClass * klass)
97 GObjectClass *gobject_class;
98 GstElementClass *gstelement_class;
99 GstBaseSinkClass *gstbasesink_class;
101 gobject_class = (GObjectClass *) klass;
102 gstelement_class = (GstElementClass *) klass;
103 gstbasesink_class = (GstBaseSinkClass *) klass;
105 gobject_class->set_property =
106 GST_DEBUG_FUNCPTR (gst_base_audio_sink_set_property);
107 gobject_class->get_property =
108 GST_DEBUG_FUNCPTR (gst_base_audio_sink_get_property);
109 gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_base_audio_sink_dispose);
111 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BUFFER_TIME,
112 g_param_spec_int64 ("buffer-time", "Buffer Time",
113 "Size of audio buffer in milliseconds (-1 = default)",
114 -1, G_MAXINT64, DEFAULT_BUFFER_TIME, G_PARAM_READWRITE));
115 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LATENCY_TIME,
116 g_param_spec_int64 ("latency-time", "Latency Time",
117 "Audio latency in milliseconds (-1 = default)",
118 -1, G_MAXINT64, DEFAULT_LATENCY_TIME, G_PARAM_READWRITE));
119 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PROVIDE_CLOCK,
120 g_param_spec_boolean ("provide-clock", "Provide Clock",
121 "Provide a clock to be used as the global pipeline clock",
122 DEFAULT_PROVIDE_CLOCK, G_PARAM_READWRITE));
124 gstelement_class->change_state =
125 GST_DEBUG_FUNCPTR (gst_base_audio_sink_change_state);
126 gstelement_class->provide_clock =
127 GST_DEBUG_FUNCPTR (gst_base_audio_sink_provide_clock);
129 gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_base_audio_sink_event);
130 gstbasesink_class->preroll = GST_DEBUG_FUNCPTR (gst_base_audio_sink_preroll);
131 gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_base_audio_sink_render);
132 gstbasesink_class->get_times =
133 GST_DEBUG_FUNCPTR (gst_base_audio_sink_get_times);
134 gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_base_audio_sink_setcaps);
138 gst_base_audio_sink_init (GstBaseAudioSink * baseaudiosink,
139 GstBaseAudioSinkClass * g_class)
141 baseaudiosink->buffer_time = DEFAULT_BUFFER_TIME;
142 baseaudiosink->latency_time = DEFAULT_LATENCY_TIME;
143 baseaudiosink->provide_clock = DEFAULT_PROVIDE_CLOCK;
145 baseaudiosink->provided_clock = gst_audio_clock_new ("clock",
146 (GstAudioClockGetTimeFunc) gst_base_audio_sink_get_time, baseaudiosink);
150 gst_base_audio_sink_dispose (GObject * object)
152 GstBaseAudioSink *sink;
154 sink = GST_BASE_AUDIO_SINK (object);
156 if (sink->provided_clock)
157 gst_object_unref (sink->provided_clock);
158 sink->provided_clock = NULL;
160 if (sink->ringbuffer)
161 gst_object_unref (sink->ringbuffer);
162 sink->ringbuffer = NULL;
164 G_OBJECT_CLASS (parent_class)->dispose (object);
168 gst_base_audio_sink_provide_clock (GstElement * elem)
170 GstBaseAudioSink *sink;
173 sink = GST_BASE_AUDIO_SINK (elem);
175 if (sink->provide_clock)
176 clock = GST_CLOCK_CAST (gst_object_ref (sink->provided_clock));
184 gst_base_audio_sink_get_time (GstClock * clock, GstBaseAudioSink * sink)
189 if (sink->ringbuffer == NULL || sink->ringbuffer->spec.rate == 0)
190 return GST_CLOCK_TIME_NONE;
192 /* our processed samples are always increasing */
193 samples = gst_ring_buffer_samples_done (sink->ringbuffer);
195 result = samples * GST_SECOND / sink->ringbuffer->spec.rate;
201 gst_base_audio_sink_set_property (GObject * object, guint prop_id,
202 const GValue * value, GParamSpec * pspec)
204 GstBaseAudioSink *sink;
206 sink = GST_BASE_AUDIO_SINK (object);
209 case PROP_BUFFER_TIME:
210 sink->buffer_time = g_value_get_int64 (value);
212 case PROP_LATENCY_TIME:
213 sink->latency_time = g_value_get_int64 (value);
215 case PROP_PROVIDE_CLOCK:
216 sink->provide_clock = g_value_get_boolean (value);
219 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
225 gst_base_audio_sink_get_property (GObject * object, guint prop_id,
226 GValue * value, GParamSpec * pspec)
228 GstBaseAudioSink *sink;
230 sink = GST_BASE_AUDIO_SINK (object);
233 case PROP_BUFFER_TIME:
234 g_value_set_int64 (value, sink->buffer_time);
236 case PROP_LATENCY_TIME:
237 g_value_set_int64 (value, sink->latency_time);
239 case PROP_PROVIDE_CLOCK:
240 g_value_set_boolean (value, sink->provide_clock);
243 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
249 gst_base_audio_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
251 GstBaseAudioSink *sink = GST_BASE_AUDIO_SINK (bsink);
252 GstRingBufferSpec *spec;
254 spec = &sink->ringbuffer->spec;
256 GST_DEBUG ("release old ringbuffer");
258 /* release old ringbuffer */
259 gst_ring_buffer_release (sink->ringbuffer);
261 GST_DEBUG ("parse caps");
263 spec->buffer_time = sink->buffer_time;
264 spec->latency_time = sink->latency_time;
267 if (!gst_ring_buffer_parse_caps (spec, caps))
270 gst_ring_buffer_debug_spec_buff (spec);
272 GST_DEBUG ("acquire new ringbuffer");
274 if (!gst_ring_buffer_acquire (sink->ringbuffer, spec))
277 /* calculate actual latency and buffer times */
279 spec->segsize * GST_MSECOND / (spec->rate * spec->bytes_per_sample);
281 spec->segtotal * spec->segsize * GST_MSECOND / (spec->rate *
282 spec->bytes_per_sample);
284 gst_ring_buffer_debug_spec_buff (spec);
291 GST_DEBUG ("could not parse caps");
296 GST_DEBUG ("could not acquire ringbuffer");
302 gst_base_audio_sink_get_times (GstBaseSink * bsink, GstBuffer * buffer,
303 GstClockTime * start, GstClockTime * end)
305 /* our clock sync is a bit too much for the base class to handle so
306 * we implement it ourselves. */
307 *start = GST_CLOCK_TIME_NONE;
308 *end = GST_CLOCK_TIME_NONE;
312 gst_base_audio_sink_event (GstBaseSink * bsink, GstEvent * event)
314 GstBaseAudioSink *sink = GST_BASE_AUDIO_SINK (bsink);
316 switch (GST_EVENT_TYPE (event)) {
317 case GST_EVENT_FLUSH_START:
318 gst_ring_buffer_set_flushing (sink->ringbuffer, TRUE);
320 case GST_EVENT_FLUSH_STOP:
321 /* always resync on sample after a flush */
322 sink->next_sample = -1;
323 gst_ring_buffer_set_flushing (sink->ringbuffer, FALSE);
326 gst_ring_buffer_start (sink->ringbuffer);
335 gst_base_audio_sink_preroll (GstBaseSink * bsink, GstBuffer * buffer)
337 GstBaseAudioSink *sink = GST_BASE_AUDIO_SINK (bsink);
339 if (!gst_ring_buffer_is_acquired (sink->ringbuffer))
342 /* we don't really do anything when prerolling. We could make a
343 * property to play this buffer to have some sort of scrubbing
349 GST_DEBUG ("ringbuffer in wrong state");
350 GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND,
351 ("sink not negotiated."), ("sink not negotiated."));
352 return GST_FLOW_NOT_NEGOTIATED;
357 gst_base_audio_sink_get_offset (GstBaseAudioSink * sink)
360 gint writeseg, segdone, sps;
363 /* assume we can append to the previous sample */
364 sample = sink->next_sample;
366 sps = sink->ringbuffer->samples_per_seg;
368 /* figure out the segment and the offset inside the segment where
369 * the sample should be written. */
370 writeseg = sample / sps;
372 /* get the currently processed segment */
373 segdone = g_atomic_int_get (&sink->ringbuffer->segdone)
374 - sink->ringbuffer->segbase;
376 /* see how far away it is from the write segment */
377 diff = writeseg - segdone;
379 /* sample would be dropped, position to next playable position */
380 sample = (segdone + 1) * sps;
387 gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
389 guint64 render_offset, in_offset;
390 GstClockTime time, render_time, duration;
391 GstClockTimeDiff render_diff;
392 GstBaseAudioSink *sink;
393 GstRingBuffer *ringbuf;
400 GstClockTime crate_num;
401 GstClockTime crate_denom;
402 GstClockTime cinternal, cexternal;
404 sink = GST_BASE_AUDIO_SINK (bsink);
406 ringbuf = sink->ringbuffer;
408 /* can't do anything when we don't have the device */
409 if (!gst_ring_buffer_is_acquired (ringbuf))
412 bps = ringbuf->spec.bytes_per_sample;
414 size = GST_BUFFER_SIZE (buf);
418 samples = size / bps;
420 in_offset = GST_BUFFER_OFFSET (buf);
421 time = GST_BUFFER_TIMESTAMP (buf);
422 duration = GST_BUFFER_DURATION (buf);
423 data = GST_BUFFER_DATA (buf);
425 GST_DEBUG ("time %" GST_TIME_FORMAT ", offset %llu, start %" GST_TIME_FORMAT,
426 GST_TIME_ARGS (time), in_offset, GST_TIME_ARGS (bsink->segment.start));
428 /* if not valid timestamp or we don't need to sync, try to play
430 if (!GST_CLOCK_TIME_IS_VALID (time) || !bsink->sync) {
431 render_offset = gst_base_audio_sink_get_offset (sink);
435 render_diff = time - bsink->segment.start;
437 /* samples should be rendered based on their timestamp. All samples
438 * arriving before the segment.start are to be thrown away */
439 /* FIXME, for now we drop the sample completely, we should
440 * in fact clip the sample. Same for the segment.stop, actually. */
444 gst_clock_get_calibration (sink->provided_clock, &cinternal, &cexternal,
445 &crate_num, &crate_denom);
447 /* bring buffer timestamp to stream time */
448 render_time = render_diff;
449 /* adjust for rate */
450 render_time /= ABS (bsink->segment.rate);
451 /* adjust for accumulated segments */
452 render_time += bsink->segment.accum;
453 /* add base time to get absolute clock time */
455 (gst_element_get_base_time (GST_ELEMENT_CAST (bsink)) - cexternal) +
457 /* and bring the time to the offset in the buffer */
458 render_offset = render_time * ringbuf->spec.rate / GST_SECOND;
460 /* roundoff errors in timestamp conversion */
461 if (sink->next_sample != -1)
462 diff = ABS ((gint64) render_offset - (gint64) sink->next_sample);
464 diff = ringbuf->spec.rate;
466 GST_DEBUG ("render time %" GST_TIME_FORMAT
467 ", render offset %llu, diff %lld, samples %lu",
468 GST_TIME_ARGS (render_time), render_offset, diff, samples);
470 /* we tollerate a 10th of a second diff before we start resyncing. This
471 * should be enough to compensate for various rounding errors in the timestamp
472 * and sample offset position. */
473 if (diff < ringbuf->spec.rate / DIFF_TOLERANCE) {
474 GST_DEBUG ("align with prev sample, %" G_GINT64_FORMAT " < %lu", diff,
475 ringbuf->spec.rate / DIFF_TOLERANCE);
476 /* just align with previous sample then */
477 render_offset = sink->next_sample;
479 GST_DEBUG ("resync");
483 crate = ((gdouble) crate_num) / crate_denom;
484 GST_DEBUG_OBJECT (sink,
485 "internal %" G_GUINT64_FORMAT ", %" G_GUINT64_FORMAT ", rate %g",
486 cinternal, cexternal, crate);
488 /* clip length based on rate */
489 samples = MIN (samples, samples / (crate * ABS (bsink->segment.rate)));
491 /* the next sample should be current sample and its length */
492 sink->next_sample = render_offset + samples;
494 gst_ring_buffer_commit (ringbuf, render_offset, data, samples);
496 if (GST_CLOCK_TIME_IS_VALID (time) && time + duration >= bsink->segment.stop) {
497 GST_DEBUG ("start playback because we are at the end of segment");
498 gst_ring_buffer_start (ringbuf);
505 GST_DEBUG ("dropping sample out of segment time %" GST_TIME_FORMAT
506 ", start %" GST_TIME_FORMAT,
507 GST_TIME_ARGS (time), GST_TIME_ARGS (bsink->segment.start));
512 GST_DEBUG ("ringbuffer not negotiated");
513 GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND,
514 ("sink not negotiated."), ("sink not negotiated."));
515 return GST_FLOW_NOT_NEGOTIATED;
519 GST_DEBUG ("wrong size");
520 GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND,
521 ("sink received buffer of wrong size."),
522 ("sink received buffer of wrong size."));
523 return GST_FLOW_ERROR;
528 gst_base_audio_sink_create_ringbuffer (GstBaseAudioSink * sink)
530 GstBaseAudioSinkClass *bclass;
531 GstRingBuffer *buffer = NULL;
533 bclass = GST_BASE_AUDIO_SINK_GET_CLASS (sink);
534 if (bclass->create_ringbuffer)
535 buffer = bclass->create_ringbuffer (sink);
538 gst_object_set_parent (GST_OBJECT (buffer), GST_OBJECT (sink));
544 gst_base_audio_sink_callback (GstRingBuffer * rbuf, guint8 * data, guint len,
547 //GstBaseAudioSink *sink = GST_BASE_AUDIO_SINK (data);
550 static GstStateChangeReturn
551 gst_base_audio_sink_change_state (GstElement * element,
552 GstStateChange transition)
554 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
555 GstBaseAudioSink *sink = GST_BASE_AUDIO_SINK (element);
557 switch (transition) {
558 case GST_STATE_CHANGE_NULL_TO_READY:
559 if (sink->ringbuffer == NULL) {
560 sink->ringbuffer = gst_base_audio_sink_create_ringbuffer (sink);
561 gst_ring_buffer_set_callback (sink->ringbuffer,
562 gst_base_audio_sink_callback, sink);
564 if (!gst_ring_buffer_open_device (sink->ringbuffer))
565 return GST_STATE_CHANGE_FAILURE;
566 sink->next_sample = 0;
568 case GST_STATE_CHANGE_READY_TO_PAUSED:
569 gst_ring_buffer_set_flushing (sink->ringbuffer, FALSE);
571 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
575 GST_OBJECT_LOCK (sink);
576 clock = GST_ELEMENT_CLOCK (sink);
577 /* if we are slaved to a clock, we need to set the initial
579 if (clock != sink->provided_clock) {
581 GstClockTime rate_num, rate_denom;
583 time = gst_clock_get_internal_time (sink->provided_clock);
585 GST_DEBUG_OBJECT (sink, "time: %" GST_TIME_FORMAT,
586 GST_TIME_ARGS (time));
588 gst_clock_set_master (sink->provided_clock, clock);
589 /* FIXME, this is not yet accurate enough for smooth playback */
590 gst_clock_get_calibration (sink->provided_clock, NULL, NULL, &rate_num,
592 /* Does not work yet. */
593 gst_clock_set_calibration (sink->provided_clock,
594 time, element->base_time, rate_num, rate_denom);
596 GST_OBJECT_UNLOCK (sink);
599 case GST_STATE_CHANGE_PAUSED_TO_READY:
600 gst_ring_buffer_set_flushing (sink->ringbuffer, TRUE);
606 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
608 switch (transition) {
609 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
610 gst_ring_buffer_pause (sink->ringbuffer);
611 /* slop slaving ourselves to the master, if any */
612 gst_clock_set_master (sink->provided_clock, NULL);
614 case GST_STATE_CHANGE_PAUSED_TO_READY:
615 gst_ring_buffer_release (sink->ringbuffer);
616 gst_pad_set_caps (GST_BASE_SINK_PAD (sink), NULL);
618 case GST_STATE_CHANGE_READY_TO_NULL:
619 gst_ring_buffer_close_device (sink->ringbuffer);