[pulseaudio-discuss] [PATCH v6 21/25] loopback: Track prediction error; debug and cosmetic changes
Georg Chini
georg at chini.tk
Sun Jun 5 19:05:24 UTC 2016
This patch is purely cosmetic. It changes debugging output to a be better readable
and tracks the prediction error for debugging purpose only. The patch also adds
Georg Chini to the authors of the module.
---
src/modules/module-loopback.c | 34 ++++++++++++++++++++++------------
1 file changed, 22 insertions(+), 12 deletions(-)
diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c
index 2189a48..442b24c 100644
--- a/src/modules/module-loopback.c
+++ b/src/modules/module-loopback.c
@@ -38,7 +38,7 @@
#include "module-loopback-symdef.h"
-PA_MODULE_AUTHOR("Pierre-Louis Bossart");
+PA_MODULE_AUTHOR("Pierre-Louis Bossart, Georg Chini");
PA_MODULE_DESCRIPTION("Loopback from source to sink");
PA_MODULE_VERSION(PACKAGE_VERSION);
PA_MODULE_LOAD_ONCE(false);
@@ -109,14 +109,15 @@ struct userdata {
pa_usec_t configured_source_latency;
pa_usec_t minimum_latency;
- /* State variables of the latency controller,
+ /* State variables of the latency controller, prediction and
* last values */
pa_usec_t extra_latency;
pa_usec_t next_latency_with_drift;
pa_usec_t next_latency_at_optimum_rate_with_drift;
int32_t last_latency_difference;
- /* Variables for Kalman filter */
+ /* Variables for Kalman filter and error tracking */
+ double latency_error;
double latency_variance;
double kalman_variance;
@@ -337,6 +338,8 @@ static void adjust_rates(struct userdata *u) {
u->next_latency_with_drift = current_latency;
} else {
+ /* Low pass filtered latency error. This value reflects how well the measured values match the prediction. */
+ u->latency_error = (1 - FILTER_PARAMETER) * u->latency_error + FILTER_PARAMETER * (double)abs((int32_t)(current_latency - u->next_latency_with_drift));
/* Low pass filtered latency variance */
current_latency_error = (double)abs((int32_t)(latency_at_optimum_rate - u->next_latency_at_optimum_rate_with_drift));
u->latency_variance = (1.0 - FILTER_PARAMETER) * u->latency_variance + FILTER_PARAMETER * current_latency_error * current_latency_error;
@@ -345,17 +348,22 @@ static void adjust_rates(struct userdata *u) {
u->kalman_variance = u->kalman_variance * u->latency_variance / (u->kalman_variance + u->latency_variance) + u->latency_variance / 4 + 200;
}
- 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) current_buffer_latency / PA_USEC_PER_MSEC,
- (double) 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);
-
/* Calculate new rate */
new_rate = rate_controller(u, base_rate, old_rate, (int)(filtered_latency - final_latency), latency_difference);
+ pa_log_debug("Loopback status %s to %s:\n Source latency: %0.2f ms\n Buffer: %0.2f ms\n Sink latency: %0.2f ms\n End-to-end latency: %0.2f ms\n"
+ " Deviation from target latency at optimum rate: %0.2f usec\n Average prediction error: ± %0.2f usec\n Optimum rate: %0.2f Hz\n Deviation from base rate: %i Hz",
+ u->source_output->source->name,
+ u->sink_input->sink->name,
+ (double) u->latency_snapshot.source_latency / PA_USEC_PER_MSEC,
+ (double) current_buffer_latency / PA_USEC_PER_MSEC,
+ (double) u->latency_snapshot.sink_latency / PA_USEC_PER_MSEC,
+ (double) current_latency / PA_USEC_PER_MSEC,
+ (double) latency_at_optimum_rate - final_latency,
+ (double) u->latency_error,
+ u->drift_compensation_rate + base_rate,
+ (int32_t)(new_rate - base_rate));
+
/* Save current latency difference at new rate for next cycle and reset flags */
u->last_latency_difference = current_source_sink_latency + current_buffer_latency * old_rate / new_rate - final_latency;
@@ -388,7 +396,6 @@ static void adjust_rates(struct userdata *u) {
/* Set rate */
pa_sink_input_set_rate(u->sink_input, new_rate);
- pa_log_debug("[%s] Updated sampling rate to %lu Hz.", u->sink_input->sink->name, (unsigned long) new_rate);
}
/* Called from main context */
@@ -627,6 +634,7 @@ static void source_output_detach_cb(pa_source_output *o) {
u->iteration_counter = 0;
u->underrun_counter = 0;
u->extra_latency = 0;
+ u->latency_error = 0;
}
/* Called from main thread */
@@ -927,6 +935,7 @@ static void sink_input_detach_cb(pa_sink_input *i) {
u->iteration_counter = 0;
u->underrun_counter = 0;
u->extra_latency = 0;
+ u->latency_error = 0;
}
/* Called from output thread context */
@@ -1186,6 +1195,7 @@ int pa__init(pa_module *m) {
u->source_sink_changed = true;
u->underrun_occured = false;
u->extra_latency = 0;
+ u->latency_error = 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) {
--
2.8.1
More information about the pulseaudio-discuss
mailing list