This patch adds a underrun_protection argument to control underrun protection algorithm. Disabling protection will keep loopback latency regardless of underruns. --- src/modules/module-loopback.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c index aecac0a..c452e1a 100644 --- a/src/modules/module-loopback.c +++ b/src/modules/module-loopback.c @@ -45,6 +45,7 @@ PA_MODULE_USAGE( "sink=<sink to connect to> " "adjust_time=<how often to readjust rates in s> " "latency_msec=<latency in ms> " + "underrun_protection=<boolean> " "format=<sample format> " "rate=<sample rate> " "channels=<number of channels> " @@ -90,6 +91,7 @@ struct userdata { /* Values from command line configuration */ pa_usec_t latency; pa_usec_t adjust_time; + bool underrun_protection; /* Latency boundaries and current values */ pa_usec_t min_source_latency; @@ -158,6 +160,7 @@ static const char* const valid_modargs[] = { "sink", "adjust_time", "latency_msec", + "underrun_protection", "format", "rate", "channels", @@ -325,11 +328,20 @@ static void adjust_rates(struct userdata *u) { /* If we are seeing underruns then the latency is too small */ if (u->underrun_counter > 2) { - u->underrun_latency_limit = PA_MAX(u->latency, u->minimum_latency) + 5 * PA_USEC_PER_MSEC; - u->underrun_latency_limit = PA_CLIP_SUB((int64_t)u->underrun_latency_limit, u->sink_latency_offset + u->source_latency_offset); - update_minimum_latency(u, u->sink_input->sink, false); - pa_log_warn("Too many underruns, increasing latency to %0.2f ms", (double)u->minimum_latency / PA_USEC_PER_MSEC); - u->underrun_counter = 0; + int64_t target_latency; + + target_latency = PA_MAX(u->latency, u->minimum_latency); + + if (u->underrun_protection) + target_latency += 5 * PA_USEC_PER_MSEC; + + u->underrun_latency_limit = PA_CLIP_SUB(target_latency, u->sink_latency_offset + u->source_latency_offset); + + if (u->minimum_latency < u->underrun_latency_limit) { + update_minimum_latency(u, u->sink_input->sink, false); + pa_log_warn("Too many underruns, increasing latency to %0.2f ms", (double)u->minimum_latency / PA_USEC_PER_MSEC); + u->underrun_counter = 0; + } } /* Allow one underrun per hour */ @@ -347,7 +359,7 @@ static void adjust_rates(struct userdata *u) { } u->adjust_time_stamp = now; - /* Rates and latencies*/ + /* Rates and latencies */ old_rate = u->sink_input->sample_spec.rate; base_rate = u->source_output->sample_spec.rate; @@ -1251,6 +1263,7 @@ int pa__init(pa_module *m) { pa_source *source = NULL; pa_source_output_new_data source_output_data; bool source_dont_move; + bool underrun_protection = true; uint32_t latency_msec; pa_sample_spec ss; pa_channel_map map; @@ -1336,10 +1349,16 @@ int pa__init(pa_module *m) { goto fail; } + if (pa_modargs_get_value_boolean(ma, "underrun_protection", &underrun_protection) < 0) { + pa_log("Failed to parse underrun_protection value."); + goto fail; + } + m->userdata = u = pa_xnew0(struct userdata, 1); u->core = m->core; u->module = m; u->latency = (pa_usec_t) latency_msec * PA_USEC_PER_MSEC; + u->underrun_protection = underrun_protection; u->output_thread_info.pop_called = false; u->output_thread_info.pop_adjust = false; u->output_thread_info.push_called = false; -- 1.8.3.1