ইন-প্রসেস ডিকোডার ব্যবহার করে অডিও পারফরম্যান্স অপ্টিমাইজ করুন

অ্যান্ড্রয়েড ১৭ (এপিআই লেভেল ৩৭) থেকে শুরু করে এবং গুগল প্লে সিস্টেম আপডেট (মেইনলাইন এপেক্স মডিউল)-এর মাধ্যমে আপডেট হওয়া অ্যান্ড্রয়েড, ওপাস এবং এএসি সহ বিভিন্ন কম্প্রেসড অডিও ফরম্যাটের জন্য ইন-প্রসেস সফটওয়্যার অডিও ডিকোডার চালু করেছে।

একটি পৃথক স্যান্ডবক্সড সিস্টেম প্রসেসে চালানোর পরিবর্তে অ্যাপের নিজস্ব প্রসেসের মধ্যেই সরাসরি অডিও ডিকোডার চালানোর মাধ্যমে, অ্যাপগুলো একটানা মিডিয়া প্লেব্যাক, ভয়েস মেসেজিং এবং গেমিং চলাকালীন অডিও ডিকোডিং ল্যাটেন্সি প্রায় ৪০% কমাতে, সিপিইউ ব্যবহার হ্রাস করতে এবং ব্যাটারির আয়ু বাড়াতে পারে।

প্রক্রিয়া-বহির্ভূত বনাম প্রক্রিয়া-মধ্যবর্তী ডিকোডিং

ঐতিহাসিকভাবে, অ্যান্ড্রয়েড অ্যাপ এবং অপারেটিং সিস্টেমকে ত্রুটিপূর্ণ মিডিয়া বিটস্ট্রিম থেকে রক্ষা করার জন্য প্ল্যাটফর্মের সমস্ত সফটওয়্যার মিডিয়া ডিকোডার একটি ডেডিকেটেড, স্যান্ডবক্সড সিস্টেম ডেমন ( mediaswcodec )-এর ভিতরে চালাত। তবে, আউট-অফ-প্রসেস স্যান্ডবক্সিং পরিমাপযোগ্য পারফরম্যান্স ওভারহেড তৈরি করে:

  • আন্তঃপ্রক্রিয়া যোগাযোগ (IPC) বিলম্ব: ডিকোডারে সারিবদ্ধ প্রতিটি অডিও ইনপুট ফ্রেম এবং ফেরত আসা প্রতিটি ডিকোড করা PCM অডিও বাফারের জন্য ক্রস-প্রসেস বাইন্ডার IPC সিরিয়ালাইজেশন এবং কনটেক্সট সুইচিং প্রয়োজন হয়।
  • শেয়ার্ড মেমোরি ওভারহেড: আন্তঃ-প্রক্রিয়া বাফার হস্তান্তরের জন্য শেয়ার্ড-মেমোরি ( C2Buffer ) সিঙ্ক্রোনাইজেশন এবং ক্যাশে ব্যবস্থাপনার প্রয়োজন হয়।
  • শিডিউলিং দ্বন্দ্ব: সিপিইউ-এর উপর অতিরিক্ত চাপ থাকলে, অ্যাপ প্রসেস এবং mediaswcodec মধ্যে থ্রেড শিডিউলিং দ্বন্দ্বের কারণে লো-ল্যাটেন্সি অডিও পাইপলাইনগুলিতে (যেমন DAW, VoIP কমিউনিকেশন, এবং ইন্টারেক্টিভ গেম) বাফার স্টারভেশন এবং অডিও স্টাটারিং হতে পারে।

ইন-প্রসেস মিডিয়া ডিকোডার চালানোর মাধ্যমে সরাসরি এই পারফরম্যান্সের প্রতিবন্ধকতাগুলো সমাধান করা হয়:

  • আইপিসি ল্যাটেন্সি দূর করে: বাইন্ডার আইপিসি ট্রানজ্যাকশন এবং কনটেক্সট সুইচ বাইপাস করে, যার ফলে এন্ড-টু-এন্ড ডিকোডিং ল্যাটেন্সি প্রায় ৪০% কমে যায়।
  • বাফার ওভারহেড কমায়: ক্রস-প্রসেস শেয়ার্ড মেমরি ম্যাপিংয়ের প্রয়োজন ছাড়াই অডিও বাফারগুলিকে সরাসরি স্থানীয় অ্যাপ মেমরি স্পেসের মধ্যে পাস করে।
  • শিডিউলিং জিটার প্রতিরোধ করে: অ্যাপের নিজস্ব প্রায়োরিটি থ্রেডে (যেমন রিয়েলটাইম AAudio বা Oboe থ্রেড) ডিকোডিং সম্পাদন করে, ফলে সিস্টেমের উপর অতিরিক্ত চাপ পড়লে অডিও ড্রপআউট এবং বাফার আন্ডাররান প্রতিরোধ করে।

