AAudio i MMAP

AAudio to interfejs API audio wprowadzony w Androidzie 8.0. Android 8.1 wersja zawiera ulepszenia, które zmniejszają opóźnienie, gdy jest używana w połączeniu z HAL i sterownik obsługujący standard MMAP. Ten dokument opisuje abstrakcję sprzętu warstwa (HAL) i sterowniki wymagane do obsługi funkcji MMAP AAudio. na urządzeniu z Androidem.

Obsługa AAudio MMAP wymaga:

  • raportowania możliwości MMAP dla HAL.
  • wdrażanie nowych funkcji w HAL.
  • opcjonalnie wdrożenie niestandardowej funkcji ioctl() dla bufora trybu WYKLUCZAJĄCEGO
  • udostępniając dodatkową ścieżkę danych dotyczących sprzętu
  • Ustawianie właściwości systemu, które włączają funkcję MMAP
.

Architektura AAudio

AAudio to nowy, natywny interfejs API C, który stanowi alternatywę dla Open SL ES. Wykorzystuje Wzór projektu konstruktora do tworzenia strumieni audio.

AAudio zapewnia ścieżkę danych z małym opóźnieniem. W trybie WYJĄTKOWYM funkcja umożliwia kodowi aplikacji klienckiej zapisywanie bezpośrednio w buforze zmapowanym pamięci które jest udostępniane sterownikowi ALSA. W trybie SHARED bufor MMAP jest używany przez z mikserem na serwerze audio. W trybie WYJĄTKOWY opóźnienie jest znacznie mniej, ponieważ dane omijają mikser.

W trybie WYJĄTKOWYM usługa żąda bufora MMAP z HAL i zarządza dostęp do zasobów. Bufor MMAP działa w trybie NOIRQ, dlatego nie ma żadnych udostępnionych liczników odczytu/zapisu w celu zarządzania dostępem do bufora. Zamiast tego, Utrzymuje model czasowy sprzętu i prognozuje, kiedy bufor zostanie przeczytaj.

Na poniższym diagramie widać przepływ danych modulacji kodu PCM (Pulse-code modulation, PCM) przez urządzenie MMAP FIFO do sterownika ALSA. Sygnatury czasowe są podawane okresowo żądane przez usługę AAudio, a następnie przekazane do modelu czasowego klienta dzięki niepodzielnej kolejki komunikatów.

Diagram przepływu danych PCM.
Rysunek 1. Przepływ danych z PCM przez FIFO do ALSA
.

W trybie SHARED używany jest również model czasowy, ale działa on w usłudze AAudioService.

Do przechwytywania dźwięku stosowany jest podobny model, ale przepływ danych PCM w przeciwnym kierunku.

Zmiany HAL

W przypadku tinyALSA zobacz:

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

Informacje o starszej wersji HAL:

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

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

Zgłaszanie obsługi MMAP

Właściwość systemowa „aaudio.mmap_policy” powinna mieć wartość 2 (AAUDIO_POLICY_AUTO), więc platforma audio wie, że tryb MMAP jest obsługiwany przez HAL audio. (zobacz „Włączanie ścieżki danych MMAP” Audio below.)

Plik audio_policy_configuration.xml musi też zawierać dane wyjściowe i dane wejściowe profilu w trybie MMAP/NO IRQ. Dzięki temu menedżer zasad dotyczących dźwięku wie, który strumień ma otwierać się podczas tworzenia klientów 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>

Otwieranie i zamykanie strumienia MMAP

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

Strumień MMAP można otwierać i zamykać za pomocą funkcji Tinyalsa.

Pozycja MMAP zapytania

Sygnatura czasowa przekazana z powrotem do modelu czasu zawiera pozycję klatki i tag Czas MONOTONICS w nanosekundach:

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

HAL może uzyskać te informacje od kierowcy ALSA, dzwoniąc pod nowy Funkcja Tinyalsa:

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

Deskryptory plików dla pamięci współdzielonej

Ścieżka danych AAudio MMAP korzysta z regionu pamięci współużytkowanego przez sprzęt i usługę audio. Odwołanie do pamięci współdzielonej odbywa się za pomocą deskryptora pliku generowane przez sterownik ALSA.

Zmiany jądra systemu

