[vlc-commits] [Git][videolan/vlc][master] 9 commits: aout: remove old documentation

Rémi Denis-Courmont (@Courmisch) gitlab at videolan.org
Tue Jan 18 13:26:23 UTC 2022



Rémi Denis-Courmont pushed to branch master at VideoLAN / VLC


Commits:
bb9f8f60 by Thomas Guillem at 2022-01-18T13:12:26+00:00
aout: remove old documentation

- - - - -
0dd8096f by Thomas Guillem at 2022-01-18T13:12:26+00:00
aout: make drain asynchronous

aout_DecDrain() is now asynchronous, except for modules still implementing
aout->drain (only during the transition).

Add aout->drain_async(). Aout modules should implement drain_async
instead of drain, and call aout_DrainedReport() to report that the
stream is drained.

Aout modules not implementing any drain functions will still rely on
aout_TimeGet() to detect the end of the stream.

- - - - -
680d334b by Thomas Guillem at 2022-01-18T13:12:26+00:00
pulse: implement drain_async

- - - - -
a8480f07 by Thomas Guillem at 2022-01-18T13:12:26+00:00
amem: implement asynchronous drain

"amem-drain" is still synchronous, the drained state is reported after
the call to this blocking callback.

- - - - -
fb08f5ee by Thomas Guillem at 2022-01-18T13:12:26+00:00
waveout: implement asynchronous drain

- - - - -
fbf9c0d3 by Thomas Guillem at 2022-01-18T13:12:26+00:00
declink: implement asynchronous drain

- - - - -
4a953e23 by Thomas Guillem at 2022-01-18T13:12:26+00:00
alsa: implement asynchronous drain

Lousy implementation since snd_pcm doesn't provide non blocking drain
API.

- - - - -
193ab0d0 by Thomas Guillem at 2022-01-18T13:12:26+00:00
aout: remove legacy drain

- - - - -
6c93cb0f by Thomas Guillem at 2022-01-18T13:12:26+00:00
aout: rename back drain_async to drain

Now that the legacy implementation is gone.

- - - - -


10 changed files:

- include/vlc_aout.h
- modules/audio_output/alsa.c
- modules/audio_output/amem.c
- modules/audio_output/pulse.c
- modules/audio_output/waveout.c
- modules/video_output/decklink.cpp
- src/audio_output/aout_internal.h
- src/audio_output/dec.c
- src/audio_output/output.c
- src/input/decoder.c


Changes:

=====================================
include/vlc_aout.h
=====================================
@@ -126,6 +126,7 @@
 
 struct vlc_audio_output_events {
     void (*timing_report)(audio_output_t *, vlc_tick_t system_now, vlc_tick_t pts);
+    void (*drained_report)(audio_output_t *);
     void (*volume_report)(audio_output_t *, float);
     void (*mute_report)(audio_output_t *, bool);
     void (*policy_report)(audio_output_t *, bool);
@@ -240,14 +241,19 @@ struct audio_output
 
     void (*flush)( audio_output_t *);
     /**< Flushes the playback buffers (mandatory, cannot be NULL).
-      *
-      * \param wait true to wait for playback of pending buffers (drain),
-      *             false to discard pending buffers (flush)
       *
       * \note This callback cannot be called in stopped state.
       */
+
     void (*drain)(audio_output_t *);
-    /**< Drain the playback buffers (can be NULL).
+    /**< Drain the playback buffers asynchronously (can be NULL).
+      *
+      * A drain operation can be cancelled by aout->flush() or aout->stop().
+      *
+      * It is legal to continue playback after a drain_async, if flush() is
+      * called before the next play().
+      *
+      * Call aout_DrainedReport() to notify that the stream is drained.
       *
       * If NULL, the caller will wait for the delay returned by time_get before
       * calling stop().
@@ -297,6 +303,14 @@ static inline int aout_TimeGet(audio_output_t *aout, vlc_tick_t *delay)
     return aout->time_get(aout, delay);
 }
 
+/**
+ * Report than the stream is drained (after a call to aout->drain_async)
+ */
+static inline void aout_DrainedReport(audio_output_t *aout)
+{
+    aout->events->drained_report(aout);
+}
+
 /**
  * Report change of configured audio volume to the core and UI.
  */


=====================================
modules/audio_output/alsa.c
=====================================
@@ -730,8 +730,12 @@ static void Drain (audio_output_t *aout)
 {
     aout_sys_t *p_sys = aout->sys;
     snd_pcm_t *pcm = p_sys->pcm;
+
+    /* XXX: Synchronous drain, not interruptible. */
     snd_pcm_drain (pcm);
     snd_pcm_prepare (pcm);
+
+    aout_DrainedReport(aout);
 }
 
 /**


=====================================
modules/audio_output/amem.c
=====================================
@@ -142,6 +142,8 @@ static void Drain (audio_output_t *aout)
     vlc_mutex_lock(&sys->lock);
     sys->drain (sys->opaque);
     vlc_mutex_unlock(&sys->lock);
+
+    aout_DrainedReport (aout);
 }
 
 static int VolumeSet (audio_output_t *aout, float vol)


=====================================
modules/audio_output/pulse.c
=====================================
@@ -66,6 +66,7 @@ typedef struct
     pa_context *context; /**< PulseAudio connection context */
     pa_threaded_mainloop *mainloop; /**< PulseAudio thread */
     pa_time_event *trigger; /**< Deferred stream trigger */
+    pa_time_event *drain_trigger; /**< Drain stream trigger */
     pa_cvolume cvolume; /**< actual sink input volume */
     vlc_tick_t last_date; /**< Play system timestamp of last buffer */
 
@@ -556,6 +557,12 @@ static void Flush(audio_output_t *aout)
 
     pa_threaded_mainloop_lock(sys->mainloop);
 
+    if (sys->drain_trigger != NULL)
+    {
+        vlc_pa_rttime_free(sys->mainloop, sys->drain_trigger);
+        sys->drain_trigger = NULL;
+    }
+
     pa_operation *op = pa_stream_flush(s, NULL, NULL);
     if (op != NULL)
         pa_operation_unref(op);
@@ -565,6 +572,21 @@ static void Flush(audio_output_t *aout)
     pa_threaded_mainloop_unlock(sys->mainloop);
 }
 
