AAudio es una API de audio que se introdujo en la versión de Android 8.0. La versión de Android 8.1 incluye mejoras para reducir la latencia cuando se usa junto con un HAL y controladores compatibles con MMAP. En este documento, se describe la abstracción de hardware capa (HAL) y controlador necesarios para admitir la función MMAP de AAudio en Android
La compatibilidad con MMAP de AAudio requiere lo siguiente:
- informar las capacidades MMAP de la HAL
- Cómo implementar funciones nuevas en la HAL
- De manera opcional, implementa un ioctl() personalizado para el búfer de modo EXCLUSIVO
- lo que proporciona una ruta de acceso adicional a los datos de hardware
- propiedades del sistema de configuración que habilitan la función MMAP
Arquitectura de AAudio
AAudio es una nueva API nativa de C que proporciona una alternativa a Open SL ES. Utiliza un Patrón de diseño de compilador para crear transmisiones de audio.
AAudio proporciona una ruta de acceso de datos de baja latencia. En el modo EXCLUSIVO, la función permite que el código de la aplicación cliente escriba directamente en un búfer asignado a la memoria que se comparte con el controlador de ALSA. En el modo SHARED, el búfer MMAP es utilizado por un mezclador que se ejecuta en el servidor de audio. En el modo EXCLUSIVO, la latencia se mucho menos porque los datos omiten el mezclador.
En el modo EXCLUSIVO, el servicio solicita el búfer MMAP a la HAL y administra los recursos. El búfer MMAP se ejecuta en modo NOIRQ, por lo que no se comparten de lectura/escritura para administrar el acceso al búfer. En cambio, el cliente mantiene un modelo de sincronización del hardware y predice cuándo se leer.
En el siguiente diagrama, podemos ver que los datos de modulación por pulso (PCM) fluyen a través del MMAP FIFO hasta el controlador ALSA. Las marcas de tiempo se muestran periódicamente solicitadas por el servicio de AAudio y, luego, pasan al modelo de tiempo del cliente a través de una cola de mensajes atómicos.
En el modo SHARED, también se usa un modelo de tiempo, pero se encuentra en AAudioService.
Para la captura de audio, se usa un modelo similar, pero los datos PCM fluyen en la dirección opuesta.
Cambios en la HAL
Para tinyALSA, consulta:
external/tinyalsa/include/tinyalsa/asoundlib.h external/tinyalsa/include/tinyalsa/pcm.c
int pcm_start(struct pcm *pcm); int pcm_stop(struct pcm *pcm); int pcm_mmap_begin(struct pcm *pcm, void **areas, unsigned int *offset, unsigned int *frames); int pcm_get_poll_fd(struct pcm *pcm); int pcm_mmap_commit(struct pcm *pcm, unsigned int offset, unsigned int frames); int pcm_mmap_get_hw_ptr(struct pcm* pcm, unsigned int *hw_ptr, struct timespec *tstamp);
Para obtener información sobre la HAL heredada, consulta lo siguiente:
hardware/libhardware/include/hardware/audio.h hardware/qcom/audio/hal/audio_hw.c
int start(const struct audio_stream_out* stream); int stop(const struct audio_stream_out* stream); int create_mmap_buffer(const struct audio_stream_out *stream, int32_t min_size_frames, struct audio_mmap_buffer_info *info); int get_mmap_position(const struct audio_stream_out *stream, struct audio_mmap_position *position);
Para la HAL de audio HIDL:
hardware/interfaces/audio/2.0/IStream.hal hardware/interfaces/audio/2.0/types.hal hardware/interfaces/audio/2.0/default/Stream.h
start() generates (Result retval); stop() generates (Result retval) ; createMmapBuffer(int32_t minSizeFrames) generates (Result retval, MmapBufferInfo info); getMmapPosition() generates (Result retval, MmapPosition position);
Informar compatibilidad con MMAP
Propiedad del sistema "aaudio.mmap_policy" debe establecerse en 2 (AAUDIO_POLICY_AUTO), por lo que el framework de audio sabrá que la HAL de audio admite el modo MMAP. (consulta "Habilitación de la ruta de datos MMAP de AAudio" a continuación).
El archivo audio_policy_configuration.xml también debe contener una salida y una entrada perfil específico para el modo MMAP/NO IRQ para que el Administrador de políticas de audio sepa qué transmisión abrir al crear los clientes MMAP:
<mixPort name="mmap_no_irq_out" role="source" flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_MMAP_NOIRQ"> <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> </mixPort> <mixPort name="mmap_no_irq_in" role="sink" flags="AUDIO_INPUT_FLAG_MMAP_NOIRQ"> <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_STEREO"/> </mixPort>
Cómo abrir y cerrar una transmisión de MMAP
createMmapBuffer(int32_t minSizeFrames) generates (Result retval, MmapBufferInfo info);
La transmisión de MMAP se puede abrir y cerrar llamando a las funciones de Timinialsa.
Posición de MMAP de consulta
La marca de tiempo que se devuelve al modelo de tiempo contiene una posición de fotograma y una Tiempo MONOTONIC en nanosegundos:
getMmapPosition() generates (Result retval, MmapPosition position);
La HAL puede obtener esta información del controlador de ALSA llamando a un nuevo Función Smallalsa:
int pcm_mmap_get_hw_ptr(struct pcm* pcm, unsigned int *hw_ptr, struct timespec *tstamp);
Descriptores de archivos para la memoria compartida
La ruta de acceso a los datos MMAP de AAudio utiliza una región de memoria compartida entre los hardware y el servicio de audio. Se hace referencia a la memoria compartida usando un descriptor de archivos generada por el controlador ALSA.
Cambios en el kernel
Si el descriptor de archivo está directamente asociado con una
/dev/snd/
, el servicio de AAudio puede usarlo en
modo SHARED. Pero el descriptor no se puede pasar al código de cliente para
modo EXCLUSIVE. El descriptor de archivo /dev/snd/
también proporcionaría
amplio de acceso al cliente, por lo que SELinux lo bloquea.
Para admitir el modo EXCLUSIVO, es necesario convertir el
el descriptor /dev/snd/
a un archivo anon_inode:dmabuf
descriptor de la aplicación. SELinux permite que el descriptor de archivos se pase al cliente. Integra
y AAudioService también las puede usar.
Se puede generar un descriptor de archivo anon_inode:dmabuf
con el
Biblioteca de memoria de Android Ion
Para obtener información adicional, consulta estos recursos externos:
- "El asignador de memoria ION de Android" https://lwn.net/Articles/480055/
- "Descripción general de Android ION" https://wiki.linaro.org/BenjaminGaignard/ion
- "Integra el asignador de memoria ION" https://lwn.net/Articles/565469/
Cambios en la HAL
El servicio de AAudio debe saber si este anon_inode:dmabuf
es
no es compatible. En versiones anteriores a Android 10.0, la única forma de hacerlo era pasar el tamaño del MMAP
búfer como un número negativo, p. ej., -2,048 en lugar de 2,048, si es compatible. En Android 10.0 y versiones posteriores
puedes configurar la marca AUDIO_MMAP_APPLICATION_SHAREABLE
.
mmapBufferInfo |= AUDIO_MMAP_APPLICATION_SHAREABLE;
Cambios en el subsistema de audio
AAudio requiere una ruta de acceso de datos adicional en el frontend de audio para que pueda operar en paralelo con la ruta de acceso de AudioFlinger original. Esa ruta heredada se usa para todos los demás sonidos del sistema y de la aplicación. Esta funcionalidad se puede proporcionar mediante un mezclador de software en una DSP o un hardware. mezclador en el SOC.
Habilitar la ruta de acceso a los datos MMAP de AAudio
AAudio utilizará la ruta de acceso de datos heredada de AudioFlinger si MMAP no es compatible o no puede abrir una transmisión. Por eso, AAudio funciona con dispositivos de audio que no admite la ruta MMAP/NOIRQ.
Cuando pruebes la compatibilidad de MMAP para AAudio, es importante que sepas si estás prueba la ruta de datos MMAP o simplemente prueba la ruta de datos heredada. El se describe cómo habilitar o forzar rutas de acceso a datos específicas y cómo consultar la ruta de acceso que usa una transmisión.
Propiedades del sistema
Puedes establecer la política MMAP a través de las propiedades del sistema:
- 1 = AAUDIO_POLICY_NEVER - Usar solo la ruta heredada Ni siquiera intentes usar MMAP.
- 2 = AAUDIO_POLICY_AUTO: Intenta usar MMAP. Si eso falla o no está disponible, y, luego, usar la ruta heredada.
- 3 = AAUDIO_POLICY_ALWAYS - Usar solo la ruta MMAP No recurrir a la versión heredada ruta de acceso.
Estos se pueden configurar en el archivo makefile de los dispositivos, de la siguiente manera:
# Enable AAudio MMAP/NOIRQ data path. # 2 is AAUDIO_POLICY_AUTO so it will try MMAP then fallback to Legacy path. PRODUCT_PROPERTY_OVERRIDES += aaudio.mmap_policy=2 # Allow EXCLUSIVE then fall back to SHARED. PRODUCT_PROPERTY_OVERRIDES += aaudio.mmap_exclusive_policy=2
También puedes anular estos valores después de que se haya iniciado el dispositivo. Deberás reiniciar el audioserver para que se aplique el cambio. Por ejemplo, para habilitar el modo AUTOMÁTICO para MMAP, sigue estos pasos:
adb root
adb shell setprop aaudio.mmap_policy 2
adb shell killall audioserver
Hay funciones proporcionadas en
ndk/sysroot/usr/include/aaudio/AAudioTesting.h
que te permiten hacer lo siguiente:
anular la política para usar la ruta MMAP:
aaudio_result_t AAudio_setMMapPolicy(aaudio_policy_t policy);
Para saber si una transmisión usa la ruta de acceso MMAP, haz la siguiente llamada:
bool AAudioStream_isMMapUsed(AAudioStream* stream);