OpenSL ES प्रोग्रामिंग नोट

चेतावनी: OpenSL ES का इस्तेमाल अब नहीं किया जा सकता. डेवलपर को GitHub पर उपलब्ध ओपन सोर्स Oboe लाइब्रेरी का इस्तेमाल करना चाहिए. Omoe एक C++ रैपर है, जो AAudio से मिलता-जुलता एपीआई उपलब्ध कराता है. AAudio उपलब्ध होने पर, Oboe इसकी मदद लेता है. अगर AAudio उपलब्ध नहीं है, तो यह OpenSL ES का इस्तेमाल करता है.

इस सेक्शन में दिए गए नोट, OpenSL ES 1.0.1 के स्पेसिफ़िकेशन के साथ काम करते हैं.

ऑब्जेक्ट और इंटरफ़ेस को शुरू करना

OpenSL ES प्रोग्रामिंग मॉडल के दो पहलू, जो शायद नए डेवलपर के लिए अनजान हों, वे हैं ऑब्जेक्ट और इंटरफ़ेस में फ़र्क़, और इनिशलाइज़ेशन सीक्वेंस.

कम शब्दों में, OpenSL ES ऑब्जेक्ट, Java और C++ जैसी प्रोग्रामिंग भाषाओं में ऑब्जेक्ट के कॉन्सेप्ट से मिलता-जुलता है. हालांकि, OpenSL ES ऑब्जेक्ट सिर्फ़ अपने इंटरफ़ेस के ज़रिए दिखता है. इसमें सभी ऑब्जेक्ट के लिए शुरुआती इंटरफ़ेस शामिल होता है, जिसे SLObjectItf कहा जाता है. ऑब्जेक्ट के लिए कोई हैंडल नहीं होता, सिर्फ़ ऑब्जेक्ट के SLObjectItf इंटरफ़ेस का हैंडल होता है.

पहले OpenSL ES ऑब्जेक्ट बनाया जाता है, जो SLObjectItf दिखाता है. इसके बाद, उसे लागू किया जाता है. यह पहले किसी ऑब्जेक्ट को बनाने के सामान्य प्रोग्रामिंग पैटर्न से मिलता-जुलता है (जो मेमोरी या अमान्य पैरामीटर की कमी के अलावा, कभी भी काम करना बंद नहीं करना चाहिए). इसके बाद, यह प्रोसेस शुरू करने (जो संसाधनों की कमी की वजह से काम नहीं कर सकता) को पूरा करता है. 'लागू करें' चरण में, ज़रूरत पड़ने पर ज़्यादा संसाधनों को तय करने के लिए, लागू करने की प्रक्रिया को एक सही जगह मिलती है.

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

ऑब्जेक्ट बनाने और उसे लागू करने के बाद, ऐप्लिकेशन को अपनी ज़रूरत के हिसाब से हर सुविधा के लिए इंटरफ़ेस हासिल करने चाहिए. इसके लिए, शुरुआती SLObjectItf पर GetInterface का इस्तेमाल करें.

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

अपने ऐप्लिकेशन के लिए ऑब्जेक्ट का इस्तेमाल करने के बाद, आपको साफ़ तौर पर उसे मिटा देना चाहिए. इसके लिए, नीचे दिया गया मिटाएं सेक्शन देखें.

ऑडियो प्लेयर के लिए, कॉन्टेंट को पहले से लोड करना

यूआरआई डेटा सोर्स वाले ऑडियो प्लेयर के लिए, Object::Realize संसाधनों को आवंटित करता है. हालांकि, वह डेटा सोर्स से कनेक्ट नहीं करता (तैयार नहीं करता) या डेटा को पहले से फ़ेच करना शुरू नहीं करता. ये तब होते हैं, जब खिलाड़ी की स्थिति को SL_PLAYSTATE_PAUSED या SL_PLAYSTATE_PLAYING पर सेट किया जाता है.

इस क्रम में, कुछ जानकारी देर से मिल सकती है. खास तौर पर, शुरुआत में Player::GetDuration, SL_TIME_UNKNOWN दिखाता है और MuteSolo::GetChannelCount, चैनल की संख्या शून्य होने पर सही नतीजा दिखाता है या गड़बड़ी का नतीजा SL_RESULT_PRECONDITIONS_VIOLATED दिखाता है. ये एपीआई, जानकारी मिलने के बाद सही वैल्यू दिखाते हैं.

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

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

