AAudio dan MMAP

AAudio adalah API audio yang diperkenalkan dalam rilis Android 8.0. Rilis Android 8.1 memiliki peningkatan 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 membutuhkan:

  • melaporkan kemampuan MMAP dari 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 audio AA

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 SHARED, buffer MMAP digunakan oleh mixer yang berjalan di AudioServer. Dalam mode EKSKLUSIF, latensi berkurang secara signifikan 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 ini, kita dapat melihat data Pulse-code modulation (PCM) mengalir turun melalui MMAP FIFO ke dalam driver ALSA. Stempel waktu secara berkala diminta 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 SHARED, model pengaturan waktu juga digunakan, tetapi model ini hidup di AAudioService.

Untuk pengambilan audio, model serupa digunakan, tetapi data PCM mengalir ke 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 warisan, 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);

Melaporkan dukungan MMAP

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

file audio_policy_configuration.xml juga harus berisi profil output dan input khusus untuk mode MMAP/NO IRQ sehingga Pengelola Kebijakan Audio mengetahui aliran mana yang akan dibuka saat 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.

Menanyakan posisi 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 dirujuk menggunakan deskriptor file yang dihasilkan oleh pengandar ALSA.

Perubahan kernel

Jika deskriptor file terkait langsung dengan file driver /dev/snd/ , maka file tersebut dapat digunakan oleh layanan AAudio dalam mode SHARED. Tetapi 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 untuk mengubah deskriptor /dev/snd/ menjadi deskriptor file anon_inode:dmabuf . SELinux memungkinkan deskriptor file itu 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 ION Android" 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, mis. -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 dari subsistem audio sehingga dapat beroperasi secara paralel dengan jalur AudioFlinger asli. Jalur warisan itu digunakan untuk semua suara sistem dan suara aplikasi lainnya. Fungsionalitas ini dapat disediakan oleh pencampur perangkat lunak di DSP atau pencampur perangkat keras di SOC.

Mengaktifkan 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 menjelaskan cara mengaktifkan atau memaksa jalur data tertentu, dan cara membuat kueri jalur yang digunakan oleh aliran.

Properti sistem

Anda dapat menyetel 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 jatuh kembali ke jalur warisan.

Ini dapat 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 ini setelah perangkat melakukan booting. Anda harus 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 untuk menggunakan jalur MMAP:

aaudio_result_t AAudio_setMMapPolicy(aaudio_policy_t policy);

Untuk mengetahui apakah streaming menggunakan jalur MMAP, hubungi:

bool AAudioStream_isMMapUsed(AAudioStream* stream);