[pulseaudio-discuss] [PATCH 04/13] loopback: Adjust rates based on latency difference

Tanu Kaskinen tanuk at iki.fi
Wed Nov 11 12:51:22 PST 2015


On Wed, 2015-11-11 at 21:13 +0100, Georg Chini wrote:
> On 11.11.2015 19:36, Tanu Kaskinen wrote:
> > On Wed, 2015-02-25 at 19:43 +0100, Georg Chini wrote:
> > > For small values of latency_difference, this forms a classical
> > > P-controller between the observed value of latency and the controlled
> > > sample rate of the sink input. The coefficient aims for the full
> > > correction of the observed difference to the next cycle - i.e. the
> > > controller is tuned optimally according to
> > > https://en.wikipedia.org/wiki/Ziegler%E2%80%93Nichols_method
> > > For higher latency values the controller limits the deviation from
> > > the base rate to 0.95%.
> > > ---
> > >   src/modules/module-loopback.c | 44 ++++++++++++++++++++++++-------------------
> > >   1 file changed, 25 insertions(+), 19 deletions(-)
> > > 
> > > diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c
> > > index 3532728..372c3ed 100644
> > > --- a/src/modules/module-loopback.c
> > > +++ b/src/modules/module-loopback.c
> > > @@ -169,9 +169,30 @@ static void teardown(struct userdata *u) {
> > >       }
> > >   }
> > >   
> > > +/* rate controller
> > > + * - maximum deviation from base rate is less than 1%
> > > + * - can create audible artifacts by changing the rate too quickly
> > > + * - exhibits hunting with USB or Bluetooth sources
> > > + */
> > > +static uint32_t rate_controller(
> > > +                uint32_t base_rate,
> > > +                pa_usec_t adjust_time,
> > > +                int32_t latency_difference_usec) {
> > > +
> > > +    uint32_t new_rate;
> > > +    double min_cycles;
> > > +
> > > +    /* 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.0095 + 1;
> > > +    new_rate = base_rate * (1.0 + (double)latency_difference_usec / min_cycles / adjust_time);
> > > +
> > > +    return new_rate;
> > > +}
> > Sorry for being obtuse, but I don't follow what this simple bit of code
> > is doing. You mentioned "P-controller" and the "Ziegler-Nichols
> > method". I followed the Wikipedia link, and found that a P-controller
> > is a very simple thing:
> > 
> > u(t) = Kp * e(t)
> > 
> > where
> > 
> > u(t): the new control variable value (the new sink input rate)
> > 
> > Kp: a tunable parameter (a magic number)
> > 
> > e(t): the error value, i.e. the difference between the current process
> > variable value and the target value (current latency minus configured
> > latency)
> > 
> > The Ziegler-Nichols method can be used to choose Kp. For a P-controller
> > Kp is defined as
> > 
> > Kp = 0.5 * Ku
> > 
> > where
> > 
> > Ku: a number that, when used in place of Kp, makes u(t) oscillate in a
> > stable manner
> > 
> > (A sidenote: I probably have understood something wrong, because Kp is
> > a plain number, and u(t) and e(t) have different units, so there
> > appears to be a unit mismatch. u(t) is a frequency and e(t) is a time
> > amount.)
> > 
> > Figuring out Ku seems to require having an initial calibration phase
> > where various Ku values are tried and the oscillation of u(t) is
> > measured. The code doesn't seem to do this. Could you explain how you
> > have derived the formula in rate_controller()?
> > 
> Hi Tanu,
> 
> the comment regarding Ziegler-Nichols method was added by
> Alexander Patrakov. I had a long discussion with him back in
> February which explains most of the background, so I would like
> to point you to the following thread:
> 
> http://thread.gmane.org/gmane.comp.audio.pulseaudio.general/22753

Thanks, I'll read it.

> I also forwarded you some math with more details on Friday.

I don't think I received that message.

-- 
Tanu


More information about the pulseaudio-discuss mailing list