রাস্ট দিয়ে মেমরি সুরক্ষা

ঐতিহাসিকভাবে, অ্যান্ড্রয়েড সফটওয়্যার ডিকোডারগুলোকে একটি পৃথক প্রসেসে ( mediaswcodec ) আলাদা করে রাখত, কারণ ডিকোডারগুলো বাহ্যিক মিডিয়া ফাইল থেকে অবিশ্বস্ত বিটস্ট্রিম প্রসেস করে, যা মেমরি-করপশন এক্সপ্লয়েট (যেমন বাফার ওভারফ্লো) কে একটি বড় নিরাপত্তা উদ্বেগের কারণ করে তোলে।

অ্যান্ড্রয়েড রাস্টের মতো মেমরি-সেফ ল্যাঙ্গুয়েজে সফটওয়্যার ডিকোডারগুলো ইমপ্লিমেন্ট করে অথবা লাইটওয়েট ফল্ট আইসোলেশন (LFI) দিয়ে সেগুলোকে আইসোলেট করে নিরাপদে সরাসরি কলিং অ্যাপ প্রসেসে স্থানান্তর করতে পারে।

AAC ( c2.android.inproc.aac.decoder )-এর জন্য আউট-অফ-প্রসেস স্যান্ডবক্সিং ওভারহেড নিরাপদে দূর করতে, অ্যান্ড্রয়েড একটি ডিকোডার প্রদান করে যা বিশুদ্ধ রাস্টে প্রয়োগ করা হয়েছে অথবা নিরাপদ রাস্ট ফরেন ফাংশন ইন্টারফেস (FFI) হারনেস দ্বারা সুরক্ষিত।

নিম্নলিখিত কারণগুলোর জন্য রাস্টকে ইন-প্রসেস ডিকোডিংয়ের জন্য নিরাপদ বলে মনে করা হয়:

  • কম্পাইল-টাইম মেমরি সুরক্ষা: রাস্টের স্ট্রিক্ট ওনারশিপ, বোরোয়িং এবং লাইফটাইম চেকিং নিশ্চিত করে যে, শেয়ারড অবস্থায় কোনো মেমরি একবার ফ্রি বা মিউটেট হয়ে গেলে তা আর অ্যাক্সেস করা যাবে না।
  • সাধারণ দুর্বলতাগুলোর নির্মূল: রাস্ট কম্পাইল টাইমে হিপ বাফার ওভারফ্লো, স্ট্যাক স্ম্যাশ, অ্যারের সীমার বাইরে রিড ও রাইট, ইউজ-আফটার-ফ্রি ত্রুটি এবং ডাবল-ফ্রি দুর্বলতাগুলোকে সম্পূর্ণরূপে প্রতিরোধ করে।
  • রানটাইম স্যান্ডবক্সিংয়ের কোনো ঝামেলা নেই: যেহেতু কম্পাইল টাইমে মেমরি সেফটি গাণিতিকভাবে প্রমাণিত এবং বাউন্ডস চেকিংয়ের মাধ্যমে যাচাই করা হয়, তাই রাস্ট ডিকোডারগুলো পেজ টেবিল ট্রানজিশন বা হার্ডওয়্যার স্যান্ডবক্স কনটেক্সট ছাড়াই অ্যাপ প্রসেসের ভেতরে নেটিভ গতিতে চলে।

লাইটওয়েট ফল্ট আইসোলেশন (LFI) এর মাধ্যমে মেমরি সুরক্ষা

জটিল লিগ্যাসি C/C++ অডিও ডিকোডারগুলির জন্য, যেগুলি এখনও রাস্টে নতুন করে লেখা হয়নি—বিশেষ করে ওপাস ডিকোডার ( c2.android.inproc.opus.decoder যা libopus দ্বারা চালিত)—অ্যান্ড্রয়েড লাইটওয়েট ফল্ট আইসোলেশন (LFI) ব্যবহার করে ইন-প্রসেস সুরক্ষা প্রদান করে।