+static void drain_trigger_cb(pa_mainloop_api *api, pa_time_event *e,
+                              const struct timeval *tv, void *userdata)
+{
+    audio_output_t *aout = userdata;
+    aout_sys_t *sys = aout->sys;
+
+    assert(sys->drain_trigger == e);
+
+    vlc_pa_rttime_free(sys->mainloop, sys->drain_trigger);
+    sys->drain_trigger = NULL;
+
+    aout_DrainedReport(aout);
+    (void) api; (void) e; (void) tv;
+}
+
 static void Drain(audio_output_t *aout)
 {
     aout_sys_t *sys = aout->sys;
@@ -593,15 +615,18 @@ static void Drain(audio_output_t *aout)
 
     /* XXX: Loosy drain emulation.
      * See #18141: drain callback is never received */
+    assert(sys->drain_trigger == NULL);
     vlc_tick_t delay;
-    if (TimeGet(aout, &delay) == 0 && delay <= VLC_TICK_FROM_SEC(5))
+    if (TimeGet(aout, &delay) == 0)
     {
-        pa_threaded_mainloop_unlock(sys->mainloop);
-        vlc_tick_sleep(delay);
-        pa_threaded_mainloop_lock(sys->mainloop);
+        delay += pa_rtclock_now();
+        sys->drain_trigger = pa_context_rttime_new(sys->context, delay,
+                                                   drain_trigger_cb, aout);
     }
 
-    stream_stop(s, aout);
+    if (sys->drain_trigger == NULL)
+        aout_DrainedReport(aout);
+
     pa_threaded_mainloop_unlock(sys->mainloop);
 }
 
@@ -828,7 +853,7 @@ static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt)
         pa_cvolume_set(cvolume, ss.channels, sys->volume_force);
     }
 
-    sys->trigger = NULL;
+    sys->trigger = sys->drain_trigger = NULL;
     pa_cvolume_init(&sys->cvolume);
     sys->last_date = VLC_TICK_INVALID;
 
@@ -1001,6 +1026,8 @@ static void Stop(audio_output_t *aout)
     pa_threaded_mainloop_lock(sys->mainloop);
     if (unlikely(sys->trigger != NULL))
         vlc_pa_rttime_free(sys->mainloop, sys->trigger);
+    if (sys->drain_trigger != NULL)
+        vlc_pa_rttime_free(sys->mainloop, sys->drain_trigger);
     pa_stream_disconnect(s);
 
     /* Clear all callbacks */


