Extensiones de Android

OpenSL ES para Android extiende la especificación de la referencia OpenSL ES para que sea compatible con Android y aprovechar la potencia y flexibilidad de la plataforma de Android.

La definición de la API para las extensiones de Android reside en OpenSLES_Android.h y en los archivos de encabezado que este incluye. Consulta OpenSLES_Android.h para obtener información sobre estas extensiones. Este archivo se encuentra en la raíz de instalación, en el directorio sysroot/usr/include/SLES. A menos que se indique lo contrario, todas las interfaces son explícitas.

Estas extensiones limitan la portabilidad de tu aplicación para otras implementaciones de OpenSL ES, ya que son específicas para Android. Para mitigar este problema, evita usar extensiones o usa #ifdef para excluirlas durante la compilación.

En la siguiente tabla, se muestran las interfaces específicas de Android y los localizadores de datos que Android OpenSL ES admite para cada tipo de objeto. Los valores de las celdas indican las interfaces y los localizadores de datos disponibles para cada tipo de objeto.

Función Reproductor de audio Grabador de audio Motor Combinación de salida
Cola de búfer de Android Sí: Fuente (decodificar) No No No
Configuración de Android No No
Efecto de Android No No
Capacidades de efectos de Android No No No
Envío de efectos de Android No No No
Cola de búfer simple de Android Sí: Fuente (reproducción) o receptor (decodificar) No No
Localizador de datos de la cola de búfer de Android Sí: Fuente (decodificar) No No No
Localizador de datos del descriptor de archivos de Android Sí: Fuente No No No
Localizador de datos de la cola de búfer simple de Android Sí: Fuente (reproducción) o receptor (decodificar) Sí: Receptor No No

Interfaz de configuración de Android

La interfaz de configuración de Android proporciona un medio para configurar parámetros específicos de la plataforma para objetos. La diferencia entre esta interfaz y otras interfaces OpenSL ES 1.0.1 recae en que tu app puede usarla antes de crear una instancia del objeto correspondiente; por lo tanto, puedes configurar el objeto antes de crear una instancia de él. El archivo de encabezado OpenSLES_AndroidConfiguration.h, que reside en /sysroot/usr/include/SLES, documenta las claves y los valores de configuración disponibles siguientes:

  • Tipo de transmisión para reproductores de audio (el predeterminado es SL_ANDROID_STREAM_MEDIA).
  • Perfil de grabación para grabadores de audio (el predeterminado es SL_ANDROID_RECORDING_PRESET_GENERIC).

En el siguiente fragmento de código, se ejemplifica la forma de establecer el tipo de transmisión de audio de Android en un reproductor de audio:

// 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.

Puedes usar código similar a fin de configurar el valor preestablecido para un grabador de audio:

// ... 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));

Interfaces de efectos de Android

Las interfaces de efectos, envío de efectos y capacidades de efectos de Android proporcionan un mecanismo genérico para que una aplicación consulte y use efectos de audio específicos del dispositivo. Los fabricantes de dispositivos deben documentar los efectos de audio específicos del dispositivo que proporcionen.

Las aplicaciones portátiles deben usar OpenSL ES 1.0.1 API para los efectos de audio en lugar de las extensiones de efectos de Android.

Localizador de datos del descriptor de archivos de Android

El localizador de datos del descriptor de archivos de Android te permite especificar la fuente para un reproductor de audio como un descriptor de archivos abierto con acceso de lectura. El formato de los datos debe ser MIME.

Esta extensión es particularmente útil junto con el administrador de recursos nativo, ya que la app lee recursos del APK a través de un descriptor de archivos.

Interfaz y localizador de datos de la cola de búfer simple de Android

En la especificación de referencia de OpenSL ES 1.0.1, las colas de búfer se pueden usar únicamente para reproductores de audio, y son compatibles con PCM y otros formatos de datos. Las especificaciones de la interfaz y el localizador de datos de la cola de búfer simple de Android son idénticas a la especificación de referencia, con dos excepciones:

  • Puedes usar colas de búfer simples de Android con grabadores y reproductores de audio.
  • Solo puedes usar el formato de datos PCM con esas colas.

Para realizar grabaciones, tu app debe colocar en cola búferes vacíos. Cuando una devolución de llamada registrada envía una notificación que indica que el sistema terminó de escribir datos en un búfer, la app puede leer datos de ese búfer.

La reproducción funciona de la misma manera. No obstante, para lograr la compatibilidad del código fuente en el futuro, recomendamos que las aplicaciones usen colas de búfer simples de Android en lugar de colas de búfer OpenSL ES 1.0.1.

Comportamiento de la cola de búfer

La implementación de Android no incluye el requisito de la especificación de referencia que indica que el cursor de reproducción debe regresar al comienzo del búfer de reproducción actual cuando la reproducción ingresa en estado SL_PLAYSTATE_STOPPED. Esta implementación puede coincidir con ese comportamiento o dejar la ubicación del cursor de reproducción sin modificar. Como consecuencia, tu app no puede suponer que ocurrirá uno de estos comportamientos. Por lo tanto, debes llamar explícitamente al método BufferQueue::Clear() después de una transición a SL_PLAYSTATE_STOPPED. Al hacerlo, la cola de búfer queda en un estado conocido.

