linux – ALSA:snd_pcm_writei调用的缓冲区欠载
在运行我最近从灰烬中带回来的旧程序时,我得到缓冲区欠载.
程序将原始声音文件完全加载到内存中(2100字节长,525帧)并准备ALSA输出(44.1khz,2个通道,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,并且snd_pcm_writei会抛出-EPIPE(“Broken pipe”).播放逻辑:
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/
编辑
刚刚发现如果一个人实际测试-EPIPE条件并在重新发出snd_pcm_writei调用之前重新准备PCM句柄,那么一切都很好.我的(新)问题是……为什么?
if(frames == -EPIPE) {
snd_pcm_prepare(pcm.handle);
frames = snd_pcm_writei(pcm.handle,
sound.data, //sound.data + (offset << 1),
write_size);
}