From 8c39a5c16c8ba1f84b286688ee42cd551fed4794 Mon Sep 17 00:00:00 2001 From: Georg Chini Date: Sun, 5 Jun 2016 21:05:06 +0200 Subject: [PATCH] loopback: Improve latency estimation To improve the overall latency estimation, the delay between the two snapshots is taken into account. To minimize the snapshot delay, the order of the snapshots is reverted. Additionally the latency at the base rate is calculated. It will be used later as the input to the latency controller. --- src/modules/module-loopback.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c index aa559aa39..6539a957a 100644 --- a/src/modules/module-loopback.c +++ b/src/modules/module-loopback.c @@ -172,36 +172,47 @@ static void teardown(struct userdata *u) { static void adjust_rates(struct userdata *u) { size_t buffer, fs; uint32_t old_rate, base_rate, new_rate; - pa_usec_t buffer_latency; + pa_usec_t current_buffer_latency, snapshot_delay, current_source_sink_latency, current_latency, latency_at_optimum_rate; pa_assert(u); pa_assert_ctl_context(); - pa_asyncmsgq_send(u->source_output->source->asyncmsgq, PA_MSGOBJECT(u->source_output), SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL); pa_asyncmsgq_send(u->sink_input->sink->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL); + pa_asyncmsgq_send(u->source_output->source->asyncmsgq, PA_MSGOBJECT(u->source_output), SOURCE_OUTPUT_MESSAGE_LATENCY_SNAPSHOT, NULL, 0, NULL); + + /* Rates and latencies*/ + old_rate = u->sink_input->sample_spec.rate; + base_rate = u->source_output->sample_spec.rate; buffer = u->latency_snapshot.sink_input_buffer; - if (u->latency_snapshot.recv_counter <= u->latency_snapshot.send_counter) buffer += (size_t) (u->latency_snapshot.send_counter - u->latency_snapshot.recv_counter); else buffer = PA_CLIP_SUB(buffer, (size_t) (u->latency_snapshot.recv_counter - u->latency_snapshot.send_counter)); - buffer_latency = pa_bytes_to_usec(buffer, &u->sink_input->sample_spec); + current_buffer_latency = pa_bytes_to_usec(buffer, &u->sink_input->sample_spec); + snapshot_delay = u->latency_snapshot.source_timestamp - u->latency_snapshot.sink_timestamp; + current_source_sink_latency = u->latency_snapshot.sink_latency + u->latency_snapshot.source_latency - snapshot_delay; + + /* Current latency */ + current_latency = current_source_sink_latency + current_buffer_latency; + + /* Latency at base rate */ + latency_at_optimum_rate = current_source_sink_latency + current_buffer_latency * old_rate / base_rate; pa_log_debug("Loopback overall latency is %0.2f ms + %0.2f ms + %0.2f ms = %0.2f ms", (double) u->latency_snapshot.sink_latency / PA_USEC_PER_MSEC, - (double) buffer_latency / PA_USEC_PER_MSEC, + (double) current_buffer_latency / PA_USEC_PER_MSEC, (double) u->latency_snapshot.source_latency / PA_USEC_PER_MSEC, - ((double) u->latency_snapshot.sink_latency + buffer_latency + u->latency_snapshot.source_latency) / PA_USEC_PER_MSEC); + (double) current_latency / PA_USEC_PER_MSEC); + + pa_log_debug("Loopback latency at base rate is %0.2f ms", (double)latency_at_optimum_rate / PA_USEC_PER_MSEC); pa_log_debug("Should buffer %zu bytes, buffered at minimum %zu bytes", u->latency_snapshot.max_request*2, u->latency_snapshot.min_memblockq_length); fs = pa_frame_size(&u->sink_input->sample_spec); - old_rate = u->sink_input->sample_spec.rate; - base_rate = u->source_output->sample_spec.rate; if (u->latency_snapshot.min_memblockq_length < u->latency_snapshot.max_request*2) new_rate = base_rate - (((u->latency_snapshot.max_request*2 - u->latency_snapshot.min_memblockq_length) / fs) *PA_USEC_PER_SEC)/u->adjust_time;