অ্যান্ড্রয়েড মাল্টিমিডিয়া ফ্রেমওয়ার্কে বিভিন্ন ধরনের সাধারণ মিডিয়া বাজানোর জন্য সমর্থন রয়েছে, যাতে আপনি সহজেই আপনার অ্যাপ্লিকেশনগুলিতে অডিও, ভিডিও এবং চিত্রগুলিকে একীভূত করতে পারেন৷ আপনি আপনার অ্যাপ্লিকেশানের সংস্থানগুলিতে সঞ্চিত মিডিয়া ফাইলগুলি থেকে অডিও বা ভিডিও চালাতে পারেন (কাঁচা সংস্থান), ফাইল সিস্টেমের স্বতন্ত্র ফাইলগুলি থেকে বা নেটওয়ার্ক সংযোগে আগত ডেটা স্ট্রীম থেকে, সমস্ত MediaPlayer
API ব্যবহার করে৷
এই নথিটি আপনাকে দেখায় কিভাবে MediaPlayer
ব্যবহার করে একটি মিডিয়া প্লেয়িং অ্যাপ্লিকেশন লিখতে হয় যা ব্যবহারকারী এবং সিস্টেমের সাথে ইন্টারঅ্যাক্ট করে যাতে ভাল পারফরম্যান্স এবং একটি আনন্দদায়ক ব্যবহারকারীর অভিজ্ঞতা পাওয়া যায়। বিকল্পভাবে, আপনি ExoPlayer ব্যবহার করতে চাইতে পারেন, যা একটি কাস্টমাইজযোগ্য ওপেন সোর্স লাইব্রেরি যা MediaPlayer
উপলব্ধ নয় এমন উচ্চ-পারফরম্যান্স বৈশিষ্ট্য সমর্থন করে
দ্রষ্টব্য: আপনি শুধুমাত্র স্ট্যান্ডার্ড আউটপুট ডিভাইসে অডিও ডেটা প্লে ব্যাক করতে পারেন। বর্তমানে, এটি মোবাইল ডিভাইস স্পিকার বা একটি ব্লুটুথ হেডসেট। আপনি কল চলাকালীন কথোপকথনের অডিওতে শব্দ ফাইলগুলি চালাতে পারবেন না৷
বুনিয়াদি
নিম্নলিখিত ক্লাসগুলি অ্যান্ড্রয়েড ফ্রেমওয়ার্কে শব্দ এবং ভিডিও চালানোর জন্য ব্যবহৃত হয়:
-
MediaPlayer
- এই ক্লাসটি সাউন্ড এবং ভিডিও চালানোর জন্য প্রাথমিক API।
-
AudioManager
- এই ক্লাসটি একটি ডিভাইসে অডিও উত্স এবং অডিও আউটপুট পরিচালনা করে।
ম্যানিফেস্ট ঘোষণা
MediaPlayer ব্যবহার করে আপনার অ্যাপ্লিকেশনের বিকাশ শুরু করার আগে, নিশ্চিত করুন যে আপনার ম্যানিফেস্টে সংশ্লিষ্ট বৈশিষ্ট্যগুলির ব্যবহারের অনুমতি দেওয়ার জন্য উপযুক্ত ঘোষণা রয়েছে৷
- ইন্টারনেট অনুমতি - আপনি যদি নেটওয়ার্ক-ভিত্তিক বিষয়বস্তু স্ট্রিম করতে MediaPlayer ব্যবহার করেন, তাহলে আপনার অ্যাপ্লিকেশনটিকে অবশ্যই নেটওয়ার্ক অ্যাক্সেসের অনুরোধ করতে হবে।
<uses-permission android:name="android.permission.INTERNET" />
- ওয়েক লক পারমিশন - যদি আপনার প্লেয়ার অ্যাপ্লিকেশনটির স্ক্রীন ম্লান হওয়া বা প্রসেসরকে ঘুমোতে না দেওয়া বা
MediaPlayer.setScreenOnWhilePlaying()
বাMediaPlayer.setWakeMode()
পদ্ধতি ব্যবহার করা প্রয়োজন, তাহলে আপনাকে অবশ্যই এই অনুমতির অনুরোধ করতে হবে।<uses-permission android:name="android.permission.WAKE_LOCK" />
মিডিয়াপ্লেয়ার ব্যবহার করে
মিডিয়া ফ্রেমওয়ার্কের সবচেয়ে গুরুত্বপূর্ণ উপাদানগুলির মধ্যে একটি হল MediaPlayer
ক্লাস। এই শ্রেণীর একটি বস্তু ন্যূনতম সেটআপ সহ অডিও এবং ভিডিও উভয়ই আনয়ন, ডিকোড এবং প্লে করতে পারে। এটি বিভিন্ন মিডিয়া উত্স সমর্থন করে যেমন:
- স্থানীয় সম্পদ
- অভ্যন্তরীণ URI, যেমন আপনি একটি বিষয়বস্তু সমাধানকারী থেকে পেতে পারেন
- বাহ্যিক URL (স্ট্রিমিং)
অ্যান্ড্রয়েড সমর্থন করে এমন মিডিয়া ফর্ম্যাটের একটি তালিকার জন্য, সমর্থিত মিডিয়া ফর্ম্যাট পৃষ্ঠাটি দেখুন৷
স্থানীয় কাঁচা সংস্থান হিসাবে উপলব্ধ অডিও কীভাবে চালানো যায় তার একটি উদাহরণ এখানে রয়েছে (আপনার অ্যাপ্লিকেশনের res/raw/
ডিরেক্টরিতে সংরক্ষিত):
কোটলিন
var mediaPlayer = MediaPlayer.create(context, R.raw.sound_file_1) mediaPlayer.start() // no need to call prepare(); create() does that for you
জাভা
MediaPlayer mediaPlayer = MediaPlayer.create(context, R.raw.sound_file_1); mediaPlayer.start(); // no need to call prepare(); create() does that for you
এই ক্ষেত্রে, একটি "কাঁচা" সম্পদ হল একটি ফাইল যা সিস্টেম কোনো নির্দিষ্ট উপায়ে পার্স করার চেষ্টা করে না। যাইহোক, এই সম্পদের বিষয়বস্তু কাঁচা অডিও হওয়া উচিত নয়। এটি একটি সমর্থিত ফর্ম্যাটে একটি সঠিকভাবে এনকোড করা এবং ফর্ম্যাট করা মিডিয়া ফাইল হওয়া উচিত৷
এবং এখানে আপনি কীভাবে সিস্টেমে স্থানীয়ভাবে উপলব্ধ একটি URI থেকে খেলতে পারেন (যেটি আপনি একটি বিষয়বস্তু সমাধানকারীর মাধ্যমে পেয়েছেন, উদাহরণস্বরূপ):
কোটলিন
val myUri: Uri = .... // initialize Uri here val mediaPlayer = MediaPlayer().apply { setAudioAttributes( AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) .setUsage(AudioAttributes.USAGE_MEDIA) .build() ) setDataSource(applicationContext, myUri) prepare() start() }
জাভা
Uri myUri = ....; // initialize Uri here MediaPlayer mediaPlayer = new MediaPlayer(); mediaPlayer.setAudioAttributes( new AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) .setUsage(AudioAttributes.USAGE_MEDIA) .build() ); mediaPlayer.setDataSource(getApplicationContext(), myUri); mediaPlayer.prepare(); mediaPlayer.start();
HTTP স্ট্রিমিং এর মাধ্যমে একটি দূরবর্তী URL থেকে বাজানো এই মত দেখায়:
কোটলিন
val url = "http://........" // your URL here val mediaPlayer = MediaPlayer().apply { setAudioAttributes( AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) .setUsage(AudioAttributes.USAGE_MEDIA) .build() ) setDataSource(url) prepare() // might take long! (for buffering, etc) start() }
জাভা
String url = "http://........"; // your URL here MediaPlayer mediaPlayer = new MediaPlayer(); mediaPlayer.setAudioAttributes( new AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) .setUsage(AudioAttributes.USAGE_MEDIA) .build() ); mediaPlayer.setDataSource(url); mediaPlayer.prepare(); // might take long! (for buffering, etc) mediaPlayer.start();
দ্রষ্টব্য: আপনি যদি একটি অনলাইন মিডিয়া ফাইল স্ট্রিম করার জন্য একটি URL পাস করেন, তাহলে ফাইলটি অবশ্যই প্রগতিশীল ডাউনলোড করতে সক্ষম হবে৷
সতর্কতা: setDataSource()
ব্যবহার করার সময় আপনাকে অবশ্যই IllegalArgumentException
এবং IOException
ধরতে হবে বা পাস করতে হবে, কারণ আপনি যে ফাইলটি উল্লেখ করছেন সেটি বিদ্যমান নাও থাকতে পারে।
অ্যাসিঙ্ক্রোনাস প্রস্তুতি
MediaPlayer
ব্যবহার করা নীতিগতভাবে সোজা হতে পারে। যাইহোক, এটি মনে রাখা গুরুত্বপূর্ণ যে একটি সাধারণ অ্যান্ড্রয়েড অ্যাপ্লিকেশনের সাথে এটিকে সঠিকভাবে সংহত করার জন্য আরও কয়েকটি জিনিস প্রয়োজন৷ উদাহরণস্বরূপ, prepare()
জন্য কলটি কার্যকর হতে অনেক সময় লাগতে পারে, কারণ এতে মিডিয়া ডেটা আনয়ন এবং ডিকোডিং জড়িত থাকতে পারে। সুতরাং, যে কোনও পদ্ধতির ক্ষেত্রে যেমনটি কার্যকর হতে দীর্ঘ সময় নিতে পারে, আপনার কখনই এটিকে আপনার অ্যাপ্লিকেশনের UI থ্রেড থেকে কল করা উচিত নয়। এটি করার ফলে পদ্ধতিটি ফিরে না আসা পর্যন্ত UI হ্যাং হয়ে যায়, যা একটি খুব খারাপ ব্যবহারকারীর অভিজ্ঞতা এবং এটি একটি ANR (অ্যাপ্লিকেশন নট রেসপন্সিং) ত্রুটির কারণ হতে পারে। এমনকি যদি আপনি আশা করেন যে আপনার সংস্থান দ্রুত লোড হবে, মনে রাখবেন যে UI-তে প্রতিক্রিয়া জানাতে এক সেকেন্ডের দশমাংশের বেশি সময় লাগে তা একটি লক্ষণীয় বিরতি ঘটায় এবং ব্যবহারকারীকে ধারণা দেয় যে আপনার অ্যাপ্লিকেশন ধীর।
আপনার UI থ্রেড ঝুলানো এড়াতে, MediaPlayer
প্রস্তুত করতে অন্য থ্রেড তৈরি করুন এবং হয়ে গেলে প্রধান থ্রেডকে অবহিত করুন। যাইহোক, যখন আপনি নিজেই থ্রেডিং লজিক লিখতে পারেন, MediaPlayer
ব্যবহার করার সময় এই প্যাটার্নটি এতটাই সাধারণ যে ফ্রেমওয়ার্কটি prepareAsync()
পদ্ধতি ব্যবহার করে এই কাজটি সম্পন্ন করার জন্য একটি সুবিধাজনক উপায় সরবরাহ করে। এই পদ্ধতিটি পটভূমিতে মিডিয়া প্রস্তুত করা শুরু করে এবং অবিলম্বে ফিরে আসে। মিডিয়ার প্রস্তুতি শেষ হলে, MediaPlayer.OnPreparedListener
onPrepared()
setOnPreparedListener()
বলা হয়।
ম্যানেজিং স্টেট
MediaPlayer
আরেকটি দিক যা আপনার মনে রাখা উচিত তা হল এটি রাষ্ট্র-ভিত্তিক। অর্থাৎ, MediaPlayer
একটি অভ্যন্তরীণ অবস্থা রয়েছে যা আপনার কোড লেখার সময় আপনাকে সর্বদা সচেতন থাকতে হবে, কারণ প্লেয়ারটি নির্দিষ্ট অবস্থায় থাকলেই কিছু অপারেশন বৈধ। আপনি যদি ভুল অবস্থায় একটি অপারেশন করেন, তবে সিস্টেমটি একটি ব্যতিক্রম নিক্ষেপ করতে পারে বা অন্যান্য অবাঞ্ছিত আচরণের কারণ হতে পারে।
MediaPlayer
ক্লাসের ডকুমেন্টেশন একটি সম্পূর্ণ স্টেট ডায়াগ্রাম দেখায়, যা স্পষ্ট করে যে কোন পদ্ধতিগুলি MediaPlayer
এক রাজ্য থেকে অন্য অবস্থায় নিয়ে যায়। উদাহরণস্বরূপ, আপনি যখন একটি নতুন MediaPlayer
তৈরি করেন, তখন এটি নিষ্ক্রিয় অবস্থায় থাকে। সেই মুহুর্তে, আপনাকে setDataSource()
কল করে এটিকে সূচনাকৃত অবস্থায় নিয়ে আসা উচিত। এর পরে, আপনাকে এটি prepare()
বা prepareAsync()
পদ্ধতি ব্যবহার করে প্রস্তুত করতে হবে। MediaPlayer
প্রস্তুতি সম্পন্ন হলে, এটি প্রস্তুত অবস্থায় প্রবেশ করে, যার মানে আপনি এটিকে মিডিয়া চালানোর জন্য start()
কল করতে পারেন। সেই মুহুর্তে, ডায়াগ্রামটি যেমন ব্যাখ্যা করে, আপনি অন্যদের মধ্যে start()
, pause()
, এবং seekTo()
এর মতো পদ্ধতিগুলিকে কল করে Started , Paused এবং PlaybackCompleted অবস্থার মধ্যে যেতে পারেন। আপনি যখন stop()
কল করেন, তবে, লক্ষ্য করুন যে আপনি MediaPlayer
আবার প্রস্তুত না করা পর্যন্ত আপনি আবার start()
কল করতে পারবেন না।
MediaPlayer
অবজেক্টের সাথে ইন্টারঅ্যাক্ট করে এমন কোড লেখার সময় সর্বদা স্টেট ডায়াগ্রামটি মাথায় রাখুন, কারণ ভুল অবস্থা থেকে এর পদ্ধতিগুলিকে কল করা বাগগুলির একটি সাধারণ কারণ।
মিডিয়াপ্লেয়ার রিলিজ করা হচ্ছে
একটি MediaPlayer
মূল্যবান সিস্টেম সম্পদ গ্রহণ করতে পারে। অতএব, আপনি প্রয়োজনের চেয়ে বেশি সময় ধরে MediaPlayer
ইনস্ট্যান্সে ঝুলে থাকবেন না তা নিশ্চিত করতে আপনার সর্বদা অতিরিক্ত সতর্কতা অবলম্বন করা উচিত। যখন আপনি এটি সম্পন্ন করেন, তখন আপনাকে সর্বদা release()
কল করা উচিত যাতে এটিতে বরাদ্দ করা সিস্টেম সংস্থান সঠিকভাবে প্রকাশ করা হয়। উদাহরণস্বরূপ, যদি আপনি একটি MediaPlayer
ব্যবহার করেন এবং আপনার কার্যকলাপ onStop()
এ একটি কল পায়, তাহলে আপনাকে অবশ্যই MediaPlayer
ছেড়ে দিতে হবে, কারণ আপনার কার্যকলাপ ব্যবহারকারীর সাথে ইন্টারঅ্যাক্ট না করার সময় এটিকে ধরে রাখা সামান্যই অর্থবহ (যদি না আপনি খেলছেন) পটভূমিতে মিডিয়া, যা পরবর্তী বিভাগে আলোচনা করা হয়েছে)। যখন আপনার কার্যকলাপ পুনরায় শুরু করা হয় বা পুনরায় চালু করা হয়, অবশ্যই, আপনাকে একটি নতুন MediaPlayer
তৈরি করতে হবে এবং প্লেব্যাক পুনরায় শুরু করার আগে এটি আবার প্রস্তুত করতে হবে।
এখানে আপনার MediaPlayer
কীভাবে প্রকাশ করা উচিত এবং তারপরে বাতিল করা উচিত:
কোটলিন
mediaPlayer?.release() mediaPlayer = null
জাভা
mediaPlayer.release(); mediaPlayer = null;
উদাহরণ হিসাবে, আপনার কার্যকলাপ বন্ধ হয়ে গেলে আপনি MediaPlayer
প্রকাশ করতে ভুলে গেলে যে সমস্যাগুলি ঘটতে পারে তা বিবেচনা করুন, কিন্তু কার্যকলাপটি আবার শুরু হলে একটি নতুন তৈরি করুন। আপনি হয়তো জানেন, ব্যবহারকারী যখন স্ক্রীনের অভিযোজন পরিবর্তন করে (অথবা অন্য উপায়ে ডিভাইসের কনফিগারেশন পরিবর্তন করে), তখন সিস্টেম এটি পরিচালনা করে যে কার্যকলাপটি পুনরায় চালু করার মাধ্যমে (ডিফল্টরূপে), তাই ব্যবহারকারীর ঘোরার সাথে সাথে আপনি দ্রুত সিস্টেমের সমস্ত সংস্থান গ্রহণ করতে পারেন। প্রতিকৃতি এবং ল্যান্ডস্কেপের মধ্যে ডিভাইসটি সামনে পিছনে, কারণ প্রতিটি অভিযোজন পরিবর্তনের সময়, আপনি একটি নতুন MediaPlayer
তৈরি করেন যা আপনি কখনই প্রকাশ করেন না। (রানটাইম রিস্টার্ট সম্পর্কে আরও তথ্যের জন্য, রানটাইম পরিবর্তনগুলি পরিচালনা করা দেখুন।)
আপনি হয়ত ভাবছেন যে আপনি "ব্যাকগ্রাউন্ড মিডিয়া" চালানো চালিয়ে যেতে চাইলেও কি হবে যখন ব্যবহারকারী আপনার কার্যকলাপ ছেড়ে চলে যায়, অনেকটা একইভাবে বিল্ট-ইন মিউজিক অ্যাপ্লিকেশনটি আচরণ করে। এই ক্ষেত্রে, আপনার যা প্রয়োজন তা হল একটি পরিষেবা দ্বারা নিয়ন্ত্রিত একটি MediaPlayer
, যা পরবর্তী বিভাগে আলোচনা করা হয়েছে
একটি পরিষেবাতে MediaPlayer ব্যবহার করা
আপনি যদি চান যে আপনার অ্যাপ্লিকেশনটি অনস্ক্রিন না থাকলেও আপনার মিডিয়া ব্যাকগ্রাউন্ডে খেলুক—অর্থাৎ, ব্যবহারকারী অন্যান্য অ্যাপ্লিকেশনের সাথে ইন্টারঅ্যাক্ট করার সময় আপনি এটি চালিয়ে যেতে চান—তাহলে আপনাকে অবশ্যই একটি পরিষেবা শুরু করতে হবে এবং সেখান থেকে MediaPlayer
ইনস্ট্যান্স নিয়ন্ত্রণ করতে হবে। আপনাকে একটি MediaBrowserServiceCompat
পরিষেবাতে MediaPlayer এম্বেড করতে হবে এবং এটিকে অন্য কার্যকলাপে একটি 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
ত্রুটির অবস্থায় চলে যায় (সম্পূর্ণ অবস্থার চিত্রের জন্য MediaPlayer
শ্রেণীর জন্য ডকুমেন্টেশন দেখুন) এবং আপনি এটি আবার ব্যবহার করার আগে আপনাকে অবশ্যই এটি পুনরায় সেট করতে হবে।
ওয়েক লক ব্যবহার করা
ব্যাকগ্রাউন্ডে মিডিয়া প্লে করে এমন অ্যাপ্লিকেশন ডিজাইন করার সময়, আপনার পরিষেবা চলাকালীন ডিভাইসটি ঘুমাতে যেতে পারে। যেহেতু অ্যান্ড্রয়েড সিস্টেমটি ডিভাইসটি ঘুমানোর সময় ব্যাটারি সংরক্ষণ করার চেষ্টা করে, তাই সিস্টেমটি ফোনের যেকোন বৈশিষ্ট্য বন্ধ করার চেষ্টা করে যা CPU এবং ওয়াইফাই হার্ডওয়্যার সহ প্রয়োজনীয় নয়। যাইহোক, যদি আপনার পরিষেবাটি বাজানো বা মিউজিক স্ট্রিমিং করে, তাহলে আপনি সিস্টেমটিকে আপনার প্লেব্যাকে হস্তক্ষেপ করা থেকে আটকাতে চান৷
এই অবস্থার অধীনে আপনার পরিষেবা চলতে থাকে তা নিশ্চিত করার জন্য, আপনাকে "ওয়েক লক" ব্যবহার করতে হবে৷ একটি ওয়েক লক হল সিস্টেমে সংকেত দেওয়ার একটি উপায় যে আপনার অ্যাপ্লিকেশনটি এমন কিছু বৈশিষ্ট্য ব্যবহার করছে যা ফোনটি নিষ্ক্রিয় থাকলেও উপলব্ধ থাকা উচিত।
দ্রষ্টব্য: আপনার সর্বদা ওয়েক লকগুলি অল্প ব্যবহার করা উচিত এবং সত্যই যতক্ষণ প্রয়োজন ততক্ষণ সেগুলি ধরে রাখা উচিত, কারণ এটি ডিভাইসের ব্যাটারির আয়ু উল্লেখযোগ্যভাবে হ্রাস করে।
আপনার MediaPlayer
বাজানোর সময় CPU চলতে থাকে তা নিশ্চিত করতে, আপনার 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);
যাইহোক, এই উদাহরণে অর্জিত ওয়েক লকটি নিশ্চিত করে যে CPU জাগ্রত থাকবে। আপনি যদি নেটওয়ার্কের মাধ্যমে মিডিয়া স্ট্রিমিং করেন এবং আপনি Wi-Fi ব্যবহার করেন, আপনি সম্ভবত একটি WifiLock
ও ধরে রাখতে চান, যা আপনাকে অবশ্যই অর্জন করতে হবে এবং ম্যানুয়ালি ছেড়ে দিতে হবে। সুতরাং, আপনি যখন দূরবর্তী URL দিয়ে MediaPlayer
প্রস্তুত করা শুরু করেন, তখন আপনার Wi-Fi লক তৈরি এবং অর্জন করা উচিত। যেমন:
কোটলিন
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();
পরিষ্কার করা হচ্ছে
যেমন আগে উল্লেখ করা হয়েছে, একটি MediaPlayer
অবজেক্ট একটি উল্লেখযোগ্য পরিমাণ সিস্টেম সংস্থান গ্রহণ করতে পারে, তাই আপনার এটি শুধুমাত্র যতক্ষণ প্রয়োজন ততক্ষণ রাখা উচিত এবং এটি শেষ করার পরে release()
কল করুন। সিস্টেম আবর্জনা সংগ্রহের উপর নির্ভর করার পরিবর্তে এই পরিষ্কারের পদ্ধতিটিকে স্পষ্টভাবে বলা গুরুত্বপূর্ণ কারণ আবর্জনা সংগ্রহকারী MediaPlayer
পুনরুদ্ধার করার আগে এটি কিছু সময় নিতে পারে, কারণ এটি শুধুমাত্র মেমরির প্রয়োজনের প্রতি সংবেদনশীল এবং অন্যান্য মিডিয়া-সম্পর্কিত সংস্থানগুলির অভাবের জন্য নয়। সুতরাং, আপনি যখন একটি পরিষেবা ব্যবহার করছেন তখন, আপনি MediaPlayer
প্রকাশ করছেন তা নিশ্চিত করতে আপনার সর্বদা onDestroy()
পদ্ধতিটি ওভাররাইড করা উচিত:
কোটলিন
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
ধরে রাখা উচিত যাতে এটি আবার তৈরি করা এবং প্রস্তুত করার ওভারহেড এড়ানো যায়।
ডিজিটাল রাইটস ম্যানেজমেন্ট (ডিআরএম)
অ্যান্ড্রয়েড 8.0 (এপিআই লেভেল 26) দিয়ে শুরু করে, MediaPlayer
এমন API অন্তর্ভুক্ত রয়েছে যা DRM-সুরক্ষিত উপাদানের প্লেব্যাক সমর্থন করে। এগুলি MediaDrm
দ্বারা প্রদত্ত নিম্ন-স্তরের API-এর অনুরূপ, কিন্তু তারা উচ্চ স্তরে কাজ করে এবং অন্তর্নিহিত এক্সট্র্যাক্টর, drm এবং ক্রিপ্টো বস্তুগুলিকে প্রকাশ করে না৷
যদিও MediaPlayer DRM API MediaDrm
এর সম্পূর্ণ কার্যকারিতা প্রদান করে না, এটি সবচেয়ে সাধারণ ব্যবহারের ক্ষেত্রে সমর্থন করে। বর্তমান বাস্তবায়ন নিম্নলিখিত বিষয়বস্তুর প্রকারগুলি পরিচালনা করতে পারে:
- ওয়াইডিভাইন-সুরক্ষিত স্থানীয় মিডিয়া ফাইল
- ওয়াইডিভাইন-সুরক্ষিত রিমোট/স্ট্রিমিং মিডিয়া ফাইল
নিম্নলিখিত কোড স্নিপেটটি দেখায় কিভাবে একটি সাধারণ সিঙ্ক্রোনাস বাস্তবায়নে নতুন ডিআরএম মিডিয়াপ্লেয়ার পদ্ধতিগুলি ব্যবহার করতে হয়।
DRM-নিয়ন্ত্রিত মিডিয়া পরিচালনা করতে, আপনাকে MediaPlayer কলের স্বাভাবিক প্রবাহের পাশাপাশি নতুন পদ্ধতিগুলি অন্তর্ভুক্ত করতে হবে, যেমনটি নীচে দেখানো হয়েছে:
কোটলিন
mediaPlayer?.apply { setDataSource() setOnDrmConfigHelper() // optional, for custom configuration prepare() drmInfo?.also { prepareDrm() getKeyRequest() provideKeyResponse() } // MediaPlayer is now ready to use start() // ...play/pause/resume... stop() releaseDrm() }
জাভা
setDataSource(); setOnDrmConfigHelper(); // optional, for custom configuration prepare(); if (getDrmInfo() != null) { prepareDrm(); getKeyRequest(); provideKeyResponse(); } // MediaPlayer is now ready to use start(); // ...play/pause/resume... stop(); releaseDrm();
MediaPlayer
অবজেক্টটি আরম্ভ করে শুরু করুন এবং স্বাভাবিকের মতো setDataSource()
ব্যবহার করে এর উত্স সেট করুন। তারপর, DRM ব্যবহার করতে, এই পদক্ষেপগুলি সম্পাদন করুন:
- আপনি যদি আপনার অ্যাপটি কাস্টম কনফিগারেশন করতে চান, তাহলে একটি
OnDrmConfigHelper
ইন্টারফেস সংজ্ঞায়িত করুন এবংsetOnDrmConfigHelper()
ব্যবহার করে প্লেয়ারের সাথে সংযুক্ত করুন। - কল
prepare()
। -
getDrmInfo()
কে কল করুন। যদি উৎসে DRM বিষয়বস্তু থাকে, পদ্ধতিটি একটি নন-নালMediaPlayer.DrmInfo
মান প্রদান করে।
যদি MediaPlayer.DrmInfo
বিদ্যমান থাকে:
- উপলব্ধ UUID এর মানচিত্র পরীক্ষা করুন এবং একটি চয়ন করুন।
-
prepareDrm()
কল করে বর্তমান উৎসের জন্য DRM কনফিগারেশন প্রস্তুত করুন। - আপনি যদি একটি
OnDrmConfigHelper
কলব্যাক তৈরি করেন এবং নিবন্ধিত করেন, তবে এটিকে বলা হয় যখনprepareDrm()
চালানো হচ্ছে। এটি আপনাকে DRM সেশন খোলার আগে DRM বৈশিষ্ট্যগুলির কাস্টম কনফিগারেশন করতে দেয়। কলব্যাককে থ্রেডে সিঙ্ক্রোনাসলি বলা হয় যাকেprepareDrm()
বলা হয়। DRM বৈশিষ্ট্যগুলি অ্যাক্সেস করতে,getDrmPropertyString()
এবংsetDrmPropertyString()
কল করুন। দীর্ঘ অপারেশন সঞ্চালন এড়িয়ে চলুন. - যদি ডিভাইসটি এখনও প্রভিশন করা না থাকে,
prepareDrm()
ডিভাইসটির প্রভিশন করার জন্য প্রভিশনিং সার্ভারেও অ্যাক্সেস করে। নেটওয়ার্ক সংযোগের উপর নির্ভর করে এটি পরিবর্তনশীল সময় নিতে পারে। - লাইসেন্স সার্ভারে পাঠানোর জন্য একটি অস্বচ্ছ কী অনুরোধ বাইট অ্যারে পেতে,
getKeyRequest()
কল করুন। - লাইসেন্স সার্ভার থেকে প্রাপ্ত মূল প্রতিক্রিয়া সম্পর্কে DRM ইঞ্জিনকে জানাতে,
provideKeyResponse()
কল করুন। ফলাফল কী অনুরোধের ধরনের উপর নির্ভর করে:- যদি প্রতিক্রিয়াটি একটি অফলাইন কী অনুরোধের জন্য হয়, ফলাফলটি একটি কী-সেট শনাক্তকারী। আপনি একটি নতুন সেশনে কীগুলি পুনরুদ্ধার করতে
restoreKeys()
এর সাথে এই কী-সেট শনাক্তকারী ব্যবহার করতে পারেন। - যদি প্রতিক্রিয়া একটি স্ট্রিমিং বা রিলিজ অনুরোধের জন্য হয়, ফলাফলটি শূন্য।
- যদি প্রতিক্রিয়াটি একটি অফলাইন কী অনুরোধের জন্য হয়, ফলাফলটি একটি কী-সেট শনাক্তকারী। আপনি একটি নতুন সেশনে কীগুলি পুনরুদ্ধার করতে
prepareDrm()
অ্যাসিঙ্ক্রোনাসভাবে চালানো হচ্ছে
ডিফল্টরূপে, prepareDrm()
সিঙ্ক্রোনাসভাবে চলে, প্রস্তুতি শেষ না হওয়া পর্যন্ত ব্লক করা। যাইহোক, একটি নতুন ডিভাইসে প্রথম DRM প্রস্তুতির জন্যও প্রভিশনের প্রয়োজন হতে পারে, যা অভ্যন্তরীণভাবে prepareDrm()
দ্বারা পরিচালিত হয়, এবং নেটওয়ার্ক অপারেশন জড়িত থাকার কারণে শেষ হতে কিছুটা সময় লাগতে পারে। আপনি একটি MediaPlayer.OnDrmPreparedListener
সংজ্ঞায়িত এবং সেট করার মাধ্যমে prepareDrm()
এ ব্লক করা এড়াতে পারেন।
আপনি যখন একটি OnDrmPreparedListener
সেট করেন, prepareDrm()
প্রভিশনিং (যদি প্রয়োজন হয়) এবং পটভূমিতে প্রস্তুতি সম্পাদন করে। বিধান এবং প্রস্তুতি শেষ হলে, শ্রোতাকে ডাকা হয়। কলিং সিকোয়েন্স বা শ্রোতা যে থ্রেডে চলে সে সম্পর্কে আপনার কোন অনুমান করা উচিত নয় (যদি না শ্রোতা একটি হ্যান্ডলার থ্রেডের সাথে নিবন্ধিত হয়)। শ্রোতাকে prepareDrm()
ফিরে আসার আগে বা পরে ডাকা যেতে পারে।
অ্যাসিঙ্ক্রোনাসভাবে DRM সেট আপ করা হচ্ছে
আপনি DRM প্রস্তুতির জন্য MediaPlayer.OnDrmInfoListener
এবং প্লেয়ার শুরু করতে MediaPlayer.OnDrmPreparedListener
তৈরি এবং নিবন্ধন করে অ্যাসিঙ্ক্রোনাসভাবে DRM শুরু করতে পারেন। তারা নিচের মত করে, prepareAsync()
এর সাথে একত্রে কাজ করে:
কোটলিন
setOnPreparedListener() setOnDrmInfoListener() setDataSource() prepareAsync() // ... // If the data source content is protected you receive a call to the onDrmInfo() callback. override fun onDrmInfo(mediaPlayer: MediaPlayer, drmInfo: MediaPlayer.DrmInfo) { mediaPlayer.apply { prepareDrm() getKeyRequest() provideKeyResponse() } } // When prepareAsync() finishes, you receive a call to the onPrepared() callback. // If there is a DRM, onDrmInfo() sets it up before executing this callback, // so you can start the player. override fun onPrepared(mediaPlayer: MediaPlayer) { mediaPlayer.start() }
জাভা
setOnPreparedListener(); setOnDrmInfoListener(); setDataSource(); prepareAsync(); // ... // If the data source content is protected you receive a call to the onDrmInfo() callback. onDrmInfo() { prepareDrm(); getKeyRequest(); provideKeyResponse(); } // When prepareAsync() finishes, you receive a call to the onPrepared() callback. // If there is a DRM, onDrmInfo() sets it up before executing this callback, // so you can start the player. onPrepared() { start(); }
এনক্রিপ্ট করা মিডিয়া পরিচালনা করা
Android 8.0 (API লেভেল 26) দিয়ে শুরু করে MediaPlayer
প্রাথমিক স্ট্রীম প্রকার H.264, এবং AAC-এর জন্য কমন এনক্রিপশন স্কিম (CENC) এবং HLS স্যাম্পল-লেভেল এনক্রিপ্টেড মিডিয়া (METHOD=SAMPLE-AES) ডিক্রিপ্ট করতে পারে। সম্পূর্ণ-সেগমেন্ট এনক্রিপ্ট করা মিডিয়া (METHOD=AES-128) পূর্বে সমর্থিত ছিল।
একটি ContentResolver থেকে মিডিয়া পুনরুদ্ধার করা হচ্ছে
আরেকটি বৈশিষ্ট্য যা মিডিয়া প্লেয়ার অ্যাপ্লিকেশনে উপযোগী হতে পারে তা হল ব্যবহারকারীর ডিভাইসে থাকা সঙ্গীত পুনরুদ্ধার করার ক্ষমতা। আপনি বহিরাগত মিডিয়ার জন্য ContentResolver
জিজ্ঞাসা করে এটি করতে পারেন:
কোটলিন
val resolver: ContentResolver = contentResolver val uri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI val cursor: Cursor? = resolver.query(uri, null, null, null, null) when { cursor == null -> { // query failed, handle error. } !cursor.moveToFirst() -> { // no media on the device } else -> { val titleColumn: Int = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media.TITLE) val idColumn: Int = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media._ID) do { val thisId = cursor.getLong(idColumn) val thisTitle = cursor.getString(titleColumn) // ...process entry... } while (cursor.moveToNext()) } } cursor?.close()
জাভা
ContentResolver contentResolver = getContentResolver(); Uri uri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; Cursor cursor = contentResolver.query(uri, null, null, null, null); if (cursor == null) { // query failed, handle error. } else if (!cursor.moveToFirst()) { // no media on the device } else { int titleColumn = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media.TITLE); int idColumn = cursor.getColumnIndex(android.provider.MediaStore.Audio.Media._ID); do { long thisId = cursor.getLong(idColumn); String thisTitle = cursor.getString(titleColumn); // ...process entry... } while (cursor.moveToNext()); }
MediaPlayer
এর সাথে এটি ব্যবহার করতে, আপনি এটি করতে পারেন:
কোটলিন
val id: Long = /* retrieve it from somewhere */ val contentUri: Uri = ContentUris.withAppendedId(android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id ) mediaPlayer = MediaPlayer().apply { setAudioAttributes( AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) .setUsage(AudioAttributes.USAGE_MEDIA) .build() ) setDataSource(applicationContext, contentUri) } // ...prepare and start...
জাভা
long id = /* retrieve it from somewhere */; Uri contentUri = ContentUris.withAppendedId( android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id); mediaPlayer = new MediaPlayer(); mediaPlayer.setAudioAttributes( new AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) .setUsage(AudioAttributes.USAGE_MEDIA) .build() ); mediaPlayer.setDataSource(getApplicationContext(), contentUri); // ...prepare and start...
আরও জানুন
এই পৃষ্ঠাগুলি অডিও এবং ভিডিও রেকর্ডিং, সঞ্চয় এবং প্লে ব্যাক সম্পর্কিত বিষয়গুলি কভার করে৷