AAudio dan MMAP

AAudio adalah API audio yang diperkenalkan pada rilis Android 8.0. Rilis Android 8.1 memiliki penyempurnaan untuk mengurangi latensi saat digunakan bersama dengan HAL dan driver yang mendukung MMAP. Dokumen ini menjelaskan lapisan abstraksi perangkat keras (HAL) dan perubahan driver yang diperlukan untuk mendukung fitur MMAP AAudio di Android.

Dukungan untuk AAudio MMAP memerlukan:

  • melaporkan kemampuan MMAP HAL
  • mengimplementasikan fungsi baru di HAL
  • secara opsional menerapkan ioctl() khusus untuk buffer mode EKSKLUSIF
  • menyediakan jalur data perangkat keras tambahan
  • mengatur properti sistem yang mengaktifkan fitur MMAP

Arsitektur AAudio

AAudio adalah C API asli baru yang menyediakan alternatif untuk Open SL ES. Ini menggunakan pola desain Builder untuk membuat aliran audio.

AAudio menyediakan jalur data latensi rendah. Dalam mode EKSKLUSIF, fitur ini memungkinkan kode aplikasi klien untuk menulis langsung ke buffer yang dipetakan memori yang dibagikan dengan driver ALSA. Dalam mode BERBAGI, buffer MMAP digunakan oleh mixer yang berjalan di AudioServer. Dalam mode EKSKLUSIF, latensi jauh lebih kecil karena data melewati mixer.

Dalam mode EKSKLUSIF, layanan meminta buffer MMAP dari HAL dan mengelola sumber daya. Buffer MMAP berjalan dalam mode NOIRQ, jadi tidak ada penghitung baca/tulis bersama untuk mengelola akses ke buffer. Sebaliknya, klien mempertahankan model waktu perangkat keras dan memprediksi kapan buffer akan dibaca.

Pada diagram di bawah, kita dapat melihat data modulasi kode pulsa (PCM) mengalir melalui MMAP FIFO ke driver ALSA. Stempel waktu diminta secara berkala oleh layanan AAudio dan kemudian diteruskan ke model waktu klien melalui antrian pesan atom.

Diagram aliran data PCM.
Gambar 1. Aliran data PCM melalui FIFO ke ALSA

Dalam mode BERBAGI, model pengaturan waktu juga digunakan, tetapi model tersebut berada di AAudioService.

Untuk pengambilan audio, model serupa digunakan, namun data PCM mengalir dalam arah yang berlawanan.

perubahan HAL

Untuk tinyALSA lihat:

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

Untuk HAL lama, lihat:

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

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

Laporkan dukungan MMAP

Properti sistem "aaudio.mmap_policy" harus disetel ke 2 (AAUDIO_POLICY_AUTO) sehingga kerangka audio mengetahui bahwa mode MMAP didukung oleh audio HAL. (lihat "Mengaktifkan Jalur Data AAudio MMAP" di bawah.)

File audio_policy_configuration.xml juga harus berisi profil keluaran dan masukan khusus untuk mode MMAP/NO IRQ sehingga Manajer Kebijakan Audio mengetahui aliran mana yang akan dibuka ketika klien MMAP dibuat:

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

Membuka dan menutup aliran MMAP

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

Aliran MMAP dapat dibuka dan ditutup dengan memanggil fungsi Tinyalsa.

Posisi kueri MMAP

Stempel waktu yang dikembalikan ke Model Pengaturan Waktu berisi posisi bingkai dan waktu MONOTONIC dalam nanodetik:

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

HAL dapat memperoleh informasi ini dari driver ALSA dengan memanggil fungsi Tinyalsa baru:

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

Deskriptor file untuk memori bersama

Jalur data AAudio MMAP menggunakan wilayah memori yang dibagi antara perangkat keras dan layanan audio. Memori bersama direferensikan menggunakan deskriptor file yang dihasilkan oleh driver ALSA.

Perubahan kernel

