Mediasession का इस्तेमाल करके, प्लेबैक को कंट्रोल करना और उसका विज्ञापन देना

मीडिया सेशन, ऑडियो या वीडियो के साथ इंटरैक्ट करने का एक बेहतर तरीका देते हैं प्लेयर. Media3 में, डिफ़ॉल्ट प्लेयर ExoPlayer क्लास होती है. यह क्लास लागू करती है Player इंटरफ़ेस. मीडिया सेशन को प्लेयर से कनेक्ट करने पर, ऐप्लिकेशन इस्तेमाल किया जा सकता है मीडिया प्लेबैक का विज्ञापन देने और बाहरी सोर्स पर क्लिक करें.

कमांड, फ़िज़िकल बटन से आ सकती हैं. जैसे, 'चलाएं' बटन हेडसेट या टीवी रिमोट कंट्रोल. वे ऐसे क्लाइंट ऐप्लिकेशन से भी आ सकते हैं जिनमें मीडिया कंट्रोलर, जैसे कि "रोकें" का निर्देश देना Assistant को चालू करें. मीडिया सेशन, इन निर्देशों को मीडिया ऐप्लिकेशन के प्लेयर को डेलिगेट करता है.

मीडिया सेशन कब चुनना चाहिए

MediaSession लागू करने पर, उपयोगकर्ताओं को प्लेबैक को कंट्रोल करने की अनुमति मिल जाती है:

  • अपने हेडफ़ोन के ज़रिए. आम तौर पर, बटन या टच इंटरैक्शन होने पर मीडिया चलाने, रोकने या अगले या पिछला ट्रैक चुनें.
  • Google Assistant से बात करके. एक सामान्य पैटर्न यह है कि "ठीक है डिवाइस पर चल रहे किसी भी मीडिया को रोकने के लिए, Google, रोको".
  • अपनी Wear OS स्मार्टवॉच के ज़रिए. इससे ज़्यादा से ज़्यादा लोगों को वे अपने फ़ोन पर वीडियो चलाने के दौरान, सामान्य प्लेबैक कंट्रोल इस्तेमाल कर सकते हैं.
  • मीडिया कंट्रोल की मदद से. यह कैरसेल हर एक के लिए कंट्रोल दिखाता है मीडिया सत्र चला रहा है.
  • टीवी पर. फ़िज़िकल प्लेबैक बटन और प्लैटफ़ॉर्म पर वीडियो चलाने की सुविधा इस्तेमाल करके कार्रवाइयां करें और पावर मैनेजमेंट (जैसे, टीवी, साउंडबार या ए/वी रिसीवर में बंद हो या इनपुट स्विच हो, तो ऐप्लिकेशन पर वीडियो चलना बंद हो जाना चाहिए).
  • वीडियो चलाने की प्रोसेस पर असर डालने वाली अन्य बाहरी प्रोसेस.

कई तरह के मामलों में यह बेहतरीन होता है. खास तौर पर, आपको इन बातों का ध्यान रखना चाहिए MediaSession का इस्तेमाल तब करें, जब:

  • लंबी अवधि के वीडियो कॉन्टेंट स्ट्रीम किया जा रहा हो, जैसे कि फ़िल्में या लाइव टीवी.
  • लंबी अवधि के ऑडियो कॉन्टेंट, जैसे कि पॉडकास्ट या संगीत को स्ट्रीम किया जा रहा हो प्लेलिस्ट.
  • कोई टीवी ऐप्लिकेशन बनाया जा रहा है.

हालांकि, इस्तेमाल के सभी उदाहरण MediaSession के हिसाब से सही नहीं होते. आप शायद ये करना चाहें नीचे दिए गए मामलों में सिर्फ़ Player का इस्तेमाल करें:

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

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

मीडिया सेशन बनाना

