Cast को अपने Android ऐप्लिकेशन में इंटिग्रेट करें

इस डेवलपर गाइड में Android सेंडर SDK टूल का इस्तेमाल करके, Android डिवाइस भेजने वाले ऐप्लिकेशन में Google Cast सहायता जोड़ने का तरीका बताया गया है.

मोबाइल डिवाइस या लैपटॉप भेजने वाला होता है, जो वीडियो को कंट्रोल करता है. साथ ही, Google Cast डिवाइस पाने वाला होता है, जो टीवी पर कॉन्टेंट दिखाता है.

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

भेजने वाले का फ़्रेमवर्क एसिंक्रोनस कॉलबैक डिज़ाइन का इस्तेमाल करता है. इसकी मदद से, भेजने वाले के ऐप्लिकेशन को इवेंट की जानकारी दी जाती है. साथ ही, Cast ऐप्लिकेशन की लाइफ़साइकल की अलग-अलग स्थितियों के बीच ट्रांज़िशन भी किया जाता है.

ऐप्लिकेशन फ़्लो

यहां दिए गए तरीके से, ईमेल भेजने वाले के Android ऐप्लिकेशन को प्रोसेस करने की सामान्य प्रोसेस के बारे में जानकारी दी जाती है:

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

Google Cast Android SDK की सभी क्लास, तरीकों, और इवेंट की पूरी सूची देखने के लिए, Android के लिए Google Cast सेंडर एपीआई रेफ़रंस देखें. Android ऐप्लिकेशन में Cast को जोड़ने का तरीका नीचे बताया गया है.

Android मेनिफ़ेस्ट कॉन्फ़िगर करें

आपके ऐप्लिकेशन की AndroidManifest.xml फ़ाइल में, आपको Cast SDK के लिए ये एलिमेंट कॉन्फ़िगर करने होंगे:

uses-sdk

वे कम से कम और टारगेट Android API लेवल सेट करें जो Cast SDK पर काम करते हैं. फ़िलहाल, यह एपीआई लेवल 21 और एपीआई लेवल 28 को ही टारगेट किया जाता है.

<uses-sdk
        android:minSdkVersion="21"
        android:targetSdkVersion="28" />

android:theme

Android SDK के कम से कम वर्शन के आधार पर अपने ऐप्लिकेशन की थीम सेट करें. उदाहरण के लिए, अगर आपको अपनी थीम लागू नहीं करनी है, तो आपको Lollipop से पहले वाले Android SDK वर्शन को टारगेट करते समय, Theme.AppCompat के वैरिएंट का इस्तेमाल करना चाहिए.

<application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/Theme.AppCompat" >
       ...
</application>

कास्ट कॉन्टेक्स्ट शुरू करें

इस फ़्रेमवर्क में एक ग्लोबल सिंगलटन ऑब्जेक्ट है, जिसे CastContext कहते हैं. यह फ़्रेमवर्क के सभी इंटरैक्शन को कोऑर्डिनेट करता है.

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

कोटलिन
class CastOptionsProvider : OptionsProvider {
    override fun getCastOptions(context: Context): CastOptions {
        return Builder()
            .setReceiverApplicationId(context.getString(R.string.app_id))
            .build()
    }

    override fun getAdditionalSessionProviders(context: Context): List<SessionProvider>? {
        return null
    }
}
Java
public class CastOptionsProvider implements OptionsProvider {
    @Override
    public CastOptions getCastOptions(Context context) {
        CastOptions castOptions = new CastOptions.Builder()
            .setReceiverApplicationId(context.getString(R.string.app_id))
            .build();
        return castOptions;
    }
    @Override
    public List<SessionProvider> getAdditionalSessionProviders(Context context) {
        return null;
    }
}

आपको भेजने वाले ऐप्लिकेशन की AndroidManifest.xml फ़ाइल में, लागू किए गए OptionsProvider के पूरी तरह क्वालिफ़ाइड नाम की जानकारी, मेटाडेटा फ़ील्ड के तौर पर देनी होगी:

<application>
    ...
    <meta-data
        android:name=
            "com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
        android:value="com.foo.CastOptionsProvider" />
</application>

CastContext.getSharedInstance() को कॉल करने पर, CastContext लेज़ीली प्रोसेस शुरू होती है.

कोटलिन
class MyActivity : FragmentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        val castContext = CastContext.getSharedInstance(this)
    }
}
Java
public class MyActivity extends FragmentActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        CastContext castContext = CastContext.getSharedInstance(this);
    }
}

Cast UX विजेट

