Воспроизводить аудио в режиме реального времени с помощью 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;
}
Другие вопросы по тегам