मीडिया सेशन उस प्लेयर के साथ होता है जिसे वह मैनेज करता है. आपके पास यह बनाने का विकल्प है Context और Player ऑब्जेक्ट वाला मीडिया सेशन. आपको बनाना चाहिए और ज़रूरत पड़ने पर मीडिया सेशन को शुरू कर सकता है, जैसे कि onStart() या Activity, Fragment या onCreate() का onResume() लाइफ़साइकल तरीका तरीका Service है जो मीडिया सेशन और उससे जुड़े प्लेयर का मालिक है.

मीडिया सेशन बनाने के लिए, Player शुरू करें और इसे MediaSession.Builder को इस तरह का कॉन्टेंट पसंद है:

Kotlin

val player = ExoPlayer.Builder(context).build()
val mediaSession = MediaSession.Builder(context, player).build()

Java

ExoPlayer player = new ExoPlayer.Builder(context).build();
MediaSession mediaSession = new MediaSession.Builder(context, player).build();

स्थिति की अपने-आप हैंडलिंग

Media3 लाइब्रेरी, खिलाड़ी की स्थिति. ऐसा करने के लिए, आपको मैन्युअल तरीके से प्लेयर टू सेशन.

यह उस लेगसी अप्रोच से बिलकुल अलग है, जहां आपको कॉन्टेंट बनाने और उसे बनाए रखने की ज़रूरत होती है PlaybackStateCompat को प्लेयर से अलग होना चाहिए. उदाहरण के लिए, कोई गड़बड़ी हुई है.

यूनीक सेशन आईडी

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

अगर कोई ऐप्लिकेशन एक साथ कई सेशन के इंस्टेंस मैनेज करना चाहता है, तो यह पक्का करना ज़रूरी है कि हर सेशन का सेशन आईडी यूनीक हो. सेशन आईडी ये काम कर सकता है: MediaSession.Builder.setId(String id) के साथ सेशन बनाते समय सेट की जाएगी.

अगर आपको लगता है कि IllegalStateException, गड़बड़ी की वजह से आपके ऐप्लिकेशन को क्रैश कर रहा है IllegalStateException: Session ID must be unique. ID= को मैसेज भेजो, तो यह है इस बात की संभावना है कि पहले बनाए गए सेशन से पहले कोई सेशन अचानक बना हो समान आईडी वाला इंस्टेंस रिलीज़ कर दिया गया है. सेशन को लीक होने से बचाने के लिए प्रोग्रामिंग की गड़बड़ी होती है, तो ऐसे मामलों का पता लगाकर उनकी सूचना दी जाती है. इसके लिए, अपवाद.

अन्य क्लाइंट को कंट्रोल दें

वीडियो को कंट्रोल करने के लिए, मीडिया सेशन सबसे अहम है. इसकी मदद से, Google News पर बाहरी स्रोतों से उस प्लेयर को आदेश दें जो आपका मीडिया. ये सोर्स, फ़िज़िकल बटन हो सकते हैं. जैसे, हेडसेट या टीवी रिमोट कंट्रोल या किसी और तरीके से दिए जाने वाले निर्देश, जैसे कि "रोको" Assistant को चालू करें. इसी तरह, हो सकता है कि आप Android को Wear OS पर सूचना पाने और लॉक स्क्रीन कंट्रोल करने की सुविधा देने वाला सिस्टम ताकि आप वॉचफेस से प्लेबैक को नियंत्रित कर सकें. बाहरी क्लाइंट यह कर सकते हैं: अपने मीडिया ऐप्लिकेशन को प्लेबैक के निर्देश देने के लिए मीडिया कंट्रोलर का इस्तेमाल करें. ये हैं जो आपके मीडिया सेशन को मिले. इससे आखिर में, मीडिया प्लेयर.

Mediasession और MediaController के बीच इंटरैक्शन को दिखाने वाला डायग्राम.
पहली इमेज: मीडिया कंट्रोलर, बाहरी सोर्स से मीडिया सेशन में भेजे जाने वाले निर्देशों का पालन करें.

