Буферизация URI на OpenSL, Android

Я пробовал OpenSL в течение нескольких недель. Я пытаюсь получить доступ к буферу при воспроизведении файла на SD-карте через SL_DATALOCATOR_URI в качестве источника. Я хочу написать несколько собственных эффектов и мне нужен буфер.

В настоящее время в коде я создаю два аудиоплеера. Один читает файл в буфер, другой записывает буфер в выходной файл. Когда я тестирую код с микрофоном (диктофоном), все в порядке. Звук на входе-выходе работает как положено.

Когда я переключаю рекордер с аудиоплеером uri, очередь выходит из строя. Стриминг не прослушивает блокировки потоков (происходит асинхронно как я понял) и вызовы буфера не корректно фаерятся, время летит незаметно.

Я поставил журналы для каждого метода, поэтому результат выглядит примерно так:

V/PDecoder( 1292): Position : 15023
V/PDecoder( 1292): Position : 16044
V/PDecoder( 1292): Position : 17043
V/PDecoder Native PL1( 1292): bqPlayerCallback
V/PDecoder Native PL1( 1292): Notify thread lock
V/PDecoder Native PL1( 1292): android_AudioIn 32768
V/PDecoder Native PL1( 1292): Wait thread lock
V/PDecoder Native PL1( 1292): android_AudioOut 32768
V/PDecoder Native PL1( 1292): android_AudioIn 32768
V/PDecoder Native PL1( 1292): android_AudioOut 32768
V/PDecoder Native PL1( 1292): Wait thread lock
V/PDecoder Native PL1( 1292): bqRecorderCallback
V/PDecoder Native PL1( 1292): Notify thread lock
V/PDecoder( 1708): Position : 18041
V/PDecoder( 1708): Position : 19040
V/PDecoder( 1708): Position : 20038

Секунды улетают еще до того, как сработают обратные вызовы очереди.

Так вот вопрос, как исправить эту проблему? Есть ли способ для аудиоплеера > буфера > выходного решения для воспроизведения uri? Что я делаю неправильно? Если кто-то может указать мне правильное направление, это очень ценится.

Код немного длинный для вставки сюда, так что вот суть


person emrahgunduz    schedule 15.07.2014    source источник


Ответы (3)


Потерявшись в коде, который я дал в вопросе, решил написать его снова, как можно чище.

Я обнаружил, что все-таки не блокировал uri player. Я добавляю рабочий окончательный код в конце ответа. Код хорош для воспроизведения локального файла или URL-адреса, но его нужно запускать в потоке, начинающемся с java, иначе вы заблокируете поток графического интерфейса.

PS. Буфер использует стек, поэтому вы можете переместить его в кучу и, возможно, сохранить указатель в структуре. Кроме того, методы воспроизведения, паузы, уничтожения не завершены. Если вы хотите использовать код, вы можете легко реализовать эти функции.

Бонус. Код также включает простой способ вызова методов экземпляра java (без ужасного *env, отправленного из java-части). Если вам это нужно, посмотрите JNI_OnLoad, затем playStatusCallback() и затем callPositionChanged() методы.

Код немного длинный для вставки сюда, так что вот суть

person emrahgunduz    schedule 17.07.2014

Эмра, это именно та проблема, с которой я столкнулся в моем проекте прямо сейчас. Я следил за этим блогом:

http://audioprograming.wordpress.com/2012/10/29/lock-free-audio-io-with-opensl-es-on-android/

который представляет собой реализацию этого кругового буфера из того же блога:

http://audioprograming.wordpress.com/2012/03/03/android-audio-streaming-with-opensl-es-and-the-ndk/

В любом случае, при изучении кода, похоже, что у него есть свои версии ваших opensl-native файлов h и c с именем opensl_io. У него также есть еще один класс, opensl_example, в котором есть входной и выходной буферы с небольшой промежуточной обработкой. Кажется, что его объект рекордера заполняет входящий буфер этого класса opensl_example, а его внешний буфер заполняет его объект аудиоплеера для воспроизведения на сток. Судя по всему, вы тоже этим занимались.