=====================================
modules/audio_output/waveout.c
=====================================
@@ -80,6 +80,7 @@ static uint32_t findDeviceID(char *);
 static int WaveOutTimeGet(audio_output_t * , vlc_tick_t *);
 static void WaveOutFlush( audio_output_t *);
 static void WaveOutDrain( audio_output_t *);
+static void WaveOutDrainAsync( audio_output_t *);
 static void WaveOutPause( audio_output_t *, bool, vlc_tick_t);
 static int WaveoutVolumeSet(audio_output_t * p_aout, float volume);
 static int WaveoutMuteSet(audio_output_t * p_aout, bool mute);
@@ -128,6 +129,8 @@ struct aout_sys_t
     vlc_mutex_t lock;
     vlc_cond_t cond;
     vlc_timer_t volume_poll_timer;
+
+    bool draining;
 };
 
 /*****************************************************************************
@@ -175,10 +178,12 @@ static int Start( audio_output_t *p_aout, audio_sample_format_t *restrict fmt )
     p_aout->play = Play;
     p_aout->pause = WaveOutPause;
     p_aout->flush = WaveOutFlush;
-    p_aout->drain = WaveOutDrain;
+    p_aout->drain = WaveOutDrainAsync;
 
     aout_sys_t *sys = p_aout->sys;
 
+    sys->draining = false;
+
     /* Default behaviour is to use software gain */
     sys->b_soft = true;
 
@@ -647,6 +652,13 @@ static void CALLBACK WaveOutCallback( HWAVEOUT h_waveout, UINT uMsg,
     p_waveheader->p_next = sys->p_free_list;
     sys->p_free_list = p_waveheader;
     sys->i_frames--;
+
+    if( sys->i_frames == 0 && sys->draining )
+    {
+        aout_DrainedReport( _p_aout );
+        sys->draining = false;
+    }
+
     vlc_cond_broadcast( &sys->cond );
     vlc_mutex_unlock( &sys->lock );
 }
@@ -851,6 +863,10 @@ static void WaveOutFlush( audio_output_t *p_aout)
     MMRESULT res;
     aout_sys_t *sys = p_aout->sys;
 
+    vlc_mutex_lock( &sys->lock );
+    sys->draining = false;
+    vlc_mutex_unlock( &sys->lock );
+
     res  = waveOutReset( sys->h_waveout );
     sys->i_played_length = 0;
     if( res != MMSYSERR_NOERROR )
@@ -869,6 +885,18 @@ static void WaveOutDrain( audio_output_t *p_aout)
     vlc_mutex_unlock( &sys->lock );
 }
 
