Вопрос или проблема
Я работаю с воспроизведением WAVE-файла через интерфейс ALSA PCM в Linux, и я услышал шум, когда воспроизводил файл быстро и частично.
Вот моя функция воспроизведения.
static int playback_function(uint8_t *pcm_buf, int pcm_frames)
{
int rc;
uint8_t *buf;
int frame_size, sent;
int periodsize;
int left;
frame_size = chan * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);
periodsize = sys_periodsize; // 320 в моей системе
buf = pcm_buf;
left = pcm_frames;
sent = 0;
while (left > 0) {
sent = (left > periodsize) ? periodsize : left;
rc = snd_pcm_writei(pcm_handle, buf, sent);
printf("rc: %d, sent: %d\n", rc, sent);
if (rc == -EAGAIN || (rc >= 0 && (size_t)rc < sent)) {
snd_pcm_wait(pcm_handle, 10);
} else if (rc == -EPIPE) {
snd_pcm_recover(pcm_handle, rc, 0);
} else if (rc < 0) {
break;
}
if (rc > 0) {
left -= rc;
buf += rc * frame_size;
}
}
return rc;
}
Массив pcm_buf
и значение pcm_frames
получены из swr_convert()
в libswresample
, в моем случае pcm_frames
равен 1187.
Добавив printf("rc: %d, sent: %d\n", rc, sent);
, я получил следующие логи.
rc: 320, sent: 320
rc: 87, sent: 87
rc: 320, sent: 320
rc: 320, sent: 320
rc: 103, sent: 103
rc: 320, sent: 320
rc: 320, sent: 320
rc: 103, sent: 103
rc: 320, sent: 320
rc: 320, sent: 320
rc: 103, sent: 103
rc: 320, sent: 320
rc: 320, sent: 320
rc: 103, sent: 103
rc: 320, sent: 320
rc: 320, sent: 320
rc: 103, sent: 103
rc: 320, sent: 320
rc: 320, sent: 320
rc: 103, sent: 103
rc: 320, sent: 320
rc: 320, sent: 320
rc: 103, sent: 103
rc: 320, sent: 320
rc: 320, sent: 320
rc: 103, sent: 103
rc: 320, sent: 320
rc: 320, sent: 320
rc: 87, sent: 87
rc: 320, sent: 320
rc: 320, sent: 320
rc: 103, sent: 103
С помощью вышеуказанной функции иногда я слышу шум при быстром и повторном воспроизведении WAVE-файла.
Как я могу улучшить воспроизведение WAVE без шума??
Я изменил вышеуказанную функцию, заполнив 0
в конце буфера данных (чтобы создать тишину).
static int playback_test(uint8_t *pcm_buf, int pcm_frames)
{
uint8_t *buf;
int trd;
int rc;
int left;
int frame_size, sent;
int periodsize;
int aligned = 0;
frame_size = chan * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);
periodsize = sys_periodsize; // 320 в моей системе
buf = pcm_buf;
left = pcm_frames;
aligned = (left/periodsize + 1) * periodsize;
memset(buf + left * frame_size, 0, (aligned - left) * frame_size);
sent = 0;
///left = periodsize; // <== Это вызывает больше шума!!
while (left > 0) {
sent = (left > periodsize) ? periodsize : left;
rc = snd_pcm_writei(pcm_handle, buf, sent);
printf("rc: %d, sent: %d\n", rc, sent);
if (rc == -EAGAIN || (rc >= 0 && (size_t)rc < sent)) {
snd_pcm_wait(pcm_handle, 10);
} else if (rc == -EPIPE) {
snd_pcm_recover(pcm_handle, rc, 0);
} else if (rc < 0) {
break;
}
if (rc > 0) {
left -= rc;
buf += rc * frame_size;
}
}
return rc;
}
Нет никаких улучшений в отношении шума.
Ответ или решение
Проблема с шумом при воспроизведении WAV-файлов через интерфейс ALSA PCM в Linux может быть вызвана несколькими факторами, связанными с тем, как происходит запись и воспроизведение звука. Ваша функция воспроизведения, которую вы предоставили, уже демонстрирует некоторые практические подходы, такие как обработка ошибок и ожидание, однако шум все еще может проявляться по ряду причин.
Анализ проблемы
-
Неправильная длина буфера: Если длина буфера не соответствует величине фрейма или перерыва, это может привести к проблемам с воспроизведением. Убедитесь, что
pcm_buf
иpcm_frames
правильно определены и соответствуют друг другу. -
Синхронизация: Недостаточная синхронизация между отправляемыми фреймами может привести к шуму. Использование
snd_pcm_wait
— правильный шаг, однако он срабатывает только в случае, если буфер переполнен. Нужно рассмотреть возможность улучшения управления потоком данных. -
Занятые ресурсы: Если звуковая карта или система заняты другими процессами, это может отразиться на качестве воспроизведения. Убедитесь, что у вас есть достаточно ресурсов для воспроизведения, и попробуйте временно отключить другие ненужные приложения.
-
Кодек и формат файла: Убедитесь, что WAV-файл имеет совместимый формат и кодек с вашей системой. Иногда несоответствие формата может вызвать артефакты воспроизведения.
-
Размер периодов: У вас установлен размер периода
320
, но его можно изменить. Попробуйте использовать больший размер, чтобы уменьшить частоту обращений к ALSA, что может уменьшить шум.
Рекомендации по улучшению функции воспроизведения
-
Проверка и корректировка размера буфера: Убедитесь, что передаваемое число фреймов,
pcm_frames
, корректно выровнено, и используяperiodsize
, чтобы избежать случайных состояний неуверенности при чтении. -
Дополнительная обработка ошибок: Убедитесь, что вы обрабатываете все возможные ошибки, чтобы приложение не зависало в проблемных состояниях, которые могут привести к шуму.
-
Нормализация и скрытие тишины: Добавление нулевых значений в конец буфера может помочь, но убедитесь, что это не создает прерывания при воспроизведении. Рассмотрите другие методы предварительной обработки данных, такие как нормализация амплитуды.
-
Параметры конфигурации ALSA: Изучите возможности настройки вашего устройства вывода в ALSA, особенно в отношении параметров сэмплинга и фреймирования.
-
Логи и диагностика: Продолжайте отладку вашей программы с использованием логов, подобно тому, как вы уже сделали с командами
printf
. Попробуйте выявить шаблоны, когда возникают шумы.
Заключение
Хотя шумы при воспроизведении аудиофайлов могут вызывать определенные трудности, соблюдение вышеуказанных методов может помочь улучшить работу звуковой аудиосистемы, основанной на интерфейсе ALSA PCM. Интегрируйте предложенные улучшения поэтапно, следите за результатами каждого изменения и корректируйте стратегию, основываясь на полученных данных. На данный момент будет полезно проверить весь процесс от загрузки файла до его воспроизведения на наличие любых несоответствий и улучшений.