ऐसा अक्सर होता है कि ऐप्लिकेशन के फ़ोरग्राउंड में न होने पर भी मीडिया चलाया जाता है. उदाहरण के लिए, आम तौर पर संगीत प्लेयर तब भी संगीत बजाता रहता है, जब उपयोगकर्ता ने अपना डिवाइस लॉक किया हो या वह किसी दूसरे ऐप्लिकेशन का इस्तेमाल कर रहा हो. Media3 लाइब्रेरी, इंटरफ़ेस की एक सीरीज़ उपलब्ध कराती है. इसकी मदद से, बैकग्राउंड में प्लेबैक की सुविधा दी जा सकती है.
MediaSessionService का इस्तेमाल करना
बैकग्राउंड में प्लेबैक की सुविधा चालू करने के लिए, Player और
MediaSession को किसी अलग सेवा में शामिल किया जाना चाहिए.
इससे, आपका ऐप्लिकेशन फ़ोरग्राउंड में न होने पर भी, डिवाइस पर मीडिया चलाया जा सकता है.
MediaSessionService की मदद से, मीडिया
सेशन को ऐप्लिकेशन की गतिविधि से अलग चलाया जा सकता हैकिसी सेवा में प्लेयर को होस्ट करते समय, MediaSessionService का इस्तेमाल किया जाना चाहिए.
इसके लिए, MediaSessionService को बढ़ाने वाली एक क्लास बनाएं और उसमें अपना मीडिया सेशन बनाएं.
MediaSessionService का इस्तेमाल करने से, Google Assistant, सिस्टम मीडिया कंट्रोल, पेरिफ़ेरल डिवाइसों पर मौजूद मीडिया बटन या Wear OS जैसे साथी डिवाइसों जैसे बाहरी क्लाइंट, आपकी सेवा को खोज सकते हैं, उससे कनेक्ट हो सकते हैं, और प्लेबैक को कंट्रोल कर सकते हैं. इसके लिए, उन्हें आपके ऐप्लिकेशन की यूज़र इंटरफ़ेस (यूआई) गतिविधि को ऐक्सेस करने की ज़रूरत नहीं होती. असल में, एक ही समय पर एक ही MediaSessionService से कई क्लाइंट ऐप्लिकेशन कनेक्ट किए जा सकते हैं. हर ऐप्लिकेशन का अपना MediaController होता है.
सेवा के लाइफ़साइकल को लागू करना
आपको अपनी सेवा के दो लाइफ़साइकल के तरीके लागू करने होंगे:
- जब पहला कंट्रोलर कनेक्ट होने वाला होता है और सेवा को इंस्टैंशिएट और शुरू किया जाता है, तब
onCreate()को कॉल किया जाता है.PlayerऔरMediaSessionबनाने के लिए, यह सबसे सही जगह है. - जब सेवा बंद की जा रही होती है, तब
onDestroy()को कॉल किया जाता है. प्लेयर और सेशन के साथ-साथ सभी संसाधनों को रिलीज़ करना ज़रूरी है.
उपयोगकर्ता के हाल ही के टास्क से ऐप्लिकेशन को खारिज करने पर क्या होता है, इसे अपनी पसंद के मुताबिक बनाने के लिए, onTaskRemoved(Intent) को ज़रूरत के हिसाब से बदला जा सकता है. डिफ़ॉल्ट रूप से, अगर प्लेबैक जारी है, तो सेवा चलती रहती है. वहीं, अगर प्लेबैक जारी नहीं है, तो सेवा बंद हो जाती है.
ExoPlayerCastPlayerMediaSessionService
Kotlin
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() } override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession? = mediaSession }
Java
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(); } @Override public MediaSession onGetSession(MediaSession.ControllerInfo controllerInfo) { return mediaSession; } }
बैकग्राउंड में प्लेबैक जारी रखने के बजाय, उपयोगकर्ता के ऐप्लिकेशन को खारिज करने पर, सेवा को किसी भी मामले में बंद किया जा सकता है:
Kotlin
@OptIn(UnstableApi::class) override fun onTaskRemoved(rootIntent: Intent?) { pauseAllPlayersAndStopSelf() }
Java
@OptIn(markerClass = UnstableApi.class) @Override public void onTaskRemoved(@Nullable Intent rootIntent) { pauseAllPlayersAndStopSelf(); }
onTaskRemoved को मैन्युअल तरीके से लागू करने के लिए, isPlaybackOngoing() का इस्तेमाल करके यह देखा जा सकता है कि प्लेबैक जारी है या नहीं. साथ ही, यह भी देखा जा सकता है कि फ़ोरग्राउंड सेवा शुरू की गई है या नहीं.
मीडिया सेशन का ऐक्सेस देना
onGetSession() तरीके को बदलकर, अन्य क्लाइंट को अपने मीडिया सेशन का ऐक्सेस दिया जा सकता है. यह मीडिया सेशन, सेवा बनाए जाने के दौरान बनाया गया था.
Kotlin
class PlaybackService : MediaSessionService() { // [...] lifecycle methods omitted override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession? = mediaSession }
Java
class PlaybackService extends MediaSessionService { // [...] 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.Callback के ज़रिए लेता है. MediaSession को शुरू करने पर, डिफ़ॉल्ट
तरीके से लागू किया गया 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
बनाएं या प्रोवाइडर इंटरफ़ेस को अपनी पसंद के मुताबिक लागू करें. अपने प्रोवाइडर को MediaSessionService में
setMediaNotificationProvider की मदद से जोड़ें.
प्लेबैक फिर से शुरू करना
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: MediaSession.ControllerInfo, isForPlayback: Boolean, ): ListenableFuture<MediaSession.MediaItemsWithStartPosition> { val settableFuture = SettableFuture.create<MediaSession.MediaItemsWithStartPosition>() 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. val resumptionPlaylist = restorePlaylist() settableFuture.set(resumptionPlaylist) }, MoreExecutors.directExecutor(), ) return settableFuture }
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 के प्लेयर को तैयार करने और कॉलबैक पूरा होने पर प्लेबैक शुरू करने से पहले, प्लेयर को इन पैरामीटर के साथ कॉन्फ़िगर किया जा सकता है.
डिवाइस को रीबूट करने के बाद, Android सिस्टम यूज़र इंटरफ़ेस (यूआई) की 'फिर से शुरू करें' सूचना बनाने के लिए, बूट होने के दौरान इस तरीके को कॉल किया जाता है. इस दौरान, isForPlayback को false पर सेट किया जाता है. बेहतर सूचना के लिए, मौजूदा आइटम के 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 onConnectAsync( session: MediaSession, controller: MediaSession.ControllerInfo, ): ListenableFuture<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 immediateFuture( AcceptedResultBuilder(session) .setMediaButtonPreferences(listOf(seekBackButton, seekForwardButton)) .setAvailablePlayerCommands(playerCommands) .build() ) } // Default commands with default button preferences for all other controllers. return immediateFuture(AcceptedResultBuilder(session).build()) }
Java
@Override public ListenableFuture<ConnectionResult> onConnectAsync( 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 immediateFuture( new AcceptedResultBuilder(session) .setMediaButtonPreferences(ImmutableList.of(seekBackButton, seekForwardButton)) .setAvailablePlayerCommands(playerCommands) .build()); } // Default commands with default button preferences for all other controllers. return immediateFuture(new AcceptedResultBuilder(session).build()); }
Android Auto को कस्टम निर्देश भेजने की अनुमति देना
MediaLibraryService
का इस्तेमाल करते समय और मोबाइल ऐप्लिकेशन के साथ Android Auto की सुविधा देने के लिए, Android Auto कंट्रोलर
को सही उपलब्ध निर्देशों की ज़रूरत होती है. ऐसा न होने पर, Media3 उस कंट्रोलर से आने वाले कस्टम निर्देशों को अस्वीकार कर देगा:
Kotlin
override fun onConnectAsync( session: MediaSession, controller: MediaSession.ControllerInfo, ): ListenableFuture<ConnectionResult> { val 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 immediateFuture( AcceptedResultBuilder(session).setAvailableSessionCommands(sessionCommands).build() ) } // Default commands for all other controllers. return immediateFuture(AcceptedResultBuilder(session).build()) }
Java
@Override public ListenableFuture<ConnectionResult> onConnectAsync( 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 immediateFuture( new AcceptedResultBuilder(session) .setAvailableSessionCommands(sessionCommands) .build()); } // Default commands for all other controllers. return immediateFuture(new AcceptedResultBuilder(session).build()); }
सेशन डेमो ऐप्लिकेशन में एक ऑटोमोटिव मॉड्यूल, है. इससे, Automotive OS के लिए सहायता मिलती है. इसके लिए, एक अलग APK की ज़रूरत होती है.