+static void WaveOutDrainAsync( audio_output_t *p_aout)
+{
+    aout_sys_t *sys = p_aout->sys;
+
+    vlc_mutex_lock( &sys->lock );
+    if( sys->i_frames == 0 )
+        aout_DrainedReport( p_aout );
+    else
+        sys->draining = true;
+    vlc_mutex_unlock( &sys->lock );
+}
+
 static void WaveOutPause( audio_output_t * p_aout, bool pause, vlc_tick_t date)
 {
     MMRESULT res;


=====================================
modules/video_output/decklink.cpp
=====================================
@@ -215,6 +215,8 @@ struct decklink_sys_t
 
     /* !With LOCK */
 
+    vlc_timer_t drain_timer;
+
     /* single video module exclusive */
     struct
     {
@@ -833,6 +835,17 @@ static void CloseVideo(vout_display_t *vd)
  * Audio
  *****************************************************************************/
 
+static void DrainReset(audio_output_t *aout)
+{
+    decklink_sys_t *sys = (decklink_sys_t *) aout->sys;
+
+    if (sys->drain_timer != NULL)
+    {
+        vlc_timer_destroy(sys->drain_timer);
+        sys->drain_timer = NULL;
+    }
+}
+
 static void Flush(audio_output_t *aout)
 {
     decklink_sys_t *sys = (decklink_sys_t *) aout->sys;
@@ -842,10 +855,19 @@ static void Flush(audio_output_t *aout)
     if (!p_output)
         return;
 
+    DrainReset(aout);
+
     if (sys->p_output->FlushBufferedAudioSamples() == E_FAIL)
         msg_Err(aout, "Flush failed");
 }
 
+static void DrainTimerCb(void *data)
+{
+    audio_output_t *aout = (audio_output_t *) data;
+
+    aout_DrainedReport(aout);
+}
+
 static void Drain(audio_output_t *aout)
 {
     decklink_sys_t *sys = (decklink_sys_t *) aout->sys;
@@ -855,9 +877,28 @@ static void Drain(audio_output_t *aout)
     if (!p_output)
         return;
 
+    assert(sys->drain_timer == NULL);
+
     uint32_t samples;
     sys->p_output->GetBufferedAudioSampleFrameCount(&samples);
-    vlc_tick_sleep(vlc_tick_from_samples(samples, sys->i_rate));
+
+    if (samples == 0)
+    {
+        aout_DrainedReport(aout);
+        return;
+    }
+
+    /* Create and arm a timer to notify when drained */
+    int ret = vlc_timer_create(&sys->drain_timer, DrainTimerCb, aout);
+    if (ret != 0)
+    {
+        aout_DrainedReport(aout);
+        return;
+    }
+
+    vlc_timer_schedule(sys->drain_timer, false,
+                       vlc_tick_from_samples(samples, sys->i_rate),
+                       VLC_TIMER_FIRE_ONCE);
 }
 
 
@@ -925,6 +966,7 @@ static int OpenAudio(vlc_object_t *p_this)
     sys->i_rate = var_InheritInteger(aout, AUDIO_CFG_PREFIX "audio-rate");
     vlc_cond_signal(&sys->cond);
     vlc_mutex_unlock(&sys->lock);
+    sys->drain_timer = NULL;
 
     aout->play      = PlayAudio;
     aout->start     = Start;
@@ -933,7 +975,7 @@ static int OpenAudio(vlc_object_t *p_this)
     aout->time_get  = TimeGet;
 
     aout->pause     = aout_PauseDefault;
-    aout->stop      = NULL;
+    aout->stop      = DrainReset;
     aout->mute_set  = NULL;
     aout->volume_set= NULL;
 


=====================================
src/audio_output/aout_internal.h
=====================================
@@ -50,6 +50,9 @@ typedef struct
     aout_volume_t *volume;
     bool bitexact;
 
+    atomic_bool drained;
+    _Atomic vlc_tick_t drain_deadline;
+
     struct
     {
         vlc_mutex_t lock;
@@ -166,6 +169,10 @@ 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 *);
 void aout_DecDrain(audio_output_t *);
+/* Contrary to other aout_Dec*() functions, this function can be called from
+ * any threads */
+bool aout_DecIsDrained(audio_output_t *);
+
 void aout_RequestRestart (audio_output_t *, unsigned);
 void aout_RequestRetiming(audio_output_t *aout, vlc_tick_t system_ts,
                           vlc_tick_t audio_ts);


=====================================
src/audio_output/dec.c
=====================================
@@ -38,18 +38,6 @@
 #include "clock/clock.h"
 #include "libvlc.h"
 
-static void aout_Drain(audio_output_t *aout)
-{
-    if (aout->drain)
-        aout->drain(aout);
-    else
-    {
-        vlc_tick_t delay;
-        if (aout_TimeGet(aout, &delay) == 0)
-            vlc_tick_sleep(delay);
-    }
-}
-
 /**
  * Creates an audio output
  */
@@ -586,10 +574,30 @@ void aout_DecFlush(audio_output_t *aout)
             owner->sync.delay = 0;
         }
     }
+
+    atomic_store_explicit(&owner->drained, false, memory_order_relaxed);
+    atomic_store_explicit(&owner->drain_deadline, VLC_TICK_INVALID,
+                          memory_order_relaxed);
+
     owner->sync.discontinuity = true;
     owner->original_pts = VLC_TICK_INVALID;
 }
 
+bool aout_DecIsDrained(audio_output_t *aout)
+{
+    aout_owner_t *owner = aout_owner (aout);
+
+    if (aout->drain == NULL)
+    {
+        vlc_tick_t drain_deadline =
+            atomic_load_explicit(&owner->drain_deadline, memory_order_relaxed);
+        return drain_deadline != VLC_TICK_INVALID
+            && vlc_tick_now() >= drain_deadline;
+    }
+    else
+        return atomic_load_explicit(&owner->drained, memory_order_relaxed);
+}
+
 void aout_DecDrain(audio_output_t *aout)
 {
     aout_owner_t *owner = aout_owner (aout);
@@ -604,7 +612,28 @@ void aout_DecDrain(audio_output_t *aout)
             aout->play(aout, block, vlc_tick_now());
     }
 