कास्ट फ़्रेमवर्क से ऐसे विजेट मिलते हैं जो Cast डिज़ाइन चेकलिस्ट का पालन करते हैं:

  • शुरुआती ओवरले: यह फ़्रेमवर्क एक कस्टम व्यू IntroductoryOverlay उपलब्ध कराता है. यह एक ऐसा व्यू होता है जिसे पहली बार रिसीवर के उपलब्ध होने पर, 'कास्ट करें' बटन पर क्लिक किया जा सकता है. सेंडर ऐप्लिकेशन टेक्स्ट और टाइटल की जगह को अपनी पसंद के मुताबिक बना सकता है.

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

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

  • एक्सपैंडेड कंट्रोलर: जब उपयोगकर्ता कॉन्टेंट कास्ट कर रहा होता है, तो वह मीडिया सूचना या मिनी कंट्रोलर पर क्लिक करता है. ऐसे में, बड़ा किया गया कंट्रोलर लॉन्च होता है. इसमें, चल रहा मीडिया मेटाडेटा दिखता है. साथ ही, मीडिया प्लेबैक को कंट्रोल करने के लिए कई बटन होते हैं.

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

  • लॉक स्क्रीन: सिर्फ़ Android. जब कोई व्यक्ति कॉन्टेंट को कास्ट करता है और लॉक स्क्रीन पर नेविगेट करता है (या डिवाइस का समय खत्म होता है), तो उसे मीडिया लॉक स्क्रीन कंट्रोल दिखता है. इस कंट्रोल में, कास्ट किए जा रहे मीडिया का मेटाडेटा और प्लेबैक कंट्रोल दिखते हैं.

नीचे दी गई गाइड में इन विजेट को अपने ऐप्लिकेशन में जोड़ने का तरीका बताया गया है.

'कास्ट करें' बटन जोड़ें

Android MediaRouter एपीआई को सेकंडरी डिवाइसों पर मीडिया दिखाने और वीडियो चलाने के लिए डिज़ाइन किया गया है. MediaRouter एपीआई का इस्तेमाल करने वाले Android ऐप्लिकेशन के यूज़र इंटरफ़ेस में 'कास्ट करें' बटन शामिल होना चाहिए. इससे उपयोगकर्ता, कास्ट डिवाइस जैसे दूसरे डिवाइस पर मीडिया चलाने के लिए कोई मीडिया रूट चुन पाएंगे.

इस फ़्रेमवर्क से Cast button MediaRouteButton को जोड़ना बहुत आसान हो जाता है. आपको सबसे पहले एक्सएमएल फ़ाइल में कोई मेन्यू आइटम या MediaRouteButton जोड़ना चाहिए, जो आपके मेन्यू के बारे में बताता हो. साथ ही, CastButtonFactory का इस्तेमाल करके इसे फ़्रेमवर्क के मुताबिक बनाएं.

// To add a Cast button, add the following snippet.
// menu.xml
<item
    android:id="@+id/media_route_menu_item"
    android:title="@string/media_route_menu_title"
    app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"
    app:showAsAction="always" />
कोटलिन
// Then override the onCreateOptionMenu() for each of your activities.
// MyActivity.kt
override fun onCreateOptionsMenu(menu: Menu): Boolean {
    super.onCreateOptionsMenu(menu)
    menuInflater.inflate(R.menu.main, menu)
    CastButtonFactory.setUpMediaRouteButton(
        applicationContext,
        menu,
        R.id.media_route_menu_item
    )
    return true
}
Java
// Then override the onCreateOptionMenu() for each of your activities.
// MyActivity.java
@Override public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);
    getMenuInflater().inflate(R.menu.main, menu);
    CastButtonFactory.setUpMediaRouteButton(getApplicationContext(),
                                            menu,
                                            R.id.media_route_menu_item);
    return true;
}

इसके बाद, अगर आपका Activity, FragmentActivity से इनहेरिट होता है, तो आपके पास अपने लेआउट में MediaRouteButton जोड़ने का विकल्प है.

// activity_layout.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:gravity="center_vertical"
   android:orientation="horizontal" >

   <androidx.mediarouter.app.MediaRouteButton
       android:id="@+id/media_route_button"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_weight="1"
       android:mediaRouteTypes="user"
       android:visibility="gone" />

</LinearLayout>
कोटलिन
// MyActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_layout)

    mMediaRouteButton = findViewById<View>(R.id.media_route_button) as MediaRouteButton
    CastButtonFactory.setUpMediaRouteButton(applicationContext, mMediaRouteButton)

    mCastContext = CastContext.getSharedInstance(this)
}
Java
// MyActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_layout);

   mMediaRouteButton = (MediaRouteButton) findViewById(R.id.media_route_button);
   CastButtonFactory.setUpMediaRouteButton(getApplicationContext(), mMediaRouteButton);

   mCastContext = CastContext.getSharedInstance(this);
}

किसी थीम का इस्तेमाल करके कास्ट बटन को दिखाने का तरीका सेट करने के लिए, 'कास्ट करें' बटन को पसंद के मुताबिक बनाएं देखें.

डिवाइस खोज कॉन्फ़िगर करें

डिवाइस डिस्कवरी को पूरी तरह से CastContext मैनेज करता है. CastContext शुरू करते समय, भेजने वाले का ऐप्लिकेशन, वेब रिसीवर ऐप्लिकेशन आईडी की जानकारी देता है. साथ ही, वह CastOptions में supportedNamespaces को सेट करके, नेमस्पेस फ़िल्टर करने का अनुरोध कर सकता है. CastContext में आंतरिक तौर पर MediaRouter का रेफ़रंस होता है और यहां दी गई स्थितियों के तहत, खोजने की प्रोसेस शुरू की जाएगी:

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

