[pulseaudio-discuss] [PATCH] module-virtual-sink: Speed up draining

David Henningsson david.henningsson at canonical.com
Thu Oct 2 06:58:57 PDT 2014

The drain speed increase done a while ago, only worked when directly connected
to ALSA sinks. Playing through an module-virtual-sink would cause slower drains.

This fix has two parts:
 1) We now refuse to process handed out silence. This has the effect
    that it tells ALSAs sink input that we're draining, and that we want to
    be woken up exactly at this sample based point in time.
 2) When we're being called to process input underruns, we know this has
    happened, so we can just forward the call up the sink chain to get
    to protocol-native, which can acknowledge that the drain has completed.

This fix is incomplete, because if more than one sink input is playing back
into the sink, only the last one will be drained in time. But it's better
than nothing.

Signed-off-by: David Henningsson <david.henningsson at canonical.com>

Happy for testing of this patch - Ubuntu runs HDA-intel with 64K buffers instead of the 2M that
some distros use, so I'm not seeing that much difference that you do anyway.

Also, when I was testing, I also noticed a bigger startup latency when playing
back through a virtual sink. This is nothing I have looked deeper at.

 src/modules/module-virtual-sink.c | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/src/modules/module-virtual-sink.c b/src/modules/module-virtual-sink.c
index 66fd8a9..c1e5969 100644
--- a/src/modules/module-virtual-sink.c
+++ b/src/modules/module-virtual-sink.c
@@ -216,6 +216,10 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk
         pa_memchunk nchunk;
         pa_sink_render(u->sink, nbytes, &nchunk);
+        if (nchunk.memblock == u->sink->silence.memblock) {
+            pa_memblock_unref(nchunk.memblock);
+            return -1;
+        }
         pa_memblockq_push(u->memblockq, &nchunk);
@@ -265,6 +269,23 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk
     return 0;
+/* Called from thread context */
+static bool sink_input_process_underrun_cb(pa_sink_input *i) {
+    struct userdata *u;
+    pa_sink_input_assert_ref(i);
+    pa_assert_se(u = i->userdata);
+    if (!PA_SINK_IS_LINKED(u->sink->thread_info.state) ||
+        !PA_SINK_INPUT_IS_LINKED(u->sink_input->thread_info.state))
+        return false;
+    pa_log_debug("sink_input_process_underrun_cb for virtual sink");
+    return pa_sink_process_input_underruns(u->sink, 0);
 /* Called from I/O thread context */
 static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
     struct userdata *u;
@@ -586,6 +607,7 @@ int pa__init(pa_module*m) {
         goto fail;
     u->sink_input->pop = sink_input_pop_cb;
+    u->sink_input->process_underrun = sink_input_process_underrun_cb;
     u->sink_input->process_rewind = sink_input_process_rewind_cb;
     u->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
     u->sink_input->update_max_request = sink_input_update_max_request_cb;

More information about the pulseaudio-discuss mailing list