在运行我最近从 Ember 中恢复的旧程序时,我遇到了缓冲区不足的情况。
程序将原始声音文件完全加载到内存中(2100 字节长,525 帧)并准备 ALSA 进行输出(44.1khz,2 channel ,带符号 16 位):
if ((err = snd_pcm_set_params(audio_handle,
SND_PCM_FORMAT_S16_LE,
SND_PCM_ACCESS_RW_INTERLEAVED,
2,
44100,
1,
sound.playback_us)) < 0) {
printf("E: Failed to prepare PCM: %s\n", snd_strerror(err));
return -1;
}
首次播放声音之前,PCM 状态为PREPARED
。声音第一次播放正确,但是,第二次播放时,状态为 RUNNING
并且 抛出
。播放逻辑:-EPIPE
(“管道损坏”) snd_pcm_writei
frames = snd_pcm_writei(audio_handle,
sound.data,
write_size);
if(frames < 0) {
printf("E: %s: attempting to recover\n", snd_strerror(frames));
frames = snd_pcm_recover(audio_handle, frames, 0);
if(frames < 0) {
printf("E: snd_pcm_writei failed\n");
break;
}
} else if(frames > 0 && frames < write_size)
printf("E: Short write (expected %li, wrote %li)\n", write_size, frames);
else
printf("wrote %li frames\n", frames);
奇怪的是,第三次播放正确,下一次又播放失败。换句话说,它每隔一段时间就会失败并出现 -EPIPE
错误。
为了简单起见,我以 1 秒的间隔播放声音。
上面的逻辑有什么问题吗?
<小时/>更新了代码以使用新的 ALSA API;可以在以下位置找到:http://paste.ubuntu.com/7257181/
<小时/>编辑
刚刚发现,如果在重新发出 snd_pcm_writei
调用之前实际测试 -EPIPE
条件并重新准备 PCM 句柄,则一切都很好。那么我的(新)问题是......为什么?
if(frames == -EPIPE) {
snd_pcm_prepare(pcm.handle);
frames = snd_pcm_writei(pcm.handle,
sound.data, //sound.data + (offset << 1),
write_size);
}
最佳答案
如果用 525 帧(约 12 毫秒)填充缓冲区,然后等待一秒钟,则肯定会出现欠载,因为剩余的 988 毫秒没有数据。
您可以使用snd_pcm_drain
等待实际数据停止播放(注意:通常,设备直到下一个周期边界才会真正停止)。
或者,继续将零个样本送入缓冲区。
关于linux - ALSA:snd_pcm_writei 调用时缓冲区不足,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23092895/