कास्ट डायलॉग बंद होने या भेजने वाले के ऐप्लिकेशन के बैकग्राउंड में जाने पर, खोजने की प्रोसेस बंद हो जाएगी.

कोटलिन
class CastOptionsProvider : OptionsProvider {
    companion object {
        const val CUSTOM_NAMESPACE = "urn:x-cast:custom_namespace"
    }

    override fun getCastOptions(appContext: Context): CastOptions {
        val supportedNamespaces: MutableList<String> = ArrayList()
        supportedNamespaces.add(CUSTOM_NAMESPACE)

        return CastOptions.Builder()
            .setReceiverApplicationId(context.getString(R.string.app_id))
            .setSupportedNamespaces(supportedNamespaces)
            .build()
    }

    override fun getAdditionalSessionProviders(context: Context): List<SessionProvider>? {
        return null
    }
}
Java
class CastOptionsProvider implements OptionsProvider {
    public static final String CUSTOM_NAMESPACE = "urn:x-cast:custom_namespace";

    @Override
    public CastOptions getCastOptions(Context appContext) {
        List<String> supportedNamespaces = new ArrayList<>();
        supportedNamespaces.add(CUSTOM_NAMESPACE);

        CastOptions castOptions = new CastOptions.Builder()
            .setReceiverApplicationId(context.getString(R.string.app_id))
            .setSupportedNamespaces(supportedNamespaces)
            .build();
        return castOptions;
    }

    @Override
    public List<SessionProvider> getAdditionalSessionProviders(Context context) {
        return null;
    }
}

सेशन मैनेजमेंट के काम करने का तरीका

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

सेशन को क्लास SessionManager मैनेज करता है. आपका ऐप्लिकेशन CastContext.getSessionManager() की मदद से इसे ऐक्सेस कर सकता है. अलग-अलग सेशन को क्लास Session क्लास के सब-क्लास के तौर पर दिखाया जाता है. उदाहरण के लिए, CastSession कास्ट डिवाइसों वाले सेशन के बारे में बताता है. आपका ऐप्लिकेशन SessionManager.getCurrentCastSession() से, मौजूदा कास्ट सेशन को ऐक्सेस कर सकता है.

आपका ऐप्लिकेशन, सेशन के इवेंट को मॉनिटर करने के लिए SessionManagerListener क्लास का इस्तेमाल कर सकता है. इनमें इवेंट बनाना, निलंबित करना, फिर से शुरू करना, और बंद करना शामिल है. यह फ़्रेमवर्क, सेशन के चालू रहने के दौरान, असामान्य/अचानक बंद होने की स्थिति से अपने-आप फिर से शुरू होने की कोशिश करता है.

MediaRouter डायलॉग से उपयोगकर्ता के जेस्चर (हाव-भाव) के जवाब में, सेशन अपने-आप बनते और बंद होते हैं.

कास्ट शुरू होने से जुड़ी गड़बड़ियों को बेहतर ढंग से समझने के लिए, ऐप्लिकेशन CastContext#getCastReasonCodeForCastStatusCode(int) का इस्तेमाल करके सेशन शुरू होने की गड़बड़ी को CastReasonCodes में बदल सकते हैं. कृपया ध्यान दें कि सेशन शुरू होने से जुड़ी कुछ गड़बड़ियां (जैसे, CastReasonCodes#CAST_CANCELLED) उम्मीद के मुताबिक होती हैं और इन्हें किसी गड़बड़ी के तौर पर लॉग नहीं किया जाना चाहिए.

अगर आपको सेशन की स्थिति में हुए बदलावों के बारे में जानकारी है, तो SessionManagerListener लागू करें. इस उदाहरण में, Activity में CastSession की उपलब्धता के बारे में बताया गया है.

कोटलिन
class MyActivity : Activity() {
    private var mCastSession: CastSession? = null
    private lateinit var mCastContext: CastContext
    private lateinit var mSessionManager: SessionManager
    private val mSessionManagerListener: SessionManagerListener<CastSession> =
        SessionManagerListenerImpl()

    private inner class SessionManagerListenerImpl : SessionManagerListener<CastSession?> {
        override fun onSessionStarting(session: CastSession?) {}

        override fun onSessionStarted(session: CastSession?, sessionId: String) {
            invalidateOptionsMenu()
        }

        override fun onSessionStartFailed(session: CastSession?, error: Int) {
            val castReasonCode = mCastContext.getCastReasonCodeForCastStatusCode(error)
            // Handle error
        }

        override fun onSessionSuspended(session: CastSession?, reason Int) {}

        override fun onSessionResuming(session: CastSession?, sessionId: String) {}

        override fun onSessionResumed(session: CastSession?, wasSuspended: Boolean) {
            invalidateOptionsMenu()
        }

        override fun onSessionResumeFailed(session: CastSession?, error: Int) {}

        override fun onSessionEnding(session: CastSession?) {}

        override fun onSessionEnded(session: CastSession?, error: Int) {
            finish()
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mCastContext = CastContext.getSharedInstance(this)
        mSessionManager = mCastContext.sessionManager
    }

    override fun onResume() {
        super.onResume()
        mCastSession = mSessionManager.currentCastSession
        mSessionManager.addSessionManagerListener(mSessionManagerListener, CastSession::class.java)
    }

    override fun onPause() {
        super.onPause()
        mSessionManager.removeSessionManagerListener(mSessionManagerListener, CastSession::class.java)
        mCastSession = null
    }
}
Java
public class MyActivity extends Activity {
    private CastContext mCastContext;
    private CastSession mCastSession;
    private SessionManager mSessionManager;
    private SessionManagerListener<CastSession> mSessionManagerListener =
            new SessionManagerListenerImpl();