По сути, я пытаюсь заменить объект рекордера входным потоком из файла, поскольку мне нужно иметь доступ к фрагментам буфера из файла, если я хочу, например, обрабатывать каждый фрагмент по-разному во время потока. вы используете SLDATA_locator из преобразованного URI utf8, что я пытаюсь сделать сейчас, но я не совсем уверен, как получить из него поток.

Прямо сейчас пример с блогом работает следующим образом: он берет аудиовход от объекта записи в потоке, помещает его в циклические буферы по мере их заполнения и обрабатывает для вывода. Я пытаюсь просто заменить источник буферов рекордера своими кусками буфера из mp3. Опять же, похоже, что ваш код делает именно это. Пример блога по аудиопрограммированию мне особенно сложно изменить, потому что я не совсем уверен в том, как работает SWIG. Но поскольку вы используете JNI, это может быть проще.

Не подскажете, как у вас работает? Вы просто вызываете StartPDecoderNative, а затем DecodeOn из Java со строкой uri в качестве параметра?

person B.C    schedule 29.07.2014
comment
Вы можете проверить код в принятом ответе. Я создаю два проигрывателя, буферный проигрыватель и проигрыватель URI. Проигрыватель URI заполняет свой собственный буфер, читая файл (или URL-адрес, если хотите) и вызывает обратный вызов очереди, затем я отправляю буфер в выходной проигрыватель. Это не слишком сложно, из-за шаблона opensl вы можете заблудиться. Я вызываю StartPDecoderNative с файлом uri (например: file:///sdcard/file.mp3). Затем я вызываю DecodeOn(), который инициализирует все необходимые объекты. Вызовите эти методы из java-части, и она сыграет. - person emrahgunduz; 30.07.2014
comment
Я преобразовал свой собственный код для проекта, над которым я работаю, и теперь я могу делать что угодно с буфером, я уже написал фильтры высоких/низких частот, усилители, 10+ полосный эквалайзер, эффекты кроссфейда, фф и т.д. анализатор спектра и т. д., вы можете напрямую обращаться к буферу и делать все, что пожелаете. Но переместите его в кучу, так как код в ответе работает в стеке и очень медленный. - person emrahgunduz; 30.07.2014

Хорошо, попытался запустить код c и h с помощью простой основной активности Java, которая запускает обе эти функции в указанном порядке при нажатии кнопки.

Кроме того, похоже, вам также нужен метод positionchanged в java. Что ты там гонишь? Я могу прокомментировать часть с помощью jmethod, и музыка играет, так что это работает. Это для поиска?

Наконец, может быть, у меня просто проблемы с пониманием, но в каком буфере вы выполняете обработку и где он находится? Это аутбуфер? Если бы я просто хотел, скажем, применить fft или, проще говоря, просто скалярное умножение к выходному звуку, я бы просто умножил его на аутбуфер, прежде чем воспроизвести его на финальном приемнике?

person B.C    schedule 30.07.2014
comment
positionChanged возвращает текущую позицию воспроизводимого звука из нативного в java в секундах. вы можете отключить его. Неважно, в каком буфере вы будете выполнять обработку. - person emrahgunduz; 31.07.2014
comment
@emrahgunduz Спасибо. Ваши обратные вызовы, кажется, не работают для меня, у меня просто есть функция void с тем же именем в java с объявлением внизу. Может быть, что-то с моей средой перепутались. Но также, что вы подразумеваете под «Но переместите его в кучу», поскольку код в ответе работает в стеке и очень медленно обрабатывает буферы? Я не совсем понимаю, что вы имеете в виду под этим, и как бы я его передвинул? Вы имеете в виду скопировать его в какое-то другое пространство памяти? - person B.C; 06.08.2014