जब कोई कंट्रोलर आपके मीडिया सेशन से कनेक्ट होने वाला होता है, तो onConnect() तरीका को कॉल किया जाता है. दिए गए ControllerInfo का इस्तेमाल करें स्वीकार करने का फ़ैसला लेने के लिए या अस्वीकार करें अनुरोध किया है. कनेक्शन अनुरोध को स्वीकार करने का उदाहरण में देखें उपलब्ध निर्देश सेक्शन में बताया गया हो.

कनेक्ट होने के बाद, कंट्रोलर, सेशन को चलाने के निर्देश भेज सकता है. कॉन्टेंट बनाने सत्र फिर उन कमांड को प्लेयर को सौंप देता है. प्लेबैक और प्लेलिस्ट Player इंटरफ़ेस में बताए गए निर्देशों को, सत्र.

कॉलबैक के अन्य तरीकों से, आपको इनके लिए अनुरोधों को मैनेज करने की सुविधा मिलती है पसंद के मुताबिक प्लेबैक निर्देश और प्लेलिस्ट में बदलाव करके. इन कॉलबैक में भी एक ControllerInfo ऑब्जेक्ट शामिल होता है, ताकि आप बदलाव कर सकें और हर कंट्रोलर के हिसाब से हर अनुरोध का जवाब कैसे दिया जाता है.

प्लेलिस्ट में बदलाव करना

मीडिया सेशन, अपने प्लेयर की प्लेलिस्ट में सीधे बदलाव कर सकता है. इसके बारे में यहां बताया गया है यह प्लेलिस्ट के लिए ExoPlayer गाइड. कंट्रोलर भी प्लेलिस्ट में बदलाव कर सकते हैं, अगर: COMMAND_SET_MEDIA_ITEM या COMMAND_CHANGE_MEDIA_ITEMS कंट्रोलर के लिए उपलब्ध है.

आम तौर पर, प्लेलिस्ट में नए आइटम जोड़ने के लिए प्लेयर को MediaItem की ज़रूरत होती है के साथ इंस्टेंस तय किया गया यूआरआई ताकि उन्हें खेलने में आसानी हो. डिफ़ॉल्ट रूप से, जोड़े गए नए आइटम अपने-आप फ़ॉरवर्ड किए जाते हैं player.addMediaItem जैसे प्लेयर मेथड का इस्तेमाल करें.

अगर आपको प्लेयर में जोड़े गए MediaItem इंस्टेंस को अपनी पसंद के मुताबिक बनाना है, तो बदलें onAddMediaItems(). यह चरण तब ज़रूरी होता है, जब आपको मीडिया का अनुरोध करने वाले कंट्रोलर की सुविधा देनी हो बिना तय यूआरआई के. इसके बजाय, MediaItem में आम तौर पर इनमें से एक या ज़्यादा फ़ील्ड को, अनुरोध किए गए मीडिया के बारे में बताने के लिए सेट किया गया है:

  • MediaItem.id: एक सामान्य आईडी, जिससे मीडिया की पहचान की जाती है.
  • MediaItem.RequestMetadata.mediaUri: एक अनुरोध यूआरआई, जो किसी कस्टम यूआरएल का इस्तेमाल कर सकता है साथ ही, ज़रूरी नहीं है कि प्लेयर सीधे उसे सीधे चलाए.
  • MediaItem.RequestMetadata.searchQuery: टेक्स्ट के तौर पर सर्च क्वेरी, उदाहरण के लिए Google Assistant से बात करें.
  • MediaItem.MediaMetadata: 'टाइटल' जैसा स्ट्रक्चर्ड मेटाडेटा या 'कलाकार' के तौर पर शामिल होना चाहिए.

