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

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

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

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

MediaSession को लागू करने पर, उपयोगकर्ताओं को वीडियो चलाने की सुविधा मिलती है:

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

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

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

हालांकि, इस्तेमाल के सभी उदाहरण MediaSession के साथ सही से फ़िट नहीं होते. इन मामलों में, सिर्फ़ Player का इस्तेमाल किया जा सकता है:

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

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

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

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

मीडिया सेशन बनाने के लिए, 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 लाइब्रेरी, प्लेयर की स्थिति का इस्तेमाल करके मीडिया सेशन को अपने-आप अपडेट करती है. इसलिए, आपको प्लेयर से सेशन तक मैपिंग को मैन्युअल तरीके से मैनेज करने की ज़रूरत नहीं है.

यह प्लैटफ़ॉर्म मीडिया सेशन से अलग है. इसमें आपको प्लेयर से अलग PlaybackState बनाना और उसे मैनेज करना पड़ता था. उदाहरण के लिए, किसी गड़बड़ी के बारे में बताने के लिए.

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

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

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

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

दूसरे क्लाइंट को कंट्रोल देना

प्लेबैक को कंट्रोल करने के लिए, मीडिया सेशन की ज़रूरत होती है. इसकी मदद से, बाहरी सोर्स से मिले निर्देशों को उस प्लेयर पर भेजा जा सकता है जो आपका मीडिया चलाता है. ये सोर्स, हेडसेट या टीवी के रिमोट कंट्रोल पर मौजूद प्ले बटन जैसे फ़िज़िकल बटन हो सकते हैं. इसके अलावा, ये Google 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() को लागू करने का सैंपल, सेशन डेमो ऐप्लिकेशन में देखा जा सकता है.

मीडिया बटन की सेटिंग मैनेज करना

सिस्टम यूज़र इंटरफ़ेस (यूआई), Android Auto या Wear OS जैसे हर कंट्रोलर के पास यह तय करने का विकल्प होता है कि उपयोगकर्ता को कौनसे बटन दिखाने हैं. यह बताने के लिए कि आपको उपयोगकर्ता को कौनसे वीडियो चलाने के कंट्रोल दिखाने हैं, MediaSession पर मीडिया बटन की प्राथमिकताएं तय करें. इन प्राथमिकताओं में, CommandButton इंस्टेंस की व्यवस्थित सूची होती है. हर इंस्टेंस, यूज़र इंटरफ़ेस में किसी बटन की प्राथमिकता तय करता है.

कमांड बटन तय करना

CommandButton इंस्टेंस का इस्तेमाल, मीडिया बटन की सेटिंग तय करने के लिए किया जाता है. हर बटन, यूज़र इंटरफ़ेस (यूआई) एलिमेंट के तीन पहलुओं के बारे में बताता है:

  1. आइकॉन, जो विज़ुअल के दिखने का तरीका तय करता है. CommandButton.Builder बनाते समय, आइकॉन को पहले से तय किए गए किसी एक कॉन्स्टेंट पर सेट करना ज़रूरी है. ध्यान दें कि यह कोई असली बिटमैप या इमेज रिसॉर्स नहीं है. सामान्य कॉन्स्टेंट की मदद से, कंट्रोलर अपने यूज़र इंटरफ़ेस (यूआई) में एक जैसा लुक और फ़ील देने के लिए, सही संसाधन चुन सकते हैं. अगर पहले से तय कोई भी आइकॉन कॉन्स्टेंट आपके इस्तेमाल के उदाहरण के हिसाब से नहीं है, तो इसके बजाय setCustomIconResId का इस्तेमाल किया जा सकता है.
  2. कमांड, जो उपयोगकर्ता के बटन से इंटरैक्ट करने पर ट्रिगर की गई कार्रवाई के बारे में बताता है. Player.Command के लिए setPlayerCommand या पहले से तय या पसंद के मुताबिक SessionCommand के लिए setSessionCommand का इस्तेमाल किया जा सकता है.
  3. स्लॉट, इससे यह तय होता है कि बटन को कंट्रोलर के यूज़र इंटरफ़ेस (यूआई) में कहां रखा जाना चाहिए. यह फ़ील्ड भरना ज़रूरी नहीं है. यह आइकॉन और कमांड के आधार पर अपने-आप सेट हो जाता है. उदाहरण के लिए, इससे यह तय किया जा सकता है कि किसी बटन को डिफ़ॉल्ट 'ओवरफ़्लो' एरिया के बजाय, यूज़र इंटरफ़ेस (यूआई) के 'आगे' नेविगेशन एरिया में दिखाया जाए.

