ASes ve MMAP

AAudio, Android 8.0 sürümünde tanıtılan bir ses API'sidir. Android 8.1 sürümü, bir HAL ve MMAP'yi destekleyen sürücüyle birlikte kullanıldığında gecikmeyi azaltacak geliştirmelere sahiptir. Bu belge, Android'de AAudio'nun MMAP özelliğini desteklemek için gereken donanım soyutlama katmanını (HAL) ve sürücü değişikliklerini açıklamaktadır.

AAudio MMAP desteği şunları gerektirir:

  • HAL'in MMAP yeteneklerini raporlama
  • HAL'de yeni işlevlerin uygulanması
  • isteğe bağlı olarak EXCLUSIVE mod arabelleği için özel bir ioctl() uygulanması
  • ek bir donanım veri yolu sağlamak
  • MMAP özelliğini etkinleştiren sistem özelliklerini ayarlama

ASes mimarisi

AAudio, Open SL ES'ye alternatif sağlayan yeni bir yerel C API'sidir. Ses akışları oluşturmak için Builder tasarım desenini kullanır.

AAudio düşük gecikmeli bir veri yolu sağlar. EXCLUSIVE modunda bu özellik, istemci uygulama kodunun doğrudan ALSA sürücüsüyle paylaşılan bellek eşlemeli ara belleğe yazılmasına olanak tanır. PAYLAŞIM modunda, MMAP arabelleği AudioServer'da çalışan bir mikser tarafından kullanılır. EXCLUSIVE modunda, veriler karıştırıcıyı atladığı için gecikme önemli ölçüde daha azdır.

ÖZEL modda hizmet, HAL'den MMAP arabelleğini ister ve kaynakları yönetir. MMAP arabelleği NOIRQ modunda çalıştığından ara belleğe erişimi yönetecek paylaşılan okuma/yazma sayaçları yoktur. Bunun yerine istemci, donanımın zamanlama modelini korur ve ara belleğin ne zaman okunacağını tahmin eder.

Aşağıdaki şemada Darbe kodu modülasyonu (PCM) verilerinin MMAP FIFO üzerinden ALSA sürücüsüne aktığını görebiliriz. Zaman damgaları AAudio hizmeti tarafından periyodik olarak talep edilir ve daha sonra atomik bir mesaj kuyruğu aracılığıyla müşterinin zamanlama modeline aktarılır.

PCM veri akış şeması.
Şekil 1. FIFO üzerinden ALSA'ya PCM veri akışı

PAYLAŞIM modunda bir zamanlama modeli de kullanılır, ancak AAudioService'te bulunur.

Ses yakalama için benzer bir model kullanılır, ancak PCM verileri ters yönde akar.

HAL değişiklikleri

TinyALSA için bkz.:

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

Eski HAL için bkz.:

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

HIDL ses HAL için:

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 desteğini bildirin

"aaudio.mmap_policy" sistem özelliği 2 (AAUDIO_POLICY_AUTO) olarak ayarlanmalıdır, böylece ses çerçevesi MMAP modunun ses HAL tarafından desteklendiğini bilir. (aşağıdaki "AAudio MMAP Veri Yolunu Etkinleştirme" konusuna bakın.)

audio_policy_configuration.xml dosyasının ayrıca MMAP/NO IRQ moduna özel bir çıkış ve giriş profili içermesi gerekir; böylece Ses Politikası Yöneticisi, MMAP istemcileri oluşturulduğunda hangi akışın açılacağını bilir:

<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 akışını açma ve kapatma

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

MMAP akışı Tinyalsa fonksiyonları çağrılarak açılıp kapatılabilir.

MMAP konumunu sorgula

Zamanlama Modeline geri iletilen zaman damgası, bir çerçeve konumu ve nanosaniye cinsinden MONOTONIC bir süre içerir:

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

HAL, yeni bir Tinyalsa işlevini çağırarak bu bilgiyi ALSA sürücüsünden alabilir:

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

Paylaşılan hafıza için dosya tanımlayıcıları

AAudio MMAP veri yolu, donanım ve ses hizmeti arasında paylaşılan bir bellek bölgesini kullanır. Paylaşılan belleğe, ALSA sürücüsü tarafından oluşturulan bir dosya tanımlayıcı kullanılarak başvurulur.

Çekirdek değişiklikleri