नई प्लेलिस्ट को अपनी पसंद के मुताबिक बनाने के ज़्यादा विकल्प देखने के लिए, अतिरिक्त रूप से बदलें onSetMediaItems() जिससे आप प्लेलिस्ट में शुरू होने वाला आइटम और उसकी पोज़िशन तय कर सकते हैं. उदाहरण के लिए, आप किसी एक अनुरोध किए गए आइटम को पूरी प्लेलिस्ट में बड़ा कर सकते हैं और निर्देश दे सकते हैं प्लेयर का इस्तेमाल करें. ऐप्लिकेशन onSetMediaItems() को लागू करने का सैंपल सेशन के डेमो ऐप्लिकेशन में यह सुविधा देखी जा सकती है.

पसंद के मुताबिक लेआउट और कस्टम निर्देश मैनेज करें

नीचे दिए सेक्शन में, कमांड बटन दबाएं और कंट्रोलर को निर्देश देखें.

सेशन के लिए पसंद के मुताबिक लेआउट तय करें

क्लाइंट ऐप्लिकेशन को यह बताने के लिए कि आपको उपयोगकर्ता, सेशन का कस्टम लेआउट सेट करें जब onCreate() तरीके में MediaSession बनाया जा रहा हो, तो: सेवा.

Kotlin

override fun onCreate() {
  super.onCreate()

  val likeButton = CommandButton.Builder()
    .setDisplayName("Like")
    .setIconResId(R.drawable.like_icon)
    .setSessionCommand(SessionCommand(SessionCommand.COMMAND_CODE_SESSION_SET_RATING))
    .build()
  val favoriteButton = CommandButton.Builder()
    .setDisplayName("Save to favorites")
    .setIconResId(R.drawable.favorite_icon)
    .setSessionCommand(SessionCommand(SAVE_TO_FAVORITES, Bundle()))
    .build()

  session =
    MediaSession.Builder(this, player)
      .setCallback(CustomMediaSessionCallback())
      .setCustomLayout(ImmutableList.of(likeButton, favoriteButton))
      .build()
}

Java

@Override
public void onCreate() {
  super.onCreate();

  CommandButton likeButton = new CommandButton.Builder()
    .setDisplayName("Like")
    .setIconResId(R.drawable.like_icon)
    .setSessionCommand(new SessionCommand(SessionCommand.COMMAND_CODE_SESSION_SET_RATING))
    .build();
  CommandButton favoriteButton = new CommandButton.Builder()
    .setDisplayName("Save to favorites")
    .setIconResId(R.drawable.favorite_icon)
    .setSessionCommand(new SessionCommand(SAVE_TO_FAVORITES, new Bundle()))
    .build();

  Player player = new ExoPlayer.Builder(this).build();
  mediaSession =
      new MediaSession.Builder(this, player)
          .setCallback(new CustomMediaSessionCallback())
          .setCustomLayout(ImmutableList.of(likeButton, favoriteButton))
          .build();
}

उपलब्ध प्लेयर और पसंद के मुताबिक निर्देशों की जानकारी देना

मीडिया ऐप्लिकेशन ऐसे कस्टम कमांड तय कर सकते हैं जिनका इस्तेमाल, उदाहरण के लिए किया जा सकता है एक कस्टम लेआउट. उदाहरण के लिए, शायद आप ऐसे बटन लागू करना चाहें जो पसंदीदा आइटम की सूची में मीडिया आइटम को सेव करने के लिए. MediaController कस्टम निर्देश भेजता है और MediaSession.Callback उन्हें रिसीव करता है.

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

Kotlin

private inner class CustomMediaSessionCallback: MediaSession.Callback {
  // Configure commands available to the controller in onConnect()
  override fun onConnect(
    session: MediaSession,
    controller: MediaSession.ControllerInfo
  ): MediaSession.ConnectionResult {
    val sessionCommands = ConnectionResult.DEFAULT_SESSION_COMMANDS.buildUpon()
        .add(SessionCommand(SAVE_TO_FAVORITES, Bundle.EMPTY))
        .build()
    return AcceptedResultBuilder(session)
        .setAvailableSessionCommands(sessionCommands)
        .build()
  }
}

Java