Kotlin

val button =
  CommandButton.Builder(CommandButton.ICON_SKIP_FORWARD_15)
    .setSessionCommand(SessionCommand(CUSTOM_ACTION_ID, Bundle.EMPTY))
    .setSlots(CommandButton.SLOT_FORWARD)
    .build()

Java

CommandButton button =
    new CommandButton.Builder(CommandButton.ICON_SKIP_FORWARD_15)
        .setSessionCommand(new SessionCommand(CUSTOM_ACTION_ID, Bundle.EMPTY))
        .setSlots(CommandButton.SLOT_FORWARD)
        .build();

मीडिया बटन की प्राथमिकताएं तय होने के बाद, यह एल्गोरिदम लागू होता है:

  1. मीडिया बटन की सेटिंग में मौजूद हर CommandButton के लिए, बटन को पहले उपलब्ध और अनुमति वाले स्लॉट में डालें.
  2. अगर सेंटर, आगे, और पीछे वाले किसी भी स्लॉट में बटन नहीं है, तो इस स्लॉट के लिए डिफ़ॉल्ट बटन जोड़ें.

CommandButton.DisplayConstraints का इस्तेमाल करके, इस बात की झलक देखी जा सकती है कि यूज़र इंटरफ़ेस (यूआई) के डिसप्ले की सीमाओं के आधार पर, मीडिया बटन की प्राथमिकताओं को कैसे हल किया जाएगा.

मीडिया बटन की सेटिंग सेट करना

मीडिया बटन की प्राथमिकताएं सेट करने का सबसे आसान तरीका यह है कि MediaSession बनाते समय सूची तय करें. इसके अलावा, कनेक्ट किए गए हर कंट्रोलर के लिए, मीडिया बटन की प्राथमिकताओं को पसंद के मुताबिक बनाने के लिए, MediaSession.Callback.onConnect को बदला जा सकता है.

Kotlin

val mediaSession =
  MediaSession.Builder(context, player)
    .setMediaButtonPreferences(ImmutableList.of(likeButton, favoriteButton))
    .build()

Java

MediaSession mediaSession =
  new MediaSession.Builder(context, player)
      .setMediaButtonPreferences(ImmutableList.of(likeButton, favoriteButton))
      .build();

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

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

Kotlin

// Handle "favoritesButton" action, replace by opposite button
mediaSession.setMediaButtonPreferences(
  ImmutableList.of(likeButton, removeFromFavoritesButton))

Java

// Handle "favoritesButton" action, replace by opposite button
mediaSession.setMediaButtonPreferences(
    ImmutableList.of(likeButton, removeFromFavoritesButton));

कस्टम निर्देश जोड़ना और डिफ़ॉल्ट व्यवहार को पसंद के मुताबिक बनाना

उपलब्ध प्लेयर कमांड को कस्टम कमांड की मदद से बढ़ाया जा सकता है. साथ ही, डिफ़ॉल्ट व्यवहार को बदलने के लिए, प्लेयर के इनकमिंग कमांड और मीडिया बटन को इंटरसेप्ट भी किया जा सकता है.

कस्टम निर्देशों को तय करना और उन्हें मैनेज करना

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

कस्टम निर्देश तय करने के लिए, आपको MediaSession.Callback.onConnect() को बदलना होगा, ताकि कनेक्ट किए गए हर कंट्रोलर के लिए उपलब्ध कस्टम निर्देश सेट किए जा सकें.

Kotlin

private 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 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)
      );
    }
    ...
  }
}

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

प्लेयर के लिए डिफ़ॉल्ट निर्देशों को पसंद के मुताबिक बनाना

