Воспроизводить аудио в режиме реального времени с помощью opensl es и android ndk
Я хотел бы записать голос, обработать его, добавив некоторый эффект к записанному аудио, и затем воспроизвести его как можно быстрее, используя opensl. У меня проблемы с поиском информации в сети о таких действиях, поэтому у меня есть пара вопросов.
Я посмотрел образец звука для Android и начало книги android ndk, с которого я начал работать с opensl, но они не очень помогли мне понять запись.
1) Итак, во-первых, чтобы немедленно воспроизвести записанное аудио, смогу ли я прочитать буфер из потока, который воспроизводит звук, в то время как поток записи записывает в буфер? Я знаю, что кто-то, вероятно, сойдет с ума от этой идеи, потому что идея одновременного доступа к какому-либо объекту в памяти двумя разными потоками может привести к проблемам, но если поток записи всегда будет записываться в память перед тем, как проигрывая аудио поток, тогда это было бы возможно, верно?
2) Или для воспроизведения в режиме реального времени, буду ли я использовать очередь буфера с двумя или тремя очень маленькими буферами и обратный вызов, который вызывается при каждом заполнении, а затем воспроизводить этот буфер, пока следующий буфер заполняется записью аудио поток? но я читал, и кто-то сказал, что обратные вызовы не всегда вызываются (самая полезная ссылка, которую я нашел по этому поводу: https://groups.google.com/forum/), также это означает, что разница во времени между записанным звуком и воспроизводимым звуком будет равна размеру буфера плюс время, которое требуется обратному вызову, чтобы сообщить объекту записи о начале записи с использованием следующего буфера. Я думаю, что был бы разрыв между тем, когда рекордер прекращает запись и когда он начинает запись снова.
3) Очередь буфера записи Android также там, где у меня проблемы с пониманием. Должен ли я использовать буферную очередь в Android для записи аудио? или это возможно для записи непосредственно в буфер без использования очереди в буфере? У меня проблемы с этим, потому что четкий метод SLAndroidSimpleBufferQueueItf
на самом деле не похоже на работу. видимо это ошибка. и я не могу записать через буфер после того, как он уже был заполнен данными. так как метод clear не работает, как я могу сказать рекордеру, в какой буфер в очереди записывать?
Я знаю, что это довольно много, чтобы спросить, и я не сказал все, что я пробовал, но я надеялся, что кто-то имеет некоторый опыт с этим и может пролить свет на меня и всех, у кого есть проблемы с воспроизведением записанных аудио в режиме реального времени с использованием opensl.
2 ответа
Я нашел в значительной степени именно то, что я ищу. Способ воспроизведения записанного звука в режиме реального времени заключается в использовании так называемого циклического буфера (или округлого буфера), в который в основном записывается записанное аудио, а воспроизводимое аудио считывает все, до чего записывается записанное аудио.
http://audioprograming.wordpress.com/
OpenSL ES в Android по-прежнему не совсем поддерживает "Low-latency", так как все еще есть небольшая задержка, но она все еще работает очень хорошо, это звучит скорее как небольшое эхо
Я понимаю, что на это ответили, и это старый вопрос. Однако, чтобы уточнить, в моей очереди воспроизведения я не использую Clear()
, Я просто прекращаю воспроизведение, а затем жду, пока очередь истечет, используя GetState(state)
в цикле, вот так:
SLresult res;
SLAndroidSimpleBufferQueueState state = {0};
res = (*playbackBufferQueue)->GetState(playbackBufferQueue, &state);
while (state.count && (res == SL_RESULT_SUCCESS))
{
prevState = state;
res = (*m_playbackBufferQueue)->GetState(m_playbackBufferQueue, &state);
// Otherwise this will peg the CPU
sleep(1);
}
А для поддержки низкой задержки вы должны использовать "оптимальную" частоту и размер выборки, которые вы запрашиваете у Android. Можете ли вы сделать это с помощью нативных вызовов API? Конечно нет, не будь глупой. Сделайте это на Java и передайте его родному:
int getBestPlaybackRate() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
return Integer.parseInt(audioManager.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE));
}
return 0;
}
int getBestBufferSize() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
return Integer.parseInt(audioManager.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER));
}
return 0;
}