class CustomMediaSessionCallback implements MediaSession.Callback {
  // Configure commands available to the controller in onConnect()
  @Override
  public ConnectionResult onConnect(
    MediaSession session,
    ControllerInfo controller) {
    SessionCommands sessionCommands =
        ConnectionResult.DEFAULT_SESSION_COMMANDS.buildUpon()
            .add(new SessionCommand(SAVE_TO_FAVORITES, new Bundle()))
            .build();
    return new AcceptedResultBuilder(session)
        .setAvailableSessionCommands(sessionCommands)
        .build();
  }
}

MediaController से अपनी पसंद के मुताबिक निर्देश पाने के अनुरोध पाने के लिए, Callback में onCustomCommand() तरीका.

Kotlin

private inner class CustomMediaSessionCallback: MediaSession.Callback {
  ...
  override fun onCustomCommand(
    session: MediaSession,
    controller: MediaSession.ControllerInfo,
    customCommand: SessionCommand,
    args: Bundle
  ): ListenableFuture<SessionResult> {
    if (customCommand.customAction == SAVE_TO_FAVORITES) {
      // Do custom logic here
      saveToFavorites(session.player.currentMediaItem)
      return Futures.immediateFuture(
        SessionResult(SessionResult.RESULT_SUCCESS)
      )
    }
    ...
  }
}

Java

class CustomMediaSessionCallback implements MediaSession.Callback {
  ...
  @Override
  public ListenableFuture<SessionResult> onCustomCommand(
    MediaSession session, 
    ControllerInfo controller,
    SessionCommand customCommand,
    Bundle args
  ) {
    if(customCommand.customAction.equals(SAVE_TO_FAVORITES)) {
      // Do custom logic here
      saveToFavorites(session.getPlayer().getCurrentMediaItem());
      return Futures.immediateFuture(
        new SessionResult(SessionResult.RESULT_SUCCESS)
      );
    }
    ...
  }
}

अनुरोध करने के लिए, MediaSession.ControllerInfo ऑब्जेक्ट की packageName प्रॉपर्टी जो Callback विधियों में पास किया गया है. इससे आप अपने ऐप्लिकेशन की सेटिंग, दिए गए निर्देश के जवाब में व्यवहार, अगर यह सिस्टम से शुरू होता है, तो आपके या अन्य क्लाइंट के ऐप्लिकेशन पर.

उपयोगकर्ता के इंटरैक्शन के बाद, कस्टम लेआउट को अपडेट करना

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

Kotlin

val removeFromFavoritesButton = CommandButton.Builder()
  .setDisplayName("Remove from favorites")
  .setIconResId(R.drawable.favorite_remove_icon)
  .setSessionCommand(SessionCommand(REMOVE_FROM_FAVORITES, Bundle()))
  .build()
mediaSession.setCustomLayout(ImmutableList.of(likeButton, removeFromFavoritesButton))

Java

CommandButton removeFromFavoritesButton = new CommandButton.Builder()
  .setDisplayName("Remove from favorites")
  .setIconResId(R.drawable.favorite_remove_icon)
  .setSessionCommand(new SessionCommand(REMOVE_FROM_FAVORITES, new Bundle()))
  .build();
mediaSession.setCustomLayout(ImmutableList.of(likeButton, removeFromFavoritesButton));

प्लेबैक निर्देश के व्यवहार को पसंद के मुताबिक बनाएं

Player इंटरफ़ेस में बताए गए निर्देश के काम करने के तरीके को पसंद के मुताबिक बनाने के लिए, जैसे play() या seekToNext() के तौर पर, अपने Player को ForwardingPlayer में रैप करें.

Kotlin

val player = ExoPlayer.Builder(context).build()

val forwardingPlayer = object : ForwardingPlayer(player) {
  override fun play() {
    // Add custom logic
    super.play()
  }

  override fun setPlayWhenReady(playWhenReady: Boolean) {
    // Add custom logic
    super.setPlayWhenReady(playWhenReady)
  }
}

