alsaloop: reduce cumulative error caused by non-atomic samples calculation

When doing loopback between two audio card with
same sampling frequency, I noticed slow increase
of pitch_diff.

When I changed order of get_queued_playback_samples()
vs get_queued_capture_samples(), I noticed same drift
of pitch_diff but if was decreasing this time.

This seems to be caused by non-atomic consecutive
snd_pcm_delay() invocation for playback then for
capture. snd_pcm_delay() measures delay between
read/write call and actual ADC/DAC operation.

So while we get this value for playback path in
get_queued_playback_samples(), next call to
get_queued_capture_samples() will happen a little
bit later so snd_pcm_delay() may return incorrect
value.

Be interleaving get_queued_{playback,capture}_samples()
order, we divide this small error between playback
and capture paths. I do not see any issues anymore
with one-way drift of pitch_diff.

Signed-off-by: Ruslan Bilovol <ruslan.bilovol@gmail.com>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
Ruslan Bilovol 2020-03-09 22:29:54 +02:00 committed by Jaroslav Kysela
parent f31f5df42a
commit ec8717d588

View file

@ -1951,8 +1951,16 @@ int pcmjob_pollfds_handle(struct loopback *loop, struct pollfd *fds)
} }
if (loop->sync != SYNC_TYPE_NONE) { if (loop->sync != SYNC_TYPE_NONE) {
snd_pcm_sframes_t pqueued, cqueued; snd_pcm_sframes_t pqueued, cqueued;
/* Reduce cumulative error by interleaving playback vs capture reading order */
if (loop->total_queued_count & 1) {
pqueued = get_queued_playback_samples(loop); pqueued = get_queued_playback_samples(loop);
cqueued = get_queued_capture_samples(loop); cqueued = get_queued_capture_samples(loop);
} else {
cqueued = get_queued_capture_samples(loop);
pqueued = get_queued_playback_samples(loop);
}
if (verbose > 4) if (verbose > 4)
snd_output_printf(loop->output, "%s: queued %li/%li samples\n", loop->id, pqueued, cqueued); snd_output_printf(loop->output, "%s: queued %li/%li samples\n", loop->id, pqueued, cqueued);
if (pqueued > 0) if (pqueued > 0)