[vlc-commits] [Git][videolan/vlc][master] 7 commits: aout: rename stream_TimeGet to stream_GetDelay

Steve Lhomme (@robUx4) gitlab at videolan.org
Wed Nov 23 08:16:03 UTC 2022



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
4d4c5b19 by Thomas Guillem at 2022-11-23T08:03:47+00:00
aout: rename stream_TimeGet to stream_GetDelay

This function is returning the aout delay (delay until the last block is
played).

But keep time_get inside aout modules.

- - - - -
2f2d608a by Thomas Guillem at 2022-11-23T08:03:47+00:00
aout: move and re-indent code

No functional changes

- - - - -
98fac7ad by Thomas Guillem at 2022-11-23T08:03:47+00:00
aout: fix stream_TimeGet emulation 1/2

NB: Emulation is when the module use aout_TimingReport()

The legacy aout->time_get return the delay, taking into account all the
data that has been played. Therefore, the emulation should also use the
true last PTS, that is first_pts + total played data, in order to
include all extra audio data played (silence, resampler, filters).

Use samples and not length to keep track of the played data because
length might not be rounded (depending on the rate).

- - - - -
d512b8b3 by Thomas Guillem at 2022-11-23T08:03:47+00:00
aout: fix stream_TimeGet emulation 2/2

Don't use the clock but interpolate the last reported timing, so that
the returned delay can drift from the clock.

This will be needed by the next fix for stream_Synchronize() that will
always use stream_GetDelay() to calculate the drift (even if the aout is
using aout_TimingReport()).

- - - - -
581dd52e by Thomas Guillem at 2022-11-23T08:03:47+00:00
aout: fix drift handling when using aout_TimingReport()

Drift handling was not fully tested when the aout was using
aout_TimingReport() (and the audio was not the master).

It was working for big drifts (silence or flush) but not for small ones,
when the resampler was used because the last set drift was reset once
used.

Furthermore, stream_Synchronize() should not use past points but up to
date points including:
 - The silence already sent
 - The block resize (bigger or smaller) due to the resampler

The simplest way to achieve that is to use the audio delay, that is now
fixed when using aout_TimingReport().

- - - - -
f406f566 by Thomas Guillem at 2022-11-23T08:03:47+00:00
aout: re-indent after previous commit

No functional changes.

- - - - -
93cc6fd9 by Thomas Guillem at 2022-11-23T08:03:47+00:00
aout: fix comment

Most aout modules -> some aout modules.

- - - - -


1 changed file:

- src/audio_output/dec.c


Changes:

=====================================
src/audio_output/dec.c
=====================================
@@ -63,16 +63,19 @@ struct vlc_aout_stream
 
     struct
     {
-        vlc_mutex_t lock; /* Guard first_pts, last_drift, rate_system_ts and
-                             rate_audio_ts */
+        vlc_mutex_t lock; /* Guard first_pts, last_drift, rate_system_ts,
+                             rate_audio_ts, system_ts, audio_ts */
 
         vlc_tick_t last_drift;
 
         vlc_tick_t first_pts;
-        vlc_tick_t last_pts; /* Used for stream_TimeGet() emulation */
+        int64_t played_samples; /* Used for stream_GetDelay() emulation */
 
         vlc_tick_t rate_system_ts;
         vlc_tick_t rate_audio_ts;
+
+        vlc_tick_t system_ts;
+        vlc_tick_t audio_ts;
         float rate;
     } timing;
 
@@ -114,26 +117,41 @@ static inline struct vlc_tracer *aout_stream_tracer(vlc_aout_stream *stream)
         vlc_object_get_tracer(VLC_OBJECT(aout_stream_aout(stream)));
 }
 
-static int stream_TimeGet(vlc_aout_stream *stream, vlc_tick_t *delay)
+static int stream_GetDelay(vlc_aout_stream *stream, vlc_tick_t *delay)
 {
     audio_output_t *aout = aout_stream_aout(stream);
 
-    if (aout->time_get == NULL)
+    if (aout->time_get != NULL)
+        return aout->time_get(aout, delay);
+
+    vlc_mutex_lock(&stream->timing.lock);
+    vlc_tick_t system_ts = stream->timing.system_ts;
+    vlc_tick_t audio_ts = stream->timing.audio_ts;
+    if (system_ts == VLC_TICK_INVALID)
     {
-        if (stream->timing.last_pts == VLC_TICK_INVALID)
-            return -1;
+        vlc_mutex_unlock(&stream->timing.lock);
+        return -1;
+    }
+    vlc_mutex_unlock(&stream->timing.lock);
 
-        /* Interpolate the last updated point. */
-        vlc_tick_t system_now = vlc_tick_now();
+    /* Interpolate the last updated point. */
+    vlc_tick_t system_now = vlc_tick_now();
 
-        vlc_tick_t play_date =
-            vlc_clock_ConvertToSystem(stream->sync.clock, system_now,
-                                      stream->timing.last_pts,
-                                      stream->sync.rate);
-        *delay = play_date - system_now;
-        return 0;
-    }
-    return aout->time_get(aout, delay);
+    /* Use all samples sent to the aout via the play function (normal
+     * blocks, silence blocks, resampled correction) */
+    vlc_tick_t played_length =
+        vlc_tick_from_samples(stream->timing.played_samples,
+                              stream->mixer_format.i_rate);
+    vlc_tick_t last_pts = stream->timing.first_pts + played_length;
+
+    /* Equivalent to vlc_clock_ConvertToSystem(), but assume the
+     * coefficient is 1.0 (audio at the same speed than the monotonic
+     * clock) since the calculation is done on a very small interval
+     * (generally less than 2 seconds). */
+    vlc_tick_t play_date = (last_pts - audio_ts) / (double) stream->sync.rate
+                         + system_ts;
+    *delay = play_date - system_now;
+    return 0;
 }
 
 static void stream_Discontinuity(vlc_aout_stream *stream)
@@ -144,8 +162,10 @@ static void stream_Discontinuity(vlc_aout_stream *stream)
     vlc_mutex_lock(&stream->timing.lock);
     stream->timing.first_pts = VLC_TICK_INVALID;
     stream->timing.last_drift = VLC_TICK_INVALID;
+    stream->timing.system_ts = VLC_TICK_INVALID;
+    stream->timing.audio_ts = VLC_TICK_INVALID;
     vlc_mutex_unlock(&stream->timing.lock);
-    stream->timing.last_pts = VLC_TICK_INVALID;
+    stream->timing.played_samples = 0;
 }
 
 static void stream_Reset(vlc_aout_stream *stream)
@@ -435,6 +455,7 @@ static void stream_Silence (vlc_aout_stream *stream, vlc_tick_t length, vlc_tick
     const vlc_tick_t system_pts =
        vlc_clock_ConvertToSystem(stream->sync.clock, system_now, pts,
                                  stream->sync.rate);
+    stream->timing.played_samples += block->i_nb_samples;
     aout->play(aout, block, system_pts);
 }
 
@@ -585,35 +606,62 @@ static void stream_Synchronize(vlc_aout_stream *stream, vlc_tick_t system_now,
      *    pts = vlc_tick_now() + delay
      */
     vlc_tick_t delay;
+    vlc_tick_t drift;
+    audio_output_t *aout = aout_stream_aout(stream);
 
-    if (stream_TimeGet(stream, &delay) != 0)
-        return; /* nothing can be done if timing is unknown */
-
-    if (stream->sync.discontinuity)
+    if (aout->time_get == NULL)
     {
-        /* Chicken-egg situation for most aout modules that can't be started
-         * deferred (all except PulseAudio). These modules will start to play
-         * data immediately and ignore the given play_date (that take the clock
-         * jitter into account). We don't want to let stream_HandleDrift()
-         * handle the first silence (from the "Early audio output" case) since
-         * this function will first update the clock without taking the jitter
-         * into account. Therefore, we manually insert silence that correspond
-         * to the clock jitter value before updating the clock.
-         */
-        vlc_tick_t play_date =
-            vlc_clock_ConvertToSystem(stream->sync.clock, system_now + delay,
-                                      dec_pts, stream->sync.rate);
-        vlc_tick_t jitter = play_date - system_now;
-        if (jitter > 0)
+        vlc_mutex_lock(&stream->timing.lock);
+        bool is_drifting = stream->timing.last_drift != VLC_TICK_INVALID;
+        vlc_mutex_unlock(&stream->timing.lock);
+
+        if (!is_drifting)
         {
-            stream_Silence(stream, jitter, dec_pts - delay);
-            if (stream_TimeGet(stream, &delay) != 0)
-                return;
+            /* module is using aout_TimingReport() and stream is master:
+             * nothing to do */
+            return;
         }
+        if (stream_GetDelay(stream, &delay) != 0)
+            return; /* nothing can be done if timing is unknown */
+
+        /* Equivalent to vlc_clock_Update() but we don't want to update points
+         * (since there are already updated via aout_TimingReport()). */
+        vlc_tick_t play_date =
+            vlc_clock_ConvertToSystem(stream->sync.clock, system_now + delay, dec_pts,
+                                      stream->sync.rate);
+        drift = play_date - system_now - delay;
     }
+    else
+    {
+        if (stream_GetDelay(stream, &delay) != 0)
+            return; /* nothing can be done if timing is unknown */
 
-    vlc_tick_t drift = vlc_clock_Update(stream->sync.clock, system_now + delay,
-                                        dec_pts, stream->sync.rate);
+        if (stream->sync.discontinuity)
+        {
+            /* Chicken-egg situation for some aout modules that can't be
+             * started deferred (like alsa). These modules will start to play
+             * data immediately and ignore the given play_date (that take the
+             * clock jitter into account). We don't want to let
+             * stream_HandleDrift() handle the first silence (from the "Early
+             * audio output" case) since this function will first update the
+             * clock without taking the jitter into account. Therefore, we
+             * manually insert silence that correspond to the clock jitter
+             * value before updating the clock. */
+            vlc_tick_t play_date =
+                vlc_clock_ConvertToSystem(stream->sync.clock, system_now + delay,
+                                          dec_pts, stream->sync.rate);
+            vlc_tick_t jitter = play_date - system_now;
+            if (jitter > 0)
+            {
+                stream_Silence(stream, jitter, dec_pts - delay);
+                if (stream_GetDelay(stream, &delay) != 0)
+                    return;
+            }
+        }
+
+        drift = vlc_clock_Update(stream->sync.clock, system_now + delay,
+                                 dec_pts, stream->sync.rate);
+    }
 
     stream_HandleDrift(stream, drift, dec_pts);
 }
