इस डेवलपर गाइड में Android Sender SDK टूल का इस्तेमाल करके अपने Android भेजने वाले ऐप्लिकेशन में Google Cast सहायता जोड़ने का तरीका बताया गया है.
मोबाइल डिवाइस या लैपटॉप भेजने वाला है जो प्लेबैक को कंट्रोल करता है और Google Cast डिवाइस पाने वाला होता है जो टीवी पर कॉन्टेंट दिखाता है.
भेजने वाले का फ़्रेमवर्क, कास्ट क्लास लाइब्रेरी की बाइनरी और उससे जुड़े रिसॉर्स के बारे में बताता है, जो भेजने वाले के रनटाइम के दौरान मौजूद होते हैं. भेजने वाले का ऐप्लिकेशन या कास्ट ऐप्लिकेशन का मतलब है कि भेजने वाले के पास मौजूद ऐप्लिकेशन भी चल रहा है. वेब रिसीवर ऐप्लिकेशन, उस एचटीएमएल ऐप्लिकेशन का मतलब है जो कास्ट की सुविधा वाले डिवाइस पर चल रहा है.
सेंडर फ़्रेमवर्क, भेजने वाले ऐप्लिकेशन को इवेंट की जानकारी देने और Cast ऐप्लिकेशन की लाइफ़साइकल की अलग-अलग स्थितियों के बीच ट्रांज़िशन के लिए, एसिंक्रोनस कॉलबैक डिज़ाइन का इस्तेमाल करता है.
ऐप्लिकेशन फ़्लो
यहां बताया गया है कि भेजने वाले के Android ऐप्लिकेशन को चलाने के सामान्य हाई-लेवल फ़्लो के बारे में यहां बताया गया है:
- कास्ट फ़्रेमवर्क,
Activity
की लाइफ़साइकल के आधार पर डिवाइस को खोजने की सुविधाMediaRouter
अपने-आप शुरू कर देता है. - जब लोग 'कास्ट करें' बटन पर क्लिक करते हैं, तो फ़्रेमवर्क, खोजे गए कास्ट डिवाइसों की सूची के साथ कास्ट डायलॉग दिखाता है.
- जब उपयोगकर्ता कोई कास्ट डिवाइस चुनता है, तो फ़्रेमवर्क कास्ट डिवाइस पर वेब रिसीवर ऐप्लिकेशन को लॉन्च करने की कोशिश करता है.
- यह फ़्रेमवर्क, भेजने वाले ऐप्लिकेशन में कॉलबैक को शुरू करता है, ताकि यह पुष्टि की जा सके कि WebRecipientr ऐप्लिकेशन लॉन्च हो गया है.
- यह फ़्रेमवर्क, भेजने वाले और वेब पाने वाले ऐप्लिकेशन के बीच एक कम्यूनिकेशन चैनल बनाता है.
- यह फ़्रेमवर्क वेब रिसीवर पर मीडिया प्लेबैक को लोड और कंट्रोल करने के लिए कम्यूनिकेशन चैनल का इस्तेमाल करता है.
- फ़्रेमवर्क, मीडिया प्लेबैक स्थिति को भेजने वाले और वेब पाने वाले के बीच सिंक करता है: जब उपयोगकर्ता भेजने वाले के यूज़र इंटरफ़ेस (यूआई) से जुड़ी कार्रवाइयां करता है, तब फ़्रेमवर्क उन मीडिया कंट्रोल के अनुरोधों को वेब रिसीवर को पास करता है. जब वेब रिसीवर मीडिया की स्थिति के अपडेट भेजता है, तब फ़्रेमवर्क भेजने वाले के यूज़र इंटरफ़ेस (यूआई) की स्थिति को अपडेट करता है.
- जब कास्ट डिवाइस से डिसकनेक्ट करने के लिए उपयोगकर्ता, 'कास्ट करें' बटन पर क्लिक करता है, तो फ़्रेमवर्क भेजने वाले ऐप्लिकेशन को वेब रिसीवर से डिसकनेक्ट कर देगा.
Google Cast Android SDK में सभी क्लास, तरीकों, और इवेंट की पूरी सूची देखने के लिए, Android के लिए Google Cast भेजने वाला एपीआई रेफ़रंस देखें. नीचे दिए सेक्शन में, Android ऐप्लिकेशन पर कास्ट करने का तरीका बताया गया है.
Android मेनिफ़ेस्ट को कॉन्फ़िगर करें
आपके ऐप्लिकेशन की AndroidManifest.xml फ़ाइल के लिए, आपको Cast SDK टूल के लिए ये एलिमेंट कॉन्फ़िगर करने होंगे:
uses-sdk
Android के ऐसे कम से कम और टारगेट किए गए एपीआई लेवल सेट करें जो Cast SDK पर काम करते हैं. फ़िलहाल, एपीआई लेवल 21 और टारगेट एपीआई लेवल 28 से कम है.
<uses-sdk
android:minSdkVersion="21"
android:targetSdkVersion="28" />
android:theme
Android SDK के कम से कम वर्शन के आधार पर अपने ऐप्लिकेशन की थीम सेट करें. उदाहरण के लिए, अगर
आपकी कोई थीम लागू नहीं है, तो आपको Android SDK के कम से कम वर्शन को टारगेट करते समय,
Theme.AppCompat
के वैरिएंट का इस्तेमाल करना चाहिए. यह वर्शन,
Lollipop से पहले के वर्शन को टारगेट करता है.
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.AppCompat" >
...
</application>
कास्ट कॉन्टेक्स्ट शुरू करें
इस फ़्रेमवर्क में एक ग्लोबल सिंगलटन ऑब्जेक्ट, CastContext
होता है, जो सभी फ़्रेमवर्क के इंटरैक्शन को सिंक करता है.
आपके ऐप्लिकेशन को
OptionsProvider
इंटरफ़ेस लागू करना होगा, ताकि CastContext
सिंगलटन शुरू करने के लिए ज़रूरी विकल्प उपलब्ध हो सकें. 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 } }
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) } }
public class MyActivity extends FragmentActivity { @Override public void onCreate(Bundle savedInstanceState) { CastContext castContext = CastContext.getSharedInstance(this); } }
Cast UX विजेट
कास्ट फ़्रेमवर्क ऐसे विजेट उपलब्ध कराता है जो कास्ट डिज़ाइन चेकलिस्ट का पालन करते हैं:
शुरुआती ओवरले: यह फ़्रेमवर्क एक कस्टम व्यू,
IntroductoryOverlay
, उपलब्ध कराता है. इससे, उपयोगकर्ता को पहली बार रिसीवर के उपलब्ध होने पर कास्ट बटन पर ध्यान देने के लिए, उसे दिखाया जा सकता है. Sender ऐप्लिकेशन, टेक्स्ट और टाइटल के टेक्स्ट की जगह को पसंद के मुताबिक बना सकता है.कास्ट करें बटन: 'कास्ट करें' बटन दिखता है, फिर चाहे कास्ट डिवाइस उपलब्ध हों या नहीं. जब लोग पहली बार 'कास्ट करें' बटन पर क्लिक करते हैं, तो कास्ट करें डायलॉग दिखता है. इस डायलॉग में, खोजे गए डिवाइसों की सूची होती है. डिवाइस के कनेक्ट होने के दौरान, जब उपयोगकर्ता कास्ट बटन पर क्लिक करता है, तो उस पर मौजूदा मीडिया मेटाडेटा (जैसे, टाइटल, रिकॉर्डिंग स्टूडियो का नाम, और थंबनेल इमेज) दिखता है या उपयोगकर्ता को कास्ट डिवाइस से डिसकनेक्ट करने की अनुमति मिलती है. "कास्ट करें बटन" को कभी-कभी "कास्ट करें आइकॉन" भी कहा जाता है.
मिनी कंट्रोलर: जब उपयोगकर्ता, कॉन्टेंट को कास्ट कर रहा होता है और कॉन्टेंट भेजने वाले ऐप्लिकेशन में किसी दूसरी स्क्रीन पर जाता है, तो स्क्रीन पर सबसे नीचे मिनी कंट्रोलर दिखता है. इससे उपयोगकर्ता, कास्ट किए जा रहे मौजूदा मीडिया मेटाडेटा को देख सकता है और वीडियो को कंट्रोल कर सकता है.
बड़ा किया गया कंट्रोलर: कॉन्टेंट कास्ट करते समय, अगर उपयोगकर्ता मीडिया नोटिफ़िकेशन या मिनी कंट्रोलर पर क्लिक करता है, तो बड़ा किया गया कंट्रोलर लॉन्च हो जाता है. इससे मीडिया का मौजूदा मेटाडेटा दिखता है और मीडिया प्लेबैक को कंट्रोल करने के लिए कई बटन मिलते हैं.
सूचना: सिर्फ़ Android के लिए. जब उपयोगकर्ता कॉन्टेंट को कास्ट कर रहा होता है और भेजने वाले ऐप्लिकेशन से बाहर जाता है, तो एक मीडिया सूचना दिखती है. इस सूचना में, कास्ट किया जा रहा मौजूदा मीडिया मेटाडेटा और प्लेबैक कंट्रोल दिखते हैं.
लॉक स्क्रीन: सिर्फ़ Android पर. जब उपयोगकर्ता कॉन्टेंट को कास्ट करता है और लॉक स्क्रीन पर नेविगेट (या डिवाइस का समय खत्म हो जाता है) करता है, तो एक मीडिया लॉक स्क्रीन कंट्रोल दिखता है. इस कंट्रोल में, कास्ट किया जा रहा मौजूदा मीडिया मेटाडेटा और प्लेबैक कंट्रोल दिखते हैं.
नीचे दी गई गाइड में, इन विजेट को अपने ऐप्लिकेशन में जोड़ने के तरीके के बारे में बताया गया है.
कास्ट बटन जोड़ें
Android MediaRouter
एपीआई को सेकंडरी डिवाइसों पर मीडिया दिखाने और चलाने की सुविधा चालू करने के लिए डिज़ाइन किया गया है.
MediaRouter
एपीआई का इस्तेमाल करने वाले Android ऐप्लिकेशन में यूज़र इंटरफ़ेस के हिस्से के तौर पर
कास्ट बटन शामिल होना चाहिए. इससे उपयोगकर्ता, कास्ट डिवाइस जैसे दूसरे डिवाइस पर मीडिया चलाने के लिए मीडिया रूट
चुन सकते हैं.
इस फ़्रेमवर्क में, MediaRouteButton
को Cast button
के तौर पर जोड़ना बहुत आसान हो जाता है. आपको सबसे पहले एक्सएमएल फ़ाइल में, उस मेन्यू आइटम या 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 }
// 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) }
// 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
का रेफ़रंस होता है और यह इन स्थितियों में, खोज की प्रोसेस शुरू करेगा:
- डिवाइस खोजे जाने में लगने वाले समय और बैटरी खर्च के बीच संतुलन बनाने के लिए बनाए गए एल्गोरिदम के आधार पर, कभी-कभी भेजने वाले ऐप्लिकेशन के फ़ोरग्राउंड में आने पर, खोज कभी-कभी अपने-आप शुरू हो जाएगी.
- कास्ट करने के लिए, डायलॉग बॉक्स खुला है.
- कास्ट 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 } }
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 } }
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 फ़ाइल में अपने-आप मर्ज होने की सुविधा चालू है, तो यह सेवा आपके ऐप्लिकेशन के मेनिफ़ेस्ट में अपने-आप मर्ज हो सकती है.
मीडिया सेशन शुरू होने पर फ़्रेमवर्क, सेवा को शुरू करेगा और मीडिया सेशन खत्म होने पर इसे बंद कर देगा.
मीडिया कंट्रोल के काम करने का तरीका
कास्ट फ़्रेमवर्क,
RemoteMediaPlayer
Cast 2.x से क्लास को नए क्लास के लिए इस्तेमाल से हटा देता है
RemoteMediaClient
जो ज़्यादा सुविधाजनक API के सेट और पास में Google API
के लिए सुविधाजनक फ़ंक्शन देता है.
जब आपका ऐप्लिकेशन, ऐसे वेब रिसीवर ऐप्लिकेशन के साथ 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))))
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.Builder
को मीडिया के मेटाडेटा के साथ पहली बार इस्तेमाल करके, MediaInfo
इंस्टेंस बनाएं. मौजूदा 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())
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 > रिमोट कंट्रोल से जुड़ी सूचनाएं दिखाएं पर जाएं. इसके बाद, सेटिंग ऐप्लिकेशन में जाएं. (सूचनाओं में, सेटिंग ऐप्लिकेशन का शॉर्टकट शामिल होता है.) ज़्यादा जानकारी के लिए, रिमोट कंट्रोल से जुड़ी सूचनाएँ कास्ट करना देखें.
मिनी कंट्रोलर जोड़ें
कास्ट डिज़ाइन चेकलिस्ट के मुताबिक, भेजने वाले ऐप्लिकेशन को एक परसिस्टेंट कंट्रोल उपलब्ध कराना चाहिए, जिसे मिनी कंट्रोलर कहा जाता है. यह कंट्रोल तब दिखना चाहिए, जब उपयोगकर्ता मौजूदा कॉन्टेंट पेज से दूर, कॉन्टेंट भेजने वाले ऐप्लिकेशन के किसी दूसरे हिस्से पर जाता है. मिनी कंट्रोलर, मौजूदा कास्ट सेशन के उपयोगकर्ता को रिमाइंडर दिखाता है. मिनी कंट्रोलर पर टैप करके, उपयोगकर्ता कास्ट करें फ़ुल-स्क्रीन पर बड़े किए गए कंट्रोलर व्यू पर वापस जा सकता है.
यह फ़्रेमवर्क एक कस्टम व्यू, MiniControllerफ़्रैगमेंट उपलब्ध कराता है. इसे हर उस गतिविधि की लेआउट फ़ाइल के नीचे जोड़ा जा सकता है जिसमें आपको मिनी कंट्रोलर दिखाना है.
<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 की डिज़ाइन चेकलिस्ट के लिए ज़रूरी है कि भेजने वाले ऐप्लिकेशन से, कास्ट किए जा रहे मीडिया के लिए बड़ा किया गया कंट्रोलर उपलब्ध हो. बड़ा किया गया कंट्रोलर, मिनी कंट्रोलर का फ़ुल स्क्रीन वर्शन है.
कास्ट 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 } }
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() }
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() ) }
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)) } }
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()
// 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()
// ... 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
आपकी ओर से ऑडियो फ़ोकस का अपने-आप अनुरोध करेगा.
गड़बड़ियां ठीक करना
भेजने वाले ऐप्लिकेशन के लिए यह बहुत ज़रूरी है कि वे सभी गड़बड़ी कॉलबैक को हैंडल करें और कास्ट की लाइफ़ साइकल के हर चरण के लिए सबसे सही रिस्पॉन्स तय करें. यह ऐप्लिकेशन, उपयोगकर्ता को गड़बड़ी वाले डायलॉग दिखा सकता है या यह तय कर सकता है कि वेब रिसीवर का कनेक्शन टूट सकता है.