val mediaSession = MediaSession.Builder(context, forwardingPlayer).build()

Java

ExoPlayer player = new ExoPlayer.Builder(context).build();

ForwardingPlayer forwardingPlayer = new ForwardingPlayer(player) {
  @Override
  public void play() {
    // Add custom logic
    super.play();
  }

  @Override
  public void setPlayWhenReady(boolean playWhenReady) {
    // Add custom logic
    super.setPlayWhenReady(playWhenReady);
  }
};

MediaSession mediaSession =
  new MediaSession.Builder(context, forwardingPlayer).build();

ForwardingPlayer के बारे में ज़्यादा जानने के लिए, ExoPlayer की गाइड देखें कस्टमाइज़ेशन.

प्लेयर कमांड के अनुरोध करने वाले कंट्रोलर की पहचान करना

जब Player तरीके को कॉल करने की प्रक्रिया MediaController से शुरू होती है, तो ये काम किए जा सकते हैं MediaSession.controllerForCurrentRequest की मदद से, मूल स्रोत की पहचान करें और मौजूदा अनुरोध के लिए ControllerInfo को हासिल करेगा:

Kotlin

class CallerAwareForwardingPlayer(player: Player) :
  ForwardingPlayer(player) {

  override fun seekToNext() {
    Log.d(
      "caller",
      "seekToNext called from package ${session.controllerForCurrentRequest?.packageName}"
    )
    super.seekToNext()
  }
}

Java

public class CallerAwareForwardingPlayer extends ForwardingPlayer {
  public CallerAwareForwardingPlayer(Player player) {
    super(player);
  }

  @Override
  public void seekToNext() {
    Log.d(
        "caller",
        "seekToNext called from package: "
            + session.getControllerForCurrentRequest().getPackageName());
    super.seekToNext();
  }
}

मीडिया बटन का जवाब दें

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

कोई ऐप्लिकेशन ओवरराइड करके डिफ़ॉल्ट व्यवहार को बदल सकता है MediaSession.Callback.onMediaButtonEvent(Intent). ऐसे मामले में, ऐप्लिकेशन को एपीआई की हर खास जानकारी को खुद हैंडल करने की ज़रूरत हो सकती है.

गड़बड़ियों को ठीक करना और उनकी रिपोर्ट करना

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

वीडियो चलाने में होने वाली घातक गड़बड़ियां

प्लेयर, सेशन में वीडियो चलाने से जुड़ी किसी गंभीर गड़बड़ी की शिकायत करता है. इसके बाद, कंट्रोलर को सूचना दी जाएगी कि Player.Listener.onPlayerError(PlaybackException) और Player.Listener.onPlayerErrorChanged(@Nullable PlaybackException).

ऐसे मामले में, वीडियो चलाने की स्थिति STATE_IDLE में बदल जाती है और MediaController.getPlaybackError() वह PlaybackException लौटाता है जिसकी वजह से ऐसा हुआ था ट्रांज़िशन. कंट्रोलर, PlayerException.errorCode की जांच करके पता लगा सकता है कि गड़बड़ी की वजह के बारे में जानकारी.

इंटरऑपरेबिलिटी के लिए, किसी गंभीर गड़बड़ी की कॉपी PlaybackStateCompat में बनाई जाती है प्लैटफ़ॉर्म सेशन की स्थिति को STATE_ERROR में बदलकर और सेटिंग PlaybackException के अनुसार गड़बड़ी कोड और मैसेज दिखाता है.

गंभीर गड़बड़ी का कस्टमाइज़ेशन

उपयोगकर्ता को स्थानीय भाषा में और काम की जानकारी देने के लिए, गड़बड़ी कोड, गड़बड़ी का मैसेज और किसी गंभीर प्लेबैक गड़बड़ी की गड़बड़ी को सेशन बनाते समय ForwardingPlayer का इस्तेमाल करने पर:

Kotlin

val forwardingPlayer = ErrorForwardingPlayer(player)
val session = MediaSession.Builder(context, forwardingPlayer).build()

