Jetpack Media3 একটি Player ইন্টারফেস সংজ্ঞায়িত করে, যা ভিডিও এবং অডিও ফাইল প্লেব্যাকের জন্য মৌলিক কার্যকারিতা বর্ণনা করে। Media3-তে ExoPlayer হলো এই ইন্টারফেসের ডিফল্ট ইমপ্লিমেন্টেশন। আমরা ExoPlayer ব্যবহার করার পরামর্শ দিই, কারণ এটি এমন একটি ব্যাপক ফিচার সেট প্রদান করে যা বেশিরভাগ প্লেব্যাক ব্যবহারের ক্ষেত্রকে কভার করে এবং আপনার যেকোনো অতিরিক্ত ব্যবহারের ক্ষেত্র সামলানোর জন্য এটিকে কাস্টমাইজ করা যায়। ExoPlayer ডিভাইস এবং ওএস ফ্র্যাগমেন্টেশনকেও অ্যাবস্ট্রাক্ট করে, ফলে আপনার কোড সম্পূর্ণ অ্যান্ড্রয়েড ইকোসিস্টেম জুড়ে সামঞ্জস্যপূর্ণভাবে কাজ করে। ExoPlayer-এ অন্তর্ভুক্ত রয়েছে:
- প্লেলিস্টের জন্য সমর্থন
- বিভিন্ন প্রগতিশীল এবং অভিযোজিত স্ট্রিমিং ফরম্যাটের জন্য সমর্থন
- ক্লায়েন্ট-সাইড এবং সার্ভার-সাইড উভয় দিকে বিজ্ঞাপন সন্নিবেশের জন্য সমর্থন
- DRM-সুরক্ষিত প্লেব্যাকের জন্য সমর্থন
এই পৃষ্ঠাটিতে একটি প্লেব্যাক অ্যাপ তৈরির কিছু গুরুত্বপূর্ণ ধাপ দেখানো হয়েছে, এবং আরও বিস্তারিত জানতে আপনি Media3 ExoPlayer-এর উপর আমাদের সম্পূর্ণ গাইডগুলো দেখতে পারেন।
শুরু করা হচ্ছে
শুরু করার জন্য, Jetpack Media3-এর ExoPlayer, UI, এবং Common মডিউলগুলিতে একটি ডিপেন্ডেন্সি যোগ করুন:
implementation "androidx.media3:media3-exoplayer:1.9.3" implementation "androidx.media3:media3-ui:1.9.3" implementation "androidx.media3:media3-common:1.9.3"
আপনার ব্যবহারের ধরনের ওপর নির্ভর করে, DASH ফরম্যাটে স্ট্রিম চালানোর জন্য আপনার Media3-এর অতিরিক্ত মডিউল, যেমন exoplayer-dash প্রয়োজন হতে পারে।
আপনার পছন্দের লাইব্রেরি সংস্করণ দিয়ে 1.9.3 প্রতিস্থাপন করতে ভুলবেন না। সর্বশেষ সংস্করণটি জানতে আপনি রিলিজ নোট দেখতে পারেন।
একটি মিডিয়া প্লেয়ার তৈরি করা
Media3-এর সাথে, আপনি হয় এর অন্তর্ভুক্ত Player ইন্টারফেসের ইমপ্লিমেন্টেশন, ExoPlayer , ব্যবহার করতে পারেন, অথবা নিজের মতো করে একটি কাস্টম ইমপ্লিমেন্টেশন তৈরি করতে পারেন।
একটি এক্সো প্লেয়ার তৈরি করা
একটি ExoPlayer ইনস্ট্যান্স তৈরি করার সবচেয়ে সহজ উপায়টি নিম্নরূপ:
কোটলিন
val player = ExoPlayer.Builder(context).build()
জাভা
ExoPlayer player = new ExoPlayer.Builder(context).build();
আপনি আপনার মিডিয়া প্লেয়ারটি যে Activity , Fragment , বা Service এ রয়েছে, তার onCreate() লাইফসাইকেল মেথডে তৈরি করতে পারেন।
Builder বিভিন্ন ধরনের কাস্টমাইজেশন অপশন রয়েছে, যেগুলোতে আপনার আগ্রহ থাকতে পারে, যেমন:
- অডিও ফোকাস হ্যান্ডলিং কনফিগার করতে
setAudioAttributes()ব্যবহার করুন - অডিও আউটপুট ডিভাইস সংযোগ বিচ্ছিন্ন হলে প্লেব্যাকের আচরণ কনফিগার করতে
setHandleAudioBecomingNoisy()করা হয়। - ট্র্যাক নির্বাচন কনফিগার করতে
setTrackSelector()ব্যবহার করুন
Media3 একটি PlayerView UI কম্পোনেন্ট প্রদান করে যা আপনি আপনার অ্যাপের লেআউট ফাইলে অন্তর্ভুক্ত করতে পারেন। এই কম্পোনেন্টটি প্লেব্যাক নিয়ন্ত্রণের জন্য একটি PlayerControlView , সাবটাইটেল প্রদর্শনের জন্য SubtitleView এবং ভিডিও রেন্ডার করার জন্য Surface এনক্যাপসুলেট করে।
খেলোয়াড়কে প্রস্তুত করা
প্লেব্যাকের জন্য প্লেলিস্টে মিডিয়া আইটেম যোগ করতে setMediaItem() এবং addMediaItem() এর মতো মেথড ব্যবহার করুন। এরপর, মিডিয়া লোড করা শুরু করতে এবং প্রয়োজনীয় রিসোর্স সংগ্রহ করতে prepare() কল করুন।
অ্যাপটি ফোরগ্রাউন্ডে আসার আগে আপনার এই ধাপগুলো সম্পাদন করা উচিত নয়। যদি আপনার প্লেয়ারটি কোনো Activity বা Fragment মধ্যে থাকে, তাহলে API লেভেল 24 এবং তার উপরের ক্ষেত্রে onStart() লাইফসাইকেল মেথডে অথবা API লেভেল 23 এবং তার নিচের ক্ষেত্রে onResume() লাইফসাইকেল মেথডে প্লেয়ারটিকে প্রস্তুত করতে হবে। কোনো Service এর মধ্যে থাকা প্লেয়ারের জন্য, আপনি এটিকে onCreate() মেথডে প্রস্তুত করতে পারেন। লাইফসাইকেল মেথডগুলো কীভাবে প্রয়োগ করতে হয় তার একটি উদাহরণের জন্য Exoplayer কোডল্যাবটি দেখুন।
খেলোয়াড়কে নিয়ন্ত্রণ করুন
প্লেয়ারটি প্রস্তুত হয়ে গেলে, আপনি প্লেয়ারের উপর বিভিন্ন মেথড কল করে প্লেব্যাক নিয়ন্ত্রণ করতে পারেন, যেমন:
- প্লেব্যাক শুরু এবং থামাতে
play()এবংpause()ব্যবহার করুন। - বর্তমান মিডিয়া আইটেমের মধ্যে কোনো একটি অবস্থানে যাওয়ার জন্য
seekTo()হয়। - প্লেলিস্টের মধ্যে নেভিগেট করার জন্য
seekToNextMediaItem()এবংseekToPreviousMediaItem()করুন।
PlayerView বা PlayerControlView মতো UI কম্পোনেন্টগুলো কোনো প্লেয়ারের সাথে যুক্ত হলে সেই অনুযায়ী আপডেট হবে।
প্লেয়ারটি ছেড়ে দিন
প্লেব্যাকের জন্য ভিডিও ডিকোডারের মতো সীমিত সরবরাহের রিসোর্সের প্রয়োজন হতে পারে, তাই প্লেয়ারটির আর প্রয়োজন না হলে রিসোর্স মুক্ত করার জন্য প্লেয়ারটিতে release() কল করা গুরুত্বপূর্ণ।
আপনার প্লেয়ার যদি কোনো Activity বা Fragment মধ্যে থাকে, তাহলে API লেভেল 24 বা তার বেশির ক্ষেত্রে onStop() লাইফসাইকেল মেথডে অথবা API লেভেল 23 বা তার কমের ক্ষেত্রে onPause() মেথডে প্লেয়ারটিকে রিলিজ করুন। কোনো Service এর মধ্যে থাকা প্লেয়ারের ক্ষেত্রে, আপনি এটিকে onDestroy() মেথডে রিলিজ করতে পারেন। লাইফসাইকেল মেথডগুলো কীভাবে প্রয়োগ করতে হয় তার একটি উদাহরণের জন্য Exoplayer কোডল্যাবটি দেখুন।
মিডিয়া সেশনের মাধ্যমে প্লেব্যাক পরিচালনা করা
অ্যান্ড্রয়েডে, মিডিয়া সেশনগুলো প্রসেসের সীমানা পেরিয়ে একটি মিডিয়া প্লেয়ারের সাথে ইন্টারঅ্যাক্ট করার একটি প্রমিত উপায় প্রদান করে। আপনার প্লেয়ারের সাথে একটি মিডিয়া সেশন সংযুক্ত করলে, আপনি আপনার মিডিয়া প্লেব্যাক বাহ্যিকভাবে প্রচার করতে এবং বাহ্যিক উৎস থেকে প্লেব্যাক কমান্ড গ্রহণ করতে পারেন; উদাহরণস্বরূপ, মোবাইল এবং বড় স্ক্রিনের ডিভাইসগুলিতে সিস্টেম মিডিয়া কন্ট্রোলের সাথে এটিকে একীভূত করার জন্য।
মিডিয়া সেশন ব্যবহার করতে, Media3 সেশন মডিউলের উপর একটি ডিপেন্ডেন্সি যোগ করুন:
implementation "androidx.media3:media3-session:1.9.3"
একটি মিডিয়া সেশন তৈরি করুন
প্লেয়ার চালু করার পর আপনি নিম্নোক্তভাবে একটি MediaSession তৈরি করতে পারেন:
কোটলিন
val player = ExoPlayer.Builder(context).build() val mediaSession = MediaSession.Builder(context, player).build()
জাভা
ExoPlayer player = new ExoPlayer.Builder(context).build(); MediaSession mediaSession = new MediaSession.Builder(context, player).build();
Media3 স্বয়ংক্রিয়ভাবে Player অবস্থাকে MediaSession এর অবস্থার সাথে সিঙ্ক করে। এটি ExoPlayer , CastPlayer বা কাস্টম ইমপ্লিমেন্টেশন সহ যেকোনো Player ইমপ্লিমেন্টেশনের সাথেই কাজ করে।
অন্যান্য ক্লায়েন্টদের নিয়ন্ত্রণ প্রদান করুন
ক্লায়েন্ট অ্যাপগুলো আপনার মিডিয়া সেশনের প্লেব্যাক নিয়ন্ত্রণ করতে একটি মিডিয়া কন্ট্রোলার প্রয়োগ করতে পারে। এই অনুরোধগুলো গ্রহণ করার জন্য, আপনার MediaSession তৈরি করার সময় একটি কলব্যাক অবজেক্ট সেট করুন।
যখন কোনো কন্ট্রোলার আপনার মিডিয়া সেশনে সংযোগ স্থাপন করতে যায়, তখন onConnect() মেথডটি কল করা হয়। অনুরোধটি গ্রহণ করবেন নাকি প্রত্যাখ্যান করবেন , তা ঠিক করার জন্য আপনি প্রদত্ত ControllerInfo ব্যবহার করতে পারেন। Media3 Session ডেমো অ্যাপে এর একটি উদাহরণ দেখুন।
একবার সংযুক্ত হলে, একটি কন্ট্রোলার সেশনে প্লেব্যাক কমান্ড পাঠাতে পারে। এরপর সেশন সেই কমান্ডগুলো প্লেয়ারের কাছে হস্তান্তর করে। Player ইন্টারফেসে সংজ্ঞায়িত প্লেব্যাক এবং প্লেলিস্ট কমান্ডগুলো সেশন দ্বারা স্বয়ংক্রিয়ভাবে পরিচালিত হয়।
অন্যান্য কলব্যাক মেথডগুলো আপনাকে, উদাহরণস্বরূপ, কাস্টম প্লেব্যাক কমান্ডের অনুরোধ এবং প্লেলিস্ট পরিবর্তনের মতো বিষয়গুলো পরিচালনা করার সুযোগ দেয়। এই কলব্যাকগুলোতেও একইভাবে একটি ControllerInfo অবজেক্ট অন্তর্ভুক্ত থাকে, যাতে আপনি প্রতিটি অনুরোধের ভিত্তিতে অ্যাক্সেস কন্ট্রোল নির্ধারণ করতে পারেন।
পটভূমিতে মিডিয়া চলছে
আপনার অ্যাপ ফোরগ্রাউন্ডে না থাকলেও মিডিয়া প্লে করা চালিয়ে যেতে, যেমন ব্যবহারকারীর অ্যাপটি খোলা না থাকলেও গান, অডিওবুক বা পডকাস্ট চালানোর জন্য, আপনার Player এবং MediaSession একটি ফোরগ্রাউন্ড সার্ভিসের মধ্যে আবদ্ধ করা উচিত। এই উদ্দেশ্যে Media3, MediaSessionService ইন্টারফেসটি প্রদান করে।
একটি MediaSessionService বাস্তবায়ন করা
MediaSessionService এক্সটেন্ড করে এমন একটি ক্লাস তৈরি করুন এবং onCreate() লাইফসাইকেল মেথডে আপনার MediaSession ইনস্ট্যানশিয়েট করুন।
কোটলিন
class PlaybackService : MediaSessionService() { private var mediaSession: MediaSession? = null // Create your Player and MediaSession in the onCreate lifecycle event override fun onCreate() { super.onCreate() val player = ExoPlayer.Builder(this).build() mediaSession = MediaSession.Builder(this, player).build() } // Remember to release the player and media session in onDestroy override fun onDestroy() { mediaSession?.run { player.release() release() mediaSession = null } super.onDestroy() } }
জাভা
public class PlaybackService extends MediaSessionService { private MediaSession mediaSession = null; @Override public void onCreate() { super.onCreate(); ExoPlayer player = new ExoPlayer.Builder(this).build(); mediaSession = new MediaSession.Builder(this, player).build(); } @Override public void onDestroy() { mediaSession.getPlayer().release(); mediaSession.release(); mediaSession = null; super.onDestroy(); } }
আপনার ম্যানিফেস্টে, একটি MediaSessionService ইন্টেন্ট ফিল্টার সহ আপনার Service ক্লাসটি যোগ করুন এবং ফোরগ্রাউন্ড সার্ভিস চালানোর জন্য FOREGROUND_SERVICE পারমিশনের জন্য অনুরোধ করুন:
<service
android:name=".PlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaSessionService"/>
</intent-filter>
</service>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
সবশেষে, আপনার তৈরি করা ক্লাসে, আপনার মিডিয়া সেশনে ক্লায়েন্টের অ্যাক্সেস নিয়ন্ত্রণ করতে onGetSession() মেথডটি ওভাররাইড করুন। কানেকশনের অনুরোধ গ্রহণ করতে একটি MediaSession রিটার্ন করুন, অথবা অনুরোধটি প্রত্যাখ্যান করতে null রিটার্ন করুন।
কোটলিন
// This example always accepts the connection request override fun onGetSession( controllerInfo: MediaSession.ControllerInfo ): MediaSession? = mediaSession
জাভা
@Override public MediaSession onGetSession(MediaSession.ControllerInfo controllerInfo) { // This example always accepts the connection request return mediaSession; }
আপনার UI-এর সাথে সংযোগ স্থাপন করা হচ্ছে
এখন যেহেতু আপনার মিডিয়া সেশনটি সেই Activity বা Fragment থেকে আলাদা একটি Service রয়েছে যেখানে আপনার প্লেয়ার UI থাকে, তাই আপনি একটি MediaController ব্যবহার করে সেগুলোকে একসাথে লিঙ্ক করতে পারেন। আপনার UI থাকা Activity বা Fragment onStart() মেথডে, আপনার MediaSession জন্য একটি SessionToken তৈরি করুন, তারপর সেই SessionToken ব্যবহার করে একটি MediaController বিল্ড করুন। একটি MediaController বিল্ড করার প্রক্রিয়াটি অ্যাসিঙ্ক্রোনাসভাবে সম্পন্ন হয়।
কোটলিন
override fun onStart() { val sessionToken = SessionToken(this, ComponentName(this, PlaybackService::class.java)) val controllerFuture = MediaController.Builder(this, sessionToken).buildAsync() controllerFuture.addListener( { // Call controllerFuture.get() to retrieve the MediaController. // MediaController implements the Player interface, so it can be // attached to the PlayerView UI component. playerView.setPlayer(controllerFuture.get()) }, MoreExecutors.directExecutor() ) }
জাভা
@Override public void onStart() { SessionToken sessionToken = new SessionToken(this, new ComponentName(this, PlaybackService.class)); ListenableFuture<MediaController> controllerFuture = new MediaController.Builder(this, sessionToken).buildAsync(); controllerFuture.addListener(() -> { // Call controllerFuture.get() to retrieve the MediaController. // MediaController implements the Player interface, so it can be // attached to the PlayerView UI component. playerView.setPlayer(controllerFuture.get()); }, MoreExecutors.directExecutor()) }
MediaController Player ইন্টারফেসটি ইমপ্লিমেন্ট করে, তাই প্লেব্যাক নিয়ন্ত্রণ করতে আপনি play() এবং pause() এর মতো একই মেথডগুলো ব্যবহার করতে পারেন। অন্যান্য কম্পোনেন্টের মতোই, যখন MediaController আর প্রয়োজন হয় না, তখন MediaController.releaseFuture() কল করে এটিকে রিলিজ করতে মনে রাখবেন; যেমন কোনো Activity র onStop() লাইফসাইকেল মেথডে।
একটি বিজ্ঞপ্তি প্রকাশ করা
সক্রিয় থাকা অবস্থায় একটি নোটিফিকেশন প্রকাশ করার জন্য ফোরগ্রাউন্ড সার্ভিস প্রয়োজন। একটি MediaSessionService স্বয়ংক্রিয়ভাবে আপনার জন্য MediaNotification আকারে একটি MediaStyle নোটিফিকেশন তৈরি করবে। একটি কাস্টম নোটিফিকেশন প্রদান করতে, DefaultMediaNotificationProvider.Builder ব্যবহার করে অথবা প্রোভাইডার ইন্টারফেসের একটি কাস্টম ইমপ্লিমেন্টেশন তৈরি করে একটি MediaNotification.Provider তৈরি করুন। setMediaNotificationProvider ব্যবহার করে আপনার প্রোভাইডারটিকে MediaSession এ যুক্ত করুন।
আপনার কন্টেন্ট লাইব্রেরির বিজ্ঞাপন
একটি MediaLibraryService MediaSessionService উপর ভিত্তি করে তৈরি হয় এবং এটি ক্লায়েন্ট অ্যাপগুলোকে আপনার অ্যাপ দ্বারা সরবরাহকৃত মিডিয়া কন্টেন্ট ব্রাউজ করার সুযোগ দেয়। ক্লায়েন্ট অ্যাপগুলো আপনার MediaLibraryService সাথে ইন্টারঅ্যাক্ট করার জন্য একটি MediaBrowser ইমপ্লিমেন্ট করে।
MediaLibraryService ইমপ্লিমেন্ট করা MediaSessionService ইমপ্লিমেন্ট করার মতোই, তবে onGetSession() ফাংশনে MediaSession এর পরিবর্তে MediaLibrarySession রিটার্ন করতে হয়। MediaSession.Callback এর তুলনায়, MediaLibrarySession.Callback এ অতিরিক্ত কিছু মেথড থাকে, যা একটি ব্রাউজার ক্লায়েন্টকে আপনার লাইব্রেরি সার্ভিসের কন্টেন্ট নেভিগেট করার সুযোগ দেয়।
MediaSessionService এর মতোই, আপনার ম্যানিফেস্টে MediaLibraryService ঘোষণা করুন এবং একটি ফোরগ্রাউন্ড সার্ভিস চালানোর জন্য FOREGROUND_SERVICE পারমিশনের জন্য অনুরোধ করুন:
<service
android:name=".PlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaLibraryService"/>
<action android:name="android.media.browse.MediaBrowserService"/>
</intent-filter>
</service>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
উপরের উদাহরণটিতে MediaLibraryService এবং, পূর্ববর্তী সংস্করণের সাথে সামঞ্জস্য রাখার জন্য, পুরোনো MediaBrowserService উভয়ের জন্যই একটি ইন্টেন্ট ফিল্টার অন্তর্ভুক্ত রয়েছে। এই অতিরিক্ত ইন্টেন্ট ফিল্টারটি MediaBrowserCompat API ব্যবহারকারী ক্লায়েন্ট অ্যাপগুলোকে আপনার Service চিনতে সক্ষম করে।
একটি MediaLibrarySession আপনাকে একটি ট্রি স্ট্রাকচারে আপনার কন্টেন্ট লাইব্রেরি পরিবেশন করতে দেয়, যেখানে একটিমাত্র রুট MediaItem থাকে। ট্রি-এর প্রতিটি MediaItem এর যেকোনো সংখ্যক চাইল্ড MediaItem নোড থাকতে পারে। ক্লায়েন্ট অ্যাপের অনুরোধের উপর ভিত্তি করে আপনি একটি ভিন্ন রুট বা একটি ভিন্ন ট্রি পরিবেশন করতে পারেন। উদাহরণস্বরূপ, প্রস্তাবিত মিডিয়া আইটেমের তালিকা খুঁজছে এমন কোনো ক্লায়েন্টকে আপনি যে ট্রি ফেরত দেবেন, তাতে শুধুমাত্র রুট MediaItem এবং এক স্তরের চাইল্ড MediaItem নোড থাকতে পারে, যেখানে অন্য কোনো ক্লায়েন্ট অ্যাপকে আপনি যে ট্রি ফেরত দেবেন তা কন্টেন্টের একটি আরও সম্পূর্ণ লাইব্রেরি উপস্থাপন করতে পারে।
একটি MediaLibrarySession তৈরি করা
MediaLibrarySession কন্টেন্ট ব্রাউজিং এপিআই যোগ করার জন্য MediaSession এপিআই-কে প্রসারিত করে। MediaSession কলব্যাকের তুলনায়, MediaLibrarySession কলব্যাক নিম্নলিখিত মেথডগুলো যোগ করে:
- যখন কোনো ক্লায়েন্ট একটি কন্টেন্ট ট্রি-এর রুট
MediaItemজন্য অনুরোধ করে, তখনonGetLibraryRoot()ব্যবহৃত হয়। - যখন কোনো ক্লায়েন্ট কন্টেন্ট ট্রিতে থাকা কোনো
MediaItemএর চাইল্ড আইটেমগুলো অনুরোধ করে, তখনonGetChildren()ব্যবহৃত হয়। - যখন কোনো ক্লায়েন্ট একটি নির্দিষ্ট কোয়েরির জন্য কন্টেন্ট ট্রি থেকে অনুসন্ধানের ফলাফল অনুরোধ করে, তখন
onGetSearchResult()ব্যবহৃত হয়।
প্রাসঙ্গিক কলব্যাক মেথডগুলোতে একটি LibraryParams অবজেক্ট অন্তর্ভুক্ত থাকবে, যা ক্লায়েন্ট অ্যাপটি কোন ধরনের কন্টেন্ট ট্রি-তে আগ্রহী সে সম্পর্কে অতিরিক্ত সংকেত দেবে।