Google si impegna a promuovere l'equità razziale per le comunità nere. Vedi come.
Questa pagina è stata tradotta dall'API Cloud Translation.
Switch to English

AAudio e MMAP

AAudio è un'API audio introdotta nella versione Android 8.0. La versione di Android 8.1 presenta miglioramenti per ridurre la latenza se utilizzata in combinazione con un HAL e un driver che supportano MMAP. Questo documento descrive il livello di astrazione hardware (HAL) e le modifiche del driver necessarie per supportare la funzione MMAP di AAudio in Android.

Il supporto per MMAP AAudio richiede:

  • riportando le capacità MMAP dell'HAL
  • implementare nuove funzioni nella HAL
  • opzionalmente implementando uno ioctl () personalizzato per il buffer in modalità EXCLUSIVE
  • fornendo un percorso dati hardware aggiuntivo
  • impostazione delle proprietà di sistema che abilitano la funzione MMAP

AAudio architecture

AAudio è una nuova API C nativa che offre un'alternativa a Open SL ES. Utilizza un modello di progettazione Builder per creare flussi audio.

AAudio fornisce un percorso dati a bassa latenza. In modalità ESCLUSIVA, la funzione consente al codice dell'applicazione client di scrivere direttamente in un buffer mappato in memoria condiviso con il driver ALSA. In modalità SHARED, il buffer MMAP viene utilizzato da un mixer in esecuzione in AudioServer. In modalità ESCLUSIVA, la latenza è significativamente inferiore perché i dati bypassano il mixer.

In modalità ESCLUSIVA, il servizio richiede il buffer MMAP dall'HAL e gestisce le risorse. Il buffer MMAP è in esecuzione in modalità NOIRQ, quindi non esistono contatori di lettura / scrittura condivisi per gestire l'accesso al buffer. Al contrario, il client mantiene un modello di temporizzazione dell'hardware e prevede quando verrà letto il buffer.

Nel diagramma seguente, possiamo vedere i dati di modulazione Pulse-code (PCM) che scorrono attraverso il MMAP FIFO nel driver ALSA. I timestamp vengono periodicamente richiesti dal servizio AAudio e quindi passati al modello di temporizzazione del client attraverso una coda di messaggi atomici.

Diagramma del flusso di dati PCM.
Figura 1. Flusso di dati PCM attraverso FIFO ad ALSA

In modalità CONDIVISO, viene utilizzato anche un modello di temporizzazione, ma vive in AAudioService.

Per l'acquisizione audio, viene utilizzato un modello simile, ma i dati PCM scorrono nella direzione opposta.

Modifiche HAL

Per tinyALSA vedi:

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

Per l'HAL legacy, vedere:

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

Per HIDL audio 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);

Supporto MMAP per la segnalazione

La proprietà di sistema "aaudio.mmap_policy" deve essere impostata su 2 (AAUDIO_POLICY_AUTO) in modo che il framework audio sappia che la modalità MMAP è supportata dall'HAL audio. (vedi "Abilitazione del percorso dati MMAP AAudio" di seguito).

Il file audio_policy_configuration.xml deve contenere anche un profilo di input e input specifico per la modalità MMAP / NO IRQ in modo che Audio Policy Manager sappia quale flusso aprire quando vengono creati i client 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>

Apertura e chiusura di un flusso MMAP

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

Il flusso MMAP può essere aperto e chiuso chiamando le funzioni Tinyalsa.

Interrogazione della posizione MMAP

Il timestamp restituito al modello di temporizzazione contiene una posizione del frame e un tempo MONOTONIC in nanosecondi:

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

L'HAL può ottenere queste informazioni dal driver ALSA chiamando una nuova funzione Tinyalsa:

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

Modifiche al kernel

Abilita la modalità MMAP / NOIRQ nel driver.

Si fa riferimento alla memoria condivisa utilizzando un descrittore di file generato dal driver ALSA. Se il descrittore di file è direttamente associato a un file /dev/snd/ driver, può essere utilizzato dal servizio AAudio in modalità SHARED. Ma il descrittore non può essere passato al codice client per la modalità ESCLUSIVA. Il descrittore /dev/snd/ file fornirebbe un accesso troppo ampio al client, quindi è bloccato da SELinux.

Per supportare la modalità ESCLUSIVA, è necessario convertire il descrittore /dev/snd/ in un anon_inode:dmabuf file anon_inode:dmabuf . SELinux consente al descrittore di file di essere passato al client. Può anche essere utilizzato da AAudioService.

Un anon_inode:dmabuf file anon_inode:dmabuf può essere generato utilizzando la libreria di memoria Android Ion.

Per ulteriori informazioni, consultare queste risorse esterne:

  1. "L'allocatore di memoria ION Android" https://lwn.net/Articles/480055/
  2. "Panoramica di Android ION" https://wiki.linaro.org/BenjaminGaignard/ion
  3. "Integrazione dell'allocatore di memoria ION" https://lwn.net/Articles/565469/

Il servizio AAudio deve sapere se questo anon_inode:dmabuf è supportato. Attualmente, l'unico modo per farlo è passare la dimensione del buffer MMAP come numero negativo, ad es. -2048 invece del 2048, se supportato. È pianificato un modo migliore per segnalarlo senza dover aprire lo stream.

Modifiche al sottosistema audio

AAudio richiede un percorso dati aggiuntivo sul front-end audio del sottosistema audio in modo che possa operare in parallelo con il percorso AudioFlinger originale. Tale percorso legacy viene utilizzato per tutti gli altri suoni di sistema e suoni dell'applicazione. Questa funzionalità potrebbe essere fornita da un mixer software in un DSP o da un mixer hardware nel SOC.

Abilitazione percorso dati MMAP AAudio

AAudio utilizzerà il percorso dati AudioFlinger legacy se MMAP non è supportato o non riesce ad aprire un flusso. Quindi AAudio funzionerà con un dispositivo audio che non supporta il percorso MMAP / NOIRQ.

Durante il test del supporto MMAP per AAudio, è importante sapere se si sta effettivamente testando il percorso dei dati MMAP o semplicemente testando il percorso dei dati legacy. Di seguito viene descritto come abilitare o forzare percorsi di dati specifici e come interrogare il percorso utilizzato da un flusso.

Proprietà di sistema

È possibile impostare il criterio MMAP tramite le proprietà di sistema:

  • 1 = AAUDIO_POLICY_NEVER: utilizza solo il percorso legacy. Non provare nemmeno a utilizzare MMAP.
  • 2 = AAUDIO_POLICY_AUTO - Prova a utilizzare MMAP. Se il problema persiste o non è disponibile, utilizzare il percorso legacy.
  • 3 = AAUDIO_POLICY_ALWAYS: utilizza solo il percorso MMAP. Non ricorrere al percorso legacy.

Questi possono essere impostati nel dispositivo Makefile, in questo modo:

# 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

Puoi anche sovrascrivere questi valori dopo l'avvio del dispositivo. Sarà necessario riavviare l'audioserver per rendere effettive le modifiche. Ad esempio, per abilitare la modalità AUTO per MMAP:

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

Ci sono funzioni fornite in ndk/sysroot/usr/include/aaudio/AAudioTesting.h che consentono di sovrascrivere la politica per l'utilizzo del percorso MMAP:

aaudio_result_t AAudio_setMMapPolicy(aaudio_policy_t policy);

Per scoprire se uno stream utilizza il percorso MMAP, chiama:

bool AAudioStream_isMMapUsed(AAudioStream* stream);