    private class SessionManagerListenerImpl implements SessionManagerListener<CastSession> {
        @Override
        public void onSessionStarting(CastSession session) {}
        @Override
        public void onSessionStarted(CastSession session, String sessionId) {
            invalidateOptionsMenu();
        }
        @Override
        public void onSessionStartFailed(CastSession session, int error) {
            int castReasonCode = mCastContext.getCastReasonCodeForCastStatusCode(error);
            // Handle error
        }
        @Override
        public void onSessionSuspended(CastSession session, int reason) {}
        @Override
        public void onSessionResuming(CastSession session, String sessionId) {}
        @Override
        public void onSessionResumed(CastSession session, boolean wasSuspended) {
            invalidateOptionsMenu();
        }
        @Override
        public void onSessionResumeFailed(CastSession session, int error) {}
        @Override
        public void onSessionEnding(CastSession session) {}
        @Override
        public void onSessionEnded(CastSession session, int error) {
            finish();
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mCastContext = CastContext.getSharedInstance(this);
        mSessionManager = mCastContext.getSessionManager();
    }
    @Override
    protected void onResume() {
        super.onResume();
        mCastSession = mSessionManager.getCurrentCastSession();
        mSessionManager.addSessionManagerListener(mSessionManagerListener, CastSession.class);
    }
    @Override
    protected void onPause() {
        super.onPause();
        mSessionManager.removeSessionManagerListener(mSessionManagerListener, CastSession.class);
        mCastSession = null;
    }
}

स्ट्रीम को ट्रांसफ़र करें

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

स्ट्रीम ट्रांसफ़र या उसे बढ़ाने के दौरान, नया डेस्टिनेशन डिवाइस पाने के लिए, CastSession#addCastListener का इस्तेमाल करके Cast.Listener को रजिस्टर करें. इसके बाद, onDeviceNameChanged कॉलबैक के दौरान CastSession#getCastDevice() को कॉल करें.

ज़्यादा जानकारी के लिए, वेब पाने वाले पर स्ट्रीम का मालिकाना हक देखें.

अपने-आप फिर से कनेक्ट होने की सुविधा

इस फ़्रेमवर्क से आपको ReconnectionService मिलता है. इसे भेजने वाले ऐप्लिकेशन, कई छोटे मामलों में फिर से कनेक्ट करने के लिए चालू कर सकता है. जैसे:

  • कुछ समय के लिए वाई-फ़ाई बंद हो जाने के बाद, डेटा वापस पाएं
  • डिवाइस की स्लीप मोड से रिकवर करें
  • ऐप्लिकेशन के बैकग्राउंड में बदलाव करके उसे वापस पाएं
  • ऐप्लिकेशन क्रैश होने पर रिकवर करना

यह सेवा डिफ़ॉल्ट रूप से चालू होती है और इसे CastOptions.Builder में बंद किया जा सकता है.

अगर आपकी Gradle फ़ाइल में अपने-आप मर्ज होने की सुविधा चालू है, तो यह सेवा आपके ऐप्लिकेशन के मेनिफ़ेस्ट में अपने-आप मर्ज हो सकती है.

मीडिया सेशन होने पर फ़्रेमवर्क, सेवा को शुरू करता है और मीडिया सेशन खत्म होने पर उसे बंद कर देता है.

मीडिया कंट्रोल कैसे काम करता है

Cast फ़्रेमवर्क, नई क्लास RemoteMediaClient के लिए Cast 2.x से RemoteMediaPlayer क्लास को रोक देता है. इससे ज़्यादा आसान एपीआई के सेट में एक जैसी सुविधाएं मिलती हैं. साथ ही, इसे GoogleApiClient में पास नहीं करना पड़ता.

जब आपका ऐप्लिकेशन, ऐसे वेब रिसीवर ऐप्लिकेशन के साथ CastSession बनाता है जो मीडिया नेमस्पेस के साथ काम करता है, तो फ़्रेमवर्क अपने-आप RemoteMediaClient का एक इंस्टेंस बना देता है. आपका ऐप्लिकेशन, CastSession इंस्टेंस पर getRemoteMediaClient() तरीके को कॉल करके इसे ऐक्सेस कर सकता है.

वेब पाने वाले को अनुरोध भेजने वाले RemoteMediaClient के सभी तरीके, Pendingनतीजे ऑब्जेक्ट को दिखाएंगे, जिसका इस्तेमाल उस अनुरोध को ट्रैक करने के लिए किया जा सकता है.

ऐसा हो सकता है कि RemoteMediaClient के इंस्टेंस को आपके ऐप्लिकेशन के कई हिस्सों के साथ-साथ, फ़्रेमवर्क के कुछ इंटरनल कॉम्पोनेंट के साथ शेयर किया जा सकता हो. उदाहरण के लिए, परसिस्टेंट मिनी कंट्रोलर और सूचना सेवा. इस वजह से, इस इंस्टेंस में RemoteMediaClient.Listener के एक से ज़्यादा इंस्टेंस के रजिस्ट्रेशन किए जा सकते हैं.

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

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

कोटलिन
val movieMetadata = MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE)

movieMetadata.putString(MediaMetadata.KEY_TITLE, mSelectedMedia.getTitle())
movieMetadata.putString(MediaMetadata.KEY_SUBTITLE, mSelectedMedia.getStudio())
movieMetadata.addImage(WebImage(Uri.parse(mSelectedMedia.getImage(0))))
movieMetadata.addImage(WebImage(Uri.parse(mSelectedMedia.getImage(1))))
Java
MediaMetadata movieMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE);

