我尝试了多个示例程序,这些程序似乎都具有在回放时处理xruns的代码:
https://albertlockett.wordpress.com/2013/11/06/creating-digital-audio-with-alsa/
[https://www.linuxjournal.com/article/6735(清单3)
[当使用snd_pcm_writei()时,当返回值为-EPIPE(即xrun / underrun)时,它们会执行以下操作:
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问题。
我也注意到,来自:https://www.alsa-project.org/alsa-doc/alsa-lib/pcm.html
SND_PCM_STATE_XRUNPCM设备达到溢出(捕获)或欠载(播放)状态。您可以使用I / O函数的-EPIPE返回代码(snd_pcm_writei(),snd_pcm_writen(),snd_pcm_readi(),snd_pcm_readn())在不检查实际状态的情况下确定此状态snd_pcm_state()调用。建议使用辅助功能snd_pcm_recover()从此状态中恢复,但是您也可以使用snd_pcm_prepare(),snd_pcm_drop()或snd_pcm_drain()调用。
再次,我不清楚。我可以使用snd_pcm_prepare()还是可以使用这些其他调用?有什么不同?我应该使用什么?
处理欠载的最佳方法是通过防止它们来避免对其进行处理。这可以通过在缓冲区为空之前尽早写入样本来完成。为此,
snd_pcm_write*()
时可以编写新的示例,和/或发生欠载时,您必须决定应该播放的样本在正确的时间没有被写入缓冲区的情况。
要同时播放以下样本,就好像实际上播放了丢失的样本一样,请配置设备,以免欠载停止它。这可以通过将停止阈值¹设置为边界值²来完成。 (其他错误,例如拔下USB设备,仍将停止该设备。)
当发生欠载时,设备将播放碰巧在环形缓冲区中的那些样本。默认情况下,这些是一段时间前的旧样本,听起来不正确。要改为播放静音(听起来也不会正确,但是会以其他方式播放),请通过将静音阈值³设置为零并将静音大小⁴设置为边界值来告诉设备在播放完缓冲区后立即清除缓冲区的每个部分。 。
要(尝试)在发生错误(xrun或其他错误)后重新初始化设备,可以调用snd_pcm_prepare()
或snd_pcm_recover()
。后者调用前者,并处理挂起的设备(通过等待其恢复)。
¹停止阈值:snd_pcm_sw_params_set_stop_threshold()
边界值:snd_pcm_sw_params_get_boundary()
静音阈值:snd_pcm_sw_params_set_silence_threshold()
⁴静音大小:snd_pcm_sw_params_set_silence_size()