Java

Player forwardingPlayer = new ErrorForwardingPlayer(player);
MediaSession session =
    new MediaSession.Builder(context, forwardingPlayer).build();

फ़ॉरवर्ड करने वाला प्लेयर, असल प्लेयर में Player.Listener रजिस्टर करता है और उन कॉलबैक को इंटरसेप्ट करता है जो गड़बड़ी की रिपोर्ट करते हैं. पसंद के मुताबिक़ इसके बाद, PlaybackException को इन लिसनर को ट्रांसफ़र कर दिया जाता है फ़ॉरवर्ड करने वाले प्लेयर पर रजिस्टर होते हों. यह काम करे, इसके लिए फ़ॉरवर्ड करने वाला प्लेयर इसकी ऐक्सेस के लिए Player.addListener और Player.removeListener को ओवरराइड करता है वे श्रोता, जिनकी मदद से कस्टमाइज़ किया गया गड़बड़ी कोड, संदेश या अतिरिक्त चीज़ें भेजना चाहते हैं:

Kotlin

class ErrorForwardingPlayer(private val context: Context, player: Player) :
  ForwardingPlayer(player) {

  private val listeners: MutableList<Player.Listener> = mutableListOf()

  private var customizedPlaybackException: PlaybackException? = null

  init {
    player.addListener(ErrorCustomizationListener())
  }

  override fun addListener(listener: Player.Listener) {
    listeners.add(listener)
  }

  override fun removeListener(listener: Player.Listener) {
    listeners.remove(listener)
  }

  override fun getPlayerError(): PlaybackException? {
    return customizedPlaybackException
  }

  private inner class ErrorCustomizationListener : Player.Listener {

    override fun onPlayerErrorChanged(error: PlaybackException?) {
      customizedPlaybackException = error?.let { customizePlaybackException(it) }
      listeners.forEach { it.onPlayerErrorChanged(customizedPlaybackException) }
    }

    override fun onPlayerError(error: PlaybackException) {
      listeners.forEach { it.onPlayerError(customizedPlaybackException!!) }
    }

    private fun customizePlaybackException(
      error: PlaybackException,
    ): PlaybackException {
      val buttonLabel: String
      val errorMessage: String
      when (error.errorCode) {
        PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW -> {
          buttonLabel = context.getString(R.string.err_button_label_restart_stream)
          errorMessage = context.getString(R.string.err_msg_behind_live_window)
        }
        // Apps can customize further error messages by adding more branches.
        else -> {
          buttonLabel = context.getString(R.string.err_button_label_ok)
          errorMessage = context.getString(R.string.err_message_default)
        }
      }
      val extras = Bundle()
      extras.putString("button_label", buttonLabel)
      return PlaybackException(errorMessage, error.cause, error.errorCode, extras)
    }

    override fun onEvents(player: Player, events: Player.Events) {
      listeners.forEach {
        it.onEvents(player, events)
      }
    }
    // Delegate all other callbacks to all listeners without changing arguments like onEvents.
  }
}

Java

private static class ErrorForwardingPlayer extends ForwardingPlayer {

  private final Context context;
  private List<Player.Listener> listeners;
  @Nullable private PlaybackException customizedPlaybackException;

  public ErrorForwardingPlayer(Context context, Player player) {
    super(player);
    this.context = context;
    listeners = new ArrayList<>();
    player.addListener(new ErrorCustomizationListener());
  }

  @Override
  public void addListener(Player.Listener listener) {
    listeners.add(listener);
  }

  @Override
  public void removeListener(Player.Listener listener) {
    listeners.remove(listener);
  }

  @Nullable
  @Override
  public PlaybackException getPlayerError() {
    return customizedPlaybackException;
  }

  private class ErrorCustomizationListener implements Listener {