प्रीफ़ेच स्टेटस इंटरफ़ेस, गड़बड़ियों का पता लगाने में भी मददगार होता है. कॉलबैक रजिस्टर करें और कम से कम SL_PREFETCHEVENT_FILLLEVELCHANGE और SL_PREFETCHEVENT_STATUSCHANGE इवेंट चालू करें. अगर ये दोनों इवेंट एक साथ डिलीवर किए जाते हैं और PrefetchStatus::GetFillLevel शून्य लेवल की रिपोर्ट करता है और PrefetchStatus::GetPrefetchStatus SL_PREFETCHSTATUS_UNDERFLOW की रिपोर्ट करता है, तो इससे पता चलता है कि डेटा सोर्स में ऐसी गड़बड़ी है जिसे ठीक नहीं किया जा सकता. इसमें, डेटा सोर्स से कनेक्ट न कर पाना शामिल है, क्योंकि लोकल फ़ाइल नाम मौजूद नहीं है या नेटवर्क यूआरआई अमान्य है.

OpenSL ES के अगले वर्शन में, डेटा सोर्स में गड़बड़ियों को मैनेज करने के लिए, ज़्यादा सटीक सहायता जोड़ी जाएगी. हालांकि, आने वाले समय में बाइनरी के साथ काम करने के लिए, हम ऐसी गड़बड़ी की शिकायत करने के लिए, मौजूदा तरीके का इस्तेमाल करना जारी रखेंगे जिसे ठीक नहीं किया जा सकता.

खास जानकारी के तौर पर, कोड का सुझाया गया क्रम यह है:

  1. Engine::CreateAudioPlayer
  2. Object:Realize
  3. SL_IID_PREFETCHSTATUS के लिए Object::GetInterface
  4. PrefetchStatus::SetCallbackEventsMask
  5. PrefetchStatus::SetFillUpdatePeriod
  6. PrefetchStatus::RegisterCallback
  7. SL_IID_PLAY के लिए Object::GetInterface
  8. Play::SetPlayState से SL_PLAYSTATE_PAUSED या SL_PLAYSTATE_PLAYING

ध्यान दें: यहां तैयारी और डेटा को पहले से लोड करने की प्रोसेस होती है. इस दौरान, स्थिति के बारे में समय-समय पर अपडेट देने के लिए, आपके कॉलबैक को कॉल किया जाता है.

खत्म करें

अपने ऐप्लिकेशन से बाहर निकलते समय, सभी ऑब्जेक्ट को मिटाना न भूलें. ऑब्जेक्ट को बनाने के क्रम के उलट, उन्हें मिटाना चाहिए. ऐसा इसलिए, क्योंकि किसी ऐसे ऑब्जेक्ट को मिटाना सुरक्षित नहीं है जिसमें कोई डिपेंडेंट ऑब्जेक्ट हो. उदाहरण के लिए, इस क्रम में मिटाएं: ऑडियो प्लेयर और रिकॉर्डर, आउटपुट मिक्स, और आखिर में इंजन.

OpenSL ES, अपने-आप ग़ैर-ज़रूरी डेटा हटाने या इंटरफ़ेस के रेफ़रंस की गिनती करने की सुविधा के साथ काम नहीं करता. Object::Destroy को कॉल करने के बाद, इससे जुड़े ऑब्जेक्ट से बने सभी मौजूदा इंटरफ़ेस अनपब्लिश हो जाते हैं.

Android OpenSL ES को लागू करने की वजह से, ऐसे इंटरफ़ेस के गलत इस्तेमाल का पता नहीं चलता. ऑब्जेक्ट के खत्म होने के बाद भी ऐसे इंटरफ़ेस का इस्तेमाल करने से, आपका ऐप्लिकेशन क्रैश हो सकता है या अप्रत्याशित तरीके से काम कर सकता है.

हमारा सुझाव है कि आप ऑब्जेक्ट को मिटाने के क्रम के तहत, प्राइमरी ऑब्जेक्ट इंटरफ़ेस और उससे जुड़े सभी इंटरफ़ेस को NULL पर सेट करें. इससे, किसी पुराने इंटरफ़ेस हैंडल का गलती से गलत इस्तेमाल होने से रोका जा सकता है.

स्टीरियो पैनिंग

