Расширения для Android

ВНИМАНИЕ: OpenSL ES устарел . Разработчикам следует использовать библиотеку Oboe с открытым исходным кодом, доступную на GitHub . Гобой — это оболочка C++, предоставляющая API, очень похожий на AAudio . Гобой вызывает AAudio, когда AAudio доступен, и возвращается к OpenSL ES, если AAudio недоступен.

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

Определение API для расширений Android находится в OpenSLES_Android.h и включаемых в него файлах заголовков. Обратитесь к OpenSLES_Android.h для получения подробной информации об этих расширениях. Этот файл находится в корне вашей установки, в каталоге sysroot/usr/include/SLES . Если не указано иное, все интерфейсы являются явными.

Эти расширения ограничивают переносимость вашего приложения на другие реализации OpenSL ES, поскольку они специфичны для Android. Вы можете смягчить эту проблему, избегая использования расширений или используя #ifdef , чтобы исключить их во время компиляции.

В следующей таблице показаны специфичные для Android интерфейсы и локаторы данных, которые Android OpenSL ES поддерживает для каждого типа объектов. Значения «Да» в ячейках указывают интерфейсы и локаторы данных, доступные для каждого типа объекта.

Особенность Аудиоплеер Аудио рекордер Двигатель Выходной микс
Буферная очередь Android Да: Источник (декодирование) Нет Нет Нет
Конфигурация Android Да Да Нет Нет
Android-эффект Да Нет Нет Да
Возможности эффектов Android Нет Нет Да Нет
Отправка эффекта Android Да Нет Нет Нет
Простая буферная очередь Android Да: источник (воспроизведение) или приемник (декодирование) Да Нет Нет
Локатор данных очереди буфера Android Да: Источник (декодирование) Нет Нет Нет
Локатор данных дескриптора файла Android Да: Источник Нет Нет Нет
Простой локатор данных очереди буфера Android Да: источник (воспроизведение) или приемник (декодирование) Да: Раковина Нет Нет

Интерфейс конфигурации Android

Интерфейс конфигурации Android предоставляет средства для установки параметров, специфичных для платформы, для объектов. Этот интерфейс отличается от других интерфейсов OpenSL ES 1.0.1 тем, что ваше приложение может использовать его перед созданием экземпляра соответствующего объекта; таким образом, вы можете настроить объект перед созданием его экземпляра. Заголовочный файл OpenSLES_AndroidConfiguration.h , который находится в /sysroot/usr/include/SLES , документирует следующие доступные ключи и значения конфигурации:

  • Тип потока для аудиоплееров (по умолчанию SL_ANDROID_STREAM_MEDIA ).
  • Профиль записи для аудиорекордеров (по умолчанию SL_ANDROID_RECORDING_PRESET_GENERIC ).

В следующем фрагменте кода показан пример установки типа аудиопотока Android в аудиоплеере:

// CreateAudioPlayer and specify SL_IID_ANDROIDCONFIGURATION
// in the required interface ID array. Do not realize player yet.
// ...
SLAndroidConfigurationItf playerConfig;
result = (*playerObject)->GetInterface(playerObject,
    SL_IID_ANDROIDCONFIGURATION, &playerConfig);
assert(SL_RESULT_SUCCESS == result);
SLint32 streamType = SL_ANDROID_STREAM_ALARM;
result = (*playerConfig)->SetConfiguration(playerConfig,
    SL_ANDROID_KEY_STREAM_TYPE, &streamType, sizeof(SLint32));
assert(SL_RESULT_SUCCESS == result);
// ...
// Now realize the player here.

Вы можете использовать аналогичный код для настройки пресета для аудиорекордера:

// ... obtain the configuration interface as the first four lines above, then:
SLuint32 presetValue = SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION;
result = (*playerConfig)->SetConfiguration(playerConfig,
    RECORDING_PRESET, &presetValue, sizeof(SLuint32));

Интерфейсы эффектов Android

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

Портативные приложения должны использовать API-интерфейсы OpenSL ES 1.0.1 для аудиоэффектов вместо расширений эффектов Android.

Локатор данных дескриптора файла Android

Локатор данных дескриптора файла Android позволяет указать источник для аудиоплеера как дескриптор открытого файла с доступом для чтения. Формат данных должен быть MIME.

Это расширение особенно полезно в сочетании со встроенным менеджером ресурсов, поскольку приложение считывает ресурсы из APK через файловый дескриптор.

Простой указатель данных и интерфейс буферной очереди Android

В справочной спецификации OpenSL ES 1.0.1 буферные очереди могут использоваться только для аудиоплееров, и они совместимы с PCM и другими форматами данных. Указатель данных простой буферной очереди Android и спецификации интерфейса идентичны эталонной спецификации, за двумя исключениями:

  • Вы можете использовать простые буферные очереди Android с аудиорекордерами и аудиоплеерами.
  • С этими очередями можно использовать только формат данных PCM.

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

Воспроизведение работает таким же образом. Однако для будущей совместимости исходного кода мы предлагаем приложениям использовать простые буферные очереди Android вместо буферных очередей OpenSL ES 1.0.1.

