পটভূমিতে মিডিয়া চালান

আপনার অ্যাপ্লিকেশনটি স্ক্রিনে না থাকলেও আপনি ব্যাকগ্রাউন্ডে মিডিয়া চালাতে পারেন, যেমন—যখন ব্যবহারকারী অন্য কোনো অ্যাপ্লিকেশন ব্যবহার করছেন।

এটি করার জন্য, আপনাকে MediaPlayer-টিকে একটি MediaBrowserServiceCompat সার্ভিসের মধ্যে এমবেড করতে হবে এবং এটিকে অন্য একটি অ্যাক্টিভিটিতে থাকা MediaBrowserCompat এর সাথে ইন্টারঅ্যাক্ট করাতে হবে।

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

এই পৃষ্ঠায় একটি সার্ভিসের ভেতরে মিডিয়া প্লেয়ার প্রয়োগ করার সময় তা পরিচালনার জন্য বিশেষ নির্দেশাবলী বর্ণনা করা হয়েছে।

অ্যাসিঙ্ক্রোনাসভাবে চালান

Activity মতোই, Service সমস্ত কাজ ডিফল্টরূপে একটিমাত্র থ্রেডে সম্পন্ন হয়। প্রকৃতপক্ষে, যখন আপনি একই অ্যাপ্লিকেশন থেকে একটি অ্যাক্টিভিটি এবং একটি সার্ভিস চালান, তখন তারা ডিফল্টরূপে একই থ্রেড ("মেইন থ্রেড") ব্যবহার করে।

সার্ভিসগুলোকে অবশ্যই আগত ইনটেন্টগুলো দ্রুত প্রসেস করতে হবে এবং সেগুলোর প্রতিক্রিয়া জানানোর সময় কখনোই দীর্ঘ গণনা সম্পাদন করা যাবে না। আপনাকে যেকোনো ভারী কাজ বা ব্লকিং কল অ্যাসিঙ্ক্রোনাসভাবে সম্পাদন করতে হবে: হয় আপনার নিজের তৈরি করা অন্য কোনো থ্রেড থেকে, অথবা অ্যাসিঙ্ক্রোনাস প্রসেসিংয়ের জন্য ফ্রেমওয়ার্কের বিভিন্ন সুবিধা ব্যবহার করে।

উদাহরণস্বরূপ, যখন আপনি আপনার প্রধান থ্রেড থেকে MediaPlayer ব্যবহার করেন, তখন আপনার যা করা উচিত তা হলো:

  • prepare() () এর পরিবর্তে prepareAsync() কল করুন, এবং
  • প্রস্তুতি সম্পন্ন হলে বিজ্ঞপ্তি পেতে এবং প্লে করা শুরু করতে, একটি MediaPlayer.OnPreparedListener প্রয়োগ করুন।

উদাহরণস্বরূপ:

কোটলিন

private const val ACTION_PLAY: String = "com.example.action.PLAY"

class MyService: Service(), MediaPlayer.OnPreparedListener {

    private var mMediaPlayer: MediaPlayer? = null

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
        ...
        val action: String = intent.action
        when(action) {
            ACTION_PLAY -> {
                mMediaPlayer = ... // initialize it here
                mMediaPlayer?.apply {
                    setOnPreparedListener(this@MyService)
                    prepareAsync() // prepare async to not block main thread
                }

            }
        }
        ...
    }

    /** Called when MediaPlayer is ready */
    override fun onPrepared(mediaPlayer: MediaPlayer) {
        mediaPlayer.start()
    }
}

জাভা

public class MyService extends Service implements MediaPlayer.OnPreparedListener {
    private static final String ACTION_PLAY = "com.example.action.PLAY";
    MediaPlayer mediaPlayer = null;

    public int onStartCommand(Intent intent, int flags, int startId) {
        ...
        if (intent.getAction().equals(ACTION_PLAY)) {
            mediaPlayer = ... // initialize it here
            mediaPlayer.setOnPreparedListener(this);
            mediaPlayer.prepareAsync(); // prepare async to not block main thread
        }
    }

