This patch flushes the buffer when the sink input is detached and discards data after attaching a sink input until the pop callback is called for the first time, thus eliminating latency arising from slow starting sinks and from streaming to the previous sink. ---- src/modules/module-loopback.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) ---- diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c index da83894..22eadfc 100644 --- a/src/modules/module-loopback.c +++ b/src/modules/module-loopback.c @@ -87,6 +87,7 @@ struct userdata { pa_usec_t latency; bool in_pop; + bool pop_called; size_t min_memblockq_length; struct { @@ -464,6 +465,8 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk pa_assert_se(u = i->userdata); pa_assert(chunk); + if (PA_SINK_IS_RUNNING(u->sink_input->sink->thread_info.state) && !u->pop_called) + u->pop_called = true; u->in_pop = true; while (pa_asyncmsgq_process_one(u->asyncmsgq) > 0) ; @@ -515,7 +518,7 @@ static int sink_input_process_msg_cb(pa_msgobject *obj, int code, void *data, in pa_sink_input_assert_io_context(u->sink_input); - if (PA_SINK_IS_OPENED(u->sink_input->sink->thread_info.state)) + if (PA_SINK_IS_RUNNING(u->sink_input->sink->thread_info.state) && u->pop_called) pa_memblockq_push_align(u->memblockq, chunk); else pa_memblockq_flush_write(u->memblockq, true); @@ -542,7 +545,7 @@ static int sink_input_process_msg_cb(pa_msgobject *obj, int code, void *data, in pa_sink_input_assert_io_context(u->sink_input); - if (PA_SINK_IS_OPENED(u->sink_input->sink->thread_info.state)) + if (PA_SINK_IS_RUNNING(u->sink_input->sink->thread_info.state) && u->pop_called) pa_memblockq_seek(u->memblockq, -offset, PA_SEEK_RELATIVE, true); else pa_memblockq_flush_write(u->memblockq, true); @@ -607,6 +610,7 @@ static void sink_input_attach_cb(pa_sink_input *i) { pa_memblockq_set_maxrewind(u->memblockq, pa_sink_input_get_max_rewind(i)); u->min_memblockq_length = (size_t) -1; + u->pop_called = false; } /* Called from output thread context */ @@ -621,6 +625,8 @@ static void sink_input_detach_cb(pa_sink_input *i) { pa_rtpoll_item_free(u->rtpoll_item_read); u->rtpoll_item_read = NULL; } + pa_memblockq_flush_write(u->memblockq, true); + update_min_memblockq_length(u); } /* Called from output thread context */ @@ -820,6 +826,7 @@ int pa__init(pa_module *m) { u->core = m->core; u->module = m; u->latency = (pa_usec_t) latency_msec * PA_USEC_PER_MSEC; + u->pop_called = false; adjust_time_sec = DEFAULT_ADJUST_TIME_USEC / PA_USEC_PER_SEC; if (pa_modargs_get_value_u32(ma, "adjust_time", &adjust_time_sec) < 0) {