किसी मोनो सोर्स के स्टीरियो पैनिंग को चालू करने के लिए Volume::EnableStereoPosition का इस्तेमाल करने पर, साउंड पावर लेवल में 3-dB की कमी आती है. ऐसा करना इसलिए ज़रूरी है, ताकि साउंड पावर के कुल लेवल को एक जैसा रखा जा सके. ऐसा इसलिए, क्योंकि सोर्स को एक चैनल से दूसरे चैनल पर पैन किया जाता है. इसलिए, स्टीरियो पोज़िशनिंग की सुविधा सिर्फ़ तब चालू करें, जब आपको इसकी ज़रूरत हो. ज़्यादा जानकारी के लिए, ऑडियो पैनिंग के बारे में Wikipedia का लेख देखें.

कॉलबैक और थ्रेड

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

कॉलबैक हैंडलर को, ऐप्लिकेशन के बाहर मौजूद उन थ्रेड से कॉल किया जाता है जो Android रनटाइम से अटैच नहीं होते. इसलिए, वे JNI का इस्तेमाल नहीं कर सकते. ये इंटरनल थ्रेड, OpenSL ES को लागू करने के लिए ज़रूरी हैं. इसलिए, कॉलबैक हैंडलर को भी ज़्यादा काम नहीं करना चाहिए या ब्लॉक नहीं करना चाहिए.

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

ध्यान दें कि इसके उलट, JNI में शामिल Android ऐप्लिकेशन थ्रेड को सीधे तौर पर OpenSL ES API को कॉल करने की अनुमति है. इनमें वे API भी शामिल हैं जो ब्लॉक करते हैं. हालांकि, मुख्य थ्रेड से कॉल ब्लॉक करने का सुझाव नहीं दिया जाता, क्योंकि इससे ऐप्लिकेशन काम नहीं कर रहा (ANR) वाली गड़बड़ी हो सकती है.

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

इस बात की कोई गारंटी नहीं है कि जिस थ्रेड पर कॉलबैक हैंडलर चलता है उसमें अलग-अलग कॉल के लिए एक ही आइडेंटिटी हो. इसलिए, सभी कॉल में एक जैसा रहने के लिए pthread_self() से मिले pthread_t या gettid() से मिले pid_t पर भरोसा न करें. इसी वजह से, कॉलबैक से जुड़े pthread_setspecific() और pthread_getspecific() जैसे थ्रेड लोकल स्टोरेज (TLS) एपीआई का इस्तेमाल न करें.

लागू करने से यह गारंटी मिलती है कि एक ही ऑब्जेक्ट के लिए, एक ही तरह के एक ही समय में कॉलबैक नहीं होते हैं. हालांकि, एक ही ऑब्जेक्ट के लिए अलग-अलग तरह के कॉलबैक, अलग-अलग थ्रेड पर एक साथ हो सकते हैं.

परफ़ॉर्मेंस

OpenSL ES एक नेटिव C API है. इसलिए, OpenSL ES को कॉल करने वाली नॉन-रनटाइम ऐप्लिकेशन थ्रेड पर, रनटाइम से जुड़ा कोई ओवरहेड नहीं होता. जैसे, गै़रबेज कलेक्शन के लिए रुकना. यहां दिए गए एक अपवाद को छोड़ दें, इसमें इसके अलावा, OpenSL ES के इस्तेमाल से परफ़ॉर्मेंस से जुड़ा कोई अतिरिक्त फ़ायदा नहीं है. खास तौर पर, OpenSL ES का इस्तेमाल करने से इस बात की कोई गारंटी नहीं मिलती कि प्लैटफ़ॉर्म पर ऑडियो के लिए इंतज़ार का समय कम और शेड्यूल करने की प्राथमिकता ज़्यादा होगी. दूसरी ओर, Android प्लैटफ़ॉर्म और किसी खास डिवाइस पर लागू होने वाले सिस्टम में लगातार बदलाव होते रहते हैं. इसलिए, आने वाले समय में सिस्टम की परफ़ॉर्मेंस में होने वाले किसी भी सुधार से, OpenSL ES ऐप्लिकेशन को फ़ायदा मिल सकता है.