    @Override
    public void onPlayerErrorChanged(@Nullable PlaybackException error) {
      customizedPlaybackException =
          error != null ? customizePlaybackException(error, context) : null;
      for (int i = 0; i < listeners.size(); i++) {
        listeners.get(i).onPlayerErrorChanged(customizedPlaybackException);
      }
    }

    @Override
    public void onPlayerError(PlaybackException error) {
      for (int i = 0; i < listeners.size(); i++) {
        listeners.get(i).onPlayerError(checkNotNull(customizedPlaybackException));
      }
    }

    private PlaybackException customizePlaybackException(
        PlaybackException error, Context context) {
      String buttonLabel;
      String errorMessage;
      switch (error.errorCode) {
        case PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW:
          buttonLabel = context.getString(R.string.err_button_label_restart_stream);
          errorMessage = context.getString(R.string.err_msg_behind_live_window);
          break;
        // Apps can customize further error messages by adding more case statements.
        default:
          buttonLabel = context.getString(R.string.err_button_label_ok);
          errorMessage = context.getString(R.string.err_message_default);
          break;
      }
      Bundle extras = new Bundle();
      extras.putString("button_label", buttonLabel);
      return new PlaybackException(errorMessage, error.getCause(), error.errorCode, extras);
    }

    @Override
    public void onEvents(Player player, Events events) {
      for (int i = 0; i < listeners.size(); i++) {
        listeners.get(i).onEvents(player, events);
      }
    }
    // Delegate all other callbacks to all listeners without changing arguments like onEvents.
  }
}

सामान्य गड़बड़ियां

ऐसी सामान्य गड़बड़ियां भेजी जा सकती हैं जो किसी तकनीकी अपवाद की वजह से नहीं हुई हों सभी या किसी खास कंट्रोलर को ऐप्लिकेशन से:

Kotlin

val sessionError = SessionError(
  SessionError.ERROR_SESSION_AUTHENTICATION_EXPIRED,
  context.getString(R.string.error_message_authentication_expired),
)

// Sending a nonfatal error to all controllers.
mediaSession.sendError(sessionError)

// Interoperability: Sending a nonfatal error to the media notification controller to set the
// error code and error message in the playback state of the platform media session.
mediaSession.mediaNotificationControllerInfo?.let {
  mediaSession.sendError(it, sessionError)
}

Java

SessionError sessionError = new SessionError(
    SessionError.ERROR_SESSION_AUTHENTICATION_EXPIRED,
    context.getString(R.string.error_message_authentication_expired));

// Sending a nonfatal error to all controllers.
mediaSession.sendError(sessionError);

// Interoperability: Sending a nonfatal error to the media notification controller to set the
// error code and error message in the playback state of the platform media session.
ControllerInfo mediaNotificationControllerInfo =
    mediaSession.getMediaNotificationControllerInfo();
if (mediaNotificationControllerInfo != null) {
  mediaSession.sendError(mediaNotificationControllerInfo, sessionError);
}

मीडिया नोटिफ़िकेशन कंट्रोलर को भेजी गई एक साधारण गड़बड़ी, प्लैटफ़ॉर्म सेशन का PlaybackStateCompat. ऐसा करने से, सिर्फ़ गड़बड़ी का कोड और गड़बड़ी का मैसेज PlaybackStateCompat पर सेट हो जाता है, जबकि PlaybackStateCompat.state को STATE_ERROR में नहीं बदला गया.

साधारण गड़बड़ियां पाएं

MediaController को लागू करने पर एक साधारण गड़बड़ी मिलती है MediaController.Listener.onError:

Kotlin

val future = MediaController.Builder(context, sessionToken)
  .setListener(object : MediaController.Listener {
    override fun onError(controller: MediaController, sessionError: SessionError) {
      // Handle nonfatal error.
    }
  })
  .buildAsync()

Java

MediaController.Builder future =
    new MediaController.Builder(context, sessionToken)
        .setListener(
            new MediaController.Listener() {
              @Override
              public void onError(MediaController controller, SessionError sessionError) {
                // Handle nonfatal error.
              }
            });