alsa:每次欠载时延迟都会增加

alsa: latency increases at every underrun

我正在编写一个典型的捕获-处理-回放循环。使用 snd_pcm_readi() 捕获,一些廉价的音频处理,然后通过 snd_pcm_writei() 播放。单线程。 在 128 周期大小和 96000KHz 下,我感觉不到任何延迟。好。

定期我在运行下得到一个缓冲区(snd_pcm_writei() returns -EPIPE);没关系,我 运行 正在使用常规 Ubuntu 16.04 桌面,未针对低音频延迟进行配置。

运行 秒后,延迟变得可察觉。我不明白为什么。

这是我的捕获设备配置:

Plug PCM: Linear Integer <-> Linear Float conversion PCM (S32_LE)
Its setup is:
  stream       : CAPTURE
  access       : RW_INTERLEAVED
  format       : FLOAT_LE
  subformat    : STD
  channels     : 1
  rate         : 96000
  exact rate   : 96000 (96000/1)
  msbits       : 32
  buffer_size  : 4096
  period_size  : 128
  period_time  : 1333
  tstamp_mode  : NONE
  tstamp_type  : MONOTONIC
  period_step  : 1
  avail_min    : 128
  period_event : 0
  start_threshold  : 0
  stop_threshold   : 4096
  silence_threshold: 0
  silence_size : 0

这是播放设备配置:

Plug PCM: Linear Integer <-> Linear Float conversion PCM (S32_LE)
Its setup is:
  stream       : PLAYBACK
  access       : RW_INTERLEAVED
  format       : FLOAT_LE
  subformat    : STD
  channels     : 1
  rate         : 96000
  exact rate   : 96000 (96000/1)
  msbits       : 32
  buffer_size  : 384
  period_size  : 128
  period_time  : 1333
  tstamp_mode  : NONE
  tstamp_type  : MONOTONIC
  period_step  : 1
  avail_min    : 128
  period_event : 0
  start_threshold  : 384
  stop_threshold   : 384
  silence_threshold: 0
  silence_size : 0
  boundary     : 6917529027641081856

当低于运行 发生时,我运行 snd_pcm_recover() 忘记了刚刚被snd_pcm_writei() 拒绝的音频周期。在我看来,下一段音频将在我 运行 snd_pcm_writei() 时立即播放,我将再次处于低延迟循环中。但这是错误的,延迟增加了。

我的循环的捕获端没有错误。

发生了什么事?我究竟做错了什么?

谢谢。

捕获缓冲区大于播放缓冲区。这是一个减少捕获溢出风险的好主意(如果硬件支持,您可能希望使其更大),但是当播放设备短时间停止时,更多数据将堆积在捕获中缓冲并且不会比你播放它时消失得更快。

为了保证采集和回放设备不失步,

  • 停止这两个设备,然后重新启动它们,或者
  • 配置播放设备禁用欠载检测(将停止阈值设置为边界值);这意味着播放将继续,即使缓冲区中没有 valid 样本,然后您的代码必须写入样本直到赶上。 (在默认设置下,环形缓冲区中的旧样本会在欠载期间再次播放;如果您将静音 threshold/size 设置为 zero/boundary,则会播放静音。)