Google se compromete a impulsar la igualdad racial para las comunidades afrodescendientes. Obtén información al respecto.
Se usó la API de Cloud Translation para traducir esta página.
Switch to English

AAudio y MMAP

AAudio es una API de audio introducida en la versión de Android 8.0. La versión de Android 8.1 tiene mejoras para reducir la latencia cuando se usa junto con un HAL y un controlador que admiten MMAP. Este documento describe la capa de abstracción de hardware (HAL) y los cambios de controlador necesarios para admitir la función MMAP de AAudio en Android.

El soporte para AAudio MMAP requiere:

  • informar las capacidades MMAP de la HAL
  • implementando nuevas funciones en el HAL
  • opcionalmente implementando un ioctl () personalizado para el búfer de modo EXCLUSIVO
  • proporcionando una ruta de datos de hardware adicional
  • configurar las propiedades del sistema que habilitan la función MMAP

Arquitectura de audio

AAudio es una nueva API C nativa que proporciona una alternativa a Open SL ES. Utiliza un patrón de diseño Builder para crear transmisiones de audio.

AAudio proporciona una ruta de datos de baja latencia. En el modo EXCLUSIVO, la función permite que el código de la aplicación del cliente se escriba directamente en un búfer asignado a la memoria que se comparte con el controlador ALSA. En el modo COMPARTIDO, el búfer MMAP es utilizado por un mezclador que se ejecuta en AudioServer. En el modo EXCLUSIVO, la latencia es significativamente menor porque los datos pasan por alto el mezclador.

En modo EXCLUSIVO, el servicio solicita el búfer MMAP del HAL y administra los recursos. El búfer MMAP se ejecuta en modo NOIRQ, por lo que no hay contadores de lectura / escritura compartidos para administrar el acceso al búfer. En cambio, el cliente mantiene un modelo de tiempo del hardware y predice cuándo se leerá el búfer.

En el diagrama a continuación, podemos ver los datos de modulación de código de pulso (PCM) fluyendo a través de la FIFO de MMAP hacia el controlador ALSA. Las marcas de tiempo son solicitadas periódicamente por el servicio AAudio y luego pasa al modelo de tiempo del cliente a través de una cola de mensajes atómicos.

Diagrama de flujo de datos PCM.
Figura 1. Flujo de datos PCM a través de FIFO a ALSA

En el modo COMPARTIDO, también se usa un modelo de temporización, pero vive en AAudioService.

Para la captura de audio, se usa un modelo similar, pero los datos PCM fluyen en la dirección opuesta.

HAL cambia

Para tinyALSA, consulte:

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 el HAL heredado, consulte:

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 audio HIDL HAL:

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

Informes de compatibilidad con MMAP

La propiedad del sistema "aaudio.mmap_policy" debe establecerse en 2 (AAUDIO_POLICY_AUTO) para que el marco de audio sepa que el modo MMAP es compatible con el audio HAL. (consulte "Habilitación de la ruta de datos MMAP de AAudio" a continuación).

El archivo audio_policy_configuration.xml también debe contener un perfil de entrada y salida específico para el modo MMAP / NO IRQ para que Audio Policy Manager sepa qué flujo abrir cuando se creen 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>

Abrir y cerrar una secuencia MMAP

createMmapBuffer(int32_t minSizeFrames)
            generates (Result retval, MmapBufferInfo info);

El flujo de MMAP se puede abrir y cerrar llamando a funciones de Tinyalsa.

Consultando posición MMAP

La marca de tiempo devuelta al modelo de temporización contiene una posición de fotograma y un tiempo MONOTÓNICO en nanosegundos:

getMmapPosition()
        generates (Result retval, MmapPosition position);

El HAL puede obtener esta información del controlador ALSA llamando a una nueva función de Tinyalsa:

int pcm_mmap_get_hw_ptr(struct pcm* pcm,
                        unsigned int *hw_ptr,
                        struct timespec *tstamp);

Cambios de kernel

Habilite el modo MMAP / NOIRQ en el controlador.

Se hace referencia a la memoria compartida mediante un descriptor de archivo que genera el controlador ALSA. Si el descriptor de archivo está directamente asociado con un archivo /dev/snd/ driver, entonces el servicio AAudio puede usarlo en modo COMPARTIDO. Pero el descriptor no se puede pasar al código de cliente para el modo EXCLUSIVO. El descriptor de archivo /dev/snd/ proporcionaría un acceso demasiado amplio al cliente, por lo que SELinux lo bloquea.

Para admitir el modo EXCLUSIVO, es necesario convertir el descriptor /dev/snd/ en un descriptor de archivo anon_inode:dmabuf . SELinux permite que ese descriptor de archivo se pase al cliente. También puede ser utilizado por AAudioService.

Se puede generar un descriptor de archivo anon_inode:dmabuf utilizando la biblioteca de memoria Android Ion.

Para obtener información adicional, consulte estos recursos externos:

  1. "El asignador de memoria ION de Android" https://lwn.net/Articles/480055/
  2. "Descripción general de Android ION" https://wiki.linaro.org/BenjaminGaignard/ion
  3. "Integración del asignador de memoria ION" https://lwn.net/Articles/565469/

El servicio AAudio necesita saber si este anon_inode:dmabuf es compatible. Actualmente, la única forma de hacerlo es pasar el tamaño del búfer MMAP como un número negativo, por ejemplo. -2048 en lugar de 2048, si es compatible. Se planea una mejor manera de informar esto sin tener que abrir la transmisión.

Cambios en el subsistema de audio

AAudio requiere una ruta de datos adicional en la parte frontal de audio del subsistema de audio para que pueda funcionar en paralelo con la ruta AudioFlinger original. Esa ruta heredada se utiliza para todos los demás sonidos del sistema y de aplicaciones. Esta funcionalidad podría proporcionarla un mezclador de software en un DSP o un mezclador de hardware en el SOC.

Habilitación de la ruta de datos de AAudio MMAP

AAudio utilizará la ruta de datos heredada de AudioFlinger si MMAP no es compatible o no puede abrir una transmisión. Entonces AAudio funcionará con un dispositivo de audio que no admita la ruta MMAP / NOIRQ.

Al probar la compatibilidad con MMAP para AAudio, es importante saber si realmente está probando la ruta de datos MMAP o simplemente probando la ruta de datos heredada. A continuación, se describe cómo habilitar o forzar rutas de datos específicas y cómo consultar la ruta utilizada por una secuencia.

Propiedades del sistema

Puede configurar la política MMAP a través de las propiedades del sistema:

  • 1 = AAUDIO_POLICY_NEVER: solo use la ruta heredada. Ni siquiera intente utilizar MMAP.
  • 2 = AAUDIO_POLICY_AUTO - Intente utilizar MMAP. Si eso falla o no está disponible, utilice la ruta heredada.
  • 3 = AAUDIO_POLICY_ALWAYS: solo use la ruta MMAP. No retroceda al camino heredado.

Estos se pueden configurar en los dispositivos Makefile, así:

# 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 puede anular estos valores después de que se haya iniciado el dispositivo. Deberá reiniciar el servidor de audio para que el cambio surta efecto. Por ejemplo, para habilitar el modo AUTO para MMAP:

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 le permiten anular la política para usar la ruta MMAP:

aaudio_result_t AAudio_setMMapPolicy(aaudio_policy_t policy);

Para saber si una secuencia está usando la ruta MMAP, llame a:

bool AAudioStream_isMMapUsed(AAudioStream* stream);