summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWim Taymans <wim.taymans@gmail.com>2007-02-15 12:06:25 +0000
committerWim Taymans <wim.taymans@gmail.com>2007-02-15 12:06:25 +0000
commita43d0f57eb36bf4115864b05fc75c264281df6f8 (patch)
tree2a814bb1ac8e624b7b7ecff531f49e1ad518205b
parent70e52caf04305a0f411bedba37c35de1bbfa1d36 (diff)
gst-libs/gst/audio/gstbaseaudiosink.c: Answer latency query.
Original commit message from CVS: * gst-libs/gst/audio/gstbaseaudiosink.c: (gst_base_audio_sink_class_init), (gst_base_audio_sink_query), (gst_base_audio_sink_render), (gst_base_audio_sink_callback), (gst_base_audio_sink_async_play), (gst_base_audio_sink_change_state): Answer latency query. Use configured latency when syncing. Fix clock slaving. * gst-libs/gst/audio/gstbaseaudiosrc.c: (gst_base_audio_src_class_init), (gst_base_audio_src_dispose), (gst_base_audio_src_query), (gst_base_audio_src_change_state): Fix possible memleak. Implement latency query. Small cleanups.
-rw-r--r--ChangeLog18
-rw-r--r--gst-libs/gst/audio/gstbaseaudiosink.c138
-rw-r--r--gst-libs/gst/audio/gstbaseaudiosrc.c85
3 files changed, 215 insertions, 26 deletions
diff --git a/ChangeLog b/ChangeLog
index 00646251..d892a2c6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,23 @@
2007-02-15 Wim Taymans <wim@fluendo.com>
+ * gst-libs/gst/audio/gstbaseaudiosink.c:
+ (gst_base_audio_sink_class_init), (gst_base_audio_sink_query),
+ (gst_base_audio_sink_render), (gst_base_audio_sink_callback),
+ (gst_base_audio_sink_async_play),
+ (gst_base_audio_sink_change_state):
+ Answer latency query.
+ Use configured latency when syncing.
+ Fix clock slaving.
+
+ * gst-libs/gst/audio/gstbaseaudiosrc.c:
+ (gst_base_audio_src_class_init), (gst_base_audio_src_dispose),
+ (gst_base_audio_src_query), (gst_base_audio_src_change_state):
+ Fix possible memleak.
+ Implement latency query.
+ Small cleanups.
+
+2007-02-15 Wim Taymans <wim@fluendo.com>
+
* ext/alsa/gstalsasink.c: (gst_alsasink_reset):
Ignore errors in reset, these are not fatal. They also grab the element
lock which is already taking when this function is called. Fixes
diff --git a/gst-libs/gst/audio/gstbaseaudiosink.c b/gst-libs/gst/audio/gstbaseaudiosink.c
index baff3c38..2167a31d 100644
--- a/gst-libs/gst/audio/gstbaseaudiosink.c
+++ b/gst-libs/gst/audio/gstbaseaudiosink.c
@@ -87,6 +87,8 @@ static GstStateChangeReturn gst_base_audio_sink_change_state (GstElement *
element, GstStateChange transition);
static gboolean gst_base_audio_sink_activate_pull (GstBaseSink * basesink,
gboolean active);
+static gboolean gst_base_audio_sink_query (GstElement * element, GstQuery *
+ query);
static GstClock *gst_base_audio_sink_provide_clock (GstElement * elem);
static GstClockTime gst_base_audio_sink_get_time (GstClock * clock,
@@ -149,6 +151,7 @@ gst_base_audio_sink_class_init (GstBaseAudioSinkClass * klass)
GST_DEBUG_FUNCPTR (gst_base_audio_sink_change_state);
gstelement_class->provide_clock =
GST_DEBUG_FUNCPTR (gst_base_audio_sink_provide_clock);
+ gstelement_class->query = GST_DEBUG_FUNCPTR (gst_base_audio_sink_query);
gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_base_audio_sink_event);
gstbasesink_class->preroll = GST_DEBUG_FUNCPTR (gst_base_audio_sink_preroll);
@@ -235,6 +238,62 @@ clock_disabled:
}
}
+static gboolean
+gst_base_audio_sink_query (GstElement * element, GstQuery * query)
+{
+ gboolean res = FALSE;
+
+ GstBaseAudioSink *basesink = GST_BASE_AUDIO_SINK (element);
+
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_LATENCY:
+ {
+ gboolean live, us_live;
+ GstClockTime min_l, max_l;
+
+ GST_DEBUG_OBJECT (basesink, "latency query");
+
+ /* ask parent first, it will do an upstream query for us. */
+ if ((res =
+ gst_base_sink_query_latency (GST_BASE_SINK_CAST (basesink), &live,
+ &us_live, &min_l, &max_l))) {
+ GstClockTime min_latency, max_latency;
+
+ /* we and upstream are both live, adjust the min_latency */
+ if (live && us_live && basesink->ringbuffer
+ && basesink->ringbuffer->spec.rate) {
+ GstRingBufferSpec *spec;
+
+ spec = &basesink->ringbuffer->spec;
+
+ max_latency =
+ spec->segtotal * spec->segsize * GST_SECOND / (spec->rate *
+ spec->bytes_per_sample);
+ min_latency = MAX (max_latency, min_l);
+
+ GST_DEBUG_OBJECT (basesink,
+ "peer min %" GST_TIME_FORMAT ", our min latency: %"
+ GST_TIME_FORMAT, GST_TIME_ARGS (min_l),
+ GST_TIME_ARGS (min_latency));
+ } else {
+ GST_DEBUG_OBJECT (basesink,
+ "peer or we are not live, don't care about latency");
+ min_latency = 0;
+ max_latency = -1;
+ }
+ gst_query_set_latency (query, live, min_latency, max_latency);
+ }
+ break;
+ }
+ default:
+ res = GST_ELEMENT_CLASS (parent_class)->query (element, query);
+ break;
+ }
+
+ return res;
+}
+
+
static GstClockTime
gst_base_audio_sink_get_time (GstClock * clock, GstBaseAudioSink * sink)
{
@@ -550,7 +609,7 @@ gst_base_audio_sink_get_offset (GstBaseAudioSink * sink)
static GstFlowReturn
gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
{
- guint64 in_offset, clock_offset;
+ guint64 in_offset;
GstClockTime time, stop, render_start, render_stop, sample_offset;
GstBaseAudioSink *sink;
GstRingBuffer *ringbuf;
@@ -563,9 +622,9 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
GstClockTime crate_num;
GstClockTime crate_denom;
gint out_samples;
- GstClockTime cinternal, cexternal;
+ GstClockTime base_time, cinternal, cexternal, latency;
GstClock *clock;
- gboolean sync;
+ gboolean sync, slaved;
sink = GST_BASE_AUDIO_SINK (bsink);
@@ -663,29 +722,62 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
"running: start %" GST_TIME_FORMAT " - stop %" GST_TIME_FORMAT,
GST_TIME_ARGS (render_start), GST_TIME_ARGS (render_stop));
- /* get calibration parameters to compensate for speed and offset differences
- * when we are slaved */
- gst_clock_get_calibration (sink->provided_clock, &cinternal, &cexternal,
- &crate_num, &crate_denom);
+ base_time = gst_element_get_base_time (GST_ELEMENT_CAST (bsink));
+
+ GST_DEBUG_OBJECT (sink, "base_time %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (base_time));
+
+ /* add base time to sync against the clock */
+ render_start += base_time;
+ render_stop += base_time;
+
+ slaved = clock != sink->provided_clock;
+ if (slaved) {
+ /* get calibration parameters to compensate for speed and offset differences
+ * when we are slaved */
+ gst_clock_get_calibration (sink->provided_clock, &cinternal, &cexternal,
+ &crate_num, &crate_denom);
+
+ GST_DEBUG_OBJECT (sink, "internal %" GST_TIME_FORMAT " external %"
+ GST_TIME_FORMAT " %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT " = %f",
+ GST_TIME_ARGS (cinternal), GST_TIME_ARGS (cexternal), crate_num,
+ crate_denom, (gdouble) crate_num / crate_denom);
+
+ /* bring to our slaved clock time */
+ if (render_start >= cexternal)
+ render_start =
+ gst_util_uint64_scale (render_start - cexternal, crate_denom,
+ crate_num) + cinternal;
+ else
+ render_start =
+ cinternal - gst_util_uint64_scale (cexternal - render_start,
+ crate_denom, crate_num);
+
+ if (render_stop >= cexternal)
+ render_stop =
+ gst_util_uint64_scale (render_stop - cexternal, crate_denom,
+ crate_num) + cinternal;
+ else
+ render_stop =
+ cinternal - gst_util_uint64_scale (cexternal - render_stop,
+ crate_denom, crate_num);
+ }
- clock_offset =
- (gst_element_get_base_time (GST_ELEMENT_CAST (bsink)) - cexternal) +
- cinternal;
+ /* compensate for latency */
+ latency = gst_base_sink_get_latency (bsink);
+ render_start += latency;
+ render_stop += latency;
- GST_DEBUG_OBJECT (sink, "clock offset %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
- "/%" G_GUINT64_FORMAT, GST_TIME_ARGS (clock_offset), crate_num,
- crate_denom);
+ GST_DEBUG_OBJECT (sink,
+ "render: start %" GST_TIME_FORMAT " - stop %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (render_start), GST_TIME_ARGS (render_stop));
/* and bring the time to the rate corrected offset in the buffer */
- render_start = gst_util_uint64_scale_int (render_start + clock_offset,
+ render_start = gst_util_uint64_scale_int (render_start,
ringbuf->spec.rate, GST_SECOND);
- render_stop = gst_util_uint64_scale_int (render_stop + clock_offset,
+ render_stop = gst_util_uint64_scale_int (render_stop,
ringbuf->spec.rate, GST_SECOND);
- GST_DEBUG_OBJECT (sink,
- "render: start %" GST_TIME_FORMAT " - stop %" GST_TIME_FORMAT,
- GST_TIME_ARGS (render_start), GST_TIME_ARGS (render_stop));
-
/* always resync after a discont */
if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT))) {
GST_DEBUG_OBJECT (sink, "resync after discont");
@@ -736,7 +828,7 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
render_start += align;
/* only align stop if we are not slaved */
- if (clock != sink->provided_clock) {
+ if (slaved) {
GST_DEBUG_OBJECT (sink, "no stop time align needed: we are slaved");
goto no_align;
}
@@ -878,7 +970,8 @@ gst_base_audio_sink_callback (GstRingBuffer * rbuf, guint8 * data, guint len,
/* would be nice to arrange for pad_alloc_buffer to return data -- as it is we
will copy twice, once into data, once into DMA */
- GST_LOG_OBJECT (basesink, "pulling %d bytes to fill audio buffer", len);
+ GST_LOG_OBJECT (basesink, "pulling %d bytes offset %" G_GUINT64_FORMAT
+ " to fill audio buffer", len, basesink->offset);
ret = gst_pad_pull_range (basesink->sinkpad, basesink->offset, len, &buf);
if (ret != GST_FLOW_OK)
goto error;
@@ -944,6 +1037,8 @@ gst_base_audio_sink_async_play (GstBaseSink * basesink)
}
no_clock:
+ gst_ring_buffer_start (sink->ringbuffer);
+
return GST_STATE_CHANGE_SUCCESS;
}
@@ -1009,7 +1104,6 @@ gst_base_audio_sink_change_state (GstElement * element,
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
gst_ring_buffer_release (sink->ringbuffer);
- gst_pad_set_caps (GST_BASE_SINK_PAD (sink), NULL);
break;
case GST_STATE_CHANGE_READY_TO_NULL:
gst_ring_buffer_close_device (sink->ringbuffer);
diff --git a/gst-libs/gst/audio/gstbaseaudiosrc.c b/gst-libs/gst/audio/gstbaseaudiosrc.c
index 992c5d61..fa0c720f 100644
--- a/gst-libs/gst/audio/gstbaseaudiosrc.c
+++ b/gst-libs/gst/audio/gstbaseaudiosrc.c
@@ -66,6 +66,7 @@ static void gst_base_audio_src_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_base_audio_src_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
+static void gst_base_audio_src_dispose (GObject * object);
static GstStateChangeReturn gst_base_audio_src_change_state (GstElement *
element, GstStateChange transition);
@@ -84,6 +85,7 @@ static gboolean gst_base_audio_src_event (GstBaseSrc * bsrc, GstEvent * event);
static void gst_base_audio_src_get_times (GstBaseSrc * bsrc,
GstBuffer * buffer, GstClockTime * start, GstClockTime * end);
static gboolean gst_base_audio_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps);
+static gboolean gst_base_audio_src_query (GstBaseSrc * bsrc, GstQuery * query);
static void gst_base_audio_src_fixate (GstBaseSrc * bsrc, GstCaps * caps);
/* static guint gst_base_audio_src_signals[LAST_SIGNAL] = { 0 }; */
@@ -110,6 +112,7 @@ gst_base_audio_src_class_init (GstBaseAudioSrcClass * klass)
GST_DEBUG_FUNCPTR (gst_base_audio_src_set_property);
gobject_class->get_property =
GST_DEBUG_FUNCPTR (gst_base_audio_src_get_property);
+ gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_base_audio_src_dispose);
g_object_class_install_property (gobject_class, PROP_BUFFER_TIME,
g_param_spec_int64 ("buffer-time", "Buffer Time",
@@ -130,6 +133,7 @@ gst_base_audio_src_class_init (GstBaseAudioSrcClass * klass)
gstbasesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_base_audio_src_setcaps);
gstbasesrc_class->event = GST_DEBUG_FUNCPTR (gst_base_audio_src_event);
+ gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_base_audio_src_query);
gstbasesrc_class->get_times =
GST_DEBUG_FUNCPTR (gst_base_audio_src_get_times);
gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_base_audio_src_create);
@@ -157,6 +161,25 @@ gst_base_audio_src_init (GstBaseAudioSrc * baseaudiosrc,
gst_base_src_set_format (GST_BASE_SRC (baseaudiosrc), GST_FORMAT_TIME);
}
+static void
+gst_base_audio_src_dispose (GObject * object)
+{
+ GstBaseAudioSrc *src;
+
+ src = GST_BASE_AUDIO_SRC (object);
+
+ if (src->clock)
+ gst_object_unref (src->clock);
+ src->clock = NULL;
+
+ if (src->ringbuffer) {
+ gst_object_unparent (GST_OBJECT_CAST (src->ringbuffer));
+ src->ringbuffer = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
static gboolean
gst_base_audio_src_set_clock (GstElement * elem, GstClock * clock)
{
@@ -379,6 +402,50 @@ gst_base_audio_src_get_times (GstBaseSrc * bsrc, GstBuffer * buffer,
}
static gboolean
+gst_base_audio_src_query (GstBaseSrc * bsrc, GstQuery * query)
+{
+ GstBaseAudioSrc *src = GST_BASE_AUDIO_SRC (bsrc);
+ gboolean res = FALSE;
+
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_LATENCY:
+ {
+ GstClockTime min_latency, max_latency;
+ GstRingBufferSpec *spec;
+
+ if (G_UNLIKELY (src->ringbuffer == NULL
+ || src->ringbuffer->spec.rate == 0))
+ goto done;
+
+ spec = &src->ringbuffer->spec;
+
+ min_latency =
+ gst_util_uint64_scale_int (spec->segsize, GST_SECOND,
+ spec->rate * spec->bytes_per_sample);
+ max_latency =
+ gst_util_uint64_scale_int (spec->segtotal * spec->segsize, GST_SECOND,
+ spec->rate * spec->bytes_per_sample);
+
+ GST_DEBUG_OBJECT (src,
+ "report latency min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
+
+ /* we are always live, the min latency is 1 segment and the max latency is
+ * the complete buffer of segments. */
+ gst_query_set_latency (query, TRUE, min_latency, max_latency);
+
+ res = TRUE;
+ break;
+ }
+ default:
+ res = GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query);
+ break;
+ }
+done:
+ return res;
+}
+
+static gboolean
gst_base_audio_src_event (GstBaseSrc * bsrc, GstEvent * event)
{
GstBaseAudioSrc *src = GST_BASE_AUDIO_SRC (bsrc);
@@ -588,15 +655,18 @@ gst_base_audio_src_change_state (GstElement * element,
src->ringbuffer = gst_base_audio_src_create_ringbuffer (src);
}
if (!gst_ring_buffer_open_device (src->ringbuffer))
- return GST_STATE_CHANGE_FAILURE;
- src->next_sample = -1;
+ goto open_failed;
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
+ src->next_sample = -1;
gst_ring_buffer_set_flushing (src->ringbuffer, FALSE);
break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
gst_ring_buffer_may_start (src->ringbuffer, TRUE);
break;
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ gst_ring_buffer_set_flushing (src->ringbuffer, TRUE);
+ break;
default:
break;
}
@@ -609,9 +679,7 @@ gst_base_audio_src_change_state (GstElement * element,
gst_ring_buffer_pause (src->ringbuffer);
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
- gst_ring_buffer_set_flushing (src->ringbuffer, TRUE);
gst_ring_buffer_release (src->ringbuffer);
- src->next_sample = -1;
break;
case GST_STATE_CHANGE_READY_TO_NULL:
gst_ring_buffer_close_device (src->ringbuffer);
@@ -623,4 +691,13 @@ gst_base_audio_src_change_state (GstElement * element,
}
return ret;
+
+ /* ERRORS */
+open_failed:
+ {
+ /* subclass must post a meaningfull error message */
+ GST_DEBUG_OBJECT (src, "open failed");
+ return GST_STATE_CHANGE_FAILURE;
+ }
+
}