[vlc-devel] [PATCH] pulse: avoid overflows

Thomas Guillem thomas at gllm.fr
Mon Feb 11 17:11:04 CET 2019


Compare the maxlength and the delay in order to detect if we should pace from
the Play() function. Overflows never happened with the default VLC
configuration, but it can be triggered easily when the input buffering is
tweaked. Furthermore, this will allow interactive playback with a low maxlength
value.

Most common audio outputs modules (on Windows, Android, macOS) are already
pacing from the play callback.

This is also a small step for the input clock/buffering rework since we may
want to pace from the output in the future.
---
 modules/audio_output/pulse.c | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/modules/audio_output/pulse.c b/modules/audio_output/pulse.c
index 8c024006af..d20553c92c 100644
--- a/modules/audio_output/pulse.c
+++ b/modules/audio_output/pulse.c
@@ -69,6 +69,7 @@ typedef struct
     pa_time_event *trigger; /**< Deferred stream trigger */
     pa_cvolume cvolume; /**< actual sink input volume */
     vlc_tick_t last_date; /**< Play system timestamp of last buffer */
+    vlc_tick_t maxlength; /**< Maximum audio buffer length */
 
     pa_volume_t volume_force; /**< Forced volume (stream must be NULL) */
     pa_stream_flags_t flags_force; /**< Forced flags (stream must be NULL) */
@@ -282,8 +283,10 @@ static void stream_state_cb(pa_stream *s, void *userdata)
 static void stream_buffer_attr_cb(pa_stream *s, void *userdata)
 {
     audio_output_t *aout = userdata;
+    aout_sys_t *sys = aout->sys;
     const pa_buffer_attr *pba = pa_stream_get_buffer_attr(s);
 
+    sys->maxlength = pba->maxlength;
     msg_Dbg(aout, "changed buffer metrics: maxlength=%u, tlength=%u, "
             "prebuf=%u, minreq=%u",
             pba->maxlength, pba->tlength, pba->prebuf, pba->minreq);
@@ -491,6 +494,20 @@ static void Play(audio_output_t *aout, block_t *block, vlc_tick_t date)
         void *ptr;
         size_t len = block->i_buffer;
 
+        /* Check if we should pace to prevent an overflow */
+        if (pa_stream_is_corked(s) <= 0)
+        {
+            assert(sys->maxlength != -1);
+            const pa_sample_spec *ss = pa_stream_get_sample_spec(s);
+            vlc_tick_t len_us = pa_usec_to_bytes(len, ss);
+            while (len_us + vlc_pa_get_latency(aout, sys->context, s)
+                   > sys->maxlength)
+            {
+                vlc_tick_t sleep_us = __MAX(len_us, sys->maxlength / 100);
+                vlc_tick_sleep(sleep_us);
+            }
+        }
+
         if (pa_stream_begin_write(s, &ptr, &len))
             vlc_pa_error(aout, "cannot begin write", sys->context);
 
@@ -772,7 +789,7 @@ static int Start(audio_output_t *aout, audio_sample_format_t *restrict fmt,
     assert(*period >= AOUT_MAX_PTS_ADVANCE);
 
     struct pa_buffer_attr attr;
-    attr.maxlength = -1;
+    sys->maxlength = attr.maxlength = -1;
     /* PulseAudio goes berserk if the target length (tlength) is not
      * significantly longer than 2 periods (minreq), or when the period length
      * is unspecified and the target length is short. */
-- 
2.20.1



More information about the vlc-devel mailing list