Я получаю опустошение буфера при запуске старой программы, которую я недавно восстановил из пепла.
Программа полностью загружает в память необработанный звуковой файл (длиной 2100 байт, 525 кадров) и подготавливает ALSA для вывода (44,1 кГц, 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
("Сломанная труба"). Логика воспроизведения:
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 секунду.
Что не так с логикой выше?
Обновлен код для использования нового API ALSA; можно найти по адресу: http://paste.ubuntu.com/7257181/
ИЗМЕНИТЬ
Только что обнаружил, что если кто-то действительно проверяет состояние -EPIPE
и повторно подготавливает дескриптор PCM перед повторным вызовом snd_pcm_writei
, все хорошо. Тогда мой (новый) вопрос: почему?
if(frames == -EPIPE) {
snd_pcm_prepare(pcm.handle);
frames = snd_pcm_writei(pcm.handle,
sound.data, //sound.data + (offset << 1),
write_size);
}