AAudio e MMAP

AAudio è un'API audio introdotta nella release di Android 8.0. Android 8.1 presenta miglioramenti per ridurre la latenza se utilizzata insieme a una release HAL e driver che supportano MMAP. Questo documento descrive l'astrazione hardware il livello (HAL) e le modifiche al driver necessarie per supportare la funzionalità MMAP di AAudio in Android.

Il supporto per AAudio MMAP richiede:

  • riportando le funzionalità MMAP dell'HAL
  • l'implementazione di nuove funzioni nell'HAL
  • facoltativamente implementare un ioctl() personalizzato per il buffer in modalità EXCLUSIVE
  • fornendo un percorso dati hardware aggiuntivo
  • impostare le proprietà di sistema che attivano la funzionalità MMAP
di Gemini Advanced.

Architettura AAudio

Audio è una nuova API C nativa che offre un'alternativa a Open SL ES. Utilizza un Pattern di progettazione di Builder per creare stream audio.

AAudio fornisce un percorso dati a bassa latenza. In modalità ESCLUSIVA, la funzionalità 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 un mixer in esecuzione nell'AudioServer. In modalità ESCLUSIVA, la latenza è notevolmente di meno perché i dati bypassano il mixer.

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

Nel diagramma seguente, possiamo vedere il flusso di dati di modulazione del codice a impulsi (PCM) attraverso il file FIFO MMAP e il driver ALSA. I timestamp vengono periodicamente come richiesto dal servizio AAudio e poi trasmesso al modello di temporizzazione del client. attraverso una coda di messaggi atomica.

Diagramma di flusso dei dati PCM.
Figura 1. Flusso di dati PCM attraverso FIFO verso ALSA
.

Nella modalità CONDIVISA viene utilizzato anche un modello di temporizzazione, che però risiede in AAudioService.

Per l'acquisizione audio si utilizza un modello simile, ma i dati PCM fluiscono nella direzione opposta.

Modifiche all'HAL

Per smallALSA, 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 precedente, consulta:

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

Segnala supporto MMAP

Proprietà di sistema "aaudio.mmap_policy" deve essere impostato su 2 (AAUDIO_POLICY_AUTO), quindi il framework audio sa che la modalità MMAP è supportata dall'HAL audio. (vedi "Attivazione del percorso dati MMAP AAudio" below.)

Il file audio_policy_configuration.xml deve contenere anche un output e un input specifico per la modalità MMAP/NO IRQ, in modo che Gestione norme audio sappia quali stream 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>

Aprire e chiudere uno stream MMAP

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

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

Posizione MMAP query

Il timestamp restituito al modello di tempo contiene la posizione del frame e un Tempo MONOTONICA in nanosecondi:

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

L'HAL può ottenere queste informazioni dal driver ALSA chiamando un nuovo Funzione Tinyalsa:

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

Descrittori dei file per la memoria condivisa

Il percorso dei dati MMAP AAudio utilizza una regione di memoria condivisa tra l'hardware e il servizio audio. Viene fatto riferimento alla memoria condivisa tramite un descrittore del file generato dal driver ALSA.

Modifiche kernel

Se il descrittore del file è direttamente associato a un /dev/snd/, potrà essere utilizzato dal servizio AAudio in Modalità CONDIVISA. Tuttavia, il descrittore non può essere passato al codice client per modalità ESCLUSIVA. Fornirebbe anche il descrittore del file /dev/snd/ ha un ampio accesso al client, quindi è bloccato da SELinux.

Per supportare la modalità ESCLUSIVA, è necessario convertire il valore descrittore /dev/snd/ a un file anon_inode:dmabuf descrittore. SELinux consente di passare il descrittore del file al client. it può essere utilizzato anche da AAudioService.

È possibile generare un descrittore di file anon_inode:dmabuf utilizzando il metodo libreria di memoria Android Ionic.

Per ulteriori informazioni, consulta queste risorse esterne:

  1. "L'allocatore di memoria Android ION" 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/

Modifiche all'HAL

Il servizio AAudio deve sapere se il anon_inode:dmabuf è supportati. Prima di Android 10.0, l'unico modo per farlo era superare le dimensioni del file MMAP buffer come numero negativo, ad esempio -2048 anziché 2048, se supportato. In Android 10.0 e versioni successive puoi impostare il flag AUDIO_MMAP_APPLICATION_SHAREABLE.

mmapBufferInfo |= AUDIO_MMAP_APPLICATION_SHAREABLE;

Modifiche al sottosistema audio

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

Attiva percorso dati MMAP AAudio

AAudio utilizzerà il percorso dati legacy di AudioFlinger se MMAP non è supportato o non riesce ad aprire uno stream. AAudio funziona con un dispositivo audio che non supportare il percorso MMAP/NOIRQ.

Durante il test del supporto MMAP per AAudio, è importante sapere se stai testare effettivamente il percorso dati MMAP o semplicemente testare il percorso dei dati legacy. La che segue descrive come attivare o forzare percorsi di dati specifici e come eseguire query il percorso utilizzato da un flusso.

Proprietà di sistema

Puoi impostare il criterio MMAP tramite le proprietà di sistema:

  • 1 = AAUDIO_POLICY_NEVER - Usa solo percorso legacy. Non provare nemmeno a utilizzare MMAP.
  • 2 = AAUDIO_POLICY_AUTO - Prova a utilizzare MMAP. Se non funziona o non è disponibile, quindi utilizza il percorso legacy.
  • 3 = AAUDIO_POLICY_ALWAYS - Utilizza solo percorso MMAP. Non utilizzare la versione precedente del tuo percorso di apprendimento.

Queste impostazioni possono essere impostate nel Makefile del dispositivo, 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 eseguire l'override di questi valori dopo l'avvio del dispositivo. Per applicare la modifica, dovrai riavviare il server audio. Ad esempio, per attivare la modalità AUTO per MMAP:

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

Esistono funzioni fornite in ndk/sysroot/usr/include/aaudio/AAudioTesting.h che ti consentono di sostituisci il criterio per utilizzare il percorso MMAP:

aaudio_result_t AAudio_setMMapPolicy(aaudio_policy_t policy);

Per scoprire se un flusso utilizza un percorso MMAP, chiama:

bool AAudioStream_isMMapUsed(AAudioStream* stream);