AAudio ist eine Audio-API, die in der Android 8.0-Version eingeführt wurde. Die Version 8.1 von Android enthält Verbesserungen zur Verringerung der Latenz bei Verwendung in Verbindung mit einer HAL und einem Treiber, die MMAP unterstützen. In diesem Dokument werden die Änderungen an der Hardwareabstraktionsschicht (HAL) und an den Treibern beschrieben, die für die Unterstützung der MMAP-Funktion von AAudio in Android erforderlich sind.
Für die Unterstützung von AAudio MMAP ist Folgendes erforderlich:
- MMAP-Funktionen des HAL melden
- Implementierung neuer Funktionen in der HAL
- Optionale Implementierung einer benutzerdefinierten ioctl() für den EXCLUSIVE-Modus-Puffer
- einen zusätzlichen Hardwaredatenpfad bereitstellen
- Systemeigenschaften festlegen, die die MMAP-Funktion aktivieren
AAudio-Architektur
AAudio ist eine neue native C API, die eine Alternative zu Open SL ES bietet. Es verwendet ein Builder-Designmuster, um Audiostreams zu erstellen.
AAudio bietet einen Datenpfad mit niedriger Latenz. Im EXCLUSIVE-Modus ermöglicht die Funktion dem Clientanwendungscode, direkt in einen speicherabgeglichenen Puffer zu schreiben, der mit dem ALSA-Treiber gemeinsam genutzt wird. Im SHARED-Modus wird der MMAP-Puffer von einem Mixer verwendet, der im AudioServer ausgeführt wird. Im EXCLUSIVE-Modus ist die Latenz deutlich geringer, da die Daten den Mixer umgehen.
Im EXCLUSIVE-Modus fordert der Dienst den MMAP-Puffer von der HAL an und verwaltet die Ressourcen. Der MMAP-Puffer wird im NOIRQ-Modus ausgeführt. Daher gibt es keine freigegebenen Lese-/Schreibzähler, um den Zugriff auf den Puffer zu verwalten. Stattdessen verwaltet der Client ein Timing-Modell der Hardware und prognostiziert, wann der Puffer gelesen wird.
Im folgenden Diagramm sehen wir, wie die PCM-Daten (Pulse-Code-Modulation) durch den MMAP-FIFO in den ALSA-Treiber fließen. Zeitstempel werden regelmäßig vom AAudio-Dienst angefordert und dann über eine atomare Nachrichtenwarteschlange an das Timing-Modell des Clients übergeben.