-    aout_Drain(aout);
+    if (aout->drain)
+    {
+        assert(!atomic_load_explicit(&owner->drained, memory_order_relaxed));
+
+        aout->drain(aout);
+    }
+    else
+    {
+        assert(atomic_load_explicit(&owner->drain_deadline,
+                                    memory_order_relaxed) == VLC_TICK_INVALID);
+
+        vlc_tick_t drain_deadline = vlc_tick_now();
+
+        vlc_tick_t delay;
+        if (aout_TimeGet(aout, &delay) == 0)
+            drain_deadline += delay;
+        /* else the deadline is now, and aout_DecIsDrained() will return true
+         * on the first call. */
+
+        atomic_store_explicit(&owner->drain_deadline, drain_deadline,
+                              memory_order_relaxed);
+    }
 
     vlc_clock_Reset(owner->sync.clock);
     if (owner->filters)


=====================================
src/audio_output/output.c
=====================================
@@ -69,6 +69,12 @@ static void aout_TimingNotify(audio_output_t *aout, vlc_tick_t system_ts,
     aout_RequestRetiming(aout, system_ts, audio_ts);
 }
 
+static void aout_DrainedNotify(audio_output_t *aout)
+{
+    aout_owner_t *owner = aout_owner (aout);
+    atomic_store_explicit(&owner->drained, true, memory_order_relaxed);
+}
+
 /**
  * Supply or update the current custom ("hardware") volume.
  * @param volume current custom volume
@@ -160,6 +166,7 @@ static int aout_GainNotify (audio_output_t *aout, float gain)
 
 static const struct vlc_audio_output_events aout_events = {
     aout_TimingNotify,
+    aout_DrainedNotify,
     aout_VolumeNotify,
     aout_MuteNotify,
     aout_PolicyNotify,
@@ -243,6 +250,9 @@ audio_output_t *aout_New (vlc_object_t *parent)
     vlc_atomic_rc_init(&owner->rc);
     vlc_audio_meter_Init(&owner->meter, aout);
 
+    atomic_init(&owner->drained, false);
+    atomic_init(&owner->drain_deadline, VLC_TICK_INVALID);
+
     /* Audio output module callbacks */
     var_Create (aout, "volume", VLC_VAR_FLOAT);
     var_AddCallback (aout, "volume", var_Copy, parent);


=====================================
src/input/decoder.c
=====================================
@@ -158,7 +158,6 @@ struct vlc_input_decoder_t
     /* Flushing */
     bool flushing;
     bool b_draining;
-    atomic_bool drained;
     bool b_idle;
     bool aborting;
 
@@ -1748,10 +1747,7 @@ static void *DecoderThread( void *p_data )
         vlc_mutex_lock( &p_owner->lock );
         vlc_fifo_Lock( p_owner->p_fifo );
         if( p_owner->b_draining && (frame == NULL) )
-        {
             p_owner->b_draining = false;
-            p_owner->drained = true;
-        }
         vlc_cond_signal( &p_owner->wait_acknowledge );
         vlc_mutex_unlock( &p_owner->lock );
     }
@@ -1857,7 +1853,6 @@ CreateDecoder( vlc_object_t *p_parent, const es_format_t *fmt,
 
     p_owner->flushing = false;
     p_owner->b_draining = false;
-    p_owner->drained = false;
     atomic_init( &p_owner->reload, RELOAD_NO_REQUEST );
     p_owner->b_idle = false;
 
@@ -2289,8 +2284,8 @@ bool vlc_input_decoder_IsEmpty( vlc_input_decoder_t * p_owner )
 #endif
     if( p_owner->fmt.i_cat == VIDEO_ES && p_owner->p_vout != NULL )
         b_empty = vout_IsEmpty( p_owner->p_vout );
-    else if( p_owner->fmt.i_cat == AUDIO_ES )
-        b_empty = !p_owner->b_draining || p_owner->drained;
+    else if( p_owner->fmt.i_cat == AUDIO_ES && p_owner->p_aout != NULL )
+        b_empty = aout_DecIsDrained( p_owner->p_aout );
     else
         b_empty = true; /* TODO subtitles support */
     vlc_mutex_unlock( &p_owner->lock );



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/1cf1991b648df877d7138ef79a3381026be2dd80...6c93cb0f0484b71048bfaf94d17e6962cfca42fd

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/1cf1991b648df877d7138ef79a3381026be2dd80...6c93cb0f0484b71048bfaf94d17e6962cfca42fd
You're receiving this email because of your account on code.videolan.org.




More information about the vlc-commits mailing list