Google 致力于为黑人社区推动种族平等。查看具体举措
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 Android 8.1 presenta miglioramenti per ridurre la latenza se utilizzata insieme a un HAL e un driver che supportano MMAP. Questo documento descrive il livello di astrazione hardware (HAL) e le modifiche al driver necessarie per supportare la funzione MMAP di AAudio in Android.

Il supporto per AAudio MMAP richiede:

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

Architettura AAudio

AAudio è una nuova API C nativa che fornisce 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 nell'AudioServer. In modalità ESCLUSIVA, la latenza è notevolmente 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 ci sono 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 della modulazione del codice a impulsi (PCM) che fluiscono attraverso il FIFO MMAP nel driver ALSA. I timestamp vengono periodicamente richiesti dal servizio AAudio e quindi passati al modello di temporizzazione del client tramite una coda di messaggi atomica.

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

Nella modalità SHARED, viene utilizzato anche un modello di temporizzazione, ma risiede in AAudioService.

Per l'acquisizione audio, viene utilizzato un modello simile, ma i dati PCM fluiscono 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'eredità HAL, 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 l'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);

Segnalazione del supporto MMAP

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

Il file audio_policy_configuration.xml deve contenere anche un profilo di input e output 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.

Query sulla posizione MMAP

Il timestamp restituito al modello di temporizzazione contiene una posizione del frame e un tempo MONOTONICO 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.

La memoria condivisa è referenziata 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 di file /dev/snd/ fornirebbe un accesso troppo ampio al client, quindi è bloccato da SELinux.

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

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

Per ulteriori informazioni, vedere queste risorse esterne:

  1. "L'allocatore di memoria ION di 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 anziché 2048, se supportato. È previsto 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 funzionare in parallelo con il percorso AudioFlinger originale. Questo percorso legacy viene utilizzato per tutti gli altri suoni di sistema e di applicazioni. Questa funzionalità potrebbe essere fornita da un mixer software in un DSP o da un mixer hardware nel SOC.

Abilitazione del percorso dati MMAP AAudio

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

Quando si testa il supporto MMAP per AAudio, è importante sapere se si sta effettivamente testando il percorso dati MMAP o se si sta semplicemente testando il percorso dati legacy. Di seguito viene descritto come abilitare o forzare percorsi dati specifici e come eseguire query sul 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 usare MMAP.
  • 2 = AAUDIO_POLICY_AUTO - Prova a usare MMAP. Se fallisce o non è disponibile, usa il percorso legacy.
  • 3 = AAUDIO_POLICY_ALWAYS - Usa solo percorso MMAP. Non tornare al percorso legacy.

Questi possono essere impostati nel Makefile dei dispositivi, 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

È inoltre possibile sovrascrivere questi valori dopo l'avvio del dispositivo. Sarà necessario riavviare il server audio affinché la modifica abbia effetto. 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);