Поведение буферной очереди

Реализация Android не включает требование эталонной спецификации о том, чтобы курсор воспроизведения возвращался в начало текущего воспроизводимого буфера, когда воспроизведение переходит в состояние SL_PLAYSTATE_STOPPED . Эта реализация может соответствовать этому поведению или может оставить расположение курсора воспроизведения неизменным. В результате ваше приложение не может предположить, что происходит какое-либо поведение. Поэтому следует явно вызывать метод BufferQueue::Clear() после перехода к SL_PLAYSTATE_STOPPED . При этом очередь буфера будет переведена в известное состояние.

Аналогично, не существует спецификации, определяющей, должен ли триггер обратного вызова буферной очереди быть переходом к SL_PLAYSTATE_STOPPED или выполнением BufferQueue::Clear() . Поэтому мы рекомендуем вам не создавать зависимости ни от того, ни от другого; вместо этого ваше приложение должно иметь возможность обрабатывать и то, и другое.

Динамические интерфейсы при создании объекта

Для удобства реализация OpenSL ES 1.0.1 в Android позволяет вашему приложению указывать динамические интерфейсы при создании экземпляра объекта. Это альтернатива использованию DynamicInterfaceManagement::AddInterface() для добавления этих интерфейсов после создания экземпляра.

Отчеты о расширениях

Существует три способа узнать, поддерживает ли платформа расширения Android. Эти методы:

  • Engine::QueryNumSupportedExtensions()
  • Engine::QuerySupportedExtension()
  • Engine::IsExtensionSupported()

Любой из этих методов возвращает ANDROID_SDK_LEVEL_<API-level> , где API-level — это уровень API платформы; например, ANDROID_SDK_LEVEL_23 . Уровень API платформы 9 или выше означает, что платформа поддерживает расширения.

Декодировать звук в PCM

В этом разделе описывается устаревшее расширение OpenSL ES 1.0.1 для Android, предназначенное для декодирования закодированного потока в PCM без немедленного воспроизведения. В таблице ниже приведены рекомендации по использованию этого расширения и альтернатив.

уровень API Альтернативы
15 и ниже Кодек с открытым исходным кодом и подходящей лицензией.
с 16 до 20 Класс MediaCodec или кодек с открытым исходным кодом с подходящей лицензией.
21 и выше NDK MediaCodec в файлах заголовков <media/NdkMedia*.h> , классе MediaCodec или кодеке с открытым исходным кодом с подходящей лицензией.

Примечание. В настоящее время документация по версии NDK API MediaCodec отсутствует. Однако в качестве примера вы можете обратиться к примеру кода собственного кодека .

Стандартный аудиоплеер воспроизводит звук на аудиоустройстве, определяя выходной микс в качестве приемника данных. Расширение Android отличается тем, что аудиоплеер вместо этого действует как декодер, если приложение указало источник данных либо как URI, либо как указатель данных дескриптора файла Android, описанный с использованием формата данных MIME. В таком случае приемник данных представляет собой простой локатор данных очереди буфера Android, который использует формат данных PCM.

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

Приложение должно изначально поставить набор пустых буферов в очередь простых буферов Android. После этого приложение заполняет буферы данными PCM. Обратный вызов очереди простого буфера Android срабатывает после заполнения каждого буфера. Обработчик обратного вызова обрабатывает данные PCM, повторно ставит в очередь теперь пустой буфер и затем завершает работу. Приложение отвечает за отслеживание декодированных буферов; список параметров обратного вызова не содержит достаточной информации для указания буфера, содержащего данные, или буфера, который должен быть поставлен в очередь следующим.

Источник данных неявно сообщает об окончании потока (EOS), доставляя событие SL_PLAYEVENT_HEADATEND в конце потока. После того как приложение декодировало все полученные данные, оно больше не вызывает обратный вызов простой буферной очереди Android.

Формат данных PCM приемника обычно соответствует формату источника закодированных данных по частоте дискретизации, количеству каналов и разрядности. Однако вы можете декодировать с другой частотой дискретизации, количеством каналов или разрядностью. Информацию о возможности определения фактического формата PCM см. в разделе Определение формата декодированных данных PCM с помощью метаданных .

Функция декодирования PCM OpenSL ES для Android поддерживает паузу и начальный поиск; он не поддерживает регулировку громкости, эффекты, циклическое воспроизведение или скорость воспроизведения.

В зависимости от реализации платформы для декодирования могут потребоваться ресурсы, которые нельзя оставлять без дела. Поэтому мы рекомендуем вам убедиться в наличии достаточного количества пустых буферов PCM; в противном случае декодер выйдет из строя. Это может произойти, например, если ваше приложение возвращается из обратного вызова очереди простого буфера Android без постановки в очередь другого пустого буфера. Результат отсутствия декодера не указан, но может включать в себя: удаление декодированных данных PCM, приостановку процесса декодирования или полное завершение работы декодера.