Dosya tanımlayıcı doğrudan bir /dev/snd/ sürücü dosyasıyla ilişkilendirilmişse, AAudio hizmeti tarafından PAYLAŞILAN modda kullanılabilir. Ancak tanımlayıcı EXCLUSIVE modu için istemci koduna aktarılamaz. /dev/snd/ dosya tanımlayıcısı istemciye çok geniş bir erişim sağlayacağından SELinux tarafından engellenir.

EXCLUSIVE modunu desteklemek için /dev/snd/ tanımlayıcısını anon_inode:dmabuf dosya tanımlayıcısına dönüştürmek gerekir. SELinux bu dosya tanımlayıcısının istemciye aktarılmasına izin verir. AAudioService tarafından da kullanılabilir.

Android Ion bellek kitaplığı kullanılarak bir anon_inode:dmabuf dosya tanımlayıcısı oluşturulabilir.

Ek bilgi için şu harici kaynaklara bakın:

  1. "Android ION bellek ayırıcı" https://lwn.net/Articles/480055/
  2. "Android ION'a genel bakış" https://wiki.linaro.org/BenjaminGaignard/ion
  3. "ION bellek ayırıcısını entegre etme" https://lwn.net/Articles/565469/

HAL değişiklikleri

AAudio hizmetinin bu anon_inode:dmabuf desteklenip desteklenmediğini bilmesi gerekir. Android 10.0'dan önce bunu yapmanın tek yolu MMAP arabelleğinin boyutunu negatif bir sayı olarak iletmekti; Destekleniyorsa 2048 yerine -2048. Android 10.0 ve sonraki sürümlerde AUDIO_MMAP_APPLICATION_SHAREABLE bayrağını ayarlayabilirsiniz.

mmapBufferInfo |= AUDIO_MMAP_APPLICATION_SHAREABLE;

Ses alt sistemi değişiklikleri

AAudio, orijinal AudioFlinger yoluyla paralel çalışabilmesi için ses alt sisteminin ses ön ucunda ek bir veri yoluna ihtiyaç duyar. Bu eski yol, diğer tüm sistem sesleri ve uygulama sesleri için kullanılır. Bu işlevsellik, bir DSP'deki bir yazılım karıştırıcısı veya SOC'deki bir donanım karıştırıcısı tarafından sağlanabilir.

AAudio MMAP veri yolunu etkinleştir

AAudio, MMAP desteklenmiyorsa veya bir akışı açamıyorsa eski AudioFlinger veri yolunu kullanacaktır. Yani AAudio, MMAP/NOIRQ yolunu desteklemeyen bir ses cihazıyla çalışacaktır.

AAudio için MMAP desteğini test ederken, aslında MMAP veri yolunu mu yoksa yalnızca eski veri yolunu mu test ettiğinizi bilmek önemlidir. Aşağıda belirli veri yollarının nasıl etkinleştirileceği veya zorlanacağı ve bir akış tarafından kullanılan yolun nasıl sorgulanacağı açıklanmaktadır.

Sistem özellikleri

MMAP politikasını sistem özellikleri aracılığıyla ayarlayabilirsiniz:

  • 1 = AAUDIO_POLICY_NEVER - Yalnızca eski yolu kullanın. MMAP kullanmayı denemeyin bile.
  • 2 = AAUDIO_POLICY_AUTO - MMAP kullanmayı deneyin. Bu başarısız olursa veya kullanılamıyorsa eski yolu kullanın.
  • 3 = AAUDIO_POLICY_ALWAYS - Yalnızca MMAP yolunu kullanın. Eski yola geri dönmeyin.

Bunlar Makefile aygıtlarında şu şekilde ayarlanabilir:

# 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

Cihaz başlatıldıktan sonra da bu değerleri geçersiz kılabilirsiniz. Değişikliğin etkili olması için ses sunucusunu yeniden başlatmanız gerekecektir. Örneğin, MMAP için OTOMATİK modunu etkinleştirmek için:

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

ndk/sysroot/usr/include/aaudio/AAudioTesting.h dosyasında, MMAP yolunu kullanma politikasını geçersiz kılmanıza olanak tanıyan işlevler mevcuttur:

aaudio_result_t AAudio_setMMapPolicy(aaudio_policy_t policy);

Bir akışın MMAP yolunu kullanıp kullanmadığını öğrenmek için şunu arayın:

bool AAudioStream_isMMapUsed(AAudioStream* stream);