O Google está comprometido em promover a equidade racial para as comunidades negras. Veja como.
Esta página foi traduzida pela API Cloud Translation.
Switch to English

AAudio e MMAP

AAudio é uma API de áudio introduzida na versão Android 8.0. A versão do Android 8.1 possui aprimoramentos para reduzir a latência quando usada em conjunto com um HAL e um driver compatível com MMAP. Este documento descreve as alterações da camada de abstração de hardware (HAL) e do driver necessárias para oferecer suporte ao recurso MMAP do AAudio no Android.

O suporte para AAudio MMAP requer:

  • relatando os recursos MMAP do HAL
  • implementando novas funções no HAL
  • opcionalmente implementando um ioctl () personalizado para o buffer do modo EXCLUSIVO
  • fornecendo um caminho de dados de hardware adicional
  • configurando propriedades do sistema que ativam o recurso MMAP

Arquitetura AAudio

AAudio é uma nova API C nativa que fornece uma alternativa ao Open SL ES. Ele usa um padrão de design do Builder para criar fluxos de áudio.

O AAudio fornece um caminho de dados de baixa latência. No modo EXCLUSIVO, o recurso permite que o código do aplicativo cliente grave diretamente em um buffer mapeado de memória que é compartilhado com o driver ALSA. No modo COMPARTILHADO, o buffer MMAP é usado por um mixer em execução no AudioServer. No modo EXCLUSIVO, a latência é significativamente menor porque os dados ignoram o mixer.

No modo EXCLUSIVO, o serviço solicita o buffer MMAP do HAL e gerencia os recursos. O buffer MMAP está sendo executado no modo NOIRQ, portanto, não há contadores de leitura / gravação compartilhados para gerenciar o acesso ao buffer. Em vez disso, o cliente mantém um modelo de temporização do hardware e prevê quando o buffer será lido.

No diagrama abaixo, podemos ver os dados da modulação de código de pulso (PCM) fluindo através do MMAP FIFO para o driver ALSA. Os registros de data e hora são solicitados periodicamente pelo serviço AAudio e depois transmitidos para o modelo de tempo do cliente por meio de uma fila de mensagens atômicas.

Diagrama de fluxo de dados PCM.
Figura 1. Fluxo de dados do PCM do FIFO ao ALSA

No modo COMPARTILHADO, também é usado um modelo de temporização, mas ele reside no AAudioService.

Para captura de áudio, um modelo semelhante é usado, mas os dados do PCM fluem na direção oposta.

Alterações HAL

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 o HAL herdado, 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 áudio 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);

Suporte a relatórios MMAP

A propriedade do sistema "aaudio.mmap_policy" deve ser definida como 2 (AAUDIO_POLICY_AUTO) para que a estrutura de áudio saiba que o modo MMAP é suportado pelo HAL de áudio. (consulte "Ativando o caminho de dados MMAP do AAudio" abaixo).

O arquivo audio_policy_configuration.xml também deve conter um perfil de saída e entrada específico para o modo MMAP / NO IRQ, para que o Audio Policy Manager saiba qual fluxo abrir quando os clientes MMAP forem criados:

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

Abrindo e fechando um fluxo MMAP

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

O fluxo MMAP pode ser aberto e fechado chamando as funções Tinyalsa.

Consultando a posição MMAP

O registro de data e hora passado para o Modelo de tempo contém uma posição do quadro e um tempo MONOTÔNICO em nanossegundos:

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

O HAL pode obter essas informações do driver ALSA chamando uma nova função Tinyalsa:

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

Mudanças no kernel

Ative o modo MMAP / NOIRQ no driver.

A memória compartilhada é referenciada usando um descritor de arquivo gerado pelo driver ALSA. Se o descritor de arquivo estiver diretamente associado a um arquivo /dev/snd/ driver, ele poderá ser usado pelo serviço AAudio no modo COMPARTILHADO. Mas o descritor não pode ser passado para o código do cliente para o modo EXCLUSIVO. O descritor /dev/snd/ file forneceria acesso muito amplo ao cliente, portanto, é bloqueado pelo SELinux.

Para suportar o modo EXCLUSIVO, é necessário converter o /dev/snd/ descriptor em um anon_inode:dmabuf arquivo anon_inode:dmabuf . O SELinux permite que esse descritor de arquivo seja passado para o cliente. Também pode ser usado pelo AAudioService.

Um anon_inode:dmabuf arquivo anon_inode:dmabuf pode ser gerado usando a biblioteca de memória Android Ion.

Para informações adicionais, consulte estes recursos externos:

  1. "O alocador de memória do Android ION" https://lwn.net/Articles/480055/
  2. "Visão geral do Android ION" https://wiki.linaro.org/BenjaminGaignard/ion
  3. "Integrando o alocador de memória ION" https://lwn.net/Articles/565469/

O serviço anon_inode:dmabuf precisa saber se esse anon_inode:dmabuf é suportado. Atualmente, a única maneira de fazer isso é passar o tamanho do buffer MMAP como um número negativo, por exemplo. -2048 em vez de 2048, se suportado. Está planejada uma maneira melhor de relatar isso sem ter que abrir o fluxo.

Alterações no subsistema de áudio

O AAudio requer um caminho de dados adicional no front-end de áudio do subsistema de áudio, para que possa operar em paralelo com o caminho original do AudioFlinger. Esse caminho herdado é usado para todos os outros sons do sistema e sons do aplicativo. Essa funcionalidade pode ser fornecida por um misturador de software em um DSP ou um misturador de hardware no SOC.

Ativando o caminho de dados AAudio MMAP

O AAudio usará o caminho de dados herdado do AudioFlinger se o MMAP não for suportado ou falhar ao abrir um fluxo. Portanto, o AAudio funcionará com um dispositivo de áudio que não suporta o caminho MMAP / NOIRQ.

Ao testar o suporte MMAP ao AAudio, é importante saber se você está realmente testando o caminho de dados MMAP ou apenas testando o caminho de dados herdado. A seguir, descreve como habilitar ou forçar caminhos de dados específicos e como consultar o caminho usado por um fluxo.

Propriedades do sistema

Você pode definir a política MMAP através das propriedades do sistema:

  • 1 = AAUDIO_POLICY_NEVER - Use apenas o caminho herdado. Nem tente usar o MMAP.
  • 2 = AAUDIO_POLICY_AUTO - Tente usar o MMAP. Se isso falhar ou não estiver disponível, use o caminho herdado.
  • 3 = AAUDIO_POLICY_ALWAYS - Use apenas o caminho MMAP. Não volte ao caminho legado.

Eles podem ser definidos nos dispositivos Makefile, da seguinte maneira:

# 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

Você também pode substituir esses valores após a inicialização do dispositivo. Você precisará reiniciar o servidor de áudio para que a alteração entre em vigor. Por exemplo, para ativar o modo AUTO para MMAP:

adb root
adb shell setprop aaudio.mmap_policy 2
adb shell killall audioserver

Existem funções fornecidas no ndk/sysroot/usr/include/aaudio/AAudioTesting.h que permitem substituir a política de uso do caminho MMAP:

aaudio_result_t AAudio_setMMapPolicy(aaudio_policy_t policy);

Para descobrir se um fluxo está usando o caminho MMAP, chame:

bool AAudioStream_isMMapUsed(AAudioStream* stream);