Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ALSA: pcm: detect xruns in no-period-wakeup mode

When period wakeups are disabled, successive calls to the pointer update
function do not have a maximum allowed distance, so xruns cannot be
detected with the pointer value only.

To detect xruns, compare the actually elapsed time with the time that
should have theoretically elapsed since the last update. When the
hardware pointer has wrapped around due to an xrun, the actually elapsed
time will be too big by about hw_ptr_buffer_jiffies.

Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>

authored by

Clemens Ladisch and committed by
Takashi Iwai
59ff878f 075140ea

+16 -2
+16 -2
sound/core/pcm_lib.c
··· 374 374 (unsigned long)runtime->hw_ptr_base); 375 375 } 376 376 377 - /* without period interrupts, there are no regular pointer updates */ 378 - if (runtime->no_period_wakeup) 377 + if (runtime->no_period_wakeup) { 378 + /* 379 + * Without regular period interrupts, we have to check 380 + * the elapsed time to detect xruns. 381 + */ 382 + jdelta = jiffies - runtime->hw_ptr_jiffies; 383 + hdelta = jdelta - delta * HZ / runtime->rate; 384 + while (hdelta > runtime->hw_ptr_buffer_jiffies / 2 + 1) { 385 + delta += runtime->buffer_size; 386 + hw_base += runtime->buffer_size; 387 + if (hw_base >= runtime->boundary) 388 + hw_base = 0; 389 + new_hw_ptr = hw_base + pos; 390 + hdelta -= runtime->hw_ptr_buffer_jiffies; 391 + } 379 392 goto no_delta_check; 393 + } 380 394 381 395 /* something must be really wrong */ 382 396 if (delta >= runtime->buffer_size + runtime->period_size) {