[vlc-devel] [RFC PATCH] pulse: hack: wait for drain completion

Thomas Guillem thomas at gllm.fr
Mon Mar 20 15:54:53 CET 2017


So, I guess the TODO was here for a good reason. stream_drain_cb is never
called after a call to pa_stream_drain(). We could be notified when pulse is
drained by listening to the underflow callback but that's not the good way.

I would prefer to find why pulseaudio doesn't send the drain cb. I looked at
some other players, they all seems to listen to the drain callback without any
issues.

I debugged a little on pulseaudio side, the drain is never sent, see
https://github.com/pulseaudio/pulseaudio/blob/master/src/pulsecore/protocol-native.c#L1475
pa_sink_input_safe_to_remove(s->sink_input) is always false since the
render_memblockq is never empty.

I'm still wondering if the problem comes from VLC or PulseAudio.

Any hints are welcome.

---

 modules/audio_output/pulse.c | 32 +++++++++++++++++++++++++++-----
 1 file changed, 27 insertions(+), 5 deletions(-)

diff --git a/modules/audio_output/pulse.c b/modules/audio_output/pulse.c
index 38a0d6624e..4b2db4b8d4 100644
--- a/modules/audio_output/pulse.c
+++ b/modules/audio_output/pulse.c
@@ -75,6 +75,8 @@ struct aout_sys_t
     char *sink_force; /**< Forced sink name (stream must be NULL) */
 
     struct sink *sinks; /**< Locally-cached list of sinks */
+
+    bool underflow;
 };
 
 static void VolumeReport(audio_output_t *aout)
@@ -352,8 +354,11 @@ static void stream_suspended_cb(pa_stream *s, void *userdata)
 static void stream_underflow_cb(pa_stream *s, void *userdata)
 {
     audio_output_t *aout = userdata;
+    aout_sys_t *sys = aout->sys;
 
     msg_Dbg(aout, "underflow");
+    sys->underflow = true;
+    pa_threaded_mainloop_signal(aout->sys->mainloop, 0);
     (void) s;
 }
 
@@ -503,6 +508,8 @@ static void Play(audio_output_t *aout, block_t *block)
      * will take place, and sooner or later a deadlock. */
     pa_threaded_mainloop_lock(sys->mainloop);
 
+    sys->underflow = false;
+
     if (sys->first_pts == VLC_TS_INVALID)
         sys->first_pts = block->i_pts;
 
@@ -548,6 +555,12 @@ static void Pause(audio_output_t *aout, bool paused, mtime_t date)
     (void) date;
 }
 
+static void stream_drain_cb(pa_stream *s, int success, void *userdata)
+{
+    (void) s; (void) success;
+    pa_threaded_mainloop_signal(userdata, 0);
+}
+
 /**
  * Flush or drain the playback stream
  */
@@ -558,14 +571,23 @@ static void Flush(audio_output_t *aout, bool wait)
     pa_operation *op;
 
     pa_threaded_mainloop_lock(sys->mainloop);
-
     if (wait)
-        op = pa_stream_drain(s, NULL, NULL);
-        /* TODO: wait for drain completion*/
+    {
+        op = pa_stream_drain(s, stream_drain_cb, sys->mainloop);
+        if (op != NULL)
+        {
+            while (pa_operation_get_state(op) == PA_OPERATION_RUNNING
+                && !sys->underflow)
+                pa_threaded_mainloop_wait(sys->mainloop);
+            pa_operation_unref(op);
+        }
+    }
     else
+    {
         op = pa_stream_flush(s, NULL, NULL);
-    if (op != NULL)
-        pa_operation_unref(op);
+        if (op != NULL)
+            pa_operation_unref(op);
+    }
     sys->first_pts = VLC_TS_INVALID;
     stream_stop(s, aout);
 
-- 
2.11.0



More information about the vlc-devel mailing list