    /** Called when MediaPlayer is ready */
    public void onPrepared(MediaPlayer player) {
        player.start();
    }
}

অ্যাসিঙ্ক্রোনাস ত্রুটিগুলি পরিচালনা করুন

সিঙ্ক্রোনাস অপারেশনের ক্ষেত্রে, ত্রুটিগুলো একটি এক্সেপশন বা এরর কোডের মাধ্যমে জানানো হয়। তবে, যখন আপনি অ্যাসিঙ্ক্রোনাস রিসোর্স ব্যবহার করেন, তখন আপনার অ্যাপ্লিকেশনকে ত্রুটি সম্পর্কে যথাযথভাবে অবহিত করা উচিত। একটি MediaPlayer এর ক্ষেত্রে, আপনি একটি MediaPlayer.OnErrorListener ইমপ্লিমেন্ট করেন এবং আপনার MediaPlayer ইনস্ট্যান্সে এটি সেট করেন:

কোটলিন

class MyService : Service(), MediaPlayer.OnErrorListener {

    private var mediaPlayer: MediaPlayer? = null

    fun initMediaPlayer() {
        // ...initialize the MediaPlayer here...
        mediaPlayer?.setOnErrorListener(this)
    }

    override fun onError(mp: MediaPlayer, what: Int, extra: Int): Boolean {
        // ... react appropriately ...
        // The MediaPlayer has moved to the Error state, must be reset!
    }
}

জাভা

public class MyService extends Service implements MediaPlayer.OnErrorListener {
    MediaPlayer mediaPlayer;

    public void initMediaPlayer() {
        // ...initialize the MediaPlayer here...
        mediaPlayer.setOnErrorListener(this);
    }

    @Override
    public boolean onError(MediaPlayer mp, int what, int extra) {
        // ... react appropriately ...
        // The MediaPlayer has moved to the Error state, must be reset!
    }
}

যখন কোনো ত্রুটি ঘটে, তখন MediaPlayer টি Error স্টেটে চলে যায়। পুনরায় ব্যবহার করার আগে আপনাকে অবশ্যই এটি রিসেট করতে হবে। বিস্তারিত জানতে, MediaPlayer ক্লাসের সম্পূর্ণ স্টেট ডায়াগ্রামটি দেখুন।

ওয়েক লক ব্যবহার করুন

যখন আপনি ব্যাকগ্রাউন্ডে গান চালান বা স্ট্রিম করেন, তখন আপনাকে অবশ্যই ওয়েক লক ব্যবহার করতে হবে, যাতে সিস্টেম আপনার প্লেব্যাকে হস্তক্ষেপ করতে না পারে, যেমন ডিভাইসটি স্লিপ মোডে চলে যাওয়া।

ওয়েক লক হলো সিস্টেমের প্রতি একটি সংকেত যে, আপনার অ্যাপ্লিকেশনটি এমন কিছু ফিচার ব্যবহার করছে যা ফোন নিষ্ক্রিয় থাকলেও উপলব্ধ থাকা উচিত।

আপনার MediaPlayer চলার সময় সিপিইউ যাতে চালু থাকে, তা নিশ্চিত করতে MediaPlayer ইনিশিয়ালাইজ করার সময় setWakeMode() মেথডটি কল করুন। MediaPlayer চলার সময় নির্দিষ্ট লকটি ধরে রাখে এবং পজ বা স্টপ করা হলে লকটি ছেড়ে দেয়।

কোটলিন

mediaPlayer = MediaPlayer().apply {
    // ... other initialization here ...
    setWakeMode(applicationContext, PowerManager.PARTIAL_WAKE_LOCK)
}

জাভা

mediaPlayer = new MediaPlayer();
// ... other initialization here ...
mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);

