[vlc-devel] [PATCH 12/18] aout: use vlc_clock_t

Thomas Guillem thomas at gllm.fr
Thu Mar 7 15:25:34 CET 2019


During the transition, the clock argument is not mandatory. If the clock is
NULL, the aout will use ts from the block_t that were converted from the
decoder.

Co-authored-by: RĂ©mi Denis-Courmont <remi at remlab.net>
---
 src/audio_output/aout_internal.h |   7 +-
 src/audio_output/dec.c           | 136 +++++++++++++++++++++++++------
 src/input/decoder.c              |   2 +-
 3 files changed, 117 insertions(+), 28 deletions(-)

diff --git a/src/audio_output/aout_internal.h b/src/audio_output/aout_internal.h
index 7cf7a83e68..1dd92e96aa 100644
--- a/src/audio_output/aout_internal.h
+++ b/src/audio_output/aout_internal.h
@@ -63,10 +63,14 @@ typedef struct
 
     struct
     {
+        struct vlc_clock_t *clock;
         float rate; /**< Play-out speed rate */
         vlc_tick_t resamp_start_drift; /**< Resampler drift absolute value */
         int resamp_type; /**< Resampler mode (FIXME: redundant / resampling) */
         bool discontinuity;
+        vlc_tick_t request_delay;
+        vlc_tick_t delay;
+        vlc_tick_t first_pts;
     } sync;
     vlc_tick_t original_pts;
 
@@ -129,12 +133,13 @@ void aout_FormatsPrint(vlc_object_t *, const char *,
 #define AOUT_DEC_FAILED VLC_EGENERIC
 
 int aout_DecNew(audio_output_t *, const audio_sample_format_t *,
-                const audio_replay_gain_t *);
+                struct vlc_clock_t *clock, const audio_replay_gain_t *);
 void aout_DecDelete(audio_output_t *);
 int aout_DecPlay(audio_output_t *aout, block_t *block);
 void aout_DecGetResetStats(audio_output_t *, unsigned *, unsigned *);
 void aout_DecChangePause(audio_output_t *, bool b_paused, vlc_tick_t i_date);
 void aout_DecChangeRate(audio_output_t *aout, float rate);
+void aout_DecChangeDelay(audio_output_t *aout, vlc_tick_t delay);
 void aout_DecFlush(audio_output_t *, bool wait);
 void aout_RequestRestart (audio_output_t *, unsigned);
 void aout_RequestRetiming(audio_output_t *aout, vlc_tick_t system_ts,
diff --git a/src/audio_output/dec.c b/src/audio_output/dec.c
index d74d3b4a93..6b79b249b6 100644
--- a/src/audio_output/dec.c
+++ b/src/audio_output/dec.c
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * dec.c : audio output API towards decoders
  *****************************************************************************
- * Copyright (C) 2002-2007 VLC authors and VideoLAN
+ * Copyright (C) 2002-2019 VLC authors, VideoLAN and Videolabs SAS
  *
  * Authors: Christophe Massiot <massiot at via.ecp.fr>
  *
@@ -35,14 +35,14 @@
 #include <vlc_aout.h>
 
 #include "aout_internal.h"
+#include "clock/clock.h"
 #include "libvlc.h"
 
 /**
  * Creates an audio output
  */
-int aout_DecNew(audio_output_t *p_aout,
-                const audio_sample_format_t *p_format,
-                const audio_replay_gain_t *p_replay_gain)
+int aout_DecNew(audio_output_t *p_aout, const audio_sample_format_t *p_format,
+                vlc_clock_t *clock, const audio_replay_gain_t *p_replay_gain)
 {
     assert(p_aout);
     assert(p_format);
@@ -80,6 +80,7 @@ int aout_DecNew(audio_output_t *p_aout,
     atomic_store_explicit(&owner->restart, 0, memory_order_relaxed);
     owner->input_format = *p_format;
     owner->mixer_format = owner->input_format;
+    owner->sync.clock = clock;
 
     owner->filters_cfg = AOUT_FILTERS_CFG_INIT;
     if (aout_OutputNew (p_aout, &owner->mixer_format, &owner->filters_cfg))
@@ -87,8 +88,9 @@ int aout_DecNew(audio_output_t *p_aout,
     aout_volume_SetFormat (owner->volume, owner->mixer_format.i_format);
 
     /* Create the audio filtering "input" pipeline */
-    owner->filters = aout_FiltersNew(p_aout, p_format, &owner->mixer_format,
-                                     &owner->filters_cfg);
+    owner->filters = aout_FiltersNewWithClock(VLC_OBJECT(p_aout), clock, p_format,
+                                              &owner->mixer_format,
+                                              &owner->filters_cfg);
     if (owner->filters == NULL)
     {
         aout_OutputDelete (p_aout);
@@ -102,6 +104,7 @@ error:
     owner->sync.resamp_type = AOUT_RESAMPLING_NONE;
     owner->sync.discontinuity = true;
     owner->original_pts = VLC_TICK_INVALID;
+    owner->sync.delay = owner->sync.request_delay = 0;
 
     atomic_init (&owner->buffers_lost, 0);
     atomic_init (&owner->buffers_played, 0);
@@ -162,14 +165,17 @@ static int aout_CheckReady (audio_output_t *aout)
 
         if (owner->mixer_format.i_format)
         {
-            owner->filters = aout_FiltersNew(aout, &owner->input_format,
-                                             &owner->mixer_format,
-                                             &owner->filters_cfg);
+            owner->filters = aout_FiltersNewWithClock(VLC_OBJECT(aout),
+                                                      owner->sync.clock,
+                                                      &owner->input_format,
+                                                      &owner->mixer_format,
+                                                      &owner->filters_cfg);
             if (owner->filters == NULL)
             {
                 aout_OutputDelete (aout);
                 owner->mixer_format.i_format = 0;
             }
+            aout_FiltersSetClockDelay(owner->filters, owner->sync.delay);
         }
         /* TODO: This would be a good time to call clean up any video output
          * left over by an audio visualization:
@@ -201,6 +207,8 @@ static void aout_StopResampling (audio_output_t *aout)
     aout_FiltersAdjustResampling (owner->filters, 0);
 }
 
+static void aout_DecSynchronize(audio_output_t *aout, vlc_tick_t system_now,
+                                vlc_tick_t dec_pts);
 static void aout_DecSilence (audio_output_t *aout, vlc_tick_t length, vlc_tick_t pts)
 {
     aout_owner_t *owner = aout_owner (aout);
@@ -218,14 +226,17 @@ static void aout_DecSilence (audio_output_t *aout, vlc_tick_t length, vlc_tick_t
     block->i_pts = pts;
     block->i_dts = pts;
     block->i_length = length;
-    aout->play(aout, block, pts);
+
+    const vlc_tick_t system_now = vlc_tick_now();
+    const vlc_tick_t system_pts = !owner->sync.clock ? pts :
+       vlc_clock_ConvertToSystem(owner->sync.clock, system_now, pts,
+                                 owner->sync.rate);
+    aout->play(aout, block, system_pts);
 }
 
-static void aout_DecSynchronize(audio_output_t *aout, vlc_tick_t dec_pts)
+static void aout_DecSynchronize(audio_output_t *aout, vlc_tick_t system_now,
+                                vlc_tick_t dec_pts)
 {
-    vlc_tick_t now = vlc_tick_now();
-    vlc_tick_t delay;
-
     /**
      * Depending on the drift between the actual and intended playback times,
      * the audio core may ignore the drift, trigger upsampling or downsampling,
@@ -242,18 +253,45 @@ static void aout_DecSynchronize(audio_output_t *aout, vlc_tick_t dec_pts)
      * all samples in the buffer will have been played. Then:
      *    pts = vlc_tick_now() + delay
      */
+    aout_owner_t *owner = aout_owner (aout);
+    vlc_tick_t delay;
+
     if (aout->time_get(aout, &delay) != 0)
         return; /* nothing can be done if timing is unknown */
 
-    aout_RequestRetiming(aout, now, dec_pts - delay);
+    if (owner->sync.discontinuity && owner->sync.clock)
+    {
+        /* 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 aout_RequestRetiming()
+         * 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(owner->sync.clock, system_now + delay,
+                                      dec_pts, owner->sync.rate);
+        vlc_tick_t jitter = play_date - system_now;
+        if (jitter > 0)
+        {
+            aout_DecSilence (aout, jitter, dec_pts - delay);
+            if (aout->time_get(aout, &delay) != 0)
+                return;
+        }
+    }
+
+    aout_RequestRetiming(aout, system_now + delay, dec_pts);
 }
 
 void aout_RequestRetiming(audio_output_t *aout, vlc_tick_t system_ts,
                           vlc_tick_t audio_ts)
 {
     aout_owner_t *owner = aout_owner (aout);
-    const float rate = owner->sync.rate;
-    vlc_tick_t drift = system_ts - audio_ts;
+    float rate = owner->sync.rate;
+    vlc_tick_t drift = !owner->sync.clock ? system_ts - audio_ts :
+        -vlc_clock_Update(owner->sync.clock, system_ts, audio_ts, rate);
 
     /* Late audio output.
      * This can happen due to insufficient caching, scheduling jitter
@@ -270,13 +308,11 @@ void aout_RequestRetiming(audio_output_t *aout, vlc_tick_t system_ts,
         else
             msg_Dbg (aout, "playback too late (%"PRId64"): "
                      "flushing buffers", drift);
-        aout->flush(aout, false);
-
+        aout_DecFlush(aout, false);
         aout_StopResampling (aout);
-        owner->sync.discontinuity = true;
 
         return; /* nothing can be done if timing is unknown */
-}
+    }
 
     /* Early audio output.
      * This is rare except at startup when the buffers are still empty. */
@@ -386,16 +422,33 @@ int aout_DecPlay(audio_output_t *aout, block_t *block)
     if (block == NULL)
         return ret;
 
+    const vlc_tick_t original_pts = owner->original_pts;
+    owner->original_pts = VLC_TICK_INVALID;
+
     /* Software volume */
     aout_volume_Amplify (owner->volume, block);
 
+    /* Update delay */
+    if (owner->sync.clock && owner->sync.request_delay != owner->sync.delay)
+    {
+        owner->sync.delay = owner->sync.request_delay;
+        vlc_tick_t delta = vlc_clock_SetDelay(owner->sync.clock, owner->sync.delay);
+        aout_FiltersSetClockDelay(owner->filters, owner->sync.delay);
+        if (delta > 0)
+            aout_DecSilence (aout, delta, block->i_pts);
+    }
+
     /* Drift correction */
-    aout_DecSynchronize(aout, owner->original_pts);
+    vlc_tick_t system_now = vlc_tick_now();
+    aout_DecSynchronize(aout, system_now, original_pts);
 
+    const vlc_tick_t play_date = !owner->sync.clock ? original_pts :
+        vlc_clock_ConvertToSystem(owner->sync.clock, system_now, original_pts,
+                                  owner->sync.rate);
     /* Output */
     owner->sync.discontinuity = false;
-    aout->play(aout, block, owner->original_pts);
-    owner->original_pts = VLC_TICK_INVALID;
+    aout->play(aout, block, play_date);
+
     atomic_fetch_add_explicit(&owner->buffers_played, 1, memory_order_relaxed);
     return ret;
 drop:
@@ -422,7 +475,12 @@ void aout_DecChangePause (audio_output_t *aout, bool paused, vlc_tick_t date)
     aout_owner_t *owner = aout_owner (aout);
 
     if (owner->mixer_format.i_format)
-        aout->pause(aout, paused, date);
+    {
+        if (aout->pause != NULL)
+            aout->pause(aout, paused, date);
+        else if (paused)
+            aout->flush(aout, false);
+    }
 }
 
 void aout_DecChangeRate(audio_output_t *aout, float rate)
@@ -432,6 +490,13 @@ void aout_DecChangeRate(audio_output_t *aout, float rate)
     owner->sync.rate = rate;
 }
 
+void aout_DecChangeDelay(audio_output_t *aout, vlc_tick_t delay)
+{
+    aout_owner_t *owner = aout_owner(aout);
+
+    owner->sync.request_delay = delay;
+}
+
 void aout_DecFlush (audio_output_t *aout, bool wait)
 {
     aout_owner_t *owner = aout_owner (aout);
@@ -442,12 +507,31 @@ void aout_DecFlush (audio_output_t *aout, bool wait)
         {
             block_t *block = aout_FiltersDrain (owner->filters);
             if (block)
-                aout->play(aout, block, block->i_pts);
+                aout->play(aout, block, vlc_tick_now());
         }
         else
             aout_FiltersFlush (owner->filters);
 
         aout->flush(aout, wait);
+        if (owner->sync.clock)
+        {
+            vlc_clock_Reset(owner->sync.clock);
+            aout_FiltersResetClock(owner->filters);
+        }
+
+        if (owner->sync.clock && owner->sync.delay > 0)
+        {
+            /* Also reset the delay in case of a positive delay. This will
+             * trigger a silence playback before the next play. Consequently,
+             * the first play date won't be (delay + dejitter) but only
+             * dejitter. This will allow the aout to update the master clock
+             * sooner.
+             */
+            vlc_clock_SetDelay(owner->sync.clock, 0);
+            aout_FiltersSetClockDelay(owner->filters, 0);
+            owner->sync.request_delay = owner->sync.delay;
+            owner->sync.delay = 0;
+        }
     }
     owner->sync.discontinuity = true;
     owner->original_pts = VLC_TICK_INVALID;
diff --git a/src/input/decoder.c b/src/input/decoder.c
index 096340f34b..a3b55d85fe 100644
--- a/src/input/decoder.c
+++ b/src/input/decoder.c
@@ -345,7 +345,7 @@ static int aout_update_format( decoder_t *p_dec )
             if( p_dec->fmt_out.i_codec == VLC_CODEC_DTS )
                 var_SetBool( p_aout, "dtshd", p_dec->fmt_out.i_profile > 0 );
 
-            if( aout_DecNew( p_aout, &format,
+            if( aout_DecNew( p_aout, &format, NULL,
                              &p_dec->fmt_out.audio_replay_gain ) )
             {
                 input_resource_PutAout( p_owner->p_resource, p_aout );
-- 
2.20.1



More information about the vlc-devel mailing list