Примечание. Чтобы декодировать закодированный поток в PCM, но не воспроизводить его немедленно, для приложений, работающих на Android 4.x (уровни API 16–20), мы рекомендуем использовать класс MediaCodec . Для новых приложений, работающих на Android 5.0 (уровень API 21) или выше, мы рекомендуем использовать эквивалент NDK, <NdkMedia*.h> . Эти заголовочные файлы находятся в каталоге media/ в корне вашей установки.

Декодирование потоковой передачи ADTS AAC в PCM

Аудиоплеер действует как потоковый декодер, если источником данных является локатор данных очереди буфера Android, который использует формат данных MIME, а приемником данных является простой локатор данных очереди буфера Android, который использует формат данных PCM. Настройте формат данных MIME следующим образом:

  • Контейнер: SL_CONTAINERTYPE_RAW
  • Строка типа MIME: SL_ANDROID_MIME_AACADTS

Эта функция в первую очередь предназначена для приложений потокового мультимедиа, которые работают со звуком AAC, но перед воспроизведением должны выполнить специальную обработку звука. Большинству приложений, которым необходимо декодировать звук в PCM, следует использовать метод, описанный в разделе «Декодирование звука в PCM» , поскольку этот метод проще и поддерживает больше аудиоформатов. Описанный здесь метод представляет собой более специализированный подход, который следует использовать только в том случае, если применимы оба этих условия:

  • Источником сжатого звука является поток кадров AAC, содержащийся в заголовках ADTS.
  • Приложение управляет этим потоком. Данные не находятся в сетевом ресурсе, идентификатором которого является URI, или в локальном файле, идентификатором которого является файловый дескриптор.

Приложение должно изначально поставить в очередь буферов Android набор заполненных буферов. Каждый буфер содержит один или несколько полных кадров ADTS AAC. Обратный вызов очереди буферов Android срабатывает после очистки каждого буфера. Обработчик обратного вызова должен перезаполнить и повторно поставить буфер в очередь, а затем вернуться. Приложению не нужно отслеживать закодированные буферы; список параметров обратного вызова включает достаточную информацию для указания буфера, который должен быть поставлен в очередь следующим. Конец потока явно отмечается путем постановки в очередь элемента EOS. После EOS очереди больше не допускаются.

Мы рекомендуем обязательно предоставить полные буферы ADTS AAC, чтобы избежать истощения декодера. Это может произойти, например, если ваше приложение возвращается из обратного вызова очереди буфера Android без постановки в очередь другого полного буфера. Результат нехватки декодера не указан.

Во всех отношениях, за исключением источника данных, метод потокового декодирования аналогичен тому, который описывает декодирование звука в PCM .

Несмотря на сходство названий, буферная очередь Android — это не то же самое, что простая буферная очередь Android . Потоковый декодер использует оба типа буферных очередей: буферную очередь Android для источника данных ADTS AAC и простую буферную очередь Android для приемника данных PCM. Дополнительные сведения об API простой буферной очереди Android см. в разделе Указатель и интерфейс данных простой буферной очереди Android . Дополнительную информацию об API буферной очереди Android см. в файле index.html в каталоге docs/Additional_library_docs/openmaxal/ в корневой папке установки.

Определите формат декодированных данных PCM с помощью метаданных

Интерфейс SLMetadataExtractionItf является частью справочной спецификации. Однако ключи метаданных, указывающие фактический формат декодированных данных PCM, специфичны для Android. Файл заголовка OpenSLES_AndroidMetadata.h определяет эти ключи метаданных. Этот заголовочный файл находится в корне вашей установки, в каталоге /sysroot/usr/include/SLES .

Индексы ключей метаданных доступны сразу после завершения выполнения метода Object::Realize() . Однако связанные значения недоступны до тех пор, пока приложение не декодирует первые закодированные данные. Хорошей практикой является запрос ключевых индексов в основном потоке после вызова Object::Realize и чтение значений метаданных формата PCM в обработчике обратного вызова простой буферной очереди Android при первом вызове. Обратитесь к примеру кода в пакете NDK для примеров работы с этим интерфейсом.

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

Данные с плавающей запятой

Приложение, работающее на Android 5.0 (уровень API 21) и выше, может передавать данные в AudioPlayer в формате одинарной точности с плавающей запятой.

В следующем примере кода метод Engine::CreateAudioPlayer() создает аудиоплеер, использующий данные с плавающей запятой:

#include <SLES/OpenSLES_Android.h>
...
SLAndroidDataFormat_PCM_EX pcm;
pcm.formatType = SL_ANDROID_DATAFORMAT_PCM_EX;
pcm.numChannels = 2;
pcm.sampleRate = SL_SAMPLINGRATE_44_1;
pcm.bitsPerSample = 32;
pcm.containerSize = 32;
pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
pcm.representation = SL_ANDROID_PCM_REPRESENTATION_FLOAT;
...
SLDataSource audiosrc;
audiosrc.pLocator = ...
audiosrc.pFormat = &pcm;
Подробнее об аудио с плавающей запятой читайте на странице «Сэмплирование аудио».