movieMetadata.putString(MediaMetadata.KEY_TITLE, mSelectedMedia.getTitle());
movieMetadata.putString(MediaMetadata.KEY_SUBTITLE, mSelectedMedia.getStudio());
movieMetadata.addImage(new WebImage(Uri.parse(mSelectedMedia.getImage(0))));
movieMetadata.addImage(new WebImage(Uri.parse(mSelectedMedia.getImage(1))));

मीडिया मेटाडेटा के साथ इमेज का इस्तेमाल करने के बारे में जानने के लिए, इमेज चुनना देखें.

मीडिया लोड करें

आपका ऐप्लिकेशन मीडिया आइटम लोड कर सकता है, जैसा कि इस कोड में दिखाया गया है. सबसे पहले, MediaInfo इंस्टेंस बनाने के लिए, मीडिया के मेटाडेटा के साथ MediaInfo.Builder का इस्तेमाल करें. मौजूदा CastSession से RemoteMediaClient को डाउनलोड करें. इसके बाद, उस RemoteMediaClient में MediaInfo लोड करें. वेब रिसीवर पर चल रहे मीडिया प्लेयर ऐप्लिकेशन को चलाने, रोकने, और उसे कंट्रोल करने के लिए, RemoteMediaClient का इस्तेमाल करें.

कोटलिन
val mediaInfo = MediaInfo.Builder(mSelectedMedia.getUrl())
    .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
    .setContentType("videos/mp4")
    .setMetadata(movieMetadata)
    .setStreamDuration(mSelectedMedia.getDuration() * 1000)
    .build()
val remoteMediaClient = mCastSession.getRemoteMediaClient()
remoteMediaClient.load(MediaLoadRequestData.Builder().setMediaInfo(mediaInfo).build())
Java
MediaInfo mediaInfo = new MediaInfo.Builder(mSelectedMedia.getUrl())
        .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
        .setContentType("videos/mp4")
        .setMetadata(movieMetadata)
        .setStreamDuration(mSelectedMedia.getDuration() * 1000)
        .build();
RemoteMediaClient remoteMediaClient = mCastSession.getRemoteMediaClient();
remoteMediaClient.load(new MediaLoadRequestData.Builder().setMediaInfo(mediaInfo).build());

साथ ही, मीडिया ट्रैक इस्तेमाल करने से जुड़ा सेक्शन भी देखें.

4K वीडियो फ़ॉर्मैट

यह देखने के लिए कि आपका मीडिया किस वीडियो फ़ॉर्मैट में है, VideoInfo का मौजूदा इंस्टेंस देखने के लिए MediaStatus में getVideoInfo() का इस्तेमाल करें. इस इंस्टेंस में एचडीआर टीवी फ़ॉर्मैट का टाइप और पिक्सल में डिसप्ले की ऊंचाई और चौड़ाई की जानकारी शामिल होती है. 4K फ़ॉर्मैट वाले वैरिएंट को कॉन्सटेंट HDR_TYPE_* के आधार पर दिखाया जाता है.

एक से ज़्यादा डिवाइसों पर रिमोट कंट्रोल की सुविधा

जब कोई उपयोगकर्ता कास्ट कर रहा होता है, तो उसी नेटवर्क पर मौजूद दूसरे Android डिवाइसों को एक सूचना मिलती है. इस सूचना में, उन्हें भी यह कंट्रोल करने की अनुमति दी जाती है. जिस किसी के डिवाइस को इस तरह की सूचनाएं मिलती हैं, वह उस डिवाइस के लिए इन सूचनाओं को बंद कर सकता है. इसके लिए, Google > Google Cast > रिमोट कंट्रोल की सूचनाएं दिखाएं पर जाएं. (सूचनाओं में सेटिंग ऐप्लिकेशन का शॉर्टकट शामिल होता है.) ज़्यादा जानकारी के लिए, रिमोट कंट्रोल की सूचनाएं कास्ट करने का तरीका लेख पढ़ें.

