Android 17 (एपीआई लेवल 37) से, Android ने कंप्रेस किए गए ऑडियो फ़ॉर्मैट के लिए इन-प्रोसेस सॉफ़्टवेयर ऑडियो डिकोडर पेश किए हैं. इन्हें Google Play सिस्टम अपडेट (मेनलाइन एपेक्स मॉड्यूल) के ज़रिए अपडेट किया जाता है. इनमें Opus और AAC शामिल हैं.
ऑडियो डिकोडर को अलग सैंडबॉक्स वाली सिस्टम प्रोसेस में चलाने के बजाय, सीधे तौर पर ऐप्लिकेशन की प्रोसेस में चलाने से, ऐप्लिकेशन ऑडियो डिकोडिंग में लगने वाले समय को लगभग 40% तक कम कर सकते हैं. साथ ही, सीपीयू के इस्तेमाल को कम कर सकते हैं. इसके अलावा, लगातार मीडिया चलाने, वॉइस मैसेज भेजने, और गेम खेलने के दौरान बैटरी लाइफ़ को बढ़ाया जा सकता है.
मुख्य प्रोसेस से हटकर काम करने वाले डीकोडर बनाम मुख्य प्रोसेस में काम करने वाले डीकोडर
पहले, Android सभी प्लैटफ़ॉर्म सॉफ़्टवेयर मीडिया डिकोडर को एक खास, सैंडबॉक्स किए गए सिस्टम डेमॉन (mediaswcodec) के अंदर चलाता था. ऐसा इसलिए किया जाता था, ताकि ऐप्लिकेशन और ओएस को खराब मीडिया बिटस्ट्रीम से सुरक्षित रखा जा सके. हालांकि, आउट-ऑफ़-प्रोसेस सैंडबॉक्सिंग से परफ़ॉर्मेंस पर असर पड़ता है:
- इंटर-प्रोसेस कम्यूनिकेशन (आईपीसी) में लगने वाला समय: डिकोडर को भेजे गए हर ऑडियो इनपुट फ़्रेम और बदले में मिले हर डिकोड किए गए पीसीएम ऑडियो बफ़र के लिए, क्रॉस-प्रोसेस बाइंडर आईपीसी सीरियलाइज़ेशन और कॉन्टेक्स्ट स्विचिंग की ज़रूरत होती है.
- शेयर की गई मेमोरी का ओवरहेड: इंटर-प्रोसेस बफ़र हैंडऑफ़ के लिए, शेयर की गई मेमोरी (
C2Buffer) को सिंक करने और कैश मेमोरी को मैनेज करने की ज़रूरत होती है. - शेड्यूलिंग से जुड़ी समस्या: सीपीयू पर ज़्यादा लोड होने की वजह से, ऐप्लिकेशन प्रोसेस और
mediaswcodecके बीच थ्रेड शेड्यूलिंग से जुड़ी समस्या हो सकती है. इससे कम समय में प्रोसेस होने वाले ऑडियो पाइपलाइन (जैसे कि DAW, VoIP कम्यूनिकेशन, और इंटरैक्टिव गेम) में बफ़रिंग की समस्या हो सकती है और ऑडियो रुक-रुककर चल सकता है.
मीडिया डिकोडर को इन-प्रोसेस में चलाने से, परफ़ॉर्मेंस से जुड़ी इन समस्याओं को सीधे तौर पर हल किया जा सकता है:
- आईपी इंटरप्रोसेस कम्यूनिकेशन (आईपीसी) की वजह से होने वाली देरी को कम करता है: यह Binder IPC लेन-देन और कॉन्टेक्स्ट स्विच को बायपास करता है. इससे एंड-टू-एंड डिकोडिंग में होने वाली देरी लगभग 40% तक कम हो जाती है.
- बफ़र ओवरहेड को कम करता है: ऑडियो बफ़र को सीधे तौर पर लोकल ऐप्लिकेशन की मेमोरी स्पेस में पास करता है. इसके लिए, क्रॉस-प्रोसेस शेयर की गई मेमोरी मैपिंग की ज़रूरत नहीं होती.
- शेड्यूलिंग में गड़बड़ी होने से रोकता है: यह ऐप्लिकेशन के प्राथमिकता वाले थ्रेड (जैसे, रीयलटाइम AAudio या Oboe थ्रेड) पर डिकोडिंग करता है. इससे सिस्टम पर ज़्यादा लोड होने पर, ऑडियो रुकने और बफ़र कम होने की समस्या नहीं होती.
Rust के साथ मेमोरी सुरक्षा
पहले, Android सॉफ़्टवेयर डिकोडर को अलग प्रोसेस (mediaswcodec) में आइसोलेट करता था. ऐसा इसलिए, क्योंकि डिकोडर बाहरी मीडिया फ़ाइलों से मिले ऐसे बिटस्ट्रीम को प्रोसेस करते हैं जिन पर भरोसा नहीं किया जा सकता. इससे मेमोरी करप्ट होने के जोखिम (जैसे, बफ़र ओवरफ़्लो) की आशंका बढ़ जाती है. इसलिए, यह सुरक्षा से जुड़ी एक बड़ी समस्या है.
Android, सॉफ़्टवेयर डिकोडर को सीधे तौर पर कॉल करने वाले ऐप्लिकेशन की प्रोसेस में सुरक्षित तरीके से ले जा सकता है. इसके लिए, उन्हें Rust जैसी मेमोरी-सेफ़ भाषाओं में लागू किया जाता है या उन्हें लाइटवेट फ़ॉल्ट आइसोलेशन (एलएफ़आई) की मदद से अलग किया जाता है.
Android, AAC (c2.android.inproc.aac.decoder) के लिए, आउट-ऑफ़-प्रोसेस सैंडबॉक्सिंग के ओवरहेड को सुरक्षित तरीके से कम करने की सुविधा देता है. इसके लिए, Android एक डिकोडर उपलब्ध कराता है. इसे प्योर रस्ट में लागू किया गया है या इसे सुरक्षित रस्ट फ़ॉरेन फ़ंक्शन इंटरफ़ेस (एफ़एफ़आई) हार्नेस से सुरक्षित किया गया है.
Rust को इन-प्रोसेस डिकोडिंग के लिए सुरक्षित माना जाता है. इसकी ये वजहें हैं:
- कंपाइल-टाइम मेमोरी सुरक्षा: Rust में मालिकाना हक, उधार लेने, और लाइफ़टाइम की जांच करने के लिए सख्त नियम हैं. इससे यह पक्का होता है कि मेमोरी को फ़्री करने के बाद या शेयर करते समय उसमें बदलाव करने के बाद, उसे ऐक्सेस नहीं किया जा सकता.
- सामान्य कमज़ोरियों को दूर करना: Rust, कंपाइल टाइम पर ही हीप बफ़र ओवरफ़्लो, स्टैक स्मैश, कलेक्शन से बाहर के डेटा को पढ़ने और लिखने, फ़्री किए गए मेमोरी ब्लॉक को फिर से इस्तेमाल करने से जुड़ी गड़बड़ियों, और डबल-फ़्री की कमज़ोरियों को पूरी तरह से रोकता है.
- रनटाइम सैंडबॉक्सिंग टैक्स नहीं लगता: मेमोरी की सुरक्षा को कंपाइल टाइम पर गणित के हिसाब से साबित किया जाता है. साथ ही, इसकी पुष्टि बाउंड्री की जांच करके की जाती है. इसलिए, Rust डिकोडर, ऐप्लिकेशन प्रोसेस के अंदर नेटिव स्पीड पर काम करते हैं. इसके लिए, पेज टेबल ट्रांज़िशन या हार्डवेयर सैंडबॉक्स कॉन्टेक्स्ट की ज़रूरत नहीं होती.
लाइटवेट फ़ॉल्ट आइसोलेशन (एलएफ़आई) की मदद से मेमोरी की सुरक्षा
Android, जटिल लेगसी C/C++ ऑडियो डिकोडर के लिए, प्रोसेस में सुरक्षा की सुविधा देता है. इन डिकोडर को अब तक Rust में नहीं लिखा गया है. खास तौर पर, Opus डिकोडर (c2.android.inproc.opus.decoder libopus की मदद से काम करता है) के लिए, Android लाइटवेट फ़ॉल्ट आइसोलेशन (एलएफ़आई) का इस्तेमाल करके, प्रोसेस में सुरक्षा की सुविधा देता है.
एलएफ़आई को C/C++ डिकोडर के लिए सुरक्षित माना जाता है. इसकी ये वजहें हैं:
- हार्डवेयर-गार्डेड लीनियर मेमोरी सैंडबॉक्सिंग: LFI, C/C++ कोडेक लाइब्रेरी को WebAssembly से मिले लीनियर मशीन कोड में कंपाइल करता है. यह कोड, हार्डवेयर-गार्डेड 4 जीबी लीनियर मेमोरी स्लॉट तक सीमित होता है.
- Linux Memory Protection Keys (
pku): एलएफ़आई, पते की जगह की अनुमतियों को बांटने के लिए Linux Memory Protection Keys (pku/pkey_mprotect) का इस्तेमाल करता है. आइसोलेट की गई लाइब्रेरी, असाइन किए गए 4 जीबी सैंडबॉक्स स्लॉट के बाहर की मेमोरी को न तो पढ़ सकती है और न ही उसमें लिख सकती है. - सिस्टम कॉल इंटरसेप्शन: सैंडबॉक्स में, होस्ट ओएस के सिस्टम कॉल (जैसे कि फ़ाइल I/O, नेटवर्क ऐक्सेस या प्रोसेस कंट्रोल) की अनुमति नहीं है. लाइब्रेरी के ऐसे कॉल जो काम नहीं करते उन्हें कम से कम डमी स्टब (
lfi_stubs.c) पर रीडायरेक्ट किया जाता है. - सुरक्षित तरीके से गड़बड़ी ठीक करना: अगर गलत तरीके से बनाया गया या नुकसान पहुंचाने वाला Opus बिटस्ट्रीम, लीनियर सैंडबॉक्स में तय सीमा से बाहर पढ़ने या लिखने की कोशिश करता है, तो LFI रनटाइम, गड़बड़ी को सुरक्षित तरीके से यूज़रस्पेस में ट्रैप करता है. साथ ही, होस्ट ऐप्लिकेशन को क्रैश किए बिना,
C2_CORRUPTEDडिकोडिंग की गड़बड़ी दिखाता है.
एलएफ़आई के लिए, काम करने वाले आर्किटेक्चर और डिवाइस
एलएफ़आई के लिए, सीपीयू के कस्टम हार्डवेयर निर्देशों की ज़रूरत नहीं होती. यह ARM64 (aarch64) और x86_64 प्रोसेसर आर्किटेक्चर पर काम करता है:
- ARM64 (
aarch64) डिवाइस: ज़्यादातर उपभोक्ता मोबाइल डिवाइस, ARM64 प्रोसेसर पर काम करते हैं. इनमें मोबाइल फ़ोन (जैसे, Google Tensor SoCs, Qualcomm Snapdragon, और MediaTek SoCs वाले Pixel डिवाइस), फ़ोल्ड किए जा सकने वाले डिवाइस, टैबलेट, और ऑटोमोटिव इन्फ़ोटेनमेंट यूनिट शामिल हैं. ये डिवाइस, LFI इन-प्रोसेस डिकोडर के साथ काम करते हैं. - x86_64 डिवाइस: Intel या AMD सीपीयू वाले डेवलपर वर्कस्टेशन पर चलने वाले Android एम्युलेटर, x86_64 आर्किटेक्चर पर काम करते हैं. साथ ही, ARC (ChromeOS के लिए Android रनटाइम) का इस्तेमाल करके Android ऐप्लिकेशन चलाने वाले ChromeOS Chromebook भी x86_64 आर्किटेक्चर पर काम करते हैं. ये सभी LFI सैंडबॉक्सिंग की सुविधा के साथ काम करते हैं.
प्रोसेस में मौजूद ऑडियो डिकोडर
| ऑडियो का फ़ॉर्मैट | MIME टाइप | प्रोसेस में मौजूद कॉम्पोनेंट का नाम | लागू करना |
|---|---|---|---|
| Opus | audio/opus |
c2.android.inproc.opus.decoder |
C/C++ libopus के साथ एलएफ़आई |
| AAC | audio/mp4a-latm |
c2.android.inproc.aac.decoder |
मेमोरी सेफ़ Rust (C2ApexAacDec) |
- AAC (
c2.android.inproc.aac.decoder): यह डाइनैमिक ADTS हेडर पार्सिंग के साथ ADTS स्ट्रीम और रॉ ऐक्सेस यूनिट (एयू) को हैंडल करता है. साथ ही, सटीक प्रज़ेंटेशन टाइमस्टैंप ट्रैकिंग करता है.AAC_PACKAGING_RAWके मामले में, सिर्फ़ सिंगल-फ़्रेम एयू प्रोसेसिंग की जाती है. - Opus (
c2.android.inproc.opus.decoder): यह स्टैंडर्ड Ogg Opus या Matroska कंटेनर पैकेट को डिकोड करता है. साथ ही, इंटरनल रीसैंपलिंग के साथ 48 kHz पीसीएम में बदलता है.
प्रोसेस में शामिल डिकोडर के लिए ऑप्ट-इन करना
फ़िलहाल, कॉल के दौरान MediaCodec.createDecoderByType() का इस्तेमाल करने पर, डिकोडर डिफ़ॉल्ट रूप से काम नहीं करते.
इकोसिस्टम की पुष्टि के दौरान, प्लैटफ़ॉर्म पुराने आउट-ऑफ़-प्रोसेस डिकोडर के लिए, Codec 2.0 को चुनने की प्राथमिकता को बनाए रखता है.
कम समय में वीडियो चलाने या जांच करने के लिए, आज ही डिकोडर में ऑप्ट इन करें. इसके लिए, कॉम्पोनेंट के नाम के हिसाब से कोडेक को साफ़ तौर पर इंस्टैंटिएट करें. इसके लिए, MediaCodec.createByCodecName() का इस्तेमाल करें.
कॉम्पोनेंट के नाम से इंस्टैंशिएट करना
यहां दिए गए उदाहरण में, इन-प्रोसेस एएसी डिकोडर को साफ़ तौर पर इंस्टैंटिएट करने का तरीका बताया गया है. अगर डिवाइस पर इन-प्रोसेस कॉम्पोनेंट उपलब्ध नहीं है, तो डिफ़ॉल्ट डिकोडर पर वापस आएं:
Kotlin
val INPROC_AAC_CODEC = "c2.android.inproc.aac.decoder" fun createAudioDecoder(): MediaCodec { return try { // Attempt to opt in to the low-latency in-process AAC decoder MediaCodec.createByCodecName(INPROC_AAC_CODEC) } catch (e: IllegalArgumentException) { // Fall back to the default platform AAC decoder MediaCodec.createDecoderByType(MediaFormat.MIMETYPE_AUDIO_AAC) } }
Java
private static final String INPROC_AAC_CODEC = "c2.android.inproc.aac.decoder"; public MediaCodec createAudioDecoder() throws IOException { try { // Attempt to opt in to the low-latency in-process AAC decoder return MediaCodec.createByCodecName(INPROC_AAC_CODEC); } catch (IllegalArgumentException e) { // Fall back to the default platform AAC decoder return MediaCodec.createDecoderByType(MediaFormat.MIMETYPE_AUDIO_AAC); } }
Jetpack Media3 या ExoPlayer को कॉन्फ़िगर करना
अगर आपका ऐप्लिकेशन Jetpack Media3 या ExoPlayer का इस्तेमाल करता है, तो कस्टम MediaCodecSelector बनाया जा सकता है. इससे डिवाइस पर उपलब्ध होने पर, प्रोसेस में शामिल डिकोडर को प्राथमिकता दी जा सकती है:
Kotlin
class InprocPreferredMediaCodecSelector : MediaCodecSelector { override fun getDecoderInfos( mimeType: String, requiresSecureDecoder: Boolean, requiresTunnelingDecoder: Boolean ): List<MediaCodecInfo> { val defaultInfos = MediaCodecUtil.getDecoderInfos( mimeType, requiresSecureDecoder, requiresTunnelingDecoder ) val inprocNames = setOf( "c2.android.inproc.opus.decoder", "c2.android.inproc.aac.decoder" ) // Sort in-process decoders to the top of the selection list return defaultInfos.sortedByDescending { it.name in inprocNames } } }
Java
public class InprocPreferredMediaCodecSelector implements MediaCodecSelector { private static final Set<String> INPROC_NAMES = new HashSet<>(Arrays.asList( "c2.android.inproc.opus.decoder", "c2.android.inproc.aac.decoder" )); @Override public List<MediaCodecInfo> getDecoderInfos( String mimeType, boolean requiresSecureDecoder, boolean requiresTunnelingDecoder) throws MediaCodecUtil.DecoderQueryException { List<MediaCodecInfo> defaultInfos = new ArrayList<>( MediaCodecUtil.getDecoderInfos(mimeType, requiresSecureDecoder, requiresTunnelingDecoder) ); // Sort in-process decoders to the top of the selection list defaultInfos.sort((a, b) -> { boolean aInproc = INPROC_NAMES.contains(a.name); boolean bInproc = INPROC_NAMES.contains(b.name); return Boolean.compare(bInproc, aInproc); }); return defaultInfos; } }
सिस्टम के डिफ़ॉल्ट डिकोडर के लिए रोडमैप
Android, मेमोरी सेफ़ इन-प्रोसेस डिकोडर को सिस्टम के डिफ़ॉल्ट डिकोडर के तौर पर इस्तेमाल करने के लिए, सक्रिय रूप से तैयारी कर रहा है. ऐसा आने वाले प्लैटफ़ॉर्म रिलीज़ में किया जाएगा. ये डिकोडर, अपने-अपने ऑडियो MIME टाइप के लिए काम करेंगे. इसकी शुरुआत, Android 18 में Opus LFI और AAC Rust से होगी. इसके अलावा, आने वाले Mainline मॉड्यूल अपडेट में भी ऐसा किया जाएगा.
जब प्रोसेस में मौजूद डिकोडर, अपने एमआईएमई टाइप के लिए Codec 2.0 का डिफ़ॉल्ट कॉम्पोनेंट बन जाता है, तो MediaCodec.createDecoderByType(...) पर किए गए स्टैंडर्ड कॉल, प्रोसेस में मौजूद डिकोडर के ज़रिए अपने-आप रूट हो जाते हैं. इससे, डिकोडिंग में लगने वाला इंतज़ार का समय करीब 40% कम हो जाता है. इसके लिए, ऐप्लिकेशन कोड में कोई बदलाव करने की ज़रूरत नहीं होती.