सभी डिफ़ॉल्ट निर्देश और स्थिति मैनेज करने की सुविधा, MediaSession पर मौजूद Player को दी जाती है. Player इंटरफ़ेस में बताए गए किसी निर्देश के व्यवहार को पसंद के मुताबिक बनाने के लिए, जैसे कि play() या seekToNext(), Player को MediaSession में भेजने से पहले, उसे ForwardingSimpleBasePlayer में रैप करें:

Kotlin

val player = (logic to build a Player instance)

val forwardingPlayer = object : ForwardingSimpleBasePlayer(player) {
  // Customizations
}

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

Java

ExoPlayer player = (logic to build a Player instance)

ForwardingSimpleBasePlayer forwardingPlayer =
    new ForwardingSimpleBasePlayer(player) {
      // Customizations
    };

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

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

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

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

Kotlin

class CallerAwarePlayer(player: Player) :
  ForwardingSimpleBasePlayer(player) {

  override fun handleSeek(
    mediaItemIndex: Int,
    positionMs: Long,
    seekCommand: Int,
  ): ListenableFuture<*> {
    Log.d(
      "caller",
      "seek operation from package ${session.controllerForCurrentRequest?.packageName}",
    )
    return super.handleSeek(mediaItemIndex, positionMs, seekCommand)
  }
}

Java

public class CallerAwarePlayer extends ForwardingSimpleBasePlayer {
  public CallerAwarePlayer(Player player) {
    super(player);
  }

  @Override
  protected ListenableFuture<?> handleSeek(
        int mediaItemIndex, long positionMs, int seekCommand) {
    Log.d(
        "caller",
        "seek operation from package: "
            + session.getControllerForCurrentRequest().getPackageName());
    return super.handleSeek(mediaItemIndex, positionMs, seekCommand);
  }
}

मीडिया बटन को पसंद के मुताबिक बनाना

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

हमारा सुझाव है कि मीडिया बटन से मिलने वाले सभी इनकमिंग इवेंट को, उससे जुड़े Player तरीके से मैनेज करें. बेहतर इस्तेमाल के उदाहरणों के लिए, MediaSession.Callback.onMediaButtonEvent(Intent) में मीडिया बटन के इवेंट को इंटरसेप्ट किया जा सकता है.

गड़बड़ी को मैनेज करना और उसकी शिकायत करना

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

वीडियो चलाने में हुई गंभीर गड़बड़ियां

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

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

इंटरऑपरेबिलिटी के लिए, किसी गंभीर गड़बड़ी को प्लैटफ़ॉर्म सेशन में दोहराया जाता है. इसके लिए, सेशन की स्थिति को 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();

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

Kotlin

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

  override fun getState(): State {
    var state = super.getState()
    if (state.playerError != null) {
      state =
        state.buildUpon()
          .setPlayerError(customizePlaybackException(state.playerError!!))
          .build()
    }
    return state
  }

  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)
      }
      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)
  }
}

Java

class ErrorForwardingPlayer extends ForwardingSimpleBasePlayer {

  private final Context context;

  public ErrorForwardingPlayer(Context context, Player player) {
    super(player);
    this.context = context;
  }

  @Override
  protected State getState() {
    State state = super.getState();
    if (state.playerError != null) {
      state =
          state.buildUpon()
              .setPlayerError(customizePlaybackException(state.playerError))
              .build();
    }
    return state;
  }

  private PlaybackException customizePlaybackException(PlaybackException error) {
    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;
      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);
  }
}

नुकसान न पहुंचाने वाली गड़बड़ियां

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

Kotlin

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

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

// Option 2: Sending a nonfatal error to the media notification controller only
// 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));

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

// Option 2: Sending a nonfatal error to the media notification controller only
// 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);
}

जब मीडिया सूचना कंट्रोलर को गैर-घातक गड़बड़ी भेजी जाती है, तो गड़बड़ी का कोड और गड़बड़ी का मैसेज, प्लैटफ़ॉर्म मीडिया सेशन में दोहराया जाता है. हालांकि, PlaybackState.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.
              }
            });