gst-libs/gst/audio/gstaudiosink.c: Choose to allocate one less segment but require...
authorWim Taymans <wim.taymans@gmail.com>
Fri, 9 May 2008 16:38:10 +0000 (16:38 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Fri, 9 May 2008 16:38:10 +0000 (16:38 +0000)
Original commit message from CVS:
* gst-libs/gst/audio/gstaudiosink.c: (gst_audioringbuffer_acquire):
Choose to allocate one less segment but require one additional segment
as latency.
* gst-libs/gst/audio/gstaudiosrc.c: (gst_audioringbuffer_acquire):
No need to increment the number of segments in the source.
* gst-libs/gst/audio/gstbaseaudiosink.c:
(gst_base_audio_sink_get_time), (clock_convert_external),
(gst_base_audio_sink_resample_slaving),
(gst_base_audio_sink_skew_slaving),
(gst_base_audio_sink_none_slaving), (gst_base_audio_sink_render),
(gst_base_audio_sink_async_play):
Remove adding latency when returning the internal time while subtracting
it again when we use the value a little later.
When calculating the end timestamp, we are making a rounding error
with the current algorithm. Ensure that we don't accumulate these
rounding errors when aligning samples by not resampling at all if we
don't need to. Fixes #419351.
Make the initial calibration of the clock slaving a little more
predictable and accurate. Also handle the case where we don't do
clock slaving.

ChangeLog
gst-libs/gst/audio/gstaudiosink.c
gst-libs/gst/audio/gstaudiosrc.c
gst-libs/gst/audio/gstbaseaudiosink.c

index 139a9a1..09a24cf 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,28 @@
+2008-05-09  Wim Taymans  <wim.taymans@collabora.co.uk>
+
+       * gst-libs/gst/audio/gstaudiosink.c: (gst_audioringbuffer_acquire):
+       Choose to allocate one less segment but require one additional segment
+       as latency. 
+
+       * gst-libs/gst/audio/gstaudiosrc.c: (gst_audioringbuffer_acquire):
+       No need to increment the number of segments in the source.
+
+       * gst-libs/gst/audio/gstbaseaudiosink.c:
+       (gst_base_audio_sink_get_time), (clock_convert_external),
+       (gst_base_audio_sink_resample_slaving),
+       (gst_base_audio_sink_skew_slaving),
+       (gst_base_audio_sink_none_slaving), (gst_base_audio_sink_render),
+       (gst_base_audio_sink_async_play):
+       Remove adding latency when returning the internal time while subtracting
+       it again when we use the value a little later.
+       When calculating the end timestamp, we are making a rounding error
+       with the current algorithm. Ensure that we don't accumulate these
+       rounding errors when aligning samples by not resampling at all if we
+       don't need to. Fixes #419351.
+       Make the initial calibration of the clock slaving a little more
+       predictable and accurate. Also handle the case where we don't do
+       clock slaving.
+
 2008-05-09  Sebastian Dröge  <slomo@circular-chaos.org>
 
        Based on a patch by:
index fd10b83..39e71ea 100644 (file)
@@ -366,8 +366,8 @@ gst_audioringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
   if (!result)
     goto could_not_prepare;
 
-  /* allocate one more segment as we need some headroom */
-  spec->segtotal++;
+  /* set latency to one more segment as we need some headroom */
+  spec->seglatency = spec->segtotal + 1;
 
   buf->data = gst_buffer_new_and_alloc (spec->segtotal * spec->segsize);
   memset (GST_BUFFER_DATA (buf->data), 0, GST_BUFFER_SIZE (buf->data));
index 2587035..2afb397 100644 (file)
@@ -360,9 +360,6 @@ gst_audioringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
   if (!result)
     goto could_not_open;
 
-  /* allocate one more segment as we need some headroom */
-  spec->segtotal++;
-
   buf->data = gst_buffer_new_and_alloc (spec->segtotal * spec->segsize);
   memset (GST_BUFFER_DATA (buf->data), 0, GST_BUFFER_SIZE (buf->data));
 
index c889c69..82abaf4 100644 (file)
@@ -371,7 +371,7 @@ gst_base_audio_sink_get_time (GstClock * clock, GstBaseAudioSink * sink)
 {
   guint64 raw, samples;
   guint delay;
-  GstClockTime result, us_latency;
+  GstClockTime result;
 
   if (sink->ringbuffer == NULL || sink->ringbuffer->spec.rate == 0)
     return GST_CLOCK_TIME_NONE;
@@ -391,15 +391,9 @@ gst_base_audio_sink_get_time (GstClock * clock, GstBaseAudioSink * sink)
   result = gst_util_uint64_scale_int (samples, GST_SECOND,
       sink->ringbuffer->spec.rate);
 
-  /* latency before starting the clock */
-  us_latency = sink->priv->us_latency;
-
-  result += us_latency;
-
   GST_DEBUG_OBJECT (sink,
       "processed samples: raw %llu, delay %u, real %llu, time %"
-      GST_TIME_FORMAT ", upstream latency %" GST_TIME_FORMAT, raw, delay,
-      samples, GST_TIME_ARGS (result), GST_TIME_ARGS (us_latency));
+      GST_TIME_FORMAT, raw, delay, samples, GST_TIME_ARGS (result));
 
   return result;
 }
