0%

Linux驱动之ALSA(七)XRUN

XRUN是缓冲区不足或溢出,X代表不足或溢出。在这两种情况下,都表明系统速度不够快,未能及时处理来自ALSA音频缓冲区的数据,因此丢失了一些数据。当我们以非常小的缓冲区大小运行时,声卡应该非常快地处理传入缓冲区的数据,否则就溢出overrun了。有些芯片无法适应较小的缓冲区大小,因此我们必须增加缓冲区长度以减轻声音芯片的工作量。通常,xruns可以听到爆裂声或爆裂声。

在录音例子中,如果应用程序读取数据不够快,循环缓存区将会被新的数据覆盖。这种数据的丢失被称为"over run" 在回放例子中,如果应用程序写入数据到缓存区中的速度不够快,缓存区将会"饿死"。这样的错误被称为"under run"

/Proc

ALSA提供了一种通过proc记录和调试xrun的方法:

1
2
3
Device Drivers  --->  <*> Sound card support  --->  <*>   Advanced Linux Sound Architecture  ---> [*]   Sound Proc FS Support

Device Drivers ---> <*> Sound card support ---> <*> Advanced Linux Sound Architecture ---> [*] Debug ---> [*] Enable PCM ring buffer overrun/underrun debugging

/proc/asound/card#/pcm0p/xrun_debug

将“#”替换为card number。该proc文件可以启用各种调试工具。必须在内核中启用 CONFIG_SND_PCM_XRUN_DEBUG、CONFIG_SND_VERBOSE_PROCFS、CONFIG_SND_DEBUG 选项(如果 xrun_debug proc 文件存在 - 该功能已启用)

1
2
3
4
5
6
7
8
1   Basic debugging - show xruns in ksyslog interface
2 Dump stack - dump stack for basic debugging
4 Jiffies check - compare the position with kernel jiffies (a sort of in-kernel monotonic clock),
show what's changed when basic debugging is enabled
8 Dump positions on each period update call
16 Dump positions on each hardware pointer update call
32 Enable logging of last 10 ring buffer positions
64 Show the last 10 ring buffer position only once (when first error situation occured)

To enable more features just do sum values of above (for example 1+2=3).

Some good value combinations:

1
2
3
# Enable basic debugging and dump stack
# Usefull to just see, if PCM stream is stopped for a reason (usually wrong audio process timing from scheduler)
echo 3 > /proc/asound/card0/pcm0p/xrun_debug
1
2
3
4
# Enable basic debugging and dump stack, check hardware pointer on the period update
# Usefull to just see, if PCM stream is stopped for a reason (usually wrong audio process timing from scheduler)
# And to check the values from driver
echo 11 > /proc/asound/card0/pcm0p/xrun_debug
1
2
3
4
# Enable basic debugging and dump stack, check hardware pointer on all updates
# Usefull to just see, if PCM stream is stopped for a reason (usually wrong audio process timing from scheduler)
# And to do the exact check the values from driver
echo 27 > /proc/asound/card0/pcm0p/xrun_debug
1
2
3
# Enable basic debugging, do jiffies check and enable one shot dump of last 10 ring buffer positions
# Usefull, when the position is broken only after some of time (to reduce ksyslog messages)
echo 101 > /proc/asound/card0/pcm0p/xrun_debug
1
2
3
# Enable basic debugging, do jiffies check and dump position on each period and hardware pointer update calls
# Usefull when the lowlevel (specific) hardware driver is somehow broken
echo 29 > /proc/asound/card0/pcm0p/xrun_debug

默认情况下,在进入XRUN状态时会停止DMA传输,直到有available空间可写入(overrun时),或者直到有数据写入(underrun时)。 但是用户空间可以通过配置silence_threshold来继续播放缓冲区的重复的音频数据或静音数据(silence_size为填充的大小),当空余空间超过silence threshold时,就hardware buffer 写入silence。

常见原因

  • Linux CFS(完全公平的调度程序)
  • 具有 SCHED_FIFO 调度的高优先级线程
  • 优先级倒置
  • 长时间调度延迟
  • 长时间运行的中断处理程序
  • 长时间中断禁用
  • 电源管理
  • 安全内核

参考文献

https://source.android.com/docs/core/audio/latency/contrib?hl=zh-cn
https://www.alsa-project.org/wiki/XRUN_Debug