[pulseaudio-discuss] [PATCH v4] Make module loopback honor requested latency

Alexander E. Patrakov patrakov at gmail.com
Sat Feb 7 11:50:10 PST 2015

06.02.2015 14:56, Georg Chini wrote:
> One more thing: There is a systematic error in the adjust_time I could
> not work around without
> introducing too much overhead. The latency snapshot varies widely in the
> execution time, I
> measured values between 50 us and more than 60 ms. So if the extreme
> values follow each other
> you will have one adjust time that is around 60 ms too long and another
> one which is 60 ms too
> short. Maybe this also contributes significantly to the (in)stability of
> regulation.

Well, I have looked into this issue.

Basically, you have a callback, time_callback, which is called every 
u->adjust_time microseconds, according to a timer. All it does is to 
send asynchronous messages to the sink input and the source output using 
pa_asyncmsgq_send(), and they fill in various portions of the latency 
snapshot by querying the relevant memblockq and the sink/source itself, 
as well as snapshotting the total length of data received or sent.

A potential problem is that pa_source_get_latency_within_thread() and 
pa_sink_get_latency_within_thread() themselves, in the case of an alsa 
source, go through a smoother (see source_get_latency() in 
src/modules/alsa/alsa-source.c), which _also_ tries to do sample rate 
estimation for you! Try to avoid that, even though this means code 

Unfortunately, this is easy to recommend, but I can't really see how 
this can be done.

The smoother is updated _after_ a successful write to the alsa device 
(via traditional UNIX write or via mmap), while the pop callbacks are 
executed just before that. So, they are called at the moment when the 
influence from a bad rate estimation via the smoother is the greatest.

Now the suggestions.

I think that, ideally, for such use cases, it is important to have 
timestamped latency snapshots for both sinks and sources in PulseAudio 
core. This would mean introducing a new message that gets the latest 
reliable latency snapshot (i.e., timestamp according to the wall clock, 
send/receive counter, input/output buffer size, and the latency itself), 
without any interpolation. If the sink does not implement this, just 
fallback (in the generic sink code) to getting the current latency. 
Also, because such snapshots for the sink and the source will not happen 
at the same moment, you have to deal with it.

Also, I have a very heretic thought. Namely, that the smoother in the 
alsa sink and source may actually be a bad idea and is better removed. I 
have not tested this. But it is used only in two places: for reporting 
latency (where it confuses your module) and for calculating the amount 
of time to sleep in the case of timer-based scheduling (where even 
module-alsa-sink does not trust the result, i.e. discards it if it is 
greater than the non-transformed time interval). And, if I recollect 
correctly, there were complaints about it being fooled by batch cards, 
and they were cited as one of the reasons not to enable timer-based 
scheduling on batch cards. So - maybe, for the purposes of timer 
based-scheduling we should just assume the worst case, i.e. the card 
that is, say, 0.75% faster than nominal, and use the nominal rate 
together with the latest snapshot time in {source,sink}_get_latency()? 
Basically, the fear is that the smoother makes a greater mistake in the 
estimated rate than just assuming the nominal one. Maybe you can try 
this suggestion?

For Tanu's patch status page: please leave the status of this patch as 
unreviewed. The general idea of the patch does not look brilliant, but 
it's the best known-working idea that we currently have on the topic, 
and I have not reviewed all the fine details.

Alexander E. Patrakov

More information about the pulseaudio-discuss mailing list