问题
I'm getting buffer underruns when running an old program I recently brought back from the ashes.
The program loads up a raw sound file fully into memory (2100 bytes long, 525 frames) and prepares ALSA for output (44.1khz, 2 channels, signed 16 bit):
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 state is PREPARED
prior to first playing the sound. Sound plays correctly the first time around, however, the second time it is played, state is RUNNING
and a -EPIPE
("Broken pipe") is thrown by snd_pcm_writei
. Playback logic:
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);
Strangely, it plays correctly at the third time, failing once again the following time. In other words, it fails with a -EPIPE
error every other time.
For the sake of simplicity, I'm playing the sounds at 1 second intervals.
What's wrong with the logic above?
Updated code to use new ALSA API; can be found at: http://paste.ubuntu.com/7257181/
EDIT
Just found out that if one actually tests for an -EPIPE
condition and re-prepares the PCM handle before re-issuing the snd_pcm_writei
call, all is good. My (new) question then is... why?
if(frames == -EPIPE) {
snd_pcm_prepare(pcm.handle);
frames = snd_pcm_writei(pcm.handle,
sound.data, //sound.data + (offset << 1),
write_size);
}
回答1:
If you fill the buffer with 525 frames (about 12 ms) and then wait for one second, you are guaranteed to get an underrun because there is no data for the remaining 988 ms.
You could use snd_pcm_drain
to wait until the actual data has stopped playing (note: typcially, the device will not actually stop until the next period boundary).
Alternatively, continue feeding zero samples into the buffer.
来源:https://stackoverflow.com/questions/23092895/alsa-buffer-underrun-on-snd-pcm-writei-call