ऑडियो और एमएमएपी

AAudio Android 8.0 रिलीज़ में पेश किया गया एक ऑडियो API है। एंड्रॉइड 8.1 रिलीज में एचएएल और एमएमएपी का समर्थन करने वाले ड्राइवर के संयोजन के साथ उपयोग किए जाने पर विलंबता को कम करने के लिए एन्हांसमेंट हैं। यह दस्तावेज़ Android में AAudio की MMAP सुविधा का समर्थन करने के लिए आवश्यक हार्डवेयर एब्स्ट्रैक्शन लेयर (HAL) और ड्राइवर परिवर्तनों का वर्णन करता है।

AAudio MMAP के लिए समर्थन की आवश्यकता है:

  • एचएएल की एमएमएपी क्षमताओं की रिपोर्ट करना
  • एचएएल . में नए कार्यों को लागू करना
  • EXCLUSIVE मोड बफर के लिए वैकल्पिक रूप से एक कस्टम ioctl() को कार्यान्वित करना
  • एक अतिरिक्त हार्डवेयर डेटा पथ प्रदान करना
  • सिस्टम गुण सेट करना जो MMAP सुविधा को सक्षम करते हैं

ऑडियो वास्तुकला

AAudio एक नया देशी C API है जो ओपन SL ES का विकल्प प्रदान करता है। यह ऑडियो स्ट्रीम बनाने के लिए एक बिल्डर डिज़ाइन पैटर्न का उपयोग करता है।

AAudio कम-विलंबता डेटा पथ प्रदान करता है। EXCLUSIVE मोड में, सुविधा क्लाइंट एप्लिकेशन कोड को सीधे मेमोरी मैप किए गए बफर में लिखने की अनुमति देती है जिसे ALSA ड्राइवर के साथ साझा किया जाता है। साझा मोड में, ऑडियो सर्वर में चल रहे मिक्सर द्वारा एमएमएपी बफर का उपयोग किया जाता है। EXCLUSIVE मोड में, विलंबता काफी कम है क्योंकि डेटा मिक्सर को बायपास करता है।

EXCLUSIVE मोड में, सेवा HAL से MMAP बफर का अनुरोध करती है और संसाधनों का प्रबंधन करती है। एमएमएपी बफर एनओआईआरक्यू मोड में चल रहा है, इसलिए बफर तक पहुंच प्रबंधित करने के लिए कोई साझा पढ़ने/लिखने काउंटर नहीं हैं। इसके बजाय, क्लाइंट हार्डवेयर का टाइमिंग मॉडल बनाए रखता है और भविष्यवाणी करता है कि बफर कब पढ़ा जाएगा।

नीचे दिए गए आरेख में, हम पल्स-कोड मॉड्यूलेशन (पीसीएम) डेटा को एमएमएपी फीफो के माध्यम से एएलएसए ड्राइवर में बहते हुए देख सकते हैं। टाइमस्टैम्प को समय-समय पर AAudio सेवा द्वारा अनुरोध किया जाता है और फिर एक परमाणु संदेश कतार के माध्यम से क्लाइंट के टाइमिंग मॉडल को पास किया जाता है।

पीसीएम डेटा प्रवाह आरेख।
चित्रा 1. पीसीएम डेटा फीफो के माध्यम से एएलएसए में प्रवाहित होता है

SHARED मोड में, एक टाइमिंग मॉडल का भी उपयोग किया जाता है, लेकिन यह AAudioService में रहता है।

ऑडियो कैप्चर के लिए, एक समान मॉडल का उपयोग किया जाता है, लेकिन पीसीएम डेटा विपरीत दिशा में बहता है।

एचएएल परिवर्तन

टिनीएएलएसए के लिए देखें:

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

विरासत एचएएल के लिए, देखें:

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

एचआईडीएल ऑडियो एचएएल के लिए:

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

रिपोर्टिंग एमएमएपी समर्थन

सिस्टम गुण "aaudio.mmap_policy" को 2 (AAUDIO_POLICY_AUTO) पर सेट किया जाना चाहिए ताकि ऑडियो फ़्रेमवर्क जानता हो कि MMAP मोड ऑडियो HAL द्वारा समर्थित है। (नीचे "एऑडियो एमएमएपी डेटा पथ सक्षम करना" देखें।)

audio_policy_configuration.xml फ़ाइल में MMAP/NO IRQ मोड के लिए विशिष्ट आउटपुट और इनपुट प्रोफ़ाइल भी होनी चाहिए ताकि ऑडियो पॉलिसी मैनेजर को पता चले कि MMAP क्लाइंट बनने पर कौन सी स्ट्रीम खोलनी है:

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

एमएमएपी स्ट्रीम खोलना और बंद करना

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

एमएमएपी स्ट्रीम को टिनयाल्सा फ़ंक्शन को कॉल करके खोला और बंद किया जा सकता है।

एमएमएपी स्थिति पूछताछ

टाइमस्टैम्प को टाइमिंग मॉडल में वापस भेज दिया गया है जिसमें एक फ्रेम स्थिति और नैनोसेकंड में एक मोनोटोनिक समय होता है:

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

HAL इस जानकारी को ALSA ड्राइवर से एक नया Tinyalsa फ़ंक्शन कॉल करके प्राप्त कर सकता है:

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

साझा मेमोरी के लिए फाइल डिस्क्रिप्टर

AAudio MMAP डेटा पथ एक मेमोरी क्षेत्र का उपयोग करता है जिसे हार्डवेयर और ऑडियो सेवा के बीच साझा किया जाता है। साझा स्मृति को एक फ़ाइल डिस्क्रिप्टर का उपयोग करके संदर्भित किया जाता है जो ALSA ड्राइवर द्वारा उत्पन्न होता है।