তবে, এই উদাহরণে অর্জিত ওয়েক লকটি শুধুমাত্র সিপিইউ-কে সজাগ রাখা নিশ্চিত করে। আপনি যদি নেটওয়ার্কের মাধ্যমে মিডিয়া স্ট্রিম করেন এবং ওয়াই-ফাই ব্যবহার করেন, তাহলে সম্ভবত আপনি একটি WifiLock ধরে রাখতে চাইবেন, যা আপনাকে ম্যানুয়ালি অর্জন এবং মুক্ত করতে হবে। সুতরাং, যখন আপনি রিমোট ইউআরএল দিয়ে MediaPlayer প্রস্তুত করা শুরু করবেন, তখন আপনার ওয়াই-ফাই লকটি তৈরি এবং অর্জন করা উচিত।

উদাহরণস্বরূপ:

কোটলিন

val wifiManager = getSystemService(Context.WIFI_SERVICE) as WifiManager
val wifiLock: WifiManager.WifiLock =
    wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock")

wifiLock.acquire()

জাভা

WifiLock wifiLock = ((WifiManager) getSystemService(Context.WIFI_SERVICE))
    .createWifiLock(WifiManager.WIFI_MODE_FULL, "mylock");

wifiLock.acquire();

যখন আপনি আপনার মিডিয়া পজ বা স্টপ করেন, অথবা যখন আপনার নেটওয়ার্কের আর প্রয়োজন হয় না, তখন লকটি রিলিজ করে দেওয়া উচিত:

কোটলিন

wifiLock.release()

জাভা

wifiLock.release();

পরিষ্কার-পরিচ্ছন্নতা সম্পাদন করুন

As mentioned earlier, a MediaPlayer object can consume a significant amount of system resources, so you should keep it only for as long as you need and call release() when you are done with it. It's important to call this cleanup method explicitly rather than rely on system garbage collection because it might take some time before the garbage collector reclaims the MediaPlayer , as it's only sensitive to memory needs and not to shortage of other media-related resources. So, in the case when you're using a service, you should always override the onDestroy() method to make sure you are releasing the MediaPlayer :

কোটলিন

class MyService : Service() {

    private var mediaPlayer: MediaPlayer? = null
    // ...

    override fun onDestroy() {
        super.onDestroy()
        mediaPlayer?.release()
    }
}

জাভা

public class MyService extends Service {
   MediaPlayer mediaPlayer;
   // ...

   @Override
   public void onDestroy() {
       super.onDestroy();
       if (mediaPlayer != null) mediaPlayer.release();
   }
}

শাটডাউন করার সময় রিলিজ করা ছাড়াও, আপনার MediaPlayer রিলিজ করার জন্য সবসময় অন্যান্য সুযোগও খোঁজা উচিত। উদাহরণস্বরূপ, যদি আপনি আশা করেন যে দীর্ঘ সময়ের জন্য মিডিয়া প্লে করতে পারবেন না (যেমন, অডিও ফোকাস হারানোর পর), তাহলে আপনার অবশ্যই বিদ্যমান MediaPlayer রিলিজ করে পরে আবার তৈরি করা উচিত। অন্যদিকে, যদি আপনি খুব অল্প সময়ের জন্য প্লেব্যাক বন্ধ করার আশা করেন, তাহলে সম্ভবত আপনার MediaPlayer রেখে দেওয়া উচিত, যাতে এটি পুনরায় তৈরি ও প্রস্তুত করার বাড়তি ঝামেলা এড়ানো যায়।

আরও জানুন

আপনার অ্যাপে মিডিয়া প্লেব্যাকের জন্য Jetpack Media3 হলো প্রস্তাবিত সমাধান। এ সম্পর্কে আরও পড়ুন

এই পৃষ্ঠাগুলিতে অডিও এবং ভিডিও রেকর্ড করা, সংরক্ষণ করা এবং প্লেব্যাক করা সম্পর্কিত বিষয়গুলি আলোচনা করা হয়েছে: