AAudio dan MMAP

AAudio adalah API audio yang diperkenalkan dalam rilis Android 8.0. Android 8.1 memiliki peningkatan untuk mengurangi latensi saat digunakan bersama dengan HAL dan driver yang mendukung MMAP. Dokumen ini menjelaskan abstraksi hardware (HAL) dan perubahan driver diperlukan untuk mendukung fitur MMAP AAudio di Android.

Dukungan untuk MMAP AAudio memerlukan:

  • melaporkan kemampuan MMAP HAL
  • menerapkan fungsi baru di HAL
  • secara opsional menerapkan ioctl() kustom untuk buffer mode EKSKLUSIF
  • menyediakan jalur data hardware tambahan
  • menyetel properti sistem yang mengaktifkan fitur MMAP

Arsitektur AAudio

AAudio adalah API C native baru yang menyediakan alternatif untuk Open SL ES. Proses ini menggunakan Pola desain pembangun untuk membuat streaming 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 {i>driver<i} ALSA. Dalam mode BERSAMA, buffer MMAP digunakan oleh mixer yang berjalan di AudioServer. Dalam mode EKSKLUSIF, latensinya secara signifikan lebih sedikit karena data mengabaikan pencampur.

Dalam mode EKSKLUSIF, layanan meminta buffer MMAP dari HAL dan mengelola resource tersebut. Buffer MMAP berjalan dalam mode NOIRQ, sehingga tidak ada baca/tulis penghitung untuk mengelola akses ke {i>buffer<i}. Sebaliknya, klien mempertahankan model pengaturan waktu perangkat keras dan memprediksi kapan dibaca.

Pada diagram di bawah ini, kita dapat melihat aliran data Pulse-code modulation (PCM) melalui MMAP FIFO ke {i>driver<i} ALSA. Stempel waktu bersifat berkala yang diminta oleh layanan AAudio lalu diteruskan ke model pengaturan waktu klien melalui antrean pesan atomik.

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

Dalam mode SHARED, model pengaturan waktu juga digunakan, tetapi terdapat di AAudioService.

Untuk rekaman audio, model serupa digunakan, tetapi data PCM mengalir di 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 HAL audio HIDL:

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 framework audio mengetahui bahwa mode MMAP didukung oleh HAL audio. (lihat "Mengaktifkan Jalur Data MMAP AAudio" di bawah.)

File audio_policy_configuration.xml juga harus berisi output dan input khusus untuk mode MMAP/NO IRQ sehingga Pengelola Kebijakan Audio mengetahui streaming 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 fungsiTinyalsa.

Membuat kueri posisi MMAP

Stempel waktu yang diteruskan kembali ke Model Waktu berisi posisi frame dan Waktu MONOTONIC dalam nanodetik:

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

HAL bisa memperoleh informasi ini dari {i>driver<i} ALSA dengan memanggil FungsiTinyalsa:

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

Deskriptor file untuk memori bersama

Jalur data MMAP AAudio menggunakan region memori yang digunakan bersama perangkat keras dan layanan audio. Memori bersama direferensikan menggunakan deskriptor file yang dihasilkan oleh {i>driver<i} ALSA.

Perubahan kernel

Jika deskriptor file terkait langsung dengan File driver /dev/snd/, lalu dapat digunakan oleh layanan AAudio di SHARED Mode. Tetapi deskriptor tidak bisa diteruskan ke kode klien untuk Mode EKSKLUSIF. Deskriptor file /dev/snd/ juga akan menyediakan akses ke klien yang luas, sehingga diblokir oleh SELinux.

Untuk mendukung mode EKSKLUSIF, Anda perlu mengonversi Deskriptor /dev/snd/ menjadi file anon_inode:dmabuf deskripsi. SELinux memungkinkan deskriptor file itu diteruskan ke klien. Ini juga dapat digunakan oleh AAudioService.

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

Untuk informasi tambahan, lihat referensi eksternal berikut:

  1. "Alokator memori Android ION" https://lwn.net/Articles/480055/
  2. "Ringkasan Android ION" https://wiki.linaro.org/BenjaminGaignard/ion
  3. "Mengintegrasikan alokator 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 MMAP buffer sebagai angka negatif, misalnya -2048, bukan 2048, jika didukung. Di Android 10.0 dan yang lebih baru Anda dapat menetapkan flag AUDIO_MMAP_APPLICATION_SHAREABLE.

mmapBufferInfo |= AUDIO_MMAP_APPLICATION_SHAREABLE;

Perubahan subsistem audio

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

Mengaktifkan jalur data MMAP AAudio

AAudio akan menggunakan jalur data AudioFlinger lama jika MMAP tidak didukung atau gagal membuka streaming. Jadi AAudio akan berfungsi 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. Tujuan berikut ini yang menjelaskan cara mengaktifkan atau memaksa jalur data tertentu, dan cara membuat kueri jalur yang digunakan oleh sebuah aliran data.

Properti sistem

Anda dapat menyetel kebijakan MMAP melalui properti sistem:

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

Opsi ini dapat disetel di perangkat Makefile, seperti berikut:

# 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 di-booting. Anda perlu memulai ulang server audio agar perubahan diterapkan. Misalnya, guna 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 untuk ganti kebijakan untuk menggunakan jalur MMAP:

aaudio_result_t AAudio_setMMapPolicy(aaudio_policy_t policy);

Untuk mengetahui apakah streaming menggunakan jalur MMAP, panggil:

bool AAudioStream_isMMapUsed(AAudioStream* stream);