मिनी कंट्रोलर जोड़ें

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

यह फ़्रेमवर्क, एक कस्टम व्यू, MiniControllerFrame उपलब्ध कराता है. इसे हर उस गतिविधि की लेआउट फ़ाइल के नीचे जोड़ा जा सकता है जिसमें आपको मिनी कंट्रोलर दिखाना है.

<fragment
    android:id="@+id/castMiniController"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:visibility="gone"
    class="com.google.android.gms.cast.framework.media.widget.MiniControllerFragment" />

जब भेजने वाला ऐप्लिकेशन कोई वीडियो या ऑडियो लाइव स्ट्रीम चला रहा होता है, तब SDK टूल, मिनी कंट्रोलर में 'चलाएं/रोकें' बटन की जगह पर, 'चलाएं/बंद करें' बटन अपने-आप दिखाता है.

पसंद के मुताबिक बनाए गए इस व्यू के टाइटल और सबटाइटल का टेक्स्ट सेट करने और बटन चुनने के लिए, मिनी कंट्रोलर को पसंद के मुताबिक बनाना लेख पढ़ें.

बड़ा किया गया कंट्रोलर जोड़ें

Google Cast डिज़ाइन चेकलिस्ट के लिए आवश्यक है कि भेजने वाला ऐप्लिकेशन कास्ट किए जा रहे मीडिया के लिए एक विस्तृत नियंत्रक हो. बड़ा किया गया कंट्रोलर, मिनी कंट्रोलर का फ़ुल स्क्रीन वर्शन है.

Cast SDK टूल, बड़े किए गए कंट्रोलर के लिए एक विजेट उपलब्ध कराता है. इस विजेट को ExpandedControllerActivity कहा जाता है. यह एक ऐब्स्ट्रैक्ट क्लास है, जिसे कास्ट बटन जोड़ने के लिए आपको सब-क्लास की ज़रूरत होती है.

सबसे पहले, 'कास्ट करें' बटन उपलब्ध कराने के लिए, बड़े किए गए कंट्रोलर के लिए एक नई मेन्यू रिसॉर्स फ़ाइल बनाएं:

<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto">

    <item
            android:id="@+id/media_route_menu_item"
            android:title="@string/media_route_menu_title"
            app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"
            app:showAsAction="always"/>

</menu>

ExpandedControllerActivity का दायरा बढ़ाने वाली नई क्लास बनाएं.

कोटलिन
class ExpandedControlsActivity : ExpandedControllerActivity() {
    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        super.onCreateOptionsMenu(menu)
        menuInflater.inflate(R.menu.expanded_controller, menu)
        CastButtonFactory.setUpMediaRouteButton(this, menu, R.id.media_route_menu_item)
        return true
    }
}
Java
public class ExpandedControlsActivity extends ExpandedControllerActivity {
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        getMenuInflater().inflate(R.menu.expanded_controller, menu);
        CastButtonFactory.setUpMediaRouteButton(this, menu, R.id.media_route_menu_item);
        return true;
    }
}

अब ऐप्लिकेशन मेनिफ़ेस्ट में, application टैग में अपनी नई गतिविधि के बारे में बताएं:

<application>
...
<activity
        android:name=".expandedcontrols.ExpandedControlsActivity"
        android:label="@string/app_name"
        android:launchMode="singleTask"
        android:theme="@style/Theme.CastVideosDark"
        android:screenOrientation="portrait"
        android:parentActivityName="com.google.sample.cast.refplayer.VideoBrowserActivity">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
    </intent-filter>
</activity>
...
</application>

टारगेट गतिविधि को अपनी नई गतिविधि के लिए सेट करने के लिए, CastOptionsProvider में बदलाव करें. साथ ही, NotificationOptions और CastMediaOptions को बदलें:

कोटलिन
override fun getCastOptions(context: Context): CastOptions? {
    val notificationOptions = NotificationOptions.Builder()
        .setTargetActivityClassName(ExpandedControlsActivity::class.java.name)
        .build()
    val mediaOptions = CastMediaOptions.Builder()
        .setNotificationOptions(notificationOptions)
        .setExpandedControllerActivityClassName(ExpandedControlsActivity::class.java.name)
        .build()

    return CastOptions.Builder()
        .setReceiverApplicationId(context.getString(R.string.app_id))
        .setCastMediaOptions(mediaOptions)
        .build()
}
Java
public CastOptions getCastOptions(Context context) {
    NotificationOptions notificationOptions = new NotificationOptions.Builder()
            .setTargetActivityClassName(ExpandedControlsActivity.class.getName())
            .build();
    CastMediaOptions mediaOptions = new CastMediaOptions.Builder()
            .setNotificationOptions(notificationOptions)
            .setExpandedControllerActivityClassName(ExpandedControlsActivity.class.getName())
            .build();

    return new CastOptions.Builder()
            .setReceiverApplicationId(context.getString(R.string.app_id))
            .setCastMediaOptions(mediaOptions)
            .build();
}

