MediasessionService के साथ बैकग्राउंड में वीडियो चलाने की सुविधा

अक्सर, किसी ऐप्लिकेशन के फ़ोरग्राउंड में न होने पर भी मीडिया चलाना होता है. उदाहरण के लिए, जब कोई उपयोगकर्ता अपने डिवाइस को लॉक करता है या किसी दूसरे ऐप्लिकेशन का इस्तेमाल करता है, तब भी संगीत प्लेयर आम तौर पर संगीत चलाता रहता है. Media3 लाइब्रेरी, इंटरफ़ेस की एक सीरीज़ उपलब्ध कराती है. इसकी मदद से, बैकग्राउंड में वीडियो चलाने की सुविधा दी जा सकती है.

MediaSessionService का इस्तेमाल करना

बैकग्राउंड में वीडियो चलाने की सुविधा चालू करने के लिए, आपको Player और MediaSession को अलग सेवा में शामिल करना होगा. इससे डिवाइस, आपका ऐप्लिकेशन फ़ोरग्राउंड में न होने पर भी मीडिया दिखाना जारी रखता है.

MediaSessionService की मदद से, मीडिया सेशन को ऐप्लिकेशन की गतिविधि से अलग चलाया जा सकता है
पहली इमेज: MediaSessionService की मदद से, मीडिया सेशन को ऐप्लिकेशन की गतिविधि से अलग चलाया जा सकता है

किसी सेवा में प्लेयर को होस्ट करते समय, आपको MediaSessionService का इस्तेमाल करना चाहिए. ऐसा करने के लिए, MediaSessionService को एक्सटेंड करने वाली क्लास बनाएं और उसमें अपना मीडिया सेशन बनाएं.

MediaSessionService का इस्तेमाल करने से, Google Assistant, सिस्टम मीडिया कंट्रोल, डिवाइसों के साथ इस्तेमाल होने वाले मीडिया बटन या Wear OS जैसे साथी डिवाइसों जैसे बाहरी क्लाइंट, आपकी सेवा को खोज सकते हैं, उससे कनेक्ट कर सकते हैं, और वीडियो चलाने की सुविधा को कंट्रोल कर सकते हैं. इसके लिए, उन्हें आपके ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) की गतिविधि को ऐक्सेस करने की ज़रूरत नहीं होती. असल में, एक ही 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 के इंटेंट फ़िल्टर और mediaPlayback को शामिल करने वाले foregroundServiceType का इस्तेमाल करें.

<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 मीडिया कंट्रोल को पसंद के मुताबिक बनाने के बारे में ज़्यादा जानें.

नोटिफ़िकेशन को ज़्यादा पसंद के मुताबिक बनाने के लिए, DefaultMediaNotificationProvider.Builder के साथ MediaNotification.Provider बनाएं या सेवा देने वाली कंपनी के इंटरफ़ेस को कस्टम तरीके से लागू करें. 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
): ListenableFuture<MediaItemsWithStartPosition> {
  val settable = SettableFuture.create<MediaItemsWithStartPosition>()
  scope.launch {
    // Your app is responsible for storing the playlist 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
) {
  SettableFuture<MediaItemsWithStartPosition> settableFuture = SettableFuture.create();
  settableFuture.addListener(() -> {
    // Your app is responsible for storing the playlist and the start position
    // to use here
    MediaItemsWithStartPosition resumptionPlaylist = restorePlaylist();
    settableFuture.set(resumptionPlaylist);
  }, MoreExecutors.directExecutor());
  return settableFuture;
}

अगर आपने वीडियो चलाने की रफ़्तार, दोहराने का मोड या गाने को शफ़ल करने का मोड जैसे अन्य पैरामीटर सेव किए हैं, तो Media3 के प्लेयर को तैयार करने और कॉलबैक पूरा होने पर वीडियो चलाने से पहले, onPlaybackResumption() में इन पैरामीटर के साथ प्लेयर को कॉन्फ़िगर किया जा सकता है.

बेहतर कंट्रोलर कॉन्फ़िगरेशन और पुराने सिस्टम के साथ काम करने की सुविधा

आम तौर पर, ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) में MediaController का इस्तेमाल, वीडियो चलाने और प्लेलिस्ट दिखाने के लिए किया जाता है. साथ ही, यह सेशन बाहरी क्लाइंट के लिए भी उपलब्ध होता है. जैसे, मोबाइल या टीवी पर Android मीडिया कंट्रोल और Assistant, स्मार्टवॉच के लिए Wear OS, और कारों में Android Auto. Media3 सेशन डेमो ऐप्लिकेशन, ऐसे ऐप्लिकेशन का उदाहरण है जो इस तरह की स्थिति को लागू करता है.

ये बाहरी क्लाइंट, लेगसी AndroidX लाइब्रेरी के MediaControllerCompat या Android प्लैटफ़ॉर्म के android.media.session.MediaController जैसे एपीआई का इस्तेमाल कर सकते हैं. Media3, लेगसी लाइब्रेरी के साथ पूरी तरह से काम करता है. साथ ही, यह Android प्लैटफ़ॉर्म एपीआई के साथ इंटरऑपरेबिलिटी की सुविधा देता है.

मीडिया कंट्रोल करने से जुड़ी सूचनाओं का इस्तेमाल करना

यह समझना ज़रूरी है कि ये लेगसी और प्लैटफ़ॉर्म कंट्रोलर एक ही स्थिति शेयर करते हैं. साथ ही, कंट्रोलर के हिसाब से, विज़िबिलिटी को पसंद के मुताबिक नहीं बनाया जा सकता. उदाहरण के लिए, उपलब्ध PlaybackState.getActions() और PlaybackState.getCustomActions(). इन लेगसी और प्लैटफ़ॉर्म कंट्रोलर के साथ काम करने के लिए, प्लैटफ़ॉर्म मीडिया सेशन में सेट की गई स्थिति को कॉन्फ़िगर करने के लिए, मीडिया सूचना कंट्रोलर का इस्तेमाल किया जा सकता है.

उदाहरण के लिए, कोई ऐप्लिकेशन, प्लैटफ़ॉर्म सेशन के लिए उपलब्ध निर्देशों और मीडिया बटन की सेटिंग को सेट करने के लिए, MediaSession.Callback.onConnect() को लागू कर सकता है. इसके लिए, यह तरीका अपनाया जा सकता है:

Kotlin

override fun onConnect(
  session: MediaSession,
  controller: MediaSession.ControllerInfo
): ConnectionResult {
  if (session.isMediaNotificationController(controller)) {
    val sessionCommands =
      ConnectionResult.DEFAULT_SESSION_COMMANDS.buildUpon()
        .add(customCommandSeekBackward)
        .add(customCommandSeekForward)
        .build()
    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(
        ImmutableList.of(
          createSeekBackwardButton(customCommandSeekBackward),
          createSeekForwardButton(customCommandSeekForward))
      )
      .setAvailablePlayerCommands(playerCommands)
      .setAvailableSessionCommands(sessionCommands)
      .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)) {
    SessionCommands sessionCommands =
        ConnectionResult.DEFAULT_SESSION_COMMANDS
            .buildUpon()
            .add(customCommandSeekBackward)
            .add(customCommandSeekForward)
            .build();
    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(
                createSeekBackwardButton(customCommandSeekBackward),
                createSeekForwardButton(customCommandSeekForward)))
        .setAvailablePlayerCommands(playerCommands)
        .setAvailableSessionCommands(sessionCommands)
        .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(customCommandSeekBackward)
      .add(customCommandSeekForward)
      .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(customCommandSeekBackward)
          .add(customCommandSeekForward)
          .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 की ज़रूरत होती है.