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,则会播放静音。)
我正在编写一个典型的捕获-处理-回放循环。使用 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,则会播放静音。)