Asimismo, no hay ninguna especificación que indique si el desencadenador de una devolución de llamada de cola de búfer debe ser una transición a SL_PLAYSTATE_STOPPED o una ejecución de BufferQueue::Clear(). Por lo tanto, te recomendamos no crear una dependencia en uno o en el otro. En cambio, tu app debería poder controlar ambos.

Interfaces dinámicas en la creación de objetos

Por motivos de conveniencia, la implementación que realiza Android de OpenSL ES 1.0.1 permite que tu app especifique interfaces dinámicas al crear una instancia de un objeto. Esta es una alternativa al uso de DynamicInterfaceManagement::AddInterface() para agregar estas interfaces después de la creación de la instancia.

Informe de extensiones

Existen tres métodos para consultar si la plataforma admite extensiones de Android. Esos métodos son los siguientes:

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

Cualquiera de estos métodos devuelve ANDROID_SDK_LEVEL_<API-level>, donde API-level es el nivel de API de la plataforma; por ejemplo, ANDROID_SDK_LEVEL_23. Un nivel de API de plataforma de 9 o más significa que la plataforma admite las extensiones.

Decodificación de audio al formato PCM

En esta sección, se describe una extensión específica de Android obsoleta para OpenSL ES 1.0.1 que decodifica a PCM una transmisión codificada sin reproducción inmediata. En la tabla siguiente, se proporcionan recomendaciones para usar esta extensión y las alternativas.

Nivel de API Alternativas
15 y menos Códec de código fuente con una licencia apropiada
De 16 a 20 Clase MediaCodec o códec de código fuente con una licencia apropiada
21 y más NDK MediaCodec en los archivos de encabezado <media/NdkMedia*.h>, la clase MediaCodec o un códec de código fuente con una licencia apropiada

Nota: Actualmente, no hay documentación para la versión de NDK de la API MediaCodec. No obstante, puedes consultar el ejemplo de código native-codec como referencia.

Un reproductor de audio estándar realiza la reproducción en un dispositivo de audio especificando la combinación de salida como receptor de datos. La extensión de Android difiere en que un reproductor de audio actúa como decodificador si la app especifica la fuente de datos como un URI o un localizador de datos del descriptor de archivos de Android descrito con el formato de datos MIME. En tal caso, el receptor de datos es un localizador de datos de la cola de búfer simple de Android que usa el formato de datos PCM.

Esta característica está orientada principalmente a juegos para cargar previamente sus recursos de audio al realizar un cambio a un nuevo nivel del juego, lo cual se asemeja a la funcionalidad que proporciona la clase SoundPool.

La aplicación inicialmente debe colocar un conjunto de búferes vacíos en la cola de búfer simple de Android. Después de esto, la app completa los búferes con datos PCM. La devolución de llamada de la cola de búfer simple de Android se activa después de que se completa cada búfer. El controlador de devolución de llamada procesa los datos PCM, vuelve a colocar en cola el búfer ahora vacío y luego regresa. La aplicación se encarga de realizar el seguimiento de los búferes decodificados; la lista de parámetros de devolución de llamada no incluye suficiente información para indicar el búfer que contiene datos o el búfer que se debe disponer en la cola a continuación.

La fuente de datos informa implícitamente el final de la transmisión (EOS) proporcionando un evento SL_PLAYEVENT_HEADATEND al final de la transmisión. Una vez que la app decodifica todos los datos que recibió, no realiza más llamadas a la devolución de llamada de cola de búfer simple de Android.

El formato de datos PCM del receptor generalmente coincide con el de la fuente de datos codificados con respecto a la tasa de muestreo, al recuento de canales y a la profundidad de bits. No obstante, puedes realizar la decodificación a una tasa de muestreo, un recuento de canales o una profundidad de bits diferente. Para obtener información sobre una disposición a fin de detectar el formato PCM real, consulta Determinación del formato de los datos PCM decodificados mediante metadatos.

OpenSL ES para la característica de decodificación de PCM de Android admite pausado y búsqueda inicial, pero no admite control de volumen, efectos, ejecución en bucle ni velocidad de reproducción.

Según la implementación de la plataforma, la decodificación puede requerir recursos que no pueden dejarse inactivos. Por lo tanto, te recomendamos que te asegures de proporcionar una cantidad suficiente de búferes PCM vacíos; de lo contrario, el decodificador se verá limitado. Esto puede ocurrir, por ejemplo, si tu app regresa de la devolución de llamada de cola de búfer simple de Android sin disponer en cola otro búfer vacío. El resultado de la limitación del decodificador no se ha determinado, pero puede incluir lo siguiente: eliminación de los datos PCM decodificados, pausado del proceso de decodificación o finalización absoluta del decodificador.

