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

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

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

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

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

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

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

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

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

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

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

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

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

tinyALSA के लिए देखें:

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 द्वारा समर्थित है। (नीचे "AAudio MMAP डेटा पथ सक्षम करना" देखें।)

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

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

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

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

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

कर्नेल बदलता है

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

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

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

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

  1. "एंड्रॉइड ION मेमोरी एलोकेटर" https://lwn.net/Articles/480055/
  2. "एंड्रॉइड ION सिंहावलोकन" https://wiki.linaro.org/BenjaminGaignard/ion
  3. "ION मेमोरी एलोकेटर को एकीकृत करना" 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 MMAP डेटा पथ सक्षम करें

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

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

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

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

  • 1 = AAUDIO_POLICY_NEVER - केवल लीगेसी पथ का उपयोग करें। MMAP का उपयोग करने का प्रयास भी न करें.
  • 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);

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

bool AAudioStream_isMMapUsed(AAudioStream* stream);