इस लेख में बताया गया है कि Android का ऑडियो सिस्टम, प्रायॉरिटी इन्वर्ज़न की समस्या से कैसे बचता है. साथ ही, इसमें ऐसी तकनीकों के बारे में भी बताया गया है जिनका इस्तेमाल आप भी कर सकते हैं.
ये तकनीकें, ज़्यादा परफ़ॉर्मेंस वाले ऑडियो ऐप्लिकेशन के डेवलपर, ओईएम, और एसओसी उपलब्ध कराने वाली कंपनियों के लिए काम की हो सकती हैं. ये कंपनियां, ऑडियो HAL लागू कर रही हैं. कृपया ध्यान दें कि इन तकनीकों को लागू करने से, गड़बड़ियां या अन्य समस्याएं ठीक हो जाएंगी, इसकी कोई गारंटी नहीं है. खास तौर पर, अगर इनका इस्तेमाल ऑडियो के संदर्भ से बाहर किया जाता है. आपके नतीजे अलग-अलग हो सकते हैं. इसलिए, आपको खुद से आकलन और जांच करनी चाहिए.
बैकग्राउंड
लेटेंसी कम करने के लिए, Android AudioFlinger ऑडियो सर्वर और AudioTrack/AudioRecord क्लाइंट के लागू करने के तरीके में बदलाव किया जा रहा है. यह काम Android 4.1 में शुरू हुआ था. इसके बाद, 4.2, 4.3, 4.4, और 5.0 में भी इसमें सुधार किए गए.
लेटेंसी कम करने के लिए, पूरे सिस्टम में कई बदलाव करने पड़े. एक अहम बदलाव यह है कि समय के हिसाब से ज़रूरी थ्रेड को सीपीयू के संसाधन असाइन करने के लिए, ज़्यादा अनुमानित शेड्यूलिंग नीति का इस्तेमाल किया जाए. भरोसेमंद शेड्यूलिंग की मदद से, ऑडियो बफ़र के साइज़ और संख्या को कम किया जा सकता है. साथ ही, अंडररन और ओवररन की समस्या से भी बचा जा सकता है.
प्राथमिकता व्युत्क्रमण
प्रायॉरिटी इन्वर्ज़न रियल-टाइम सिस्टम में होने वाली एक क्लासिक समस्या है. इसमें, ज़्यादा प्राथमिकता वाला टास्क, कम प्राथमिकता वाले टास्क के किसी संसाधन (जैसे, म्यूटेक्स) को रिलीज़ करने का इंतज़ार करते हुए, अनिश्चित समय के लिए ब्लॉक हो जाता है.
ऑडियो सिस्टम में, प्रायॉरिटी इन्वर्ज़न की समस्या आम तौर पर गड़बड़ी (क्लिक, पॉप, ड्रॉपआउट), सर्कुलर बफ़र का इस्तेमाल करने पर बार-बार ऑडियो सुनाई देना या किसी कमांड का जवाब देने में देरी के तौर पर दिखती है.
प्रायॉरिटी इन्वर्ज़न की समस्या को ठीक करने का एक सामान्य तरीका, ऑडियो बफ़र के साइज़ को बढ़ाना है. हालांकि, इस तरीके से लेटेंसी बढ़ जाती है और समस्या को हल करने के बजाय, सिर्फ़ छिपाया जाता है. प्रायॉरिटी इन्वर्ज़न की समस्या को समझना और इससे बचना बेहतर है. इसके बारे में यहां बताया गया है.
Android के ऑडियो को लागू करने के दौरान, प्रायॉरिटी इन्वर्ज़न की समस्या इन जगहों पर होने की संभावना सबसे ज़्यादा होती है. इसलिए, आपको इन पर ध्यान देना चाहिए:
- AudioFlinger में, सामान्य मिक्सर थ्रेड और फ़ास्ट मिक्सर थ्रेड के बीच
- फ़ास्ट AudioTrack और फ़ास्ट मिक्सर थ्रेड के लिए, ऐप्लिकेशन कॉलबैक थ्रेड के बीच (इन दोनों की प्राथमिकता ज़्यादा होती है, लेकिन इनमें थोड़ा अंतर होता है)
- फ़ास्ट AudioRecord और फ़ास्ट कैप्चर थ्रेड के लिए, ऐप्लिकेशन कॉलबैक थ्रेड के बीच (यह पहले जैसा ही है)
- ऑडियो हार्डवेयर ऐब्स्ट्रैक्शन लेयर (HAL) को लागू करने के दौरान. जैसे, टेलीफ़ोनी या इको कैंसल करने के लिए
- कर्नल में मौजूद ऑडियो ड्राइवर के अंदर
- AudioTrack या AudioRecord कॉलबैक थ्रेड और ऐप्लिकेशन के अन्य थ्रेड के बीच (यह हमारे कंट्रोल से बाहर है)
आम तौर पर इस्तेमाल होने वाले समाधान
आम तौर पर इस्तेमाल होने वाले समाधानों में ये शामिल हैं:
- इंटरप्ट बंद करना
- प्रायॉरिटी इनहेरिटेंस म्यूटेक्स
Linux के उपयोगकर्ता स्पेस में इंटरप्ट बंद करना मुमकिन नहीं है. साथ ही, यह सिमेट्रिक मल्टी-प्रोसेसर (एसएमपी) के लिए काम नहीं करता.
ऑडियो सिस्टम में, प्रायॉरिटी इनहेरिटेंस फ़्यूटेक्स (फ़ास्ट यूज़र-स्पेस म्यूटेक्स) का इस्तेमाल नहीं किया जाता. इसकी वजह यह है कि ये अपेक्षाकृत भारी होते हैं. साथ ही, ये भरोसेमंद क्लाइंट पर निर्भर करते हैं.
Android में इस्तेमाल की जाने वाली तकनीकें
एक्सपेरिमेंट, "ट्राई लॉक" और टाइम आउट के साथ लॉक से शुरू हुए. ये म्यूटेक्स लॉक ऑपरेशन के नॉन-ब्लॉकिंग और बाउंडेड ब्लॉकिंग वैरिएंट हैं. ट्राई लॉक और टाइम आउट के साथ लॉक, काफ़ी अच्छी तरह से काम करते थे. हालांकि, इनमें गड़बड़ी के कुछ ऐसे मोड थे जिनके बारे में कम ही पता था. जैसे, अगर क्लाइंट बिज़ी है, तो सर्वर के शेयर किए गए स्टेट को ऐक्सेस करने की कोई गारंटी नहीं थी. साथ ही, अगर बिना किसी संबंध वाले लॉक की लंबी सीरीज़ थी और सभी का टाइम आउट हो गया था, तो कुल टाइम आउट बहुत ज़्यादा हो सकता था.
हम एटॉमिक ऑपरेशन का भी इस्तेमाल करते हैं. जैसे:
- ज़्यादा
- बिटवाइज़ "ऑर"
- बिटवाइज़ "एंड"
इन सभी से पिछली वैल्यू मिलती है और इनमें ज़रूरी एसएमपी बैरियर शामिल होते हैं. इसका नुकसान यह है कि इनमें अनगिनत बार फिर से कोशिश करनी पड़ सकती है. असल में, हमने पाया है कि फिर से कोशिश करने में कोई समस्या नहीं होती.
ध्यान दें: एटॉमिक ऑपरेशन और मेमोरी बैरियर के साथ उनके इंटरैक्शन को गलत तरीके से समझा और इस्तेमाल किया जाता है. हमने यहां इन तरीकों को पूरी जानकारी देने के लिए शामिल किया है. हालांकि, हमारा सुझाव है कि ज़्यादा जानकारी के लिए, Android के लिए एसएमपी प्राइमर लेख भी पढ़ें.
हमारे पास अब भी ऊपर बताए गए ज़्यादातर टूल मौजूद हैं और हम उनका इस्तेमाल करते हैं. साथ ही, हमने हाल ही में ये तकनीकें जोड़ी हैं:
- डेटा के लिए, नॉन-ब्लॉकिंग सिंगल-रीडर सिंगल-राइटर FIFO क्यू का इस्तेमाल करें.
- ज़्यादा और कम प्राथमिकता वाले मॉड्यूल के बीच, स्टेट को शेयर करने के बजाय, कॉपी करने की कोशिश करें.
- अगर स्टेट को शेयर करना ज़रूरी है, तो स्टेट को ज़्यादा से ज़्यादा साइज़ वाले शब्द तक सीमित रखें जिसे बिना फिर से कोशिश किए, एक बस ऑपरेशन में एटॉमिक तरीके से ऐक्सेस किया जा सके.
- मल्टी-वर्ड स्टेट के लिए, स्टेट क्यू का इस्तेमाल करें. स्टेट क्यू, असल में नॉन-ब्लॉकिंग सिंगल-रीडर सिंगल-राइटर FIFO क्यू होता है. इसका इस्तेमाल डेटा के बजाय स्टेट के लिए किया जाता है. हालांकि, राइटर, आस-पास के पुश को एक पुश में बदल देता है.
- एसएमपी की सही जानकारी के लिए, मेमोरी बैरियर पर ध्यान दें.
- भरोसा करें, लेकिन पुष्टि करें. प्रोसेस के बीच स्टेट शेयर करते समय, यह न मान लें कि स्टेट सही फ़ॉर्मैट में है. उदाहरण के लिए, देखें कि इंडेक्स, बाउंड के अंदर हैं या नहीं. एक ही प्रोसेस में मौजूद थ्रेड के बीच, एक-दूसरे पर भरोसा करने वाली प्रोसेस (जिनका यूआईडी आम तौर पर एक ही होता है) के बीच, इस पुष्टि की ज़रूरत नहीं होती. शेयर किए गए डेटा के लिए भी इसकी ज़रूरत नहीं होती. जैसे, पीसीएम ऑडियो, जिसमें गड़बड़ी होने पर कोई फ़र्क़ नहीं पड़ता.
नॉन-ब्लॉकिंग एल्गोरिदम
नॉन-ब्लॉकिंग एल्गोरिदम हाल ही में किए गए कई अध्ययनों का विषय रहे हैं. हालांकि, सिंगल-रीडर सिंगल-राइटर FIFO क्यू को छोड़कर, हमने पाया है कि ये जटिल और गड़बड़ी वाले होते हैं.
Android 4.2 से, आपको नॉन-ब्लॉकिंग, सिंगल-रीडर/राइटर क्लास इन जगहों पर मिल सकती हैं:
- frameworks/av/include/media/nbaio/
- frameworks/av/media/libnbaio/
- frameworks/av/services/audioflinger/StateQueue*
इन्हें खास तौर पर AudioFlinger के लिए डिज़ाइन किया गया है. ये सामान्य इस्तेमाल के लिए नहीं हैं. नॉन-ब्लॉकिंग एल्गोरिदम को डीबग करना मुश्किल होता है. इस कोड को मॉडल के तौर पर देखा जा सकता है. हालांकि, ध्यान रखें कि इसमें गड़बड़ियां हो सकती हैं. साथ ही, इस बात की कोई गारंटी नहीं है कि ये क्लास अन्य उद्देश्यों के लिए सही होंगी.
डेवलपर के लिए, OpenSL ES ऐप्लिकेशन कोड के कुछ सैंपल को नॉन-ब्लॉकिंग एल्गोरिदम का इस्तेमाल करने या Android के अलावा किसी ओपन सोर्स लाइब्रेरी का रेफ़रंस देने के लिए अपडेट किया जाना चाहिए.
हमने नॉन-ब्लॉकिंग FIFO को लागू करने का एक उदाहरण पब्लिश किया है. इसे खास तौर पर ऐप्लिकेशन कोड के लिए डिज़ाइन किया गया है. प्लेटफ़ॉर्म सोर्स डायरेक्ट्री frameworks/av/audio_utils में मौजूद इन फ़ाइलों को देखें:
टूल
हमारी जानकारी के मुताबिक, प्रायॉरिटी इन्वर्ज़न की समस्या को ढूंढने के लिए कोई ऑटोमैटिक टूल नहीं है. खास तौर पर, समस्या होने से पहले. स्टैटिक कोड विश्लेषण के कुछ रिसर्च टूल, प्रायॉरिटी इन्वर्ज़न की समस्या को ढूंढ सकते हैं. हालांकि, इसके लिए उन्हें पूरे कोडबेस को ऐक्सेस करना होगा. ज़ाहिर है कि अगर इसमें उपयोगकर्ता का कोई कोड शामिल है (जैसा कि यहां ऐप्लिकेशन के लिए है) या यह एक बड़ा कोड बेस है (जैसे, Linux कर्नेल और डिवाइस ड्राइवर के लिए), तो स्टैटिक विश्लेषण करना मुश्किल हो सकता है. सबसे ज़रूरी बात यह है कि कोड को ध्यान से पढ़ें और पूरे सिस्टम और इंटरैक्शन को अच्छी तरह से समझें. systrace और
जैसे टूल, प्रायॉरिटी इन्वर्ज़न की समस्या होने के बाद उसे देखने के लिए काम के हैं. हालांकि, ये आपको पहले से इसकी जानकारी नहीं देते.ps -t -p
आखिरी बात
इस पूरी चर्चा के बाद, म्यूटेक्स से न डरें. सामान्य इस्तेमाल के लिए, म्यूटेक्स आपके काम के हैं. हालांकि, इनका इस्तेमाल और इन्हें लागू सही तरीके से किया जाना चाहिए. साथ ही, इनका इस्तेमाल ऐसे मामलों में किया जाना चाहिए जिनमें समय की पाबंदी न हो. हालांकि, ज़्यादा और कम प्राथमिकता वाले टास्क के बीच और समय के हिसाब से ज़रूरी सिस्टम में, म्यूटेक्स की वजह से समस्या होने की संभावना ज़्यादा होती है.