summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorg Chini <georg@chini.tk>2020-01-27 19:22:35 +0100
committerGeorg Chini <georg@chini.tk>2021-11-07 18:17:37 +0000
commit285427ce30c966cf149acef7096aec10c2eaa769 (patch)
tree634f7eea2d7d118d7a6312d8f63b441029b210b7
parente7abd862b140685bc7559604ba1c0a8abd876378 (diff)
loopback: Limit controller step size to 2.01‰
The current loopback controller can produce a rate jump of up to 1% at startup, which may be audible. To prevent large initial jumps, a second controller is introduced, which produces a rate, that is not more than 2‰ away from the last rate. Only during the startup phase, the rates produced by this controller will be nearer to the base rate than those produced by the original controller. Therefore choosing the rate which is nearer to the base rate will ensure that the secondary controller only moderates the startup phase and has no influence during continued operation. The maximum step size of the original controller after the initial jump is limited to 2.01‰ of the base rate, see documentation at https://www.freedesktop.org/software/pulseaudio/misc/rate_estimator.odt Part-of: <https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/56>
-rw-r--r--src/modules/module-loopback.c28
1 files changed, 19 insertions, 9 deletions
diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c
index e3e260900..0f6467fff 100644
--- a/src/modules/module-loopback.c
+++ b/src/modules/module-loopback.c
@@ -240,21 +240,31 @@ static void teardown(struct userdata *u) {
/* rate controller, called from main context
* - maximum deviation from base rate is less than 1%
- * - can create audible artifacts by changing the rate too quickly
+ * - controller step size is limited to 2.01‰
* - exhibits hunting with USB or Bluetooth sources
*/
static uint32_t rate_controller(
- uint32_t base_rate,
- pa_usec_t adjust_time,
+ struct userdata *u,
+ uint32_t base_rate, uint32_t old_rate,
int32_t latency_difference_usec) {
- uint32_t new_rate;
- double min_cycles;
+ uint32_t new_rate, new_rate_1, new_rate_2;
+ double min_cycles_1, min_cycles_2;
+
+ /* Calculate next rate that is not more than 2‰ away from the last rate */
+ min_cycles_1 = (double)abs(latency_difference_usec) / u->real_adjust_time / 0.002 + 1;
+ new_rate_1 = old_rate + base_rate * (double)latency_difference_usec / min_cycles_1 / u->real_adjust_time;
/* Calculate best rate to correct the current latency offset, limit at
- * slightly below 1% difference from base_rate */
- min_cycles = (double)abs(latency_difference_usec) / adjust_time / 0.01 + 1;
- new_rate = base_rate * (1.0 + (double)latency_difference_usec / min_cycles / adjust_time);
+ * 1% difference from base_rate */
+ min_cycles_2 = (double)abs(latency_difference_usec) / u->real_adjust_time / 0.01 + 1;
+ new_rate_2 = (double)base_rate * (1.0 + (double)latency_difference_usec / min_cycles_2 / u->real_adjust_time);
+
+ /* Choose the rate that is nearer to base_rate */
+ if (abs((int)new_rate_1 - (int)base_rate) < abs((int)new_rate_2 - (int)base_rate))
+ new_rate = new_rate_1;
+ else
+ new_rate = new_rate_2;
return new_rate;
}
@@ -415,7 +425,7 @@ static void adjust_rates(struct userdata *u) {
}
/* Calculate new rate */
- new_rate = rate_controller(base_rate, u->real_adjust_time, latency_difference);
+ new_rate = rate_controller(u, base_rate, old_rate, latency_difference);
u->source_sink_changed = false;