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 incluye. Consulta OpenSLES_Android.h para obtener información sobre estas extensiones. Este archivo se encuentra en el directorio raíz de la instalación: 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 de Android. Para atenuar este problema, evita usar extensiones, o bien usa #ifdef para excluirlas durante el tiempo de 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 (reproducir) 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 (reproducir) 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 y otras interfaces de 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 siguientes claves y valores de configuración disponibles:

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

En el siguiente fragmento de código, se muestra un ejemplo de cómo 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, el envío y las capacidades de efectos de Android proporcionan un mecanismo genérico para que una aplicación busque y use efectos de audio específicos del dispositivo. Los fabricantes de dispositivos deben documentar los efectos de audio específicos del dispositivo disponibles que proporcionen.

Las aplicaciones portátiles deben usar las APIs de OpenSL ES 1.0.1 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 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 grabadoras 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 alcanzar 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 de 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 seguir ese comportamiento o no modificar la ubicación del cursor de reproducción. 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 activador 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 instancias de un objeto. Esta es una alternativa al uso de DynamicInterfaceManagement::AddInterface() para agregar estas interfaces después de crear la instancia.

Informe de extensiones

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

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

Cualquiera de estos métodos muestra ANDROID_SDK_LEVEL_<API-level>, donde API-level es el nivel de API de la plataforma; por ejemplo, ANDROID_SDK_LEVEL_23. Si la plataforma tiene una API nivel 9 o más, significa que 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 en 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 abierto 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 abierto con una licencia apropiada

Nota: Actualmente, no hay documentación para la versión del NDK de la API de MediaCodec. No obstante, puedes consultar el código de muestra 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 especificó la fuente de datos como un URI o un localizador de datos del descriptor de archivos de Android con el formato de datos MIME. En ese 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 función está diseñada principalmente para que los juegos carguen previamente sus elementos de audio cuando cambien a un nuevo nivel, lo que es similar a la funcionalidad que proporciona la clase SoundPool.

Inicialmente, la aplicación 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 disponer 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 qué búfer contiene datos o cuál debe ponerse en cola a continuación.

La fuente de datos informa implícitamente el final de la transmisión (EOS) y proporciona un evento SL_PLAYEVENT_HEADATEND al final de esta. Una vez que la app haya decodificado todos los datos que recibió, no realizará 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 con una tasa de muestreo, un recuento de canales o una profundidad de bits diferentes. Para obtener información sobre una disposición a fin de detectar el formato PCM real, consulta Cómo determinar el formato de datos PCM decodificados a través de metadatos.

OpenSL ES para la función de decodificación de PCM de Android admite pausado y búsqueda inicial, pero no admite control de volumen, efectos, repetición indefinida 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 de 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 especificó, pero puede incluir lo siguiente: eliminación de los datos PCM decodificados, pausa del proceso de decodificación o cierre absoluto del decodificador.

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

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 función está orientada principalmente a aplicaciones de medios de transmisión que usan audio AAC, pero que deben realizar un procesamiento personalizado de audio antes de la reproducción. La mayoría de las aplicaciones que debe decodificar audio al formato PCM debe usar el método descrito en Cómo decodificar 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 usarse si se cumplen las dos condiciones siguientes:

  • 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 archivo.

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 cola otro búfer completo. La consecuencia de la limitación del decodificador no se especifica.

En todo sentido, excepto para la fuente de datos, el método de decodificación de la transmisión es el mismo que el que se describe en Cómo decodificar 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 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 raíz de la instalación, docs/Additional_library_docs/openmaxal/.

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 de Android. El archivo de encabezado OpenSLES_AndroidMetadata.h define esas claves de metadatos. Este archivo de encabezado reside en el directorio raíz de la instalación, /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. Te recomendamos 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 ejecuciones diferentes ni que varias instancias de objetos comparten índices en la misma ejecución.

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.