Как использовать ALSA snd_pcm_writei()?

Может кто-нибудь объяснить, как snd_pcm_writei

snd_pcm_sframes_t snd_pcm_writei(snd_pcm_t *pcm, const void *buffer,
                                 snd_pcm_uframes_t size)

работает?

Я использовал это так:

for (int i = 0; i < 1; i++) {
   f = snd_pcm_writei(handle, buffer, frames);

   ...
}

Полный исходный код на http://pastebin.com/m2f28b578

Значит ли это, что я должен snd_pcm_writei() указывать не количество всех кадров в buffer, а только

частота_выборки * задержка = frames

?

Итак, если я, например. есть: sample_rate = 44100 задержка = 0,5 [с] all_frames = 100000

Количество кадров, которые я должен дать snd_pcm_writei(), будет

Sample_rate * задержка = кадры 44100 * 0,5 = 22050

и количество итераций цикла for?:

(целое) 100000/22050 = 4; с кадрами=22050

и один дополнительный, но только с

100000 по модулю 22050 = 11800

кадры?

Так это работает?

Луиза

http://www.alsa-project.org/alsa-doc/alsa-lib/group___p_c_m.html#gf13067c0ebde29118ca05af76e5b17a9


person Louise    schedule 01.02.2010    source источник


Ответы (4)


frames должно быть числом кадров (сэмплов), которые вы хотите записать из буфера. Звуковой драйвер вашей системы сразу же начнет передавать эти сэмплы на звуковую карту, и они будут воспроизводиться с постоянной скоростью.

Задержка вводится в нескольких местах. Существует задержка из-за буферизации данных драйвером в ожидании передачи на карту. Есть по крайней мере один буфер, полный данных, которые передаются на карту в любой момент, и есть буферизация на стороне приложения, что вас, кажется, беспокоит.

Чтобы уменьшить задержку на стороне приложения, вам нужно написать наименьший буфер, который будет работать на вас. Если ваше приложение выполняет задачу DSP, обычно это данные одного окна.

Нет никакого преимущества в написании небольших буферов в цикле — просто идите вперед и записывайте все за один раз — но есть важный момент, который нужно понять: чтобы свести к минимуму задержку, ваше приложение должно писать в драйвер не быстрее, чем драйвер записывает данные в звуковая карта, или вы в конечном итоге накапливаете больше данных и накапливаете все большую и большую задержку.

Дизайн, который позволяет относительно легко создавать данные синхронно с звуковым драйвером, смотрите на jack (http://jackaudio.org/), который основан на регистрации функции обратного вызова в механизме воспроизведения звука. На самом деле, вам, вероятно, лучше использовать jack вместо того, чтобы пытаться сделать это самостоятельно, если вы действительно беспокоитесь о задержке.

person Ori Pessach    schedule 02.02.2010
comment
Мне нужно воспроизвести всего около 17000 кадров, так что задержка на стороне приложения будет приемлемой. Самое странное, что если я передаю snd_pcm_writei() все кадры и удаляю цикл for, ничего не воспроизводится. Если я сохраню цикл for и, например. установите его на 5 итераций, он дважды перебирает ~ 17000 кадров. Если я посмотрю в примере libsndfile на строку 11, pastebin.com/m559397b3, он пройдет через буфер. Когда я это делаю, ничего не воспроизводится. Также мне кажется странным, что snd_pcm_writei() всегда возвращает то же количество кадров, которое я ему задал. Он никогда не возвращает меньшее число, которое я ожидал бы. ? - person Louise; 03.02.2010
comment
17000 сэмплов — это меньше одной секунды воспроизведения. Повторно записывая буфер в звуковой драйвер, вы, по сути, воспроизводите его снова и снова, но из вашего описания это звучит так, как будто что-то в вашей системе препятствует воспроизведению начала звука. Во-первых, пошаговое выполнение буфера — это правильно; вам не нужно писать образец более одного раза. Во-вторых, чтобы увидеть, не воспроизводит ли ваш звуковой драйвер или звуковая карта начало звука, попробуйте дополнить буфер нулевыми сэмплами в начале секунды и посмотрите, будет ли это иметь значение. - person Ori Pessach; 03.02.2010
comment
Большое спасибо за то, что вычистили все это. Теперь, когда вы упомянули об этом, у меня действительно есть некоторые проблемы со звуком при воспроизведении ALSA, например. MPlayer. Первые 2 секунды ничего не воспроизводится, а потом играет. Я попробую обновиться до Fedora 12, а потом попробую еще раз. Еще раз спасибо =) - person Louise; 04.02.2010
comment
Я хотел бы добавить, что кадры равны number_of_samples/channels. - person stare; 26.06.2020

Я думаю, что причина «преждевременного» закрытия устройства заключается в том, что вам нужно вызвать snd_pcm_drain(handle); до snd_pcm_close(handle);, чтобы убедиться, что все данные воспроизведены до закрытия устройства.

person cordeg    schedule 07.03.2013

Я провел некоторое тестирование, чтобы определить, почему snd_pcm_writei() не работает для меня, используя несколько примеров, которые я нашел в руководствах по ALSA, и пришел к выводу, что простые примеры выполняли snd_pcm_close () до того, как звуковое устройство могло воспроизвести полный поток, отправленный на Это.

Я установил скорость 11025, использовал случайный буфер на 128 байт, а для зацикленного snd_pcm_writei() на 11025/128 на каждую секунду звука. Две секунды потребовали 86*2 вызовов snd_pcm_write(), чтобы получить две секунды звука.

Чтобы дать устройству достаточно времени для преобразования данных в аудио, я поместил цикл for после цикла snd_pcm_writei(), чтобы отложить выполнение функции snd_pcm_close().

После тестирования я пришел к выводу, что в примере кода недостаточно примеров для преодоления задержки устройства до вызова функции snd_pcm_close, что означает, что функция закрытия имеет меньшую задержку, чем функция snd_pcm_write().

person axismann    schedule 18.11.2012

Если порог запуска драйвера ALSA не установлен должным образом (если в вашем случае это около 2 с), то вам нужно будет вызвать snd_pcm_start(), чтобы начать рендеринг данных сразу после snd_pcm_writei(). Или вы можете установить соответствующий порог в параметрах ПО устройства ALSA.

ссылка:

person Community    schedule 21.09.2014