कर्नेल परिवर्तन

यदि फ़ाइल डिस्क्रिप्टर सीधे /dev/snd/ ड्राइवर फ़ाइल से जुड़ा है, तो इसका उपयोग AAudio सेवा द्वारा SHARED मोड में किया जा सकता है। लेकिन डिस्क्रिप्टर को EXCLUSIVE मोड के लिए क्लाइंट कोड में पास नहीं किया जा सकता है। /dev/snd/ फाइल डिस्क्रिप्टर क्लाइंट को बहुत व्यापक एक्सेस प्रदान करेगा, इसलिए इसे SELinux द्वारा ब्लॉक किया गया है।

EXCLUSIVE मोड को सपोर्ट करने के लिए, /dev/snd/ डिस्क्रिप्टर को anon_inode:dmabuf फाइल डिस्क्रिप्टर में बदलना जरूरी है। SELinux उस फाइल डिस्क्रिप्टर को क्लाइंट को पास करने की अनुमति देता है। इसका उपयोग AAudioService द्वारा भी किया जा सकता है।

anon_inode:dmabuf फ़ाइल डिस्क्रिप्टर Android आयन मेमोरी लाइब्रेरी का उपयोग करके उत्पन्न किया जा सकता है।

अतिरिक्त जानकारी के लिए, ये बाहरी संसाधन देखें:

  1. "एंड्रॉइड आयन मेमोरी एलोकेटर" https://lwn.net/Articles/480055/
  2. "एंड्रॉइड आयन अवलोकन" https://wiki.linaro.org/BenjaminGaignard/ion
  3. "आयन मेमोरी एलोकेटर को एकीकृत करना" https://lwn.net/Articles/565469/

एचएएल परिवर्तन

AAudio सेवा को यह जानने की जरूरत है कि क्या यह anon_inode:dmabuf समर्थित है। एंड्रॉइड 10.0 से पहले, ऐसा करने का एकमात्र तरीका एमएमएपी बफर के आकार को ऋणात्मक संख्या के रूप में पास करना था, उदाहरण के लिए। -2048 के बजाय 2048, यदि समर्थित हो। Android 10.0 और बाद के संस्करण में आप AUDIO_MMAP_APPLICATION_SHAREABLE ध्वज सेट कर सकते हैं।

mmapBufferInfo |= AUDIO_MMAP_APPLICATION_SHAREABLE;

ऑडियो सबसिस्टम में बदलाव

AAudio को ऑडियो सबसिस्टम के ऑडियो फ्रंट एंड पर एक अतिरिक्त डेटा पथ की आवश्यकता होती है ताकि यह मूल AudioFlinger पथ के समानांतर काम कर सके। वह विरासती पथ अन्य सभी सिस्टम ध्वनियों और अनुप्रयोग ध्वनियों के लिए उपयोग किया जाता है। यह कार्यक्षमता एक डीएसपी में एक सॉफ्टवेयर मिक्सर या एसओसी में एक हार्डवेयर मिक्सर द्वारा प्रदान की जा सकती है।

AAudio MMAP डेटा पथ को सक्षम करना

यदि एमएमएपी समर्थित नहीं है या स्ट्रीम खोलने में विफल रहता है, तो एऑडियो लीगेसी ऑडियोफ्लिंगर डेटा पथ का उपयोग करेगा। तो AAudio एक ऑडियो डिवाइस के साथ काम करेगा जो MMAP/NOIRQ पथ का समर्थन नहीं करता है।

AAudio के लिए MMAP समर्थन का परीक्षण करते समय, यह जानना महत्वपूर्ण है कि क्या आप वास्तव में MMAP डेटा पथ का परीक्षण कर रहे हैं या केवल लीगेसी डेटा पथ का परीक्षण कर रहे हैं। निम्नलिखित वर्णन करता है कि विशिष्ट डेटा पथों को कैसे सक्षम या बाध्य किया जाए, और किसी स्ट्रीम द्वारा उपयोग किए जाने वाले पथ को कैसे क्वेरी किया जाए।

प्रणाली के गुण

आप सिस्टम गुणों के माध्यम से MMAP नीति सेट कर सकते हैं:

  • 1 = AAUDIO_POLICY_NEVER - केवल लीगेसी पथ का उपयोग करें। एमएमएपी का इस्तेमाल करने की कोशिश भी न करें।
  • 2 = AAUDIO_POLICY_AUTO - MMAP का उपयोग करने का प्रयास करें। यदि वह विफल रहता है या उपलब्ध नहीं है, तो विरासत पथ का उपयोग करें।
  • 3 = AAUDIO_POLICY_ALWAYS - केवल MMAP पथ का उपयोग करें। विरासत पथ पर वापस मत आना।

इन्हें मेकफ़ाइल डिवाइस में सेट किया जा सकता है, जैसे:

# 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

डिवाइस के बूट होने के बाद आप इन मानों को ओवरराइड भी कर सकते हैं। परिवर्तन को प्रभावी करने के लिए आपको ऑडियोसर्वर को पुनरारंभ करना होगा। उदाहरण के लिए, एमएमएपी के लिए ऑटो मोड को सक्षम करने के लिए:

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

ndk/sysroot/usr/include/aaudio/AAudioTesting.h में ऐसे फ़ंक्शन उपलब्ध हैं जो आपको MMAP पथ का उपयोग करने के लिए नीति को ओवरराइड करने की अनुमति देते हैं:

aaudio_result_t AAudio_setMMapPolicy(aaudio_policy_t policy);

यह पता लगाने के लिए कि क्या कोई स्ट्रीम MMAP पथ का उपयोग कर रही है, कॉल करें:

bool AAudioStream_isMMapUsed(AAudioStream* stream);