নিম্নলিখিত কারণগুলোর জন্য C/C++ ডিকোডারের ক্ষেত্রে LFI-কে নিরাপদ বলে বিবেচনা করা হয়:

  • হার্ডওয়্যার-সুরক্ষিত লিনিয়ার মেমরি স্যান্ডবক্সিং: LFI, C/C++ কোডেক লাইব্রেরিকে WebAssembly-ভিত্তিক লিনিয়ার মেশিন কোডে কম্পাইল করে, যা একটি হার্ডওয়্যার-সুরক্ষিত ৪ জিবি লিনিয়ার মেমরি স্লটের মধ্যে সীমাবদ্ধ থাকে।
  • লিনাক্স মেমরি প্রোটেকশন কী ( pku ): LFI অ্যাড্রেস স্পেসের অনুমতি বিভাজন করার জন্য লিনাক্স মেমরি প্রোটেকশন কী ( pku / pkey_mprotect ) ব্যবহার করে। আইসোলেটেড লাইব্রেরিটি তার জন্য নির্ধারিত ৪ জিবি স্যান্ডবক্স স্লটের বাইরে মেমরি পড়তে বা লিখতে পারে না।
  • সিস্টেম কল বাধা প্রদান: স্যান্ডবক্সের ভিতরে হোস্ট OS-এর কোনো সিস্টেম কল (যেমন ফাইল I/O, নেটওয়ার্ক অ্যাক্সেস, বা প্রসেস কন্ট্রোল) অনুমোদিত নয়। যেকোনো অসমর্থিত লাইব্রেরি কলকে ন্যূনতম ডামি স্টাব ( lfi_stubs.c )-এ পাঠানো হয়।
  • নিরাপদ ফল্ট পুনরুদ্ধার: যদি কোনো ত্রুটিপূর্ণ বা প্রতিকূল Opus বিটস্ট্রিম লিনিয়ার স্যান্ডবক্সের ভিতরে সীমার বাইরে রিড বা রাইট করার চেষ্টা করে, তাহলে LFI রানটাইম ব্যবহারকারী স্পেসে নিরাপদে ফল্টটি শনাক্ত করে এবং হোস্ট অ্যাপ ক্র্যাশ না করেই একটি পরিষ্কার C2_CORRUPTED ডিকোডিং ত্রুটি ফেরত দেয়।

LFI-এর জন্য সমর্থিত আর্কিটেকচার এবং ডিভাইস

LFI-এর জন্য কোনো কাস্টম সিপিইউ হার্ডওয়্যার নির্দেশাবলীর প্রয়োজন হয় না এবং এটি ARM64 ( aarch64 ) এবং x86_64 প্রসেসর আর্কিটেকচারে সমর্থিত:

  • ARM64 ( aarch64 ) ডিভাইস: বেশিরভাগ ভোক্তা-ব্যবহারযোগ্য মোবাইল ডিভাইস—যার মধ্যে রয়েছে মোবাইল ফোন (যেমন গুগল টেনসর এসওসি, কোয়ালকম স্ন্যাপড্রাগন এবং মিডিয়াটেক এসওসি যুক্ত পিক্সেল ডিভাইস), ফোল্ডেবল ডিভাইস, ট্যাবলেট এবং গাড়ির ইনফোটেইনমেন্ট ইউনিট—ARM64 প্রসেসরে চলে এবং LFI ইন-প্রসেস ডিকোডার সমর্থন করে।
  • x86_64 ডিভাইস: ইন্টেল বা এএমডি সিপিইউ সহ ডেভেলপার ওয়ার্কস্টেশনে চলমান অ্যান্ড্রয়েড এমুলেটর, সেইসাথে ARC (অ্যান্ড্রয়েড রানটাইম ফর ক্রোমওএস) ব্যবহার করে অ্যান্ড্রয়েড অ্যাপ চালিত ক্রোমওএস ক্রোমবুকগুলো x86_64 আর্কিটেকচারে চলে এবং LFI স্যান্ডবক্সিং সমর্থন করে।

