ASes ve MMAP

AAudio, Android 8.0 sürümünde tanıtılan bir ses API'sidir. Android 8.1 sürümü, MMAP'yi destekleyen bir HAL ve sürücü ile birlikte kullanıldığında gecikmeyi azaltan 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çıklar.

AAudio MMAP desteği şunları gerektirir:

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

ASes mimarisi

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

AAudio, düşük gecikmeli bir veri yolu sağlar. ÖZEL modda, bu özellik, istemci uygulama kodunun doğrudan ALSA sürücüsü ile paylaşılan bir bellek eşlemeli arabelleğe yazmasına izin verir. SHARED modunda, MMAP arabelleği AudioServer'da çalışan bir mikser tarafından kullanılır. ÖZEL 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ışıyor, bu nedenle arabelleğe erişimi yönetmek için paylaşılan okuma/yazma sayacı yok. Bunun yerine, istemci donanımın bir zamanlama modelini korur ve ara belleğin ne zaman okunacağını tahmin eder.

Aşağıdaki şemada, MMAP FIFO'dan ALSA sürücüsüne akan Darbe kodu modülasyonu (PCM) verilerini görebiliriz. Zaman damgaları, AAudio hizmeti tarafından periyodik olarak istenir ve daha sonra bir atomik mesaj kuyruğu aracılığıyla müşterinin zamanlama modeline iletilir.

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

SHARED modunda, bir zamanlama modeli de kullanılır, ancak AAudioService'de 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 bakınız:

external/tinyalsa/include/tinyalsa/asoundlib.h
external/tinyalsa/include/tinyalsa/pcm.c
tutucu1 l10n-yer
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
tutucu3 l10n-yer
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
tutucu5 l10n-yer
start() generates (Result retval);
stop() generates (Result retval) ;
createMmapBuffer(int32_t minSizeFrames)
       generates (Result retval, MmapBufferInfo info);
getMmapPosition()
       generates (Result retval, MmapPosition position);

Raporlama MMAP desteği

"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" bölümüne bakın.)

audio_policy_configuration.xml dosyası ayrıca MMAP/NO IRQ moduna özel bir çıkış ve giriş profili içermelidir, böylece Audio Policy Manager 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>

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

Zamanlama Modeline geri gönderilen zaman damgası, nanosaniye cinsinden bir çerçeve konumu ve bir MONOTONİK zaman içerir:

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

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

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

Paylaşılan Bellek 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ıtıcısı kullanılarak başvurulur.

Çekirdek değişiklikleri

Dosya tanıtıcı bir /dev/snd/ sürücü dosyasıyla doğrudan ilişkiliyse, AAudio hizmeti tarafından PAYLAŞIM modunda kullanılabilir. Ancak tanımlayıcı, ÖZEL mod için istemci koduna aktarılamaz. /dev/snd/ dosya tanımlayıcısı, istemciye çok geniş erişim sağlar, bu nedenle SELinux tarafından engellenir.

ÖZEL modunu desteklemek için /dev/snd/ tanımlayıcısını bir anon_inode:dmabuf dosya tanımlayıcısına dönüştürmek gerekir. SELinux, bu dosya tanımlayıcısının istemciye geçirilmesine 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 dış 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, örn. 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 yolu ile paralel olarak çalışabilmesi için ses alt sisteminin ses ön ucunda ek bir veri yolu gerektirir. 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ştirme

MMAP desteklenmiyorsa veya bir akışı açamıyorsa, AAudio eski AudioFlinger veri yolunu kullanır. Böylece AAudio, MMAP/NOIRQ yolunu desteklemeyen bir ses aygıtıyla çalışacaktır.

AAudio için MMAP desteğini test ederken, gerçekten 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 ilkesini 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 cihazları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

Aygıt önyüklendikten sonra da bu değerleri geçersiz kılabilirsiniz. Değişikliğin etkili olması için ses sunucusunu yeniden başlatmanız gerekecek. Örneğin, MMAP için OTOMATİK modunu etkinleştirmek için:

adb root
adb shell setprop aaudio.mmap_policy 2
-yer tutucu14 l10n-yer
adb shell killall audioserver

ndk/sysroot/usr/include/aaudio/AAudioTesting.h içinde sağlanan ve MMAP yolunu kullanma ilkesini geçersiz kılmanıza izin veren işlevler vardır:

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