ALSA:snd_pcm_writei调用缓冲区欠载

时间:2014-04-15 19:37:32

标签: linux alsa

在运行我最近从灰烬中带回来的旧程序时,我得到了缓冲区不足。

程序将原始声音文件完全加载到内存中(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-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/

找到

修改

刚刚发现如果一个人实际测试-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);
}

1 个答案:

答案 0 :(得分:5)

如果用525帧(大约12 ms)填充缓冲区然后等待一秒钟,则可以保证得到欠载,因为剩余的988 ms没有数据。

您可以使用snd_pcm_drain等待实际数据停止播放(注意:通常情况下,设备实际上不会停止直到下一个周期边界)。 或者,继续将零样品送入缓冲液。