Jika deskriptor file dikaitkan langsung dengan file driver /dev/snd/ , maka deskriptor tersebut dapat digunakan oleh layanan AAudio dalam mode BERBAGI. Namun deskriptor tidak dapat diteruskan ke kode klien untuk mode EKSKLUSIF. Deskriptor file /dev/snd/ akan memberikan akses yang terlalu luas ke klien, sehingga diblokir oleh SELinux.

Untuk mendukung mode EKSKLUSIF, perlu mengonversi deskriptor /dev/snd/ menjadi deskriptor file anon_inode:dmabuf . SELinux memungkinkan deskriptor file tersebut diteruskan ke klien. Itu juga dapat digunakan oleh AAudioService.

Deskriptor file anon_inode:dmabuf dapat dibuat menggunakan pustaka memori Android Ion.

Untuk informasi tambahan, lihat sumber daya eksternal berikut:

  1. "Pengalokasi memori Android ION" https://lwn.net/Articles/480055/
  2. "Ikhtisar Android ION" https://wiki.linaro.org/BenjaminGaignard/ion
  3. "Mengintegrasikan pengalokasi memori ION" https://lwn.net/Articles/565469/

perubahan HAL

Layanan AAudio perlu mengetahui apakah anon_inode:dmabuf ini didukung. Sebelum Android 10.0, satu-satunya cara untuk melakukannya adalah dengan meneruskan ukuran buffer MMAP sebagai angka negatif, misalnya. -2048 bukannya 2048, jika didukung. Di Android 10.0 dan yang lebih baru, Anda dapat menyetel tanda AUDIO_MMAP_APPLICATION_SHAREABLE .

mmapBufferInfo |= AUDIO_MMAP_APPLICATION_SHAREABLE;

Perubahan subsistem audio

AAudio memerlukan jalur data tambahan di ujung depan audio subsistem audio sehingga dapat beroperasi secara paralel dengan jalur AudioFlinger asli. Jalur lama tersebut digunakan untuk semua suara sistem dan suara aplikasi lainnya. Fungsionalitas ini dapat disediakan oleh mixer perangkat lunak di DSP atau mixer perangkat keras di SOC.

Aktifkan jalur data AAudio MMAP

AAudio akan menggunakan jalur data AudioFlinger lama jika MMAP tidak didukung atau gagal membuka streaming. Jadi AAudio akan bekerja dengan perangkat audio yang tidak mendukung jalur MMAP/NOIRQ.

Saat menguji dukungan MMAP untuk AAudio, penting untuk mengetahui apakah Anda benar-benar menguji jalur data MMAP atau hanya menguji jalur data lama. Berikut ini penjelasan cara mengaktifkan atau memaksa jalur data tertentu, dan cara mengkueri jalur yang digunakan oleh aliran.

Properti sistem

Anda dapat mengatur kebijakan MMAP melalui properti sistem:

  • 1 = AAUDIO_POLICY_NEVER - Hanya gunakan jalur lama. Jangan coba-coba menggunakan MMAP.
  • 2 = AAUDIO_POLICY_AUTO - Coba gunakan MMAP. Jika gagal atau tidak tersedia, gunakan jalur lama.
  • 3 = AAUDIO_POLICY_ALWAYS - Hanya gunakan jalur MMAP. Jangan kembali ke jalur warisan.

Ini mungkin diatur di perangkat Makefile, seperti:

# 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

Anda juga dapat mengganti nilai-nilai ini setelah perangkat melakukan booting. Anda perlu memulai ulang server audio agar perubahan diterapkan. Misalnya, untuk mengaktifkan mode AUTO untuk MMAP:

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

Ada fungsi yang disediakan di ndk/sysroot/usr/include/aaudio/AAudioTesting.h yang memungkinkan Anda mengganti kebijakan penggunaan jalur MMAP:

aaudio_result_t AAudio_setMMapPolicy(aaudio_policy_t policy);

Untuk mengetahui apakah streaming menggunakan jalur MMAP, hubungi:

bool AAudioStream_isMMapUsed(AAudioStream* stream);