@@ -641,6 +689,8 @@ void vlc_aout_stream_NotifyTiming(vlc_aout_stream *stream, vlc_tick_t system_ts,
                    * stream->timing.rate;
     }
 
+    stream->timing.system_ts = system_ts;
+    stream->timing.audio_ts = audio_ts;
     stream->timing.last_drift =
         vlc_clock_Update(stream->sync.clock, system_ts,
                          audio_ts, stream->timing.rate);
@@ -711,16 +761,7 @@ int vlc_aout_stream_Play(vlc_aout_stream *stream, block_t *block)
 
     /* Drift correction */
     vlc_tick_t system_now = vlc_tick_now();
-    if (aout->time_get != NULL)
-        stream_Synchronize(stream, system_now, original_pts);
-    else
-    {
-        vlc_mutex_lock(&stream->timing.lock);
-        vlc_tick_t drift = stream->timing.last_drift;
-        stream->timing.last_drift = VLC_TICK_INVALID;
-        vlc_mutex_unlock(&stream->timing.lock);
-        stream_HandleDrift(stream, drift, original_pts);
-    }
+    stream_Synchronize(stream, system_now, original_pts);
 
     vlc_tick_t play_date =
         vlc_clock_ConvertToSystem(stream->sync.clock, system_now, original_pts,
@@ -758,10 +799,10 @@ int vlc_aout_stream_Play(vlc_aout_stream *stream, block_t *block)
         stream->timing.first_pts = original_pts;
         vlc_mutex_unlock(&stream->timing.lock);
     }
-    stream->timing.last_pts = original_pts;
 
     /* Output */
     stream->sync.discontinuity = false;
+    stream->timing.played_samples += block->i_nb_samples;
     aout->play(aout, block, play_date);
 
     atomic_fetch_add_explicit(&stream->buffers_played, 1, memory_order_relaxed);
@@ -893,7 +934,7 @@ void vlc_aout_stream_Drain(vlc_aout_stream *stream)
         vlc_tick_t drain_deadline = vlc_tick_now();
 
         vlc_tick_t delay;
-        if (stream_TimeGet(stream, &delay) == 0)
+        if (stream_GetDelay(stream, &delay) == 0)
             drain_deadline += delay;
         /* else the deadline is now, and vlc_aout_stream_IsDrained() will
          * return true on the first call. */



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/76397ea351daefd31062fcc21c14d3e8ee6d246e...93cc6fd943c47a4bede668d4ff4c3490375c5048

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/76397ea351daefd31062fcc21c14d3e8ee6d246e...93cc6fd943c47a4bede668d4ff4c3490375c5048
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list