[pulseaudio-discuss] [PATCH 13/22] loopback: Track and use average adjust time
Georg Chini
georg at chini.tk
Mon Feb 13 12:02:10 UTC 2017
The configured adjust time does not match exactly the real adjust time. Also
the adjust time varies. To improve latency estimation use an average of the
measured adjust times instead of the configured value in all calculations.
---
src/modules/module-loopback.c | 36 ++++++++++++++++++++++++++++++++----
1 file changed, 32 insertions(+), 4 deletions(-)
diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c
index aee8658..52e026e 100644
--- a/src/modules/module-loopback.c
+++ b/src/modules/module-loopback.c
@@ -83,6 +83,12 @@ struct userdata {
pa_time_event *time_event;
+ /* Variables used to calculate the average time between
+ * subsequent calls of adjust_rates() */
+ pa_usec_t adjust_time_stamp;
+ pa_usec_t real_adjust_time;
+ pa_usec_t real_adjust_time_sum;
+
/* Values from command line configuration */
pa_usec_t latency;
pa_usec_t adjust_time;
@@ -104,8 +110,10 @@ struct userdata {
/* Various counters */
uint32_t iteration_counter;
uint32_t underrun_counter;
+ uint32_t adjust_counter;
bool fixed_alsa_source;
+ bool source_sink_changed;
/* Used for sink input and source output snapshots */
struct {
@@ -318,14 +326,14 @@ static void adjust_rates(struct userdata *u) {
int32_t latency_difference;
pa_usec_t current_buffer_latency, snapshot_delay;
int64_t current_source_sink_latency, current_latency, latency_at_optimum_rate;
- pa_usec_t final_latency;
+ pa_usec_t final_latency, now;
pa_assert(u);
pa_assert_ctl_context();
/* Runtime and counters since last change of source or sink
* or source/sink latency */
- run_hours = u->iteration_counter * u->adjust_time / PA_USEC_PER_SEC / 3600;
+ run_hours = u->iteration_counter * u->real_adjust_time / PA_USEC_PER_SEC / 3600;
u->iteration_counter +=1;
/* If we are seeing underruns then the latency is too small */
@@ -338,11 +346,20 @@ static void adjust_rates(struct userdata *u) {
}
/* Allow one underrun per hour */
- if (u->iteration_counter * u->adjust_time / PA_USEC_PER_SEC / 3600 > run_hours) {
+ if (u->iteration_counter * u->real_adjust_time / PA_USEC_PER_SEC / 3600 > run_hours) {
u->underrun_counter = PA_CLIP_SUB(u->underrun_counter, 1u);
pa_log_info("Underrun counter: %u", u->underrun_counter);
}
+ /* Calculate real adjust time */
+ now = pa_rtclock_now();
+ if (!u->source_sink_changed) {
+ u->adjust_counter++;
+ u->real_adjust_time_sum += now - u->adjust_time_stamp;
+ u->real_adjust_time = u->real_adjust_time_sum / u->adjust_counter;
+ }
+ u->adjust_time_stamp = now;
+
/* Rates and latencies*/
old_rate = u->sink_input->sample_spec.rate;
base_rate = u->source_output->sample_spec.rate;
@@ -375,7 +392,9 @@ static void adjust_rates(struct userdata *u) {
pa_log_debug("Loopback latency at base rate is %0.2f ms", (double)latency_at_optimum_rate / PA_USEC_PER_MSEC);
/* Calculate new rate */
- new_rate = rate_controller(base_rate, u->adjust_time, latency_difference);
+ new_rate = rate_controller(base_rate, u->real_adjust_time, latency_difference);
+
+ u->source_sink_changed = false;
/* Set rate */
pa_sink_input_set_rate(u->sink_input, new_rate);
@@ -697,6 +716,8 @@ static void source_output_moving_cb(pa_source_output *o, pa_source *dest) {
u->iteration_counter = 0;
u->underrun_counter = 0;
+ u->source_sink_changed = true;
+
/* Send a mesage to the output thread that the source has changed.
* If the sink is invalid here during a profile switching situation
* we can safely set push_called to false directly. Also, the current
@@ -1065,6 +1086,8 @@ static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) {
u->iteration_counter = 0;
u->underrun_counter = 0;
+ u->source_sink_changed = true;
+
/* Send a message to the output thread that the sink has changed */
pa_asyncmsgq_send(dest->asyncmsgq, PA_MSGOBJECT(u->sink_input), SINK_INPUT_MESSAGE_SINK_CHANGED, NULL, 0, NULL);
@@ -1319,6 +1342,9 @@ int pa__init(pa_module *m) {
u->iteration_counter = 0;
u->underrun_counter = 0;
u->underrun_latency_limit = 0;
+ u->source_sink_changed = true;
+ u->real_adjust_time_sum = 0;
+ u->adjust_counter = 0;
adjust_time_sec = DEFAULT_ADJUST_TIME_USEC / PA_USEC_PER_SEC;
if (pa_modargs_get_value_u32(ma, "adjust_time", &adjust_time_sec) < 0) {
@@ -1331,6 +1357,8 @@ int pa__init(pa_module *m) {
else
u->adjust_time = DEFAULT_ADJUST_TIME_USEC;
+ u->real_adjust_time = u->adjust_time;
+
pa_sink_input_new_data_init(&sink_input_data);
sink_input_data.driver = __FILE__;
sink_input_data.module = m;
--
2.10.1
More information about the pulseaudio-discuss
mailing list