使用snd_pcm_writei()播放音频时,如何正确处理ALSA编程中的xrun?
我尝试了多个示例程序,这些程序似乎都有代码来处理回放下的xruns: (清单3) 使用snd_pcm_writei()时,当返回值为-eppe(即xrun/underrun)时,它们会执行以下操作:使用snd_pcm_writei()播放音频时,如何正确处理ALSA编程中的xrun?,c,alsa,C,Alsa,我尝试了多个示例程序,这些程序似乎都有代码来处理回放下的xruns: (清单3) 使用snd_pcm_writei()时,当返回值为-eppe(即xrun/underrun)时,它们会执行以下操作: if (rc == -EPIPE) { /* EPIPE means underrun */ fprintf(stderr, "underrun occurred\n"); snd_pcm_prepare(handle); } 即调用手柄上的snd_pcm_prepare() 然而,
if (rc == -EPIPE) {
/* EPIPE means underrun */
fprintf(stderr, "underrun occurred\n");
snd_pcm_prepare(handle);
}
即调用手柄上的snd_pcm_prepare()
然而,当我试图运行这样的程序时,我仍然会口吃。通常情况下,我会得到至少几次,可能是六次xrun,然后它会流畅地连续播放,而不会再进行xrun。但是,如果我有其他使用声卡的东西,比如Firefox,我会得到更多的xruns,有时只有xruns。但同样,即使我杀死了任何其他使用声卡的程序,我仍然会遇到一些初始的Xrun和扬声器上的实际口吃问题
这对我来说是不可接受的,我如何修改这种类型的xrun处理以防止口吃
我自己试图弄明白这一点:
从ALSA API中,我看到snd_pcm_prepare()可以:
准备PCM以备使用
这对像我这样的ALSA初学者来说不是很有帮助。没有解释如何使用它来恢复xrun问题
我还注意到:
SND_PCM_状态_XRUN
PCM设备达到超限(捕获)或欠载(播放)。您可以使用I/O函数中的-eppe返回代码
(snd_pcm_writei()、snd_pcm_writen()、snd_pcm_readi()、snd_pcm_readn())
在不通过检查实际状态的情况下确定此状态
snd_pcm_state()调用。建议使用helper函数
snd_pcm_recover()从该状态恢复,但也可以使用
snd_pcm_prepare()、snd_pcm_drop()或snd_pcm_drain()调用
我也不清楚。我可以使用snd_pcm_prepare()或其他调用?有什么区别?我应该使用什么?处理欠载的最佳方法是通过防止它们来避免处理它们。这可以通过在缓冲区为空之前足够早地写入样本来实现。为此,
- 重新组织您的程序,以便在需要调用
,和/或snd\u pcm\u write*()
- 增加进程/线程的优先级(如果可能;如果其他程序干扰磁盘OI/O,这可能没有帮助),和/或
- 增加缓冲区大小(这也会增加延迟)
- 要稍后播放这些样本(即,将所有后续样本移到稍后的时间),请配置设备,以便在运行不足时停止播放。(这是默认设置。)当有新样本时,程序必须重新启动设备
- 若要在实际播放丢失的样本的同时继续播放以下样本,请配置设备,使欠载不会停止播放。这可以通过将停止阈值设置为边界值²来实现。(其他错误,如拔下USB设备,仍将停止设备。) 当发生欠载时,设备将播放那些恰好在环形缓冲区中的样本。默认情况下,这些是很久以前的旧样本,听起来不正确。要改为播放静音(听起来也不正确,但方式不同),请告诉设备在播放后立即清除缓冲区的每个部分,方法是将静音阈值³设置为零,并将静音大小设置为零⁴ 到边界值
snd\u pcm\u prepare()
或snd\u pcm\u recover()
。后者调用前者,并处理挂起的设备(通过等待设备恢复)
\\停止阈值:snd\u pcm\u sw\u params\u set\u stop\u threshold()
²边界值:
snd\u pcm\u sw\u params\u get\u boundary()
静音阈值:
snd\u pcm\u sw\u params\u set\u静音阈值()
⁴静音大小:snd\u pcm\u sw\u params\u set\u静音大小()