ऐसा अक्सर होता है, जब ऐप्लिकेशन फ़ोरग्राउंड में न होने पर भी मीडिया चलाया जाता है. उदाहरण के लिए, आम तौर पर कोई म्यूज़िक प्लेयर, उपयोगकर्ता के डिवाइस लॉक करने या किसी दूसरे ऐप्लिकेशन का इस्तेमाल करने पर भी संगीत चलाता रहता है. Media3 लाइब्रेरी, इंटरफ़ेस की एक सीरीज़ उपलब्ध कराती है. इससे आपको बैकग्राउंड में वीडियो चलाने की सुविधा मिलती है.
MediaSessionService का इस्तेमाल करना
बैकग्राउंड में वीडियो चलाने की सुविधा चालू करने के लिए, आपको Player और MediaSession को अलग Service में शामिल करना होगा.
इससे डिवाइस, मीडिया को तब भी ऐक्सेस कर सकता है, जब आपका ऐप्लिकेशन फ़ोरग्राउंड में न हो.
MediaSessionService की मदद से, मीडिया सेशन को ऐप्लिकेशन की गतिविधि से अलग चलाया जा सकता हैकिसी सेवा में प्लेयर को होस्ट करते समय, आपको MediaSessionService का इस्तेमाल करना चाहिए.
इसके लिए, MediaSessionService को बढ़ाने वाली क्लास बनाएं और इसके अंदर अपना मीडिया सेशन बनाएं.
MediaSessionService का इस्तेमाल करने से, Google Assistant, सिस्टम मीडिया कंट्रोल, पेरिफ़ेरल डिवाइसों पर मौजूद मीडिया बटन या Wear OS जैसे कंपैनियन डिवाइसों जैसे बाहरी क्लाइंट आपकी सेवा को ढूंढ सकते हैं, उससे कनेक्ट हो सकते हैं, और प्लेबैक को कंट्रोल कर सकते हैं. इसके लिए, उन्हें आपके ऐप्लिकेशन की यूज़र इंटरफ़ेस (यूआई) गतिविधि को ऐक्सेस करने की ज़रूरत नहीं होती. दरअसल, एक ही MediaSessionService से एक साथ कई क्लाइंट ऐप्लिकेशन कनेक्ट किए जा सकते हैं. हर ऐप्लिकेशन का अपना MediaSessionService होता है.MediaController
सेवा की लाइफ़साइकल लागू करना
आपको अपनी सेवा के दो लाइफ़साइकल तरीके लागू करने होंगे:
onCreate()को तब कॉल किया जाता है, जब पहला कंट्रोलर कनेक्ट होने वाला होता है और सेवा शुरू हो जाती है.PlayerऔरMediaSessionबनाने के लिए, यह सबसे अच्छी जगह है.onDestroy()को तब कॉल किया जाता है, जब सेवा बंद की जा रही हो. सभी संसाधनों को रिलीज़ किया जाना चाहिए. इनमें प्लेयर और सेशन शामिल हैं.
आपके पास onTaskRemoved(Intent) को बदलने का विकल्प होता है, ताकि यह तय किया जा सके कि जब उपयोगकर्ता, हाल ही के टास्क से ऐप्लिकेशन को खारिज करे, तो क्या हो. डिफ़ॉल्ट रूप से, अगर वीडियो चल रहा है, तो सेवा चालू रहती है. अगर वीडियो नहीं चल रहा है, तो सेवा बंद हो जाती है.
Kotlin
class PlaybackService : MediaSessionService() { private var mediaSession: MediaSession? = null // Create your player and media session 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() } }
Java
public class PlaybackService extends MediaSessionService { private MediaSession mediaSession = null; // Create your Player and MediaSession in the onCreate lifecycle event @Override public void onCreate() { super.onCreate(); ExoPlayer player = new ExoPlayer.Builder(this).build(); mediaSession = new MediaSession.Builder(this, player).build(); } // Remember to release the player and media session in onDestroy @Override public void onDestroy() { mediaSession.getPlayer().release(); mediaSession.release(); mediaSession = null; super.onDestroy(); } }
बैकग्राउंड में वीडियो चलाने की सुविधा के बजाय, जब उपयोगकर्ता ऐप्लिकेशन को खारिज कर दे, तब सेवा को बंद किया जा सकता है:
Kotlin
override fun onTaskRemoved(rootIntent: Intent?) { pauseAllPlayersAndStopSelf() }
Java
@Override public void onTaskRemoved(@Nullable Intent rootIntent) { pauseAllPlayersAndStopSelf(); }
onTaskRemoved को मैन्युअल तरीके से लागू करने के लिए, isPlaybackOngoing() का इस्तेमाल करके यह देखा जा सकता है कि वीडियो अब भी चल रहा है या नहीं. साथ ही, यह भी देखा जा सकता है कि फ़ोरग्राउंड सेवा शुरू हो गई है या नहीं.
मीडिया सेशन का ऐक्सेस देना
onGetSession() तरीके को बदलकर, अन्य क्लाइंट को अपने मीडिया सेशन का ऐक्सेस दें. यह सेशन, सेवा बनाते समय बनाया गया था.
Kotlin
class PlaybackService : MediaSessionService() { private var mediaSession: MediaSession? = null // [...] lifecycle methods omitted override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession? = mediaSession }
Java
public class PlaybackService extends MediaSessionService { private MediaSession mediaSession = null; // [...] lifecycle methods omitted @Override public MediaSession onGetSession(MediaSession.ControllerInfo controllerInfo) { return mediaSession; } }
मेनिफ़ेस्ट में सेवा की जानकारी देना
किसी ऐप्लिकेशन को फ़ोरग्राउंड सेवा के तौर पर वीडियो चलाने के लिए, FOREGROUND_SERVICE और FOREGROUND_SERVICE_MEDIA_PLAYBACK अनुमतियों की ज़रूरत होती है:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
आपको मेनिफ़ेस्ट में अपनी Service क्लास का एलान भी करना होगा. इसके लिए, MediaSessionService का इंटेंट फ़िल्टर और foregroundServiceType का इस्तेमाल करना होगा, जिसमें mediaPlayback शामिल हो.
<service
android:name=".PlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaSessionService"/>
<action android:name="android.media.browse.MediaBrowserService"/>
</intent-filter>
</service>
MediaController का इस्तेमाल करके, वीडियो चलाने की सुविधा को कंट्रोल करना
अपने प्लेयर यूज़र इंटरफ़ेस (यूआई) वाले ऐप्लिकेशन या फ़्रैगमेंट में, MediaController का इस्तेमाल करके यूआई और मीडिया सेशन के बीच लिंक बनाया जा सकता है. आपका यूज़र इंटरफ़ेस (यूआई), मीडिया कंट्रोलर का इस्तेमाल करता है. इससे, सेशन में मौजूद प्लेयर को यूज़र इंटरफ़ेस (यूआई) से निर्देश भेजे जाते हैं. MediaController बनाने और इस्तेमाल करने के बारे में ज़्यादा जानने के लिए, MediaController बनाना गाइड देखें.
MediaController कमांड मैनेज करना
MediaSession को कंट्रोलर से निर्देश मिलते हैं. ये निर्देश, MediaSession के MediaSession.Callback के ज़रिए मिलते हैं. MediaSession को शुरू करने पर, MediaSession.Callback का डिफ़ॉल्ट वर्शन बनता है. यह MediaSession.Callback, MediaController से आपके प्लेयर को भेजे गए सभी निर्देशों को अपने-आप मैनेज करता है.
सूचना
MediaSessionService आपके लिए अपने-आप एक MediaNotification बनाता है. यह ज़्यादातर मामलों में काम करता है. डिफ़ॉल्ट रूप से, पब्लिश की गई सूचना एक MediaStyle सूचना होती है. यह आपके मीडिया सेशन की नई जानकारी के साथ अपडेट होती रहती है और इसमें प्लेबैक कंट्रोल दिखते हैं. MediaNotification को आपके सेशन के बारे में पता होता है. इसका इस्तेमाल, उसी सेशन से कनेक्ट किए गए किसी भी अन्य ऐप्लिकेशन के लिए, वीडियो चलाने की सुविधा को कंट्रोल करने के लिए किया जा सकता है.
उदाहरण के लिए, MediaSessionService का इस्तेमाल करने वाला संगीत स्ट्रीम करने वाला कोई ऐप्लिकेशन, MediaNotification बनाएगा. इसमें, मौजूदा मीडिया आइटम का टाइटल, कलाकार, और एल्बम आर्ट दिखेगा. साथ ही, इसमें आपके MediaSession कॉन्फ़िगरेशन के आधार पर प्लेबैक कंट्रोल भी दिखेंगे.
ज़रूरी मेटाडेटा को मीडिया में दिया जा सकता है या मीडिया आइटम के हिस्से के तौर पर घोषित किया जा सकता है. इसके लिए, यहां दिया गया स्निपेट देखें:
Kotlin
val mediaItem = MediaItem.Builder() .setMediaId("media-1") .setUri(mediaUri) .setMediaMetadata( MediaMetadata.Builder() .setArtist("David Bowie") .setTitle("Heroes") .setArtworkUri(artworkUri) .build() ) .build() mediaController.setMediaItem(mediaItem) mediaController.prepare() mediaController.play()
Java
MediaItem mediaItem = new MediaItem.Builder() .setMediaId("media-1") .setUri(mediaUri) .setMediaMetadata( new MediaMetadata.Builder() .setArtist("David Bowie") .setTitle("Heroes") .setArtworkUri(artworkUri) .build()) .build(); mediaController.setMediaItem(mediaItem); mediaController.prepare(); mediaController.play();
सूचना की लाइफ़साइकल
सूचना तब बनाई जाती है, जब Player की प्लेलिस्ट में MediaItem इंस्टेंस मौजूद हों.
सूचना से जुड़े सभी अपडेट, Player और MediaSession की स्थिति के आधार पर अपने-आप होते हैं.
फ़ोरग्राउंड सेवा चालू होने पर, सूचना को हटाया नहीं जा सकता. सूचना को तुरंत हटाने के लिए, आपको Player.release() पर कॉल करना होगा या Player.clearMediaItems() का इस्तेमाल करके प्लेलिस्ट मिटानी होगी.
अगर प्लेयर को 10 मिनट से ज़्यादा समय तक रोका जाता है, बंद किया जाता है या वह काम नहीं करता है और इस दौरान उपयोगकर्ता कोई कार्रवाई नहीं करता है, तो सेवा अपने-आप फ़ोरग्राउंड सेवा की स्थिति से बाहर निकल जाती है. इससे सिस्टम उसे बंद कर सकता है. वीडियो फिर से चलाने की सुविधा लागू की जा सकती है, ताकि उपयोगकर्ता सेवा के लाइफ़साइकल को फिर से शुरू कर सके और बाद में वीडियो फिर से चला सके.
सूचना को पसंद के मुताबिक बनाना
फ़िलहाल चल रहे आइटम के मेटाडेटा को, MediaItem.MediaMetadata में बदलाव करके पसंद के मुताबिक बनाया जा सकता है. अगर आपको किसी मौजूदा आइटम का मेटाडेटा अपडेट करना है, तो Player.replaceMediaItem का इस्तेमाल करके मेटाडेटा अपडेट किया जा सकता है. इससे वीडियो चलाने में कोई रुकावट नहीं आएगी.
Android मीडिया कंट्रोल के लिए, मीडिया बटन की पसंद के मुताबिक सेटिंग करके, सूचना में दिखाए गए कुछ बटन को भी अपनी पसंद के मुताबिक बनाया जा सकता है. Android मीडिया कंट्रोल को अपनी पसंद के मुताबिक बनाने के बारे में ज़्यादा जानें.
नोटिफ़िकेशन को और ज़्यादा कस्टमाइज़ करने के लिए, MediaNotification.Provider बनाएं. इसके लिए, DefaultMediaNotificationProvider.Builder का इस्तेमाल करें या प्रोवाइडर इंटरफ़ेस का कस्टम वर्शन लागू करें. setMediaNotificationProvider का इस्तेमाल करके, सेवा देने वाली कंपनी को अपने MediaSessionService में जोड़ें.
वीडियो फिर से शुरू करना
MediaSessionService बंद होने के बाद और डिवाइस को रीबूट करने के बाद भी, उपयोगकर्ताओं को वीडियो फिर से चलाने की सुविधा दी जा सकती है. इससे वे सेवा को फिर से शुरू कर पाएंगे और वीडियो को वहीं से देख पाएंगे जहां उन्होंने छोड़ा था. वीडियो फिर से चलाने की सुविधा डिफ़ॉल्ट रूप से बंद होती है. इसका मतलब है कि सेवा बंद होने पर, उपयोगकर्ता वीडियो फिर से नहीं चला पाएगा. इस सुविधा में शामिल होने के लिए, आपको मीडिया बटन रिसीवर के बारे में बताना होगा और onPlaybackResumption तरीके को लागू करना होगा.
Media3 मीडिया बटन रिसीवर की जानकारी देना
अपने मेनिफ़ेस्ट में MediaButtonReceiver का एलान करके शुरुआत करें:
<receiver android:name="androidx.media3.session.MediaButtonReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
वीडियो फिर से शुरू करने के लिए कॉलबैक लागू करना
जब किसी ब्लूटूथ डिवाइस या Android सिस्टम यूज़र इंटरफ़ेस (यूआई) की फिर से शुरू करने की सुविधा से, प्लेबैक फिर से शुरू करने का अनुरोध किया जाता है, तब onPlaybackResumption() कॉलबैक तरीके को कॉल किया जाता है.
Kotlin
override fun onPlaybackResumption( mediaSession: MediaSession, controller: ControllerInfo, isForPlayback: Boolean, ): ListenableFuture<MediaItemsWithStartPosition> { val settable = SettableFuture.create<MediaItemsWithStartPosition>() scope.launch { // Your app is responsible for storing the playlist, metadata (like title // and artwork) of the current item and the start position to use here. val resumptionPlaylist = restorePlaylist() settable.set(resumptionPlaylist) } return settable }
Java
@Override public ListenableFuture<MediaItemsWithStartPosition> onPlaybackResumption( MediaSession mediaSession, ControllerInfo controller, boolean isForPlayback ) { SettableFuture<MediaItemsWithStartPosition> settableFuture = SettableFuture.create(); settableFuture.addListener(() -> { // Your app is responsible for storing the playlist, metadata (like title // and artwork) of the current item and the start position to use here. MediaItemsWithStartPosition resumptionPlaylist = restorePlaylist(); settableFuture.set(resumptionPlaylist); }, MoreExecutors.directExecutor()); return settableFuture; }
अगर आपने प्लेबैक की स्पीड, दोहराने का मोड या शफ़ल मोड जैसे अन्य पैरामीटर सेव किए हैं, तो onPlaybackResumption() एक अच्छी जगह है. यहां Media3, प्लेयर तैयार करने और कॉलबैक पूरा होने पर प्लेबैक शुरू करने से पहले, इन पैरामीटर के साथ प्लेयर को कॉन्फ़िगर किया जा सकता है.
इस तरीके को बूट होने के दौरान कॉल किया जाता है, ताकि डिवाइस को isForPlayback पर सेट करके false के साथ रीबूट करने के बाद, Android सिस्टम यूज़र इंटरफ़ेस (यूआई) को फिर से शुरू करने की सूचना बनाई जा सके. रिच सूचना के लिए, हमारा सुझाव है कि MediaMetadata जैसे फ़ील्ड में, स्थानीय तौर पर उपलब्ध वैल्यू डालें. जैसे, मौजूदा आइटम के लिए title और artworkData या artworkUri. ऐसा इसलिए, क्योंकि हो सकता है कि नेटवर्क ऐक्सेस अभी उपलब्ध न हो. वीडियो चलाने की स्थिति को फिर से शुरू करने के लिए, MediaMetadata.extras में MediaConstants.EXTRAS_KEY_COMPLETION_STATUS और MediaConstants.EXTRAS_KEY_COMPLETION_PERCENTAGE भी जोड़ा जा सकता है.
कंट्रोलर को बेहतर तरीके से कॉन्फ़िगर करने और पुराने सिस्टम के साथ काम करने की सुविधा
आम तौर पर, ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) में MediaController का इस्तेमाल, प्लेलिस्ट दिखाने और मीडिया चलाने को कंट्रोल करने के लिए किया जाता है. साथ ही, सेशन को Android मीडिया कंट्रोल और मोबाइल या टीवी पर Assistant जैसे बाहरी क्लाइंट के लिए उपलब्ध कराया जाता है. इसके अलावा, इसे स्मार्टवॉच के लिए Wear OS और कारों में Android Auto के लिए भी उपलब्ध कराया जाता है. Media3 सेशन डेमो ऐप्लिकेशन, ऐसे ऐप्लिकेशन का एक उदाहरण है जो इस तरह के किसी मामले को लागू करता है.
ये बाहरी क्लाइंट, लेगसी AndroidX लाइब्रेरी के MediaControllerCompat या Android प्लैटफ़ॉर्म के android.media.session.MediaController जैसे एपीआई का इस्तेमाल कर सकते हैं. Media3, लेगसी लाइब्रेरी के साथ पूरी तरह से काम करता है. साथ ही, यह Android प्लैटफ़ॉर्म एपीआई के साथ इंटरऑपरेबिलिटी की सुविधा देता है.
भरोसेमंद कंट्रोलर की पहचान करना
कोई भी ऐप्लिकेशन, आपके मीडिया सेशन या लाइब्रेरी से कनेक्ट करने की कोशिश कर सकता है. अगर आपको सिस्टम कंट्रोलर, मीडिया कॉन्टेंट कंट्रोल करने की अनुमति वाले कंट्रोलर, और अपने ऐप्लिकेशन के ऐक्सेस को सीमित करना है, तो ControllerInfo.isTrusted() का इस्तेमाल करके, ऐक्सेस की बुनियादी जांच की जा सकती है. इसके अलावा, ज़्यादा खास कंट्रोलर की पहचान की जा सकती है. जैसे, मीडिया सूचना कंट्रोलर या Android Auto कंट्रोलर. इसके बारे में यहां बताया गया है.
मीडिया सूचना कंट्रोलर का इस्तेमाल करना
यह समझना ज़रूरी है कि लेगसी और प्लैटफ़ॉर्म कंट्रोलर, एक ही स्थिति शेयर करते हैं. साथ ही, कंट्रोलर के हिसाब से यह तय नहीं किया जा सकता कि कौनसी चीज़ दिखेगी. उदाहरण के लिए, उपलब्ध PlaybackState.getActions() और PlaybackState.getCustomActions(). इन लेगसी और प्लैटफ़ॉर्म कंट्रोलर के साथ काम करने के लिए, प्लैटफ़ॉर्म मीडिया सेशन में सेट की गई स्थिति को कॉन्फ़िगर करने के लिए, मीडिया सूचना कंट्रोलर का इस्तेमाल किया जा सकता है.
उदाहरण के लिए, कोई ऐप्लिकेशन MediaSession.Callback.onConnect() को लागू कर सकता है. इससे, प्लैटफ़ॉर्म सेशन के लिए उपलब्ध कमांड और मीडिया बटन की प्राथमिकताएं सेट की जा सकती हैं. ऐसा इस तरह किया जा सकता है:
Kotlin
override fun onConnect( session: MediaSession, controller: MediaSession.ControllerInfo ): ConnectionResult { if (session.isMediaNotificationController(controller)) { val playerCommands = ConnectionResult.DEFAULT_PLAYER_COMMANDS.buildUpon() .remove(COMMAND_SEEK_TO_PREVIOUS) .remove(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM) .remove(COMMAND_SEEK_TO_NEXT) .remove(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM) .build() // Custom button preferences and commands to configure the platform session. return AcceptedResultBuilder(session) .setMediaButtonPreferences( listOf(seekBackButton, seekForwardButton) ) .setAvailablePlayerCommands(playerCommands) .build() } // Default commands with default button preferences for all other controllers. return AcceptedResultBuilder(session).build() }
Java
@Override public ConnectionResult onConnect( MediaSession session, MediaSession.ControllerInfo controller) { if (session.isMediaNotificationController(controller)) { Player.Commands playerCommands = ConnectionResult.DEFAULT_PLAYER_COMMANDS .buildUpon() .remove(COMMAND_SEEK_TO_PREVIOUS) .remove(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM) .remove(COMMAND_SEEK_TO_NEXT) .remove(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM) .build(); // Custom button preferences and commands to configure the platform session. return new AcceptedResultBuilder(session) .setMediaButtonPreferences( ImmutableList.of(seekBackButton, seekForwardButton)) .setAvailablePlayerCommands(playerCommands) .build(); } // Default commands with default button preferences for all other controllers. return new AcceptedResultBuilder(session).build(); }
Android Auto को कस्टम कमांड भेजने की अनुमति देना
MediaLibraryService का इस्तेमाल करते समय और मोबाइल ऐप्लिकेशन के साथ Android Auto का इस्तेमाल करने के लिए, Android Auto कंट्रोलर को सही कमांड की ज़रूरत होती है. ऐसा न होने पर, Media3 उस कंट्रोलर से आने वाली कस्टम कमांड को अस्वीकार कर देगा:
Kotlin
override fun onConnect( session: MediaSession, controller: MediaSession.ControllerInfo ): ConnectionResult { val sessionCommands = ConnectionResult.DEFAULT_SESSION_AND_LIBRARY_COMMANDS.buildUpon() .add(customCommand) .build() if (session.isMediaNotificationController(controller)) { // [...] See above. } else if (session.isAutoCompanionController(controller)) { // Available session commands to accept incoming custom commands from Auto. return AcceptedResultBuilder(session) .setAvailableSessionCommands(sessionCommands) .build() } // Default commands for all other controllers. return AcceptedResultBuilder(session).build() }
Java
@Override public ConnectionResult onConnect( MediaSession session, MediaSession.ControllerInfo controller) { SessionCommands sessionCommands = ConnectionResult.DEFAULT_SESSION_COMMANDS .buildUpon() .add(customCommand) .build(); if (session.isMediaNotificationController(controller)) { // [...] See above. } else if (session.isAutoCompanionController(controller)) { // Available commands to accept incoming custom commands from Auto. return new AcceptedResultBuilder(session) .setAvailableSessionCommands(sessionCommands) .build(); } // Default commands for all other controllers. return new AcceptedResultBuilder(session).build(); }
सेशन डेमो ऐप्लिकेशन में एक ऑटोमोटिव मॉड्यूल है. यह Automotive OS के लिए सपोर्ट दिखाता है. इसके लिए, अलग APK की ज़रूरत होती है.