इनमें से एक, ऑडियो आउटपुट में लगने वाले समय को कम करने की सुविधा है. आउटपुट में लगने वाले समय को कम करने के लिए, सबसे पहले Android 4.1 (एपीआई लेवल 16) में इस सुविधा को शामिल किया गया था. इसके बाद, Android 4.2 (एपीआई लेवल 17) में इस सुविधा को और बेहतर बनाया गया. ये सुधार, डिवाइस में android.hardware.audio.low_latency सुविधा का दावा करने के लिए, OpenSL ES के ज़रिए उपलब्ध हैं. अगर डिवाइस इस सुविधा पर दावा नहीं करता, लेकिन Android 2.3 (एपीआई लेवल 9) या उसके बाद के वर्शन पर काम करता है, तो आपके पास अब भी OpenSL ES API का इस्तेमाल करने का विकल्प है. हालांकि, आउटपुट में लगने वाला समय ज़्यादा हो सकता है. कम आउटपुट इंतज़ार के समय का पाथ सिर्फ़ तब इस्तेमाल किया जाता है, जब ऐप्लिकेशन ऐसे बफ़र साइज़ और सैंपल रेट का अनुरोध करता है जो डिवाइस के नेटिव आउटपुट कॉन्फ़िगरेशन के साथ काम करते हैं. ये पैरामीटर, डिवाइस के हिसाब से होते हैं और इन्हें यहां बताए गए तरीके से हासिल किया जाना चाहिए.

Android 4.2 (एपीआई लेवल 17) से, कोई ऐप्लिकेशन डिवाइस की मुख्य आउटपुट स्ट्रीम के लिए, प्लैटफ़ॉर्म के नेटिव या ऑप्टिमाइज़ किए गए आउटपुट सैंपल रेट और बफ़र साइज़ के लिए क्वेरी कर सकता है. इस सुविधा की जांच के साथ, ऐप्लिकेशन अब उन डिवाइसों पर कम इंतज़ार के आउटपुट के लिए, अपने-आप सही तरीके से कॉन्फ़िगर हो सकता है जिन पर यह सुविधा काम करती है.

Android 4.2 (एपीआई लेवल 17) और उससे पहले के वर्शन के लिए, कम इंतज़ार के समय के लिए, दो या उससे ज़्यादा बफ़र की ज़रूरत होती है. Android 4.3 (एपीआई लेवल 18) से, इंतज़ार का समय कम करने के लिए, एक बफ़र काफ़ी है.

आउटपुट इफ़ेक्ट के लिए, OpenSL ES के सभी इंटरफ़ेस में, कम इंतज़ार वाले पाथ का इस्तेमाल नहीं किया जा सकता.

सुझाया गया क्रम यह है:

  1. OpenSL ES के इस्तेमाल की पुष्टि करने के लिए, एपीआई लेवल 9 या उससे ज़्यादा की जांच करें.
  2. इस तरह के कोड का इस्तेमाल करके, android.hardware.audio.low_latency सुविधा की जांच करें:

    Kotlin

    import android.content.pm.PackageManager
    ...
    val pm: PackageManager = context.packageManager
    val claimsFeature: Boolean = pm.hasSystemFeature(PackageManager.FEATURE_AUDIO_LOW_LATENCY)

    Java

    import android.content.pm.PackageManager;
    ...
    PackageManager pm = getContext().getPackageManager();
    boolean claimsFeature = pm.hasSystemFeature(PackageManager.FEATURE_AUDIO_LOW_LATENCY);
  3. android.media.AudioManager.getProperty() के इस्तेमाल की पुष्टि करने के लिए, एपीआई लेवल 17 या उसके बाद के लेवल की जांच करें.
  4. इस तरह के कोड का इस्तेमाल करके, इस डिवाइस के प्राइमरी आउटपुट स्ट्रीम के लिए, नेटिव या सबसे बेहतर आउटपुट सैंपल रेट और बफ़र साइज़ पाएं:

    Kotlin

    import android.media.AudioManager
    ...
    val am = getSystemService(Context.AUDIO_SERVICE) as AudioManager
    val sampleRate: String = am.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE)
    val framesPerBuffer: String = am.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER)

    Java

    import android.media.AudioManager;
    ...
    AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
    String sampleRate = am.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
    String framesPerBuffer = am.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER);
    ध्यान दें कि sampleRate और framesPerBuffer स्ट्रिंग हैं. सबसे पहले शून्य की जांच करें और फिर Integer.parseInt() का इस्तेमाल करके पूर्णांक में बदलें.
  5. अब PCM बफ़र कतार डेटा लोकेटर के साथ AudioPlayer बनाने के लिए, OpenSL ES का इस्तेमाल करें.

ध्यान दें: ऑडियो बफ़र साइज़ टेस्ट ऐप्लिकेशन का इस्तेमाल करके, अपने ऑडियो डिवाइस पर OpenSL ES ऑडियो ऐप्लिकेशन के लिए मूल बफ़र साइज़ और सैंपल रेट का पता लगाया जा सकता है. audio-buffer-size सैंपल देखने के लिए, GitHub पर भी जाया जा सकता है.

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

ऑडियो में आने वाली गड़बड़ियों से बचने के लिए, बफ़र कतार के कॉलबैक हैंडलर को कम और अनुमानित समयसीमा के अंदर पूरा करना होगा. आम तौर पर, इसका मतलब है कि म्यूटेक्स, शर्तों या I/O ऑपरेशन पर अनलिमिटेड ब्लॉकिंग नहीं है. इसके बजाय, try locks, लॉक, और टाइम आउट के साथ इंतज़ार करने की सुविधा का इस्तेमाल करें. साथ ही, ब्लॉक न करने वाले एल्गोरिदम का इस्तेमाल करें.

AudioPlayer के लिए, अगला बफ़र रेंडर करने या पिछले बफ़र का इस्तेमाल करने ( AudioRecord के लिए) को रेंडर करने के लिए ज़रूरी कंप्यूटेशन को हर कॉलबैक में करीब उतना ही समय लगेगा. ऐसे एल्गोरिदम इस्तेमाल करने से बचें जो तय समय में काम नहीं करते या जिनके कैलकुलेशन में बहुत ज़्यादा समय लगता है. अगर किसी दिए गए कॉलबैक में सीपीयू का बिताया गया समय, औसत से काफ़ी ज़्यादा होता है, तो कॉलबैक कंप्यूटेशन को काफ़ी ज़्यादा क्रैक किया जाता है. खास तौर पर, हैंडलर के सीपीयू एक्ज़ीक्यूशन में लगने वाले समय में ज़्यादा अंतर नहीं होना चाहिए. साथ ही, हैंडलर को अनलिमिटेड समय तक ब्लॉक नहीं किया जाना चाहिए.

कम इंतज़ार वाला ऑडियो सिर्फ़ इन आउटपुट के लिए उपलब्ध है:

कुछ डिवाइसों पर, स्पीकर में सुधार करने और उसे सुरक्षित रखने की सुविधा के लिए डिजिटल सिग्नल प्रोसेसिंग की वजह से, स्पीकर इंतज़ार का समय ज़्यादा होता है.

Android 5.0 (एपीआई लेवल 21) से, चुनिंदा डिवाइसों पर कम इंतज़ार वाला ऑडियो इनपुट काम करता है. इस सुविधा का फ़ायदा पाने के लिए, पहले इस बात की पुष्टि करें कि इंतज़ार का समय कम करने वाला आउटपुट ऊपर बताए गए तरीके से उपलब्ध है. इंतज़ार का समय कम करने वाले आउटपुट की सुविधा होना ज़रूरी है. इसके बाद, आउटपुट के लिए इस्तेमाल किए जाने वाले सैंपल रेट और बफ़र साइज़ के साथ ऑडियो रिकॉर्डर बनाएं. इनपुट इफ़ेक्ट के लिए OpenSL ES इंटरफ़ेस कम इंतज़ार का समय पाथ को रोकता है. रिकॉर्ड करने के लिए, रिकॉर्ड करने के लिए सेट किए गए SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION का इस्तेमाल किया जाना चाहिए. इससे, रिकॉर्डिंग में लगने वाला समय कम हो जाता है. यह सेटअप, डिवाइस के हिसाब से डिजिटल सिग्नल प्रोसेसिंग को बंद कर देता है. इससे इनपुट पाथ में लगने वाला समय बढ़ सकता है. रिकॉर्ड प्रीसेट के बारे में ज़्यादा जानकारी के लिए, ऊपर दिए गए Android कॉन्फ़िगरेशन इंटरफ़ेस सेक्शन देखें.

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

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

परफ़ॉर्मेंस मोड