প্রক্রিয়াধীন অডিও ডিকোডার উপলব্ধ

অডিও ফরম্যাট MIME টাইপ প্রক্রিয়াধীন উপাদানের নাম বাস্তবায়ন
ওপাস audio/opus c2.android.inproc.opus.decoder LFI সহ C/C++ libopus
এএসি audio/mp4a-latm c2.android.inproc.aac.decoder মেমরি-সেফ রাস্ট ( C2ApexAacDec )
  • AAC ( c2.android.inproc.aac.decoder ): ADTS স্ট্রিম (ডাইনামিক ADTS হেডার পার্সিং সহ) এবং সঠিক প্রেজেন্টেশন টাইমস্ট্যাম্প ট্র্যাকিং সহ র অ্যাক্সেস ইউনিট (AU) পরিচালনা করে ( AAC_PACKAGING_RAW এর ক্ষেত্রে শুধুমাত্র একক-ফ্রেম AU প্রক্রিয়াকরণ)।
  • Opus ( c2.android.inproc.opus.decoder ): অভ্যন্তরীণভাবে ৪৮ কিলোহার্জ পিসিএম-এ রিস্যাম্পলিং করে স্ট্যান্ডার্ড Ogg Opus বা Matroska কন্টেইনার প্যাকেট ডিকোড করে।

প্রক্রিয়াধীন ডিকোডারগুলিতে অপ্ট ইন করুন

বর্তমানে, MediaCodec.createDecoderByType() কল করার সময় ইন-প্রসেস ডিকোডারগুলো সিস্টেমের ডিফল্ট হিসেবে থাকে না। ইকোসিস্টেম যাচাইকরণের সময় প্ল্যাটফর্মটি লিগ্যাসি আউট-অফ-প্রসেস ডিকোডারগুলোর জন্য উচ্চতর কোডেক ২.০ নির্বাচনের অগ্রাধিকার বজায় রাখে।

কম-লেটেন্সি প্লেব্যাক বা পরীক্ষার জন্য আজই একটি ইন-প্রসেস ডিকোডার ব্যবহার করতে, MediaCodec.createByCodecName() ব্যবহার করে কম্পোনেন্টের নাম দিয়ে কোডেকটি স্পষ্টভাবে ইনস্ট্যানশিয়েট করুন।

কম্পোনেন্টের নাম দ্বারা ইনস্ট্যানশিয়েট করুন

নিম্নলিখিত উদাহরণটি দেখায় কিভাবে ইন-প্রসেস AAC ডিকোডারকে স্পষ্টভাবে ইনস্ট্যানশিয়েট করতে হয় এবং ডিভাইসে ইন-প্রসেস কম্পোনেন্টটি অনুপলব্ধ থাকলে ডিফল্ট ডিকোডারে ফিরে যেতে হয়:

কোটলিন

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

জাভা

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 তৈরি করতে পারেন:

কোটলিন

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 }
    }
}

জাভা

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

ডিফল্ট সিস্টেম ডিকোডারগুলির রোডম্যাপ

অ্যান্ড্রয়েড আসন্ন প্ল্যাটফর্ম রিলিজগুলিতে (অ্যান্ড্রয়েড ১৮-এর Opus LFI ও AAC Rust অথবা আসন্ন মেইনলাইন মডিউল আপডেটগুলির মাধ্যমে শুরু করে) এই মেমরি-সেফ ইন-প্রসেস ডিকোডারগুলিকে তাদের নিজ নিজ অডিও MIME টাইপের জন্য সিস্টেমের ডিফল্ট ডিকোডার হিসেবে রূপান্তর করার জন্য সক্রিয়ভাবে প্রস্তুতি নিচ্ছে।

একবার কোনো ইন-প্রসেস ডিকোডার তার MIME টাইপের জন্য ডিফল্ট কোডেক ২.০ কম্পোনেন্ট হয়ে গেলে, MediaCodec.createDecoderByType(...) এর স্ট্যান্ডার্ড কলগুলো স্বয়ংক্রিয়ভাবে ইন-প্রসেস ইমপ্লিমেন্টেশনের মাধ্যমে রাউট হবে, যার ফলে অ্যাপ কোডে কোনো পরিবর্তন ছাড়াই ডিকোডিং ল্যাটেন্সি প্রায় ৪০% কমে যাবে।