Nota: Para decodificar una transmisión codificada en PCM sin reproducir de inmediato, en las apps que se ejecutan en Android 4.x (niveles de API 16 a 20), te recomendamos usar la clase MediaCodec. Para las aplicaciones nuevas que se ejecutan en Android 5.0 (nivel de API 21) o versiones posteriores, te recomendamos usar el equivalente del NDK, <NdkMedia*.h>. Estos archivos de encabezado residen en el directorio media/, en la raíz de tu instalación.

Decodificación de transmisiones ADTS AAC en PCM

Un reproductor de audio funciona como decodificador de transmisiones si la fuente de datos es un localizador de datos en la cola de búfer de Android que usa el formato de datos MIME y el receptor de datos es un localizador de datos en la cola de búfer simple de Android que usa el formato de datos PCM. Configura el formato de datos MIME de la siguiente manera:

  • Contenedor: SL_CONTAINERTYPE_RAW
  • String de tipo MIME: SL_ANDROID_MIME_AACADTS

Esta característica está orientada principalmente a aplicaciones de medios de transmisión que usan audio AAC y deben realizar procesamiento de audio personalizado antes de la reproducción. La mayoría de las aplicaciones que deben decodificar audio al formato PCM deben usar el método descrito en Decodificación de audio al formato PCM, ya que ese método es más simple y admite más formatos de audio. La técnica descrita aquí representa un enfoque más especializado que solo debe aplicarse si se cumplen estas dos condiciones:

  • La fuente de audio comprimido es una transmisión de tramas AAC contenidas en encabezados ADTS.
  • La aplicación controla esta transmisión. Los datos no se ubican en un recurso de red cuyo identificador sea un URI ni en un archivo local cuyo identificador sea un descriptor de archivos.

La aplicación debe colocar inicialmente en cola un conjunto de búferes llenos en la cola de búfer de Android. Cada búfer contiene una o más tramas ADTS AAC completas. La devolución de llamada de la cola de búfer de Android se activa después de que se vacía cada búfer. El controlador de devolución de llamada debe volver a completar el búfer y disponerlo en la cola, y luego regresar. La aplicación no necesita realizar un seguimiento de los búferes codificados; la lista de parámetros de devolución de llamada incluye suficiente información para indicar el búfer que debe disponerse en la cola a continuación. El final de la transmisión está explícitamente marcado por la colocación de un elemento EOS en la cola. Después de EOS, no se permiten más elementos en la cola.

Te recomendamos asegurarte de proporcionar búferes ADTS AAC completos para evitar la limitación del decodificador. Esto puede ocurrir, por ejemplo, si tu app regresa de la devolución de llamada de la cola de búfer de Android sin disponer en esta otro búfer completo. La consecuencia de la limitación del decodificador no se especifica.

En todo sentido, salvo por la fuente de datos, el método de decodificación de la transmisión es el mismo que el que se describe en Decodificación de audio al formato PCM.

A pesar de la similitud de los nombres, una cola de búfer de Android no es lo mismo que una cola de búfer simple de Android. El decodificador de transmisiones usa ambos tipos de colas de búfer: una cola de búfer de Android para la fuente de datos ADTS AAC y una cola de búfer simple de Android para el receptor de datos PCM. Para obtener más información sobre la API de cola de búfer simple de Android, consulta Interfaz y localizador de datos de la cola de búfer simple de Android. Para obtener más información sobre la API de cola de búfer de Android, consulta el archivo index.html en el directorio docs/Additional_library_docs/openmaxal/, en la raíz de instalación.

Determinación del formato de los datos PCM decodificados mediante metadatos

La interfaz SLMetadataExtractionItf forma parte de la especificación de referencia. No obstante, las claves de los metadatos que indican el formato real de los datos PCM decodificados son específicas para Android. El archivo de encabezado OpenSLES_AndroidMetadata.h define esas claves de metadatos. Este archivo de encabezado reside en la raíz de instalación, en el directorio /sysroot/usr/include/SLES.

Los índices de las claves de metadatos están disponibles inmediatamente una vez que el método Object::Realize() termina de ejecutarse. Sin embargo, los valores asociados no están disponibles hasta después de que la app decodifica los primeros datos codificados. Una buena práctica es consultar los índices de claves en el subproceso principal después de llamar al método Object::Realize y leer los valores de los metadatos en formato PCM en el controlador de devolución de llamada de la cola de búfer simple de Android al llamarlo por primera vez. Consulta el código de ejemplo en el paquete del NDK para hallar ejemplos relacionados con la forma de trabajar con esta interfaz.

Los nombres de las claves de metadatos son estables, pero los índices de claves no están documentados y pueden modificarse. Una aplicación no debe suponer que los índices persisten en diferentes pasadas de ejecución ni que varias instancias de objetos comparten índices en la misma pasada.

Datos de punto flotante

Una app que se ejecuta en Android 5.0 (nivel de API 21) y versiones posteriores puede proporcionar datos a un reproductor de audio en formato de punto flotante de precisión sencilla.

En el siguiente código de ejemplo, el método Engine::CreateAudioPlayer() crea un reproductor de audio que usa datos de punto flotante:

#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;
Obtén más información sobre el audio de punto flotante en la página Muestreo de audio.