रिमोट मीडिया लोड होने पर, अपनी नई गतिविधि दिखाने के लिए LocalPlayerActivity loadRemoteMedia तरीके को अपडेट करें:

कोटलिन
private fun loadRemoteMedia(position: Int, autoPlay: Boolean) {
    val remoteMediaClient = mCastSession?.remoteMediaClient ?: return

    remoteMediaClient.registerCallback(object : RemoteMediaClient.Callback() {
        override fun onStatusUpdated() {
            val intent = Intent(this@LocalPlayerActivity, ExpandedControlsActivity::class.java)
            startActivity(intent)
            remoteMediaClient.unregisterCallback(this)
        }
    })

    remoteMediaClient.load(
        MediaLoadRequestData.Builder()
            .setMediaInfo(mSelectedMedia)
            .setAutoplay(autoPlay)
            .setCurrentTime(position.toLong()).build()
    )
}
Java
private void loadRemoteMedia(int position, boolean autoPlay) {
    if (mCastSession == null) {
        return;
    }
    final RemoteMediaClient remoteMediaClient = mCastSession.getRemoteMediaClient();
    if (remoteMediaClient == null) {
        return;
    }
    remoteMediaClient.registerCallback(new RemoteMediaClient.Callback() {
        @Override
        public void onStatusUpdated() {
            Intent intent = new Intent(LocalPlayerActivity.this, ExpandedControlsActivity.class);
            startActivity(intent);
            remoteMediaClient.unregisterCallback(this);
        }
    });
    remoteMediaClient.load(new MediaLoadRequestData.Builder()
            .setMediaInfo(mSelectedMedia)
            .setAutoplay(autoPlay)
            .setCurrentTime(position).build());
}

जब आपका भेजने वाला ऐप्लिकेशन कोई वीडियो या ऑडियो लाइव स्ट्रीम चला रहा होता है, तो SDK टूल बड़े किए गए कंट्रोलर में चलाएं/रोकें बटन की जगह पर अपने-आप एक चलाएं/बंद करें बटन दिखाता है.

थीम का इस्तेमाल करके थीम सेट करने, यह चुनने के लिए कि कौनसे बटन दिखाने हैं, और कस्टम बटन जोड़ने के लिए, एक्सपैंडेड कंट्रोलर को पसंद के मुताबिक बनाना देखें.

वॉल्यूम कंट्रोल

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

फ़िज़िकल बटन की आवाज़ को कम या ज़्यादा करने का बटन

Android पर, भेजने वाले के डिवाइस पर मौजूद फ़िज़िकल बटन का इस्तेमाल, वेब रिसीवर पर कास्ट सेशन की आवाज़ को डिफ़ॉल्ट रूप से बदलने के लिए किया जा सकता है. ऐसा जैली बीन या उसके बाद के वर्शन का इस्तेमाल करने वाले किसी भी डिवाइस के लिए किया जा सकता है.

जैली बीन से पहले वास्तविक बटन वॉल्यूम नियंत्रण

फ़िज़िकल वॉल्यूम बटन का इस्तेमाल करके जैली बीन से पुराने Android डिवाइसों पर वेब रिसीवर डिवाइस वॉल्यूम को कंट्रोल करें. इसके लिए, भेजने वाले ऐप्लिकेशन को अपनी ऐक्टिविटी में dispatchKeyEvent को बदलना होगा और CastContext.onDispatchVolumeKeyEventBeforeJellyBean() को कॉल करना होगा:

कोटलिन
class MyActivity : FragmentActivity() {
    override fun dispatchKeyEvent(event: KeyEvent): Boolean {
        return (CastContext.getSharedInstance(this)
            .onDispatchVolumeKeyEventBeforeJellyBean(event)
                || super.dispatchKeyEvent(event))
    }
}
Java
class MyActivity extends FragmentActivity {
    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        return CastContext.getSharedInstance(this)
            .onDispatchVolumeKeyEventBeforeJellyBean(event)
            || super.dispatchKeyEvent(event);
    }
}

सूचना और लॉक स्क्रीन पर मीडिया कंट्रोल जोड़ें

केवल Android पर, Google Cast डिज़ाइन चेकलिस्ट के लिए यह आवश्यक है कि भेजने वाला ऐप्लिकेशन किसी नोटिफ़िकेशन में मीडिया नियंत्रण लागू करे और लॉक स्क्रीन में, जहां भेजने वाला कास्ट कर रहा है, लेकिन भेजने वाले ऐप्लिकेशन पर फ़ोकस नहीं है. फ़्रेमवर्क में, MediaNotificationService और MediaIntentReceiver की मदद से, सूचना भेजने और लॉक स्क्रीन पर मीडिया कंट्रोल बनाने में मदद मिलती है.

जब भेजने वाला व्यक्ति कास्ट कर रहा होता है, तब MediaNotificationService ट्रिगर होता है. इसमें एक सूचना दिखती है, जिसमें इमेज का थंबनेल और कास्ट करने वाले मौजूदा आइटम के बारे में जानकारी, चलाएं/रोकें बटन, और 'रोकें' बटन होता है.