Jeśli deskryptor pliku jest bezpośrednio powiązany z /dev/snd/, może być używany przez usługę AAudio Tryb UDOSTĘPNIONE. Nie można jednak przekazać deskryptora do kodu klienta dla Tryb WYJĄTKOWY. Deskryptor pliku /dev/snd/ również dostarczyłby do szerokiego dostępu do klienta, dlatego blokuje go SELinux.

Do obsługi trybu WYJĄTKOWEGO trzeba przekonwertować parametr Deskryptor /dev/snd/ do pliku anon_inode:dmabuf deskryptor. SELinux zezwala na przekazanie deskryptora pliku do klienta. it może być również używany przez usługę AAudioService.

Deskryptor pliku anon_inode:dmabuf można wygenerować za pomocą Biblioteka pamięci Android Ion.

Więcej informacji znajdziesz w tych materiałach zewnętrznych:

  1. „Funkcja przydzielania pamięci Androida ION” https://lwn.net/Articles/480055/
  2. „Android ION przegląd” https://wiki.linaro.org/BenjaminGaignard/ion
  3. „Integrowanie pamięci przydzielającej ION” https://lwn.net/Articles/565469/

Zmiany HAL

Usługa AAudio musi wiedzieć, czy to anon_inode:dmabuf obsługiwane. Przed Androidem 10.0 jedynym sposobem na to było przesłanie pliku MMAP buforuj jako liczbę ujemną, np. -2048 zamiast 2048, jeśli jest obsługiwana. Na Androidzie 10.0 i nowszych możesz ustawić flagę AUDIO_MMAP_APPLICATION_SHAREABLE.

mmapBufferInfo |= AUDIO_MMAP_APPLICATION_SHAREABLE;

Zmiany podsystemu audio

AAudio wymaga dodatkowej ścieżki danych po stronie interfejsu audio więc może on działać równolegle z pierwotną ścieżką dźwiękową AudioFlinger. Ta starsza ścieżka będzie używana w przypadku wszystkich pozostałych dźwięków systemowych i dźwięków aplikacji. Funkcję tę może zapewnić mikser oprogramowania na platformie DSP lub sprzęt mikser w SOC.

Włącz ścieżkę danych AAudio MMAP

AAudio będzie używać starszej ścieżki danych AudioFlinger, jeśli format MMAP nie będzie obsługiwany lub nie udało się otworzyć strumienia. Dlatego AAudio będzie działać z urządzeniem audio, które nie obsługi ścieżki MMAP/NOIRQ.

Podczas testowania obsługi MMAP w AAudio trzeba sprawdzić, czy testowanie ścieżki danych MMAP lub tylko testowanie starszej ścieżki danych. Z tego artykułu dowiesz się, jak włączyć lub wymusić określone ścieżki danych oraz jak tworzyć zapytania ścieżkę używaną przez strumień.

Właściwości systemowe

Zasadę MMAP możesz ustawić za pomocą właściwości systemowych:

  • 1 = AAUDIO_POLICY_NEVER – używaj tylko starszej ścieżki. Nie próbuj nawet używać MMAP.
  • 2 = AAUDIO_POLICY_AUTO – staraj się używać MMAP. Jeśli to się nie uda lub będzie niedostępne, użyj starszej ścieżki.
  • 3 = AAUDIO_POLICY_ALWAYS – używaj tylko ścieżki MMAP. Nie powracaj do starszej wersji ścieżki konwersji.

Możesz je ustawić w pliku Makefile na urządzeniu:

# 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

Możesz też zastąpić te wartości po uruchomieniu urządzenia. Aby zmiana zaczęła obowiązywać, musisz ponownie uruchomić serwer audio. Aby na przykład włączyć tryb AUTO w przypadku MMAP:

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

Funkcje dostępne w ndk/sysroot/usr/include/aaudio/AAudioTesting.h, dzięki którym możesz: zastąp zasadę dotyczącą korzystania ze ścieżki MMAP:

aaudio_result_t AAudio_setMMapPolicy(aaudio_policy_t policy);

Aby sprawdzić, czy strumień korzysta ze ścieżki MMAP, wywołaj:

bool AAudioStream_isMMapUsed(AAudioStream* stream);