Воспроизведение генеративного звука с помощью OpenSL

Я создаю приложение, которое будет генерировать звук (пока что это в основном экспериментально) и воспроизводить его на телефоне Android.

На данный момент я пытаюсь воспроизвести простой синусоидальный звук (440 Гц) и сначала попробовал с аудиодорожкой, но испытал некоторое опустошение буфера. Поэтому я решил взглянуть на OpenSL.

Теперь я прочитал множество руководств и сообщений в блогах по этому поводу и, наконец, сделал свою собственную реализацию, используя OpenSL Engine с простой буферной очередью Android.

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

Мой вопрос: какова наилучшая практика/архитектура для сгенерированных звуков в OpenSL? Должен ли я заполнить буфер в альтернативном потоке (тогда потребуется некоторый процесс синхронизации с обратным вызовом буфера)?

Я еще не нашел руководств по OpenSL ES для сгенерированных звуков (большинство из них посвящено воспроизведению аудиофайлов или перенаправлению аудиовхода на аудиовыход).


person XGouchet    schedule 17.01.2014    source источник
comment
задержка намного хуже, чем у звуковой дорожки (я слышу промежутки между каждым буфером). Мне кажется, вы описываете опустошение буфера (буферы ставятся в очередь, но не заполнены полностью). Если вы не останавливаете и не перезапускаете свой объект игрока между каждым буфером, между буферами не должно быть задержки; только начальный, когда вы впервые запускаете объект игрока. Что касается вашего вопроса; Я просто использую обратный вызов очереди буфера, чтобы поставить в очередь следующий буфер, но мне пришлось попробовать разные размеры буфера, прежде чем я нашел тот, который работал.   -  person Michael    schedule 27.01.2014


Ответы (1)


Что касается задержки: важно выбрать правильную частоту дискретизации и размер буфера для вашего устройства. Вы можете запросить у устройства рекомендуемые значения с помощью AudioManager Android SDK (PROPERTY_OUTPUT_SAMPLE_RATE и PROPERTY_OUTPUT_FRAMES_PER_BUFFER доступны только с уровня API 17) и передать значения в приложение NDK:

// getting the samplerate and buffer size
if ( android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 )
{
    AudioManager am = ( AudioManager ) aContext.getSystemService( Context.AUDIO_SERVICE );
    int sampleRate = Integer.parseInt( am.getProperty( AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE ));
    int bufferSize = Integer.parseInt( am.getProperty( AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER ));
}

Важность правильной установки частоты дискретизации заключается в том, что, если она отличается от предпочтительной частоты дискретизации устройства (некоторые используют 48 кГц, другие 44,1 кГц), звук направляется через системный ресемплер до того, как он будет выведен аппаратным обеспечением, добавляя к общему задержка. Кроме того, важно получить правильный размер буфера, чтобы предотвратить отбрасывание выборок/кадров после нескольких обратных вызовов буфера, что может привести к описанной вами проблеме, когда между обратными вызовами возникают промежутки/сбои. Вы можете использовать множители (степень 2), чтобы уменьшить/увеличить размер буфера для экспериментов с более стабильным движком (больший размер буфера) и более быстрым откликом (меньший размер буфера).

Создав несколько простых приложений для Android, делающих именно это, я написал небольшую статью, объясняющую приведенную выше рекомендацию более подробно, а также то, как можно построить базовый секвенсорный движок для приложений, связанных с музыкой, однако страница представляет собой просто базовую архитектуру. план и может быть совершенно бесполезным в зависимости от ваших потребностей > Android audio engine в OpenSL

person Igor Zinken    schedule 27.01.2014
comment
я не понимаю, google рекламирует Oboe как API 16+, но все же AudioManager является обязательным для OpenSL и требует API 17. Я запутался. Мой минимальный SDK - api16, но теперь мне нужно сделать его 17? я не хочу терять 0,6% доли рынка, есть обходные пути? - person cs guy; 07.11.2020
comment
AudioManager на самом деле доступен из API 1, однако свойства частоты дискретизации и выборки на буфер были добавлены только в API 17. OpenSL фактически работает с API 10. Что вы можете сделать для пользователей ‹ API 17 по умолчанию использует частоту дискретизации (48 кГц хорошая ставка) и взять размер буфера 512 сэмплов. Если есть несоответствие между частотой дискретизации и частотой дискретизации устройства, будет некоторая дополнительная задержка, поскольку система заставит аудиопоток проходить через ресемплер. Если размер буфера не кратен собственному размеру, это может привести к менее чем оптимальному циклу рендеринга. Хотя лучше, чем ничего! - person Igor Zinken; 07.11.2020
comment
звучит очень разумно, спасибо за это. я думаю, что я установлю свой API как 16 и попробую это - person cs guy; 07.11.2020