OpenSL ES ने ऑडियो पाथ के लिए परफ़ॉर्मेंस मोड तय करने का एक तरीका पेश किया है. इसकी शुरुआत Android 7.1 (एपीआई लेवल 25) से हुई थी. आपके पास ये विकल्प हैं:

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

ध्यान दें: अगर आपको इंतज़ार का समय कम रखना है और आपको डिवाइस में पहले से मौजूद ऑडियो इफ़ेक्ट का फ़ायदा लेना है, (जैसे कि वीडियो चलाने के लिए अकूस्टिक क्वालिटी को बेहतर बनाना), तो आपको परफ़ॉर्मेंस मोड को SL_ANDROID_PERFORMANCE_NONE पर सेट करना होगा.

परफ़ॉर्मेंस मोड सेट करने के लिए, आपको Android कॉन्फ़िगरेशन इंटरफ़ेस का इस्तेमाल करके SetConfiguration को कॉल करना होगा, जैसा कि यहां दिखाया गया है:

  // Obtain the Android configuration interface using a previously configured SLObjectItf.
  SLAndroidConfigurationItf configItf = nullptr;
  (*objItf)->GetInterface(objItf, SL_IID_ANDROIDCONFIGURATION, &configItf);

  // Set the performance mode.
  SLuint32 performanceMode = SL_ANDROID_PERFORMANCE_NONE;
    result = (*configItf)->SetConfiguration(configItf, SL_ANDROID_KEY_PERFORMANCE_MODE,
                                                     &performanceMode, sizeof(performanceMode));

सुरक्षा और अनुमतियां

Android में सुरक्षा, प्रोसेस लेवल पर की जाती है. इससे यह तय होता है कि कौन क्या कर सकता है. Java प्रोग्रामिंग भाषा का कोड, नेटिव कोड से ज़्यादा कुछ नहीं कर सकता. इसके अलावा, नेटिव कोड भी Java प्रोग्रामिंग भाषा के कोड से ज़्यादा कुछ नहीं कर सकता. इन दोनों के बीच का अंतर सिर्फ़ उपलब्ध एपीआई है.

OpenSL ES का इस्तेमाल करने वाले ऐप्लिकेशन को उन अनुमतियों का अनुरोध करना होगा जो एक जैसे नॉन-नेटिव एपीआई के लिए ज़रूरी हैं. उदाहरण के लिए, अगर आपका ऐप्लिकेशन ऑडियो रिकॉर्ड करता है, तो उसे android.permission.RECORD_AUDIO की अनुमति की ज़रूरत होगी. ऑडियो इफ़ेक्ट का इस्तेमाल करने वाले ऐप्लिकेशन के लिए ज़रूरी है कि android.permission.MODIFY_AUDIO_SETTINGS. नेटवर्क यूआरआई संसाधनों को चलाने वाले ऐप्लिकेशन को android.permission.NETWORK की ज़रूरत होती है. ज़्यादा जानकारी के लिए, सिस्टम अनुमतियों के साथ काम करना लेख पढ़ें.

प्लैटफ़ॉर्म के वर्शन और लागू करने के तरीके के आधार पर, मीडिया कॉन्टेंट पार्स करने वाले टूल और सॉफ़्टवेयर कोडेक, OpenSL ES को कॉल करने वाले Android ऐप्लिकेशन के कॉन्टेक्स्ट में चल सकते हैं. हार्डवेयर कोडेक, डिवाइस के हिसाब से अलग-अलग होते हैं. पार्स करने वाले टूल और कोडेक की कमजोरियों का फ़ायदा उठाने के लिए बनाया गया गलत कॉन्टेंट, हमले का एक जाना-पहचाना तरीका है. हमारा सुझाव है कि आप सिर्फ़ भरोसेमंद सोर्स से मीडिया चलाएं या अपने ऐप्लिकेशन को इस तरह से बांटें कि भरोसेमंद सोर्स से मिलने वाले मीडिया को मैनेज करने वाला कोड, सैंडबॉक्स वाले एनवायरमेंट में चलता हो. उदाहरण के लिए, गैर-भरोसेमंद सोर्स से मीडिया को किसी अलग प्रोसेस में प्रोसेस किया जा सकता है. हालांकि, दोनों प्रोसेस अब भी एक ही यूआईडी के तहत चलेंगी, लेकिन अलग-अलग होने की वजह से हमले को रोकना ज़्यादा आसान हो जाता है.