MediaIntentReceiver एक BroadcastReceiver है, जो सूचनाओं से उपयोगकर्ता की कार्रवाइयों को मैनेज करता है.

आपका ऐप्लिकेशन NotificationOptions की मदद से, लॉक स्क्रीन पर सूचना और मीडिया कंट्रोल को कॉन्फ़िगर कर सकता है. आपका ऐप्लिकेशन यह कॉन्फ़िगर कर सकता है कि सूचना में कौनसे कंट्रोल बटन दिखाए जाएं और जब उपयोगकर्ता उस सूचना पर टैप करे, तो किस Activity को खुले. अगर कार्रवाइयां साफ़ तौर पर नहीं दी गई हैं, तो डिफ़ॉल्ट वैल्यू, MediaIntentReceiver.ACTION_TOGGLE_PLAYBACK, और MediaIntentReceiver.ACTION_STOP_CASTING का इस्तेमाल किया जाएगा.

कोटलिन
// Example showing 4 buttons: "rewind", "play/pause", "forward" and "stop casting".
val buttonActions: MutableList<String> = ArrayList()
buttonActions.add(MediaIntentReceiver.ACTION_REWIND)
buttonActions.add(MediaIntentReceiver.ACTION_TOGGLE_PLAYBACK)
buttonActions.add(MediaIntentReceiver.ACTION_FORWARD)
buttonActions.add(MediaIntentReceiver.ACTION_STOP_CASTING)

// Showing "play/pause" and "stop casting" in the compat view of the notification.
val compatButtonActionsIndices = intArrayOf(1, 3)

// Builds a notification with the above actions. Each tap on the "rewind" and "forward" buttons skips 30 seconds.
// Tapping on the notification opens an Activity with class VideoBrowserActivity.
val notificationOptions = NotificationOptions.Builder()
    .setActions(buttonActions, compatButtonActionsIndices)
    .setSkipStepMs(30 * DateUtils.SECOND_IN_MILLIS)
    .setTargetActivityClassName(VideoBrowserActivity::class.java.name)
    .build()
Java
// Example showing 4 buttons: "rewind", "play/pause", "forward" and "stop casting".
List<String> buttonActions = new ArrayList<>();
buttonActions.add(MediaIntentReceiver.ACTION_REWIND);
buttonActions.add(MediaIntentReceiver.ACTION_TOGGLE_PLAYBACK);
buttonActions.add(MediaIntentReceiver.ACTION_FORWARD);
buttonActions.add(MediaIntentReceiver.ACTION_STOP_CASTING);

// Showing "play/pause" and "stop casting" in the compat view of the notification.
int[] compatButtonActionsIndices = new int[]{1, 3};

// Builds a notification with the above actions. Each tap on the "rewind" and "forward" buttons skips 30 seconds.
// Tapping on the notification opens an Activity with class VideoBrowserActivity.
NotificationOptions notificationOptions = new NotificationOptions.Builder()
    .setActions(buttonActions, compatButtonActionsIndices)
    .setSkipStepMs(30 * DateUtils.SECOND_IN_MILLIS)
    .setTargetActivityClassName(VideoBrowserActivity.class.getName())
    .build();

सूचना और लॉक स्क्रीन से मीडिया कंट्रोल दिखाने की सुविधा डिफ़ॉल्ट रूप से चालू होती है. इसे setNotificationOptions को शून्य CastMediaOptions.Builder के साथ कॉल करके बंद किया जा सकता है. फ़िलहाल, लॉक स्क्रीन की सुविधा तब तक चालू रहती है, जब तक सूचना पाने की सुविधा चालू रहती है.

कोटलिन
// ... continue with the NotificationOptions built above
val mediaOptions = CastMediaOptions.Builder()
    .setNotificationOptions(notificationOptions)
    .build()
val castOptions: CastOptions = Builder()
    .setReceiverApplicationId(context.getString(R.string.app_id))
    .setCastMediaOptions(mediaOptions)
    .build()
Java
// ... continue with the NotificationOptions built above
CastMediaOptions mediaOptions = new CastMediaOptions.Builder()
        .setNotificationOptions(notificationOptions)
        .build();
CastOptions castOptions = new CastOptions.Builder()
        .setReceiverApplicationId(context.getString(R.string.app_id))
        .setCastMediaOptions(mediaOptions)
        .build();

जब भेजने वाला ऐप्लिकेशन, कोई वीडियो या ऑडियो लाइव स्ट्रीम चला रहा होता है, तब SDK टूल, सूचना कंट्रोल पर 'चलाएं/रोकें' बटन की जगह, अपने-आप 'चलाएं/बंद करें' बटन दिखाता है, लेकिन लॉक स्क्रीन कंट्रोल पर नहीं.

ध्यान दें: प्री-Lollipop डिवाइसों पर लॉक स्क्रीन कंट्रोल दिखाने के लिए, RemoteMediaClient आपकी ओर से ऑडियो फ़ोकस का अपने-आप अनुरोध करेगा.

गड़बड़ियां ठीक करना

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