@@ -787,8 +781,7 @@ gst_base_audio_sink_get_offset (GstBaseAudioSink * sink)
 
 static GstClockTime
 clock_convert_external (GstClockTime external, GstClockTime cinternal,
-    GstClockTime cexternal, GstClockTime crate_num, GstClockTime crate_denom,
-    GstClockTime us_latency)
+    GstClockTime cexternal, GstClockTime crate_num, GstClockTime crate_denom)
 {
   /* adjust for rate and speed */
   if (external >= cexternal) {
@@ -803,12 +796,6 @@ clock_convert_external (GstClockTime external, GstClockTime cinternal,
     else
       external = 0;
   }
-  /* adjust for offset when slaving started */
-  if (external > us_latency)
-    external -= us_latency;
-  else
-    external = 0;
-
   return external;
 }
 
@@ -838,9 +825,9 @@ gst_base_audio_sink_resample_slaving (GstBaseAudioSink * sink,
 
   /* bring external time to internal time */
   render_start = clock_convert_external (render_start, cinternal, cexternal,
-      crate_num, crate_denom, sink->priv->us_latency);
+      crate_num, crate_denom);
   render_stop = clock_convert_external (render_stop, cinternal, cexternal,
-      crate_num, crate_denom, sink->priv->us_latency);
+      crate_num, crate_denom);
 
   GST_DEBUG_OBJECT (sink,
       "after slaving: start %" GST_TIME_FORMAT " - stop %" GST_TIME_FORMAT,
@@ -875,6 +862,9 @@ gst_base_audio_sink_skew_slaving (GstBaseAudioSink * sink,
   etime = etime > cexternal ? etime - cexternal : 0;
   itime = itime > cinternal ? itime - cinternal : 0;
 
+  /* do itime - etime.
+   * positive value means external clock goes slower
+   * negative value means external clock goes faster */
   skew = GST_CLOCK_DIFF (etime, itime);
   if (sink->priv->avg_skew == -1) {
     /* first observation */
@@ -945,9 +935,9 @@ gst_base_audio_sink_skew_slaving (GstBaseAudioSink * sink,
 
   /* convert, ignoring speed */
   render_start = clock_convert_external (render_start, cinternal, cexternal,
-      crate_num, crate_denom, sink->priv->us_latency);
+      crate_num, crate_denom);
   render_stop = clock_convert_external (render_stop, cinternal, cexternal,
-      crate_num, crate_denom, sink->priv->us_latency);
+      crate_num, crate_denom);
 
   *srender_start = render_start;
   *srender_stop = render_stop;
@@ -967,9 +957,9 @@ gst_base_audio_sink_none_slaving (GstBaseAudioSink * sink,
 
   /* convert, ignoring speed */
   render_start = clock_convert_external (render_start, cinternal, cexternal,
-      crate_num, crate_denom, sink->priv->us_latency);
+      crate_num, crate_denom);
   render_stop = clock_convert_external (render_stop, cinternal, cexternal,
-      crate_num, crate_denom, sink->priv->us_latency);
+      crate_num, crate_denom);
 
   *srender_start = render_start;
   *srender_stop = render_stop;
@@ -1153,26 +1143,34 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
   render_stop = gst_util_uint64_scale_int (render_stop,
       ringbuf->spec.rate, GST_SECOND);
 
+  /* positive playback rate, first sample is render_start, negative rate, first
+   * sample is render_stop. When no rate conversion is active, render exactly
+   * the amount of input samples to avoid aligning to rounding errors. */
+  if (bsink->segment.rate >= 0.0) {
+    sample_offset = render_start;
+    if (bsink->segment.rate == 1.0)
+      render_stop = sample_offset + samples;
+  } else {
+    sample_offset = render_stop;
+    if (bsink->segment.rate == -1.0)
+      render_start = sample_offset + samples;
+  }
+
   /* 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");
     goto no_align;
   }
 
+  /* resync when we don't know what to align the sample with */
   if (G_UNLIKELY (sink->next_sample == -1)) {
     GST_DEBUG_OBJECT (sink,
         "no align possible: no previous sample position known");
     goto no_align;
   }
 
-  /* positive playback rate, first sample is render_start, negative rate, first
-   * sample is render_stop */
-  if (bsink->segment.rate >= 0.0)
-    sample_offset = render_start;
-  else
-    sample_offset = render_stop;
-
-  /* now try to align the sample to the previous one */
+  /* now try to align the sample to the previous one, first see how big the
+   * difference is. */
   if (sample_offset >= sink->next_sample)
     diff = sample_offset - sink->next_sample;
   else
@@ -1422,12 +1420,22 @@ gst_base_audio_sink_async_play (GstBaseSink * basesink)
   /* if we are slaved to a clock, we need to set the initial
    * calibration */
   /* get external and internal time to set as calibration params */
-  etime = gst_clock_get_time (clock);
-  itime = gst_clock_get_internal_time (sink->provided_clock);
-
-  sink->priv->avg_skew = -1;
-  sink->next_sample = -1;
+  etime = GST_ELEMENT_CAST (sink)->base_time;
+  itime = gst_base_audio_sink_get_time (sink->provided_clock, sink);
 
+  switch (sink->priv->slave_method) {
+    case GST_BASE_AUDIO_SINK_SLAVE_SKEW:
+    case GST_BASE_AUDIO_SINK_SLAVE_RESAMPLE:
+      /* adjust with upstream latency, when we are prerolled, our internal clock
+       * should exactly have been the time of the upstream latency */
+      etime += sink->priv->us_latency;
+      break;
+    case GST_BASE_AUDIO_SINK_SLAVE_NONE:
+      /* no slaving, base_time corresponds to our 0 time */
+      itime = 0;
+    default:
+      break;
+  }
   GST_DEBUG_OBJECT (sink,
       "internal time: %" GST_TIME_FORMAT " external time: %" GST_TIME_FORMAT,
       GST_TIME_ARGS (itime), GST_TIME_ARGS (etime));
@@ -1439,14 +1447,19 @@ gst_base_audio_sink_async_play (GstBaseSink * basesink)
 
   switch (sink->priv->slave_method) {
     case GST_BASE_AUDIO_SINK_SLAVE_RESAMPLE:
-      /* only set as master if we need to resample */
+      /* only set as master when we are resampling */
       GST_DEBUG_OBJECT (sink, "Setting clock as master");
       gst_clock_set_master (sink->provided_clock, clock);
       break;
+    case GST_BASE_AUDIO_SINK_SLAVE_SKEW:
+    case GST_BASE_AUDIO_SINK_SLAVE_NONE:
     default:
       break;
   }
 
+  sink->priv->avg_skew = -1;
+  sink->next_sample = -1;
+
   /* start ringbuffer so we can start slaving right away when we need to */
   gst_ring_buffer_start (sink->ringbuffer);