Im SHARED-Modus wird auch ein Timing-Modell verwendet, das sich aber im AAudioService befindet.
Für die Audioaufnahme wird ein ähnliches Modell verwendet, aber die PCM-Daten fließen in die entgegengesetzte Richtung.
HAL-Änderungen
tinyALSA:
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);
Informationen zur bisherigen HAL finden Sie unter:
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);
Für 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);
MMAP-Unterstützung melden
Die Systemeigenschaft „aaudio.mmap_policy“ muss auf „2“ (AAUDIO_POLICY_AUTO) gesetzt sein, damit das Audio-Framework weiß, dass der MMAP-Modus von der Audio-HAL unterstützt wird. (siehe unten „AAudio-MMAP-Datenpfad aktivieren“).
Die Datei „audio_policy_configuration.xml“ muss außerdem ein Ausgabe- und ein Eingabeprofil für den MMAP/NO IRQ-Modus enthalten, damit der Audio Policy Manager weiß, welchen Stream er öffnen soll, wenn MMAP-Clients erstellt werden:
<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>
MMAP-Stream öffnen und schließen
createMmapBuffer(int32_t minSizeFrames) generates (Result retval, MmapBufferInfo info);
Der MMAP-Stream kann durch Aufrufen von Tinyalsa-Funktionen geöffnet und geschlossen werden.
MMAP-Position abfragen
Der an das Timing-Modell zurückgegebene Zeitstempel enthält eine Frame-Position und eine MONOTONIC-Zeit in Nanosekunden:
getMmapPosition() generates (Result retval, MmapPosition position);
Die HAL kann diese Informationen vom ALSA-Treiber abrufen, indem sie eine neue Tinyalsa-Funktion aufruft:
int pcm_mmap_get_hw_ptr(struct pcm* pcm, unsigned int *hw_ptr, struct timespec *tstamp);
Dateideskriptoren für gemeinsam genutzten Speicher
Der AAudio-MMAP-Datenpfad verwendet einen Speicherbereich, der zwischen der Hardware und dem Audiodienst gemeinsam genutzt wird. Auf den gemeinsamen Speicher wird über einen Dateideskriptor verwiesen, der vom ALSA-Treiber generiert wird.
Kerneländerungen
Wenn der Dateideskriptor direkt mit einer /dev/snd/
-Treiberdatei verknüpft ist, kann er vom AAudio-Dienst im SHARED-Modus verwendet werden. Der Descriptor kann jedoch nicht an den Clientcode für den EXCLUSIVE-Modus übergeben werden. Der Dateideskriptor /dev/snd/
würde dem Client zu viel Zugriff gewähren und wird daher von SELinux blockiert.
Um den EXCLUSIVE-Modus zu unterstützen, muss der /dev/snd/
-Beschreibungsblock in einen anon_inode:dmabuf
-Dateibeschreibungsblock konvertiert werden. SELinux ermöglicht die Weitergabe dieses Dateideskriptors an den Client. Sie kann auch vom AAudioService verwendet werden.
Ein anon_inode:dmabuf
-Dateideskriptor kann mit der Android Ion-Speicherbibliothek generiert werden.
Weitere Informationen finden Sie in den folgenden externen Ressourcen:
- „The Android ION memory allocator“ https://lwn.net/Articles/480055/
- „Android ION overview“ https://wiki.linaro.org/BenjaminGaignard/ion
- „Integrating the ION memory allocator“ https://lwn.net/Articles/565469/
HAL-Änderungen
Der AAudio-Dienst muss wissen, ob diese anon_inode:dmabuf
unterstützt wird. Vor Android 10.0 war dies nur möglich, indem die Größe des MMAP-Buffers als negative Zahl übergeben wurde, z. B. -2048 anstelle von 2048, sofern unterstützt. Unter Android 10.0 und höher können Sie das AUDIO_MMAP_APPLICATION_SHAREABLE
-Flag setzen.
mmapBufferInfo |= AUDIO_MMAP_APPLICATION_SHAREABLE;
Änderungen am Audio-Subsystem
AAudio benötigt einen zusätzlichen Datenpfad am Audio-Frontend des Audio-Subsystems, damit es parallel zum ursprünglichen AudioFlinger-Pfad ausgeführt werden kann. Dieser alte Pfad wird für alle anderen System- und Anwendungstöne verwendet. Diese Funktion kann von einem Software-Mixer in einem DSP oder einem Hardware-Mixer im SOC bereitgestellt werden.
AAudio-MMAP-Datenpfad aktivieren
AAudio verwendet den alten AudioFlinger-Datenpfad, wenn MMAP nicht unterstützt wird oder ein Stream nicht geöffnet werden kann. AAudio funktioniert also mit einem Audiogerät, das den MMAP/NOIRQ-Pfad nicht unterstützt.
Beim Testen der MMAP-Unterstützung für AAudio ist es wichtig zu wissen, ob Sie tatsächlich den MMAP-Datenpfad oder nur den bisherigen Datenpfad testen. Im Folgenden wird beschrieben, wie Sie bestimmte Datenpfade aktivieren oder erzwingen und den von einem Stream verwendeten Pfad abfragen.
Systemeigenschaften
Sie können die MMAP-Richtlinie über Systemeigenschaften festlegen:
- 1 = AAUDIO_POLICY_NEVER – Nur den alten Pfad verwenden. Versuchen Sie nicht einmal, MMAP zu verwenden.
- 2 = AAUDIO_POLICY_AUTO – MMAP wird verwendet. Wenn das fehlschlägt oder nicht verfügbar ist, verwenden Sie den bisherigen Pfad.
- 3 = AAUDIO_POLICY_ALWAYS – Nur MMAP-Pfad verwenden. Der bisherige Pfad darf nicht verwendet werden.
Diese können im Makefile des Geräts so festgelegt werden:
# 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
Sie können diese Werte auch nach dem Starten des Geräts überschreiben. Sie müssen den Audioserver neu starten, damit die Änderung wirksam wird. So aktivieren Sie beispielsweise den AUTO-Modus für MMAP:
adb root
adb shell setprop aaudio.mmap_policy 2
adb shell killall audioserver
In ndk/sysroot/usr/include/aaudio/AAudioTesting.h
gibt es Funktionen, mit denen Sie die Richtlinie für die Verwendung des MMAP-Pfads überschreiben können:
aaudio_result_t AAudio_setMMapPolicy(aaudio_policy_t policy);
Rufe Folgendes auf, um herauszufinden, ob für einen Stream ein MMAP-Pfad verwendet wird:
bool AAudioStream_isMMapUsed(AAudioStream* stream);