प्राथमिकता के उलट होने से बचना

इस लेख में बताया गया है कि Android का ऑडियो सिस्टम, प्राथमिकता बदलने से कैसे बचने की कोशिश करता है. साथ ही, इसमें उन तकनीकों के बारे में भी बताया गया है जिनका इस्तेमाल आप भी कर सकते हैं.

ये तकनीकें, बेहतर परफ़ॉर्मेंस वाले ऑडियो ऐप्लिकेशन के डेवलपर, OEM, और SoC सेवा देने वाली कंपनियों के लिए काम की हो सकती हैं. ये कंपनियां ऑडियो एचएएल लागू कर रही हैं. कृपया ध्यान दें कि इन तकनीकों को लागू करने से, गड़बड़ियों या अन्य समस्याओं को रोकने की गारंटी नहीं मिलती. ऐसा खास तौर पर तब होता है, जब इनका इस्तेमाल ऑडियो कॉन्टेक्स्ट के बाहर किया जाता है. आपके नतीजे अलग-अलग हो सकते हैं. इसलिए, आपको खुद ही आकलन और जांच करनी चाहिए.

बैकग्राउंड

इंतज़ार का समय कम करने के लिए, Android AudioFlinger ऑडियो सर्वर और AudioTrack/AudioRecord क्लाइंट को फिर से डिज़ाइन किया जा रहा है. यह काम Android 4.1 में शुरू हुआ था. इसके बाद, 4.2, 4.3, 4.4, और 5.0 में इसे और बेहतर बनाया गया.

इंतज़ार का समय कम करने के लिए, पूरे सिस्टम में कई बदलाव करने पड़े. एक अहम बदलाव यह है कि ज़्यादा समय लेने वाली थ्रेड के लिए, शेड्यूलिंग की ज़्यादा अनुमानित नीति के साथ सीपीयू संसाधन असाइन किए जाते हैं. भरोसेमंद शेड्यूलिंग की सुविधा से, ऑडियो बफ़र के साइज़ और संख्या को कम किया जा सकता है. साथ ही, ऑडियो के कम या ज़्यादा चलने से भी बचा जा सकता है.

प्राथमिकता में बदलाव

प्रायॉरिटी इन्वर्ज़न, रीयल-टाइम सिस्टम में गड़बड़ी का एक सामान्य मोड है. इसमें, ज़्यादा प्राथमिकता वाले टास्क को अनलिमिटेड समय के लिए ब्लॉक किया जाता है. ऐसा तब होता है, जब ज़्यादा प्राथमिकता वाले टास्क के लिए ज़रूरी संसाधन, कम प्राथमिकता वाले टास्क के पास हो. जैसे, म्यूटेक्स से सुरक्षित किया गया शेयर किया गया स्टेटस.

ऑडियो सिस्टम में, प्राथमिकता उलटने की समस्या आम तौर पर गड़बड़ी (क्लिक, पॉप, ड्रॉपआउट) के तौर पर दिखती है. यह तब होता है, जब सर्कुलर बफ़र का इस्तेमाल किया जाता है या किसी निर्देश का जवाब देने में देरी होती है. साथ ही, ऑडियो दोहराने की समस्या भी हो सकती है.

प्राथमिकता बदलने की समस्या को हल करने का एक सामान्य तरीका यह है कि ऑडियो बफ़र का साइज़ बढ़ाया जाए. हालांकि, इस तरीके से इंतज़ार का समय बढ़ जाता है और समस्या को हल करने के बजाय, उसे छिपा दिया जाता है. प्राथमिकता के उलट होने की समस्या को समझना और इससे बचना बेहतर है. इस बारे में यहां बताया गया है.

Android ऑडियो लागू करने के दौरान, प्राथमिकता बदलने की समस्या इन जगहों पर सबसे ज़्यादा होने की संभावना होती है. इसलिए, आपको इन बातों पर ध्यान देना चाहिए:

  • AudioFlinger में सामान्य मिक्सर थ्रेड और फ़ास्ट मिक्सर थ्रेड के बीच
  • फ़ास्ट ऑडियो ट्रैक और फ़ास्ट मिक्सर थ्रेड के लिए, ऐप्लिकेशन कॉलबैक थ्रेड के बीच (दोनों की प्राथमिकता बढ़ाई गई है, लेकिन थोड़ी अलग प्राथमिकताएं हैं)
  • फ़ास्ट ऑडियो रिकॉर्ड के लिए ऐप्लिकेशन कॉलबैक थ्रेड और फ़ास्ट कैप्चर थ्रेड के बीच (पिछले जैसा)
  • ऑडियो हार्डवेयर ऐब्स्ट्रैक्शन लेयर (एचएएल) के लागू होने के दौरान, जैसे कि टेलीफ़ोन या गूंज को कम करने के लिए
  • कर्नेल में ऑडियो ड्राइवर में
  • AudioTrack या AudioRecord कॉलबैक थ्रेड और ऐप्लिकेशन की अन्य थ्रेड के बीच (यह हमारे कंट्रोल से बाहर है)

सामान्य समस्याओं के समाधान

आम तौर पर, ये समस्याएं हल करने के लिए ये तरीके अपनाए जा सकते हैं:

  • रुकावटें बंद करना
  • प्राथमिकता इनहेरिटेंस म्यूटेक्स

Linux उपयोगकर्ता स्पेस में, इंटरप्ट बंद नहीं किए जा सकते. साथ ही, यह सुविधा सिमेट्रिक मल्टी-प्रोसेसर (एसएमपी) के लिए काम नहीं करती.

ऑडियो सिस्टम में प्राथमिकता इनहेरिटेंस futexes (फ़ास्ट यूज़र-स्पेस म्यूटेक्स) का इस्तेमाल नहीं किया जाता, क्योंकि ये अपेक्षाकृत ज़्यादा भारी होते हैं और भरोसेमंद क्लाइंट पर निर्भर होते हैं.

Android के इस्तेमाल की जाने वाली तकनीकें

"लॉक करने की कोशिश करें" और टाइम आउट के साथ लॉक करने की सुविधा के लिए एक्सपेरिमेंट शुरू किए गए. ये, म्यूटेक्स लॉक ऑपरेशन के नॉन-ब्लॉकिंग और बाउंडेड ब्लॉकिंग वैरिएंट हैं. 'लॉक करें' और 'लॉक करें और टाइम आउट' फ़ंक्शन काफ़ी अच्छी तरह से काम करते हैं. हालांकि, इनमें कुछ गड़बड़ियां हो सकती हैं: अगर क्लाइंट व्यस्त है, तो यह गारंटी नहीं है कि सर्वर, शेयर की गई स्थिति को ऐक्सेस कर पाएगा. साथ ही, अगर एक-दूसरे से जुड़े नहीं होने वाले लॉक का लंबा क्रम है और सभी लॉक का टाइम आउट हो गया है, तो कुल टाइम आउट बहुत ज़्यादा हो सकता है.

हम एटॉमिक ऑपरेशन का भी इस्तेमाल करते हैं. जैसे:

  • ज़्यादा
  • बिटवाइज़ "या"
  • बिटवाइज़ "और"

ये सभी फ़ंक्शन पिछली वैल्यू दिखाते हैं और ज़रूरी एसएमपी बैरियर शामिल करते हैं. हालांकि, इनका नुकसान यह है कि इनमें अनगिनत बार कोशिश करनी पड़ सकती है. हमने पाया है कि बार-बार कोशिश करने से कोई समस्या नहीं होती.

ध्यान दें: एटॉमिक ऑपरेशन और मेमोरी बैरियर के साथ उनके इंटरैक्शन को बहुत गलत तरीके से समझा जाता है और उनका गलत इस्तेमाल किया जाता है. हम यहां इन तरीकों को इसलिए शामिल करते हैं, ताकि आपको पूरी जानकारी मिल सके. हालांकि, हमारा सुझाव है कि ज़्यादा जानकारी के लिए, Android के लिए एसएमपी प्राइमर लेख भी पढ़ें.

हम अब भी ऊपर बताए गए ज़्यादातर टूल इस्तेमाल करते हैं. साथ ही, हमने हाल ही में ये तकनीकें जोड़ी हैं:

  • डेटा के लिए, नॉन-ब्लॉकिंग सिंगल-रीडर सिंगल-राइटर्स एफ़आईएफ़ओ कतारें इस्तेमाल करें.
  • ज़्यादा और कम प्राथमिकता वाले मॉड्यूल के बीच, स्थिति को शेयर करने के बजाय, कॉपी करने की कोशिश करें.
  • जब स्टेटस शेयर करना ज़रूरी हो, तो स्टेटस को ज़्यादा से ज़्यादा साइज़ वाले शब्द तक सीमित करें. इस स्टेटस को, एक बार कोशिश करने के बाद, एक बस ऑपरेशन में ऐटॉमिक तौर पर ऐक्सेस किया जा सकता है.
  • एक से ज़्यादा शब्दों वाली जटिल स्थिति के लिए, स्टेटस कतार का इस्तेमाल करें. स्टेटस क्यू, मूल रूप से एक नॉन-ब्लॉकिंग सिंगल-रीडर सिंगल-राइटर्स एफ़आईएफ़ओ क्यू होती है. इसका इस्तेमाल डेटा के बजाय स्टेटस के लिए किया जाता है. हालांकि, राइटर्स आस-पास के पुश को एक ही पुश में बदल देता है.
  • एसएमपी के सही तरीके से काम करने के लिए, मेमोरी बैरियर पर ध्यान दें.
  • भरोसा करें, लेकिन पुष्टि करें. प्रोसेस के बीच स्टेटस शेयर करते समय, यह न मानें कि स्टेटस सही है. उदाहरण के लिए, देखें कि इंडेक्स तय सीमा में हैं या नहीं. एक ही प्रोसेस में मौजूद थ्रेड के बीच, एक-दूसरे पर भरोसा करने वाली प्रोसेस (जिनमें आम तौर पर एक ही यूआईडी होता है) के बीच, इस पुष्टि की ज़रूरत नहीं होती. यह शेयर किए गए डेटा के लिए भी ज़रूरी नहीं है, जैसे कि PCM ऑडियो, जहां डेटा खराब होने से कोई फ़र्क़ नहीं पड़ता.

मिलते-जुलते वीडियो को ब्लॉक न करने वाले एल्गोरिदम

बिना ब्लॉक करने वाले एल्गोरिदम पर हाल ही में काफ़ी रिसर्च की गई है. हालांकि, हमें एक रीडर और एक लेखक वाली 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 जैसे टूल, प्राथमिकता बदलने की समस्या होने के बाद उसे देखने के लिए काम के होते हैं. हालांकि, ये आपको पहले से इसकी जानकारी नहीं देते.

आखिरी बात

इस पूरी चर्चा के बाद, म्यूटेक्स से डरें नहीं. सामान्य तौर पर इस्तेमाल करने के लिए, म्यूटेक्स आपके काम के होते हैं. हालांकि, इन्हें सही तरीके से इस्तेमाल करने के लिए ज़रूरी है कि इन्हें सामान्य और समय के हिसाब से ज़रूरी न होने वाले इस्तेमाल के उदाहरणों में लागू किया जाए. हालांकि, ज़्यादा और कम प्राथमिकता वाले टास्क के बीच और समय के हिसाब से काम करने वाले सिस्टम में, म्यूटेक्स से समस्या होने की संभावना ज़्यादा होती है.