डेवलपर के लिए बनी इस गाइड में, Android Sender SDK टूल का इस्तेमाल करके, अपने Android सेंडर ऐप्लिकेशन में Google Cast की सुविधा जोड़ने का तरीका बताया गया है.
मोबाइल डिवाइस या लैपटॉप, सेंडर होता है. यह प्लेबैक को कंट्रोल करता है. वहीं, Google Cast डिवाइस, रिसीवर होता है. यह टीवी पर कॉन्टेंट दिखाता है.
सेंडर फ़्रेमवर्क का मतलब, Cast क्लास लाइब्रेरी बाइनरी और सेंडर पर रनटाइम के दौरान मौजूद उससे जुड़े रिसॉर्स से है. सेंडर ऐप्लिकेशन या Cast ऐप्लिकेशन का मतलब, सेंडर पर चल रहे किसी ऐप्लिकेशन से है. वेब रिसीवर ऐप्लिकेशन का मतलब, Cast की सुविधा वाले डिवाइस पर चल रहे एचटीएमएल ऐप्लिकेशन से है.
सेंडर फ़्रेमवर्क, एसिंक्रोनस कॉलबैक डिज़ाइन का इस्तेमाल करके, सेंडर ऐप्लिकेशन को इवेंट की जानकारी देता है. साथ ही, यह Cast ऐप्लिकेशन के लाइफ़साइकल की अलग-अलग स्थितियों के बीच ट्रांज़िशन करता है.
ऐप्लिकेशन का फ़्लो
यहां दिए गए चरणों में, सेंडर Android ऐप्लिकेशन के लिए, सामान्य हाई-लेवल एक्ज़ीक्यूशन फ़्लो के बारे में बताया गया है:
- Cast फ़्रेमवर्क,
Activityलाइफ़साइकल के आधार पर,MediaRouterडिवाइस की खोज की सुविधा अपने-आप शुरू कर देता है. - जब उपयोगकर्ता, कास्ट बटन पर क्लिक करता है, तो फ़्रेमवर्क, खोजे गए कास्ट डिवाइसों की सूची के साथ Cast डायलॉग दिखाता है.
- जब उपयोगकर्ता कोई Cast डिवाइस चुनता है, तो फ़्रेमवर्क, Cast डिवाइस पर वेब रिसीवर ऐप्लिकेशन लॉन्च करने की कोशिश करता है.
- फ़्रेमवर्क, सेंडर ऐप्लिकेशन में कॉलबैक शुरू करता है, ताकि यह पुष्टि की जा सके कि वेब रिसीवर ऐप्लिकेशन लॉन्च हो गया है.
- फ़्रेमवर्क, सेंडर और वेब रिसीवर ऐप्लिकेशन के बीच कम्यूनिकेशन चैनल बनाता है.
- फ़्रेमवर्क, कम्यूनिकेशन चैनल का इस्तेमाल करके, वेब रिसीवर पर मीडिया प्लेबैक को लोड और कंट्रोल करता है.
- फ़्रेमवर्क, सेंडर और वेब रिसीवर के बीच मीडिया प्लेबैक की स्थिति को सिंक करता है: जब उपयोगकर्ता, सेंडर यूज़र इंटरफ़ेस (यूआई) पर कोई कार्रवाई करता है, तो फ़्रेमवर्क, मीडिया कंट्रोल के उन अनुरोधों को वेब रिसीवर को पास करता है. वहीं, जब वेब रिसीवर, मीडिया की स्थिति के अपडेट भेजता है, तो फ़्रेमवर्क, सेंडर यूज़र इंटरफ़ेस (यूआई) की स्थिति को अपडेट करता है.
- जब उपयोगकर्ता, Cast डिवाइस से डिसकनेक्ट करने के लिए, Cast बटन पर क्लिक करता है, तो फ़्रेमवर्क, सेंडर ऐप्लिकेशन को वेब रिसीवर से डिसकनेक्ट कर देगा.
Google Cast Android SDK टूल में मौजूद सभी क्लास, तरीकों, और इवेंट की पूरी सूची देखने के लिए, Android के लिए Google Cast Sender API रेफ़रंस देखें. यहां दिए गए सेक्शन में, अपने Android ऐप्लिकेशन में Cast की सुविधा जोड़ने के चरणों के बारे में बताया गया है.
Android मेनिफ़ेस्ट को कॉन्फ़िगर करना
आपके ऐप्लिकेशन की AndroidManifest.xml फ़ाइल में, Cast SDK टूल के लिए इन एलिमेंट को कॉन्फ़िगर करना ज़रूरी है:
uses-sdk
Cast SDK टूल के लिए, Android के कम से कम और टारगेट एपीआई लेवल सेट करें. फ़िलहाल, कम से कम एपीआई लेवल 24 है और टारगेट एपीआई लेवल 35 है.
<uses-sdk
android:minSdkVersion="24"
android:targetSdkVersion="35" />
android:theme
Android SDK टूल के कम से कम वर्शन के आधार पर, अपने ऐप्लिकेशन की थीम सेट करें. उदाहरण के लिए, अगर आपने अपनी थीम लागू नहीं की है, तो आपको Android SDK टूल के Lollipop से पहले के वर्शन को टारगेट करते समय, Theme.AppCompat के किसी वैरिएंट का इस्तेमाल करना चाहिए.
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme=">;@style/Them<e.AppCompat&>quot;
...
/application
Cast कॉन्टेक्स्ट को शुरू करना
फ़्रेमवर्क में एक ग्लोबल सिंगलेटन ऑब्जेक्ट, CastContext होता है. यह फ़्रेमवर्क के सभी इंटरैक्शन को कोऑर्डिनेट करता है.
आपके ऐप्लिकेशन को
OptionsProvider
इंटरफ़ेस लागू करना होगा, ताकि
CastContext
सिंगलेटन को शुरू करने के लिए ज़रूरी विकल्प दिए जा सकें. OptionsProvider एक इंस्टेंस उपलब्ध कराता है
CastOptions
जिसमें ऐसे विकल्प होते हैं जो फ़्रेमवर्क के व्यवहार पर असर डालते हैं. इनमें सबसे अहम, वेब रिसीवर ऐप्लिकेशन का आईडी है. इसका इस्तेमाल, खोज के नतीजों को फ़िल्टर करने और Cast सेशन शुरू होने पर, वेब रिसीवर ऐप्लिकेशन लॉन्च करने के लिए किया जाता है.
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; } }
आपको लागू किए गए OptionsProvider के पूरी तरह क्वालिफ़ाइड नाम को, सेंडर ऐप्लिकेशन की AndroidManifest.xml फ़ाइल में, मेटाडेटा फ़ील्ड के तौर पर एलान करना होगा:
<application>
...
<meta-data
android:name=
"com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
android:value="com.foo.CastOpt>i<onsProvider&>quot; /
/application
CastContext को कॉल करने पर, CastContext.getSharedInstance()
को लेज़ी तरीके से शुरू किया जाता है.
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 विजेट
Cast फ़्रेमवर्क, Cast डिज़ाइन चेकलिस्ट के मुताबिक विजेट उपलब्ध कराता है:
इंट्रोडक्ट्री ओवरले: फ़्रेमवर्क,
IntroductoryOverlayनाम का एक कस्टम व्यू उपलब्ध कराता है. जब पहली बार कोई रिसीवर उपलब्ध होता है, तो उपयोगकर्ता को यह व्यू दिखाया जाता है, ताकि उसका ध्यान कास्ट बटन की ओर खींचा जा सके. सेंडर ऐप्लिकेशन, टाइटल टेक्स्ट के टेक्स्ट और उसकी जगह को पसंद के मुताबिक बना सकता है.कास्ट बटन: कास्ट डिवाइसों की उपलब्धता के बावजूद, कास्ट बटन दिखता है. जब उपयोगकर्ता पहली बार Cast बटन पर क्लिक करता है, तो Cast डायलॉग दिखता है. इसमें खोजे गए डिवाइसों की सूची दिखती है. जब डिवाइस कनेक्ट होने के दौरान, उपयोगकर्ता Cast बटन पर क्लिक करता है, तो मौजूदा मीडिया का मेटाडेटा (जैसे, टाइटल, रिकॉर्डिंग स्टूडियो का नाम, और थंबनेल इमेज) दिखता है. इसके अलावा, उपयोगकर्ता को Cast डिवाइस से डिसकनेक्ट करने का विकल्प भी मिलता है. "Cast बटन" को कभी-कभी "Cast आइकॉन" भी कहा जाता है.
मिनी कंट्रोलर: जब उपयोगकर्ता कॉन्टेंट कास्ट कर रहा होता है और मौजूदा कॉन्टेंट वाले पेज या बड़े कंट्रोलर से सेंडर ऐप्लिकेशन की किसी दूसरी स्क्रीन पर जाता है, तो स्क्रीन के सबसे नीचे मिनी कंट्रोलर दिखता है. इससे उपयोगकर्ता, मौजूदा समय में कास्ट किए जा रहे मीडिया का मेटाडेटा देख सकता है और प्लेबैक को कंट्रोल कर सकता है.
बड़ा कंट्रोलर: जब उपयोगकर्ता कॉन्टेंट कास्ट कर रहा होता है, तब मीडिया की सूचना या मिनी कंट्रोलर पर क्लिक करने पर, बड़ा कंट्रोलर लॉन्च होता है. इसमें, मौजूदा समय में चल रहे मीडिया का मेटाडेटा दिखता है. साथ ही, मीडिया प्लेबैक को कंट्रोल करने के लिए कई बटन मिलते हैं.
सूचना: सिर्फ़ Android के लिए. जब उपयोगकर्ता कॉन्टेंट कास्ट कर रहा होता है और सेंडर ऐप्लिकेशन से बाहर जाता है, तो मीडिया की सूचना दिखती है. इसमें, मौजूदा समय में कास्ट किए जा रहे मीडिया का मेटाडेटा और प्लेबैक कंट्रोल दिखते हैं.
लॉक स्क्रीन: सिर्फ़ Android के लिए. जब उपयोगकर्ता कॉन्टेंट कास्ट कर रहा होता है और लॉक स्क्रीन पर जाता है (या डिवाइस का टाइम आउट हो जाता है), तो मीडिया लॉक स्क्रीन कंट्रोल दिखता है. इसमें, मौजूदा समय में कास्ट किए जा रहे मीडिया का मेटाडेटा और प्लेबैक कंट्रोल दिखते हैं.
यहां दी गई गाइड में, अपने ऐप्लिकेशन में इन विजेट को जोड़ने के तरीके के बारे में बताया गया है.
Cast बटन जोड़ना
Android के
MediaRouter
एपीआई, सेकंडरी डिवाइसों पर मीडिया दिखाने और चलाने के लिए डिज़ाइन किए गए हैं.
Android के जिन ऐप्लिकेशन में MediaRouter एपीआई का इस्तेमाल किया जाता है उनमें, यूज़र इंटरफ़ेस (यूआई) के हिस्से के तौर पर, Cast बटन शामिल होना चाहिए. इससे उपयोगकर्ता, Cast डिवाइस जैसे सेकंडरी डिवाइस पर मीडिया चलाने के लिए, मीडिया रूट चुन सकते हैं.
फ़्रेमवर्क की मदद से, a
MediaRouteButton
को a
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&qu>ot;
< 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_wei>gh<t="1&quo>t;
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 को शुरू करते समय, सेंडर ऐप्लिकेशन, वेब रिसीवर
ऐप्लिकेशन का आईडी तय करता है. साथ ही, नेमस्पेस फ़िल्टर करने का अनुरोध भी किया जा सकता है. इसके लिए,
supportedNamespaces को
CastOptions में सेट करें.
CastContext , इंटरनल तौर पर MediaRouter का रेफ़रंस रखता है. साथ ही, इन स्थितियों में खोज की प्रोसेस शुरू करेगा:
- डिवाइस की खोज में लगने वाले समय और बैटरी के इस्तेमाल के बीच बैलेंस बनाने के लिए डिज़ाइन किए गए किसी एल्गोरिदम के आधार पर, सेंडर ऐप्लिकेशन के फ़ोरग्राउंड में आने पर, खोज की सुविधा कभी-कभी अपने-आप शुरू हो जाएगी.
- Cast डायलॉग खुला है.
- Cast SDK टूल, Cast सेशन को वापस पाने की कोशिश कर रहा है.
Cast डायलॉग बंद होने या सेंडर ऐप्लिकेशन के बैकग्राउंड में जाने पर, खोज की प्रोसेस बंद हो जाएगी.
class CastOptionsProvider : OptionsProvider { companion object { const val CUSTOM_NAMESPACE = "urn:x-cast:custom_namespace" } override fun getCastOptions(appContext: Context): CastOptions { val supportedNamespaces: M<utable>ListString = ArrayList() supportedNamespaces.add(CUSTOM_NAMESPACE) return CastOptions.Builder() .setReceiverApplicationId(context.getString(R.string.app_id)) .setSupportedNamespaces(supportedNamespaces) .build() } override fun getAdditionalSessionProviders(context: Cont<ext): ListSessi>onProvider? { return null } }
class CastOptionsProvider implements OptionsProvider { public static final String CUSTOM_NAMESPACE = "urn:x-cast:custom_namespace"; @Override public CastOptions getCastOptions(Context appContext) { < >ListString 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 p<ublic ListSessi>onProvider getAdditionalSessionProviders(Context context) { return null; } }
सेशन मैनेजमेंट की सुविधा कैसे काम करती है
Cast SDK टूल, Cast सेशन का कॉन्सेप्ट पेश करता है. इसे सेट अप करने के लिए, डिवाइस से कनेक्ट करना, वेब रिसीवर ऐप्लिकेशन लॉन्च करना (या उसमें शामिल होना), उस ऐप्लिकेशन से कनेक्ट करना, और मीडिया कंट्रोल चैनल को शुरू करना जैसे चरण शामिल हैं. Cast सेशन और वेब रिसीवर के लाइफ़साइकल के बारे में ज़्यादा जानने के लिए, वेब रिसीवर ऐप्लिकेशन का लाइफ़साइकल गाइड देखें.
सेशन को क्लास
SessionManager मैनेज करती है,
जिसे आपका ऐप्लिकेशन
CastContext.getSessionManager() के ज़रिए ऐक्सेस कर सकता है.
अलग-अलग सेशन को, क्लास के सबक्लास से दिखाया जाता है
Session.
उदाहरण के लिए,
CastSession
Cast डिवाइसों के साथ सेशन दिखाता है. आपका ऐप्लिकेशन, मौजूदा समय में चालू
Cast सेशन को
SessionManager.getCurrentCastSession() के ज़रिए ऐक्सेस कर सकता है.
आपका ऐप्लिकेशन, सेशन के इवेंट की निगरानी करने के लिए,
SessionManagerListener
क्लास का इस्तेमाल कर सकता है. जैसे, सेशन बनाना, निलंबित करना, फिर से शुरू करना, और
खत्म करना. जब कोई सेशन चालू होता है और वह अचानक/असामान्य तरीके से खत्म हो जाता है, तो फ़्रेमवर्क उसे अपने-आप फिर से शुरू करने की कोशिश करता है.
MediaRouter डायलॉग से उपयोगकर्ता के जेस्चर के जवाब में, सेशन अपने-आप बनते और खत्म होते हैं.
Cast शुरू होने में होने वाली गड़बड़ियों को बेहतर तरीके से समझने के लिए, ऐप्लिकेशन,
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 mSessionManager.addSessionManagerListener(mSessionManagerListener, CastSession::class.java) } override fun onResume() { super.onResume() mCastSession = mSessionManager.currentCastSession } override fun onDestroy() { super.onDestroy() mSessionManager.removeSessionManagerListener(mSessionManagerListener, CastSession::class.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(); mSessionManager.addSessionManagerListener(mSessionManagerListener, CastSession.class); } @Override protected void onResume() { super.onResume(); mCastSession = mSessionManager.getCurrentCastSession(); } @Override protected void onDestroy() { super.onDestroy(); mSessionManager.removeSessionManagerListener(mSessionManagerListener, CastSession.class); } }
संगीत को दूसरे स्पीकर पर चलाएं
सेशन की स्थिति को बनाए रखना, संगीत को दूसरे स्पीकर पर चलाने की सुविधा का आधार है. इसमें उपयोगकर्ता, आवाज़ के निर्देश, Google Home ऐप्लिकेशन या स्मार्ट डिसप्ले का इस्तेमाल करके, मौजूदा ऑडियो और वीडियो स्ट्रीम को अलग-अलग डिवाइसों पर चला सकते हैं. मीडिया, एक डिवाइस (सोर्स) पर चलना बंद हो जाता है और दूसरे डिवाइस (डेस्टिनेशन) पर चलता रहता है. लेटेस्ट फ़र्मवेयर वाला कोई भी कास्ट डिवाइस, संगीत को दूसरे स्पीकर पर चलाने की सुविधा में सोर्स या डेस्टिनेशन के तौर पर काम कर सकता है.
संगीत को दूसरे स्पीकर पर चलाने या बड़ा करने के दौरान, नए डेस्टिनेशन डिवाइस की जानकारी पाने के लिए,
रजिस्टर करें
Cast.Listener
का इस्तेमाल करके
CastSession#addCastListener.
इसके बाद,
CastSession#getCastDevice()
को onDeviceNameChanged कॉलबैक के दौरान कॉल करें.
ज़्यादा जानकारी के लिए, वेब रिसीवर पर संगीत को दूसरे स्पीकर पर चलाने की सुविधा देखें.
अपने-आप फिर से कनेक्ट होने की सुविधा
फ़्रेमवर्क, a
ReconnectionService
उपलब्ध कराता है. इसे सेंडर ऐप्लिकेशन चालू कर सकता है, ताकि कई मुश्किल
स्थितियों में फिर से कनेक्ट होने की सुविधा को मैनेज किया जा सके. जैसे:
- वाई-फ़ाई कनेक्शन के अस्थायी तौर पर बंद होने पर, फिर से कनेक्ट होना
- डिवाइस के स्लीप मोड में जाने पर, फिर से कनेक्ट होना
- ऐप्लिकेशन के बैकग्राउंड में जाने पर, फिर से कनेक्ट होना
- ऐप्लिकेशन के क्रैश होने पर, फिर से कनेक्ट होना
यह सेवा डिफ़ॉल्ट रूप से चालू होती है. इसे
CastOptions.Builder में बंद किया जा सकता है.
अगर आपकी gradle फ़ाइल में, ऑटो-मर्ज की सुविधा चालू है, तो इस सेवा को आपके ऐप्लिकेशन के मेनिफ़ेस्ट में अपने-आप मर्ज किया जा सकता है.
जब कोई मीडिया सेशन होगा, तो फ़्रेमवर्क इस सेवा को शुरू करेगा. मीडिया सेशन खत्म होने पर, यह सेवा बंद हो जाएगी.
मीडिया कंट्रोल की सुविधा कैसे काम करती है
Cast 2.x में, Cast फ़्रेमवर्क,
RemoteMediaPlayer
क्लास को बंद कर देता है. इसके बजाय,
RemoteMediaClient,
नाम की नई क्लास का इस्तेमाल किया जाता है. यह क्लास, ज़्यादा सुविधाजनक एपीआई के सेट में वही फ़ंक्शन उपलब्ध कराती है. साथ ही, इसमें
को पास करने की ज़रूरत नहीं होती.
जब आपका ऐप्लिकेशन, मीडिया नेमस्पेस के साथ काम करने वाले वेब रिसीवर ऐप्लिकेशन के साथ
CastSession
सेट अप करता है, तो फ़्रेमवर्क,
RemoteMediaClient का एक इंस्टेंस अपने-आप बना लेगा. आपका ऐप्लिकेशन, CastSession
इंस्टेंस पर getRemoteMediaClient() तरीके को कॉल करके इसे
ऐक्सेस कर सकता है.
RemoteMediaClient के सभी तरीके, वेब रिसीवर को अनुरोध भेजेंगे. साथ ही, ये सभी तरीके, PendingResult ऑब्जेक्ट दिखाएंगे. इसका इस्तेमाल, उस अनुरोध को ट्रैक करने के लिए किया जा सकता है.
उम्मीद है कि RemoteMediaClient का इंस्टेंस, आपके ऐप्लिकेशन के कई हिस्सों के साथ-साथ, फ़्रेमवर्क के कुछ इंटरनल कॉम्पोनेंट भी शेयर करेंगे. जैसे, परसिस्टेंट मिनी कंट्रोलर और सूचना सेवा.
इसलिए, यह इंस्टेंस, RemoteMediaClient.Listener के कई इंस्टेंस के रजिस्ट्रेशन के साथ काम करता है.
मीडिया मेटाडेटा सेट करना
The
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 वीडियो फ़ॉर्मैट
यह देखने के लिए कि आपका मीडिया किस वीडियो फ़ॉर्मैट में है, MediaStatus में
getVideoInfo()
का इस्तेमाल करके,
VideoInfoका मौजूदा इंस्टेंस पाएं.
इस इंस्टेंस में, एचडीआर टीवी फ़ॉर्मैट का टाइप और पिक्सल में डिसप्ले की ऊंचाई और चौड़ाई शामिल होती है. 4K फ़ॉर्मैट के वैरिएंट को, कॉन्स्टैंट
HDR_TYPE_* से दिखाया जाता है.
कई डिवाइसों के लिए, रिमोट कंट्रोल की सूचनाएं
जब कोई उपयोगकर्ता कास्ट कर रहा होता है, तो उसी नेटवर्क पर मौजूद अन्य Android डिवाइसों को भी सूचना मिलेगी. इससे वे भी प्लेबैक को कंट्रोल कर पाएंगे. जिसके डिवाइस पर ऐसी सूचनाएं मिलती हैं वह Google > Google Cast > रिमोट कंट्रोल की सूचनाएं दिखाएं में जाकर, सेटिंग ऐप्लिकेशन में उस डिवाइस के लिए सूचनाएं बंद कर सकता है. (सूचनाओं में, सेटिंग ऐप्लिकेशन का शॉर्टकट शामिल होता है.) ज़्यादा जानकारी के लिए, Cast के रिमोट कंट्रोल की सूचनाएं देखें.
मिनी कंट्रोलर जोड़ना
Cast डिज़ाइन चेकलिस्ट के मुताबिक, सेंडर ऐप्लिकेशन को एक परसिस्टेंट कंट्रोल उपलब्ध कराना चाहिए. इसे मिनी कंट्रोलर कहा जाता है. जब उपयोगकर्ता, मौजूदा कॉन्टेंट वाले पेज से सेंडर ऐप्लिकेशन के किसी दूसरे हिस्से पर जाता है, तो यह मिनी कंट्रोलर दिखना चाहिए. मिनी कंट्रोलर, उपयोगकर्ता को मौजूदा Cast सेशन के बारे में याद दिलाता है. मिनी कंट्रोलर पर टैप करके, उपयोगकर्ता Cast के फ़ुल-स्क्रीन बड़े कंट्रोलर व्यू पर वापस जा सकता है.
फ़्रेमवर्क, MiniControllerFragment नाम का एक कस्टम व्यू उपलब्ध कराता है. इसे हर उस गतिविधि की लेआउट फ़ाइल के सबसे नीचे जोड़ा जा सकता है जिसमें आपको मिनी कंट्रोलर दिखाना है.
<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.gm>s.cast.framework.media.widget.MiniControllerFragment" /
जब आपका सेंडर ऐप्लिकेशन, वीडियो या ऑडियो लाइव स्ट्रीम चला रहा होता है, तो एसडीके, मिनी कंट्रोलर में मौजूद 'चलाएं/रोकें' बटन की जगह, 'चलाएं/बंद करें' बटन अपने-आप दिखाता है.
इस कस्टम व्यू के टाइटल और सबटाइटल का टेक्स्ट अपीयरेंस सेट करने, और बटन चुनने के लिए, मिनी कंट्रोलर को पसंद के मुताबिक बनाना देखें.
बड़ा कंट्रोलर जोड़ना
Google Cast डिज़ाइन चेकलिस्ट के मुताबिक, सेंडर ऐप्लिकेशन को कास्ट किए जा रहे मीडिया के लिए, बड़ा कंट्रोलर उपलब्ध कराना चाहिए. बड़ा कंट्रोलर, मिनी कंट्रोलर का फ़ुल स्क्रीन वर्शन होता है.
Cast SDK टूल, बड़े कंट्रोलर के लिए एक विजेट उपलब्ध कराता है. इसे
ExpandedControllerActivity कहा जाता है.
यह एक ऐब्स्ट्रैक्ट क्लास है. Cast बटन जोड़ने के लिए, आपको इसका सबक्लास बनाना होगा.
सबसे पहले, Cast बटन उपलब्ध कराने के लिए, बड़े कंट्रोलर के लिए एक नई मेन्यू रिसॉर्स फ़ाइल बनाएं:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.co>m/apk/<res-auto"
item
android:id="@+id/media_route_menu_item"
android:title="@string/media_route_menu_title"
app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionPro>vi<der&q>uot;
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.ref<player.VideoBrowserActivity"
intent-filt>er
< action a>n<droid:nam>e=&qu<ot;android.i>ntent.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()); }
जब आपका सेंडर ऐप्लिकेशन, वीडियो या ऑडियो लाइव स्ट्रीम चला रहा होता है, तो एसडीके, बड़े कंट्रोलर में मौजूद 'चलाएं/रोकें' बटन की जगह, 'चलाएं/बंद करें' बटन अपने-आप दिखाता है.
थीम का इस्तेमाल करके अपीयरेंस सेट करने, यह चुनने कि कौनसा बटन दिखाना है, और कस्टम बटन जोड़ने के लिए, देखें बड़े कंट्रोलर को पसंद के मुताबिक बनाना.
आवाज़ कंट्रोल करें
फ़्रेमवर्क, सेंडर ऐप्लिकेशन के लिए आवाज़ को अपने-आप मैनेज करता है. फ़्रेमवर्क, सेंडर और वेब रिसीवर ऐप्लिकेशन को अपने-आप सिंक करता है, ताकि सेंडर यूज़र इंटरफ़ेस (यूआई) हमेशा वेब रिसीवर की ओर से तय की गई आवाज़ की जानकारी दे.
फ़िज़िकल बटन से आवाज़ कंट्रोल करना
Android पर, Jelly Bean या उसके बाद के वर्शन का इस्तेमाल करने वाले किसी भी डिवाइस के लिए, सेंडर डिवाइस पर मौजूद फ़िज़िकल बटन का इस्तेमाल करके, वेब रिसीवर पर Cast सेशन की आवाज़ को डिफ़ॉल्ट रूप से बदला जा सकता है.
Jelly Bean से पहले के वर्शन में, फ़िज़िकल बटन से आवाज़ कंट्रोल करना
Jelly Bean से पहले के 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 casti<ng&quo>t;. val buttonActions: MutableListString = 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&<quot; >and "stop casting". <>ListString 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();
सूचना और लॉक स्क्रीन से मीडिया कंट्रोल दिखाने की सुविधा, डिफ़ॉल्ट रूप से चालू होती है. इसे
null के साथ
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();
जब आपका सेंडर ऐप्लिकेशन, वीडियो या ऑडियो लाइव स्ट्रीम चला रहा होता है, तो एसडीके, सूचना कंट्रोल पर मौजूद 'चलाएं/रोकें' बटन की जगह, 'चलाएं/बंद करें' बटन अपने-आप दिखाता है. हालांकि, यह बटन लॉक स्क्रीन कंट्रोल पर नहीं दिखता.
ध्यान दें: Lollipop से पहले के डिवाइसों पर, लॉक स्क्रीन कंट्रोल दिखाने के लिए,
RemoteMediaClient आपकी ओर से ऑडियो फ़ोकस का अनुरोध अपने-आप करेगा.
गड़बड़ियां मैनेज करना
सेंडर ऐप्लिकेशन के लिए, गड़बड़ी से जुड़े सभी कॉलबैक को मैनेज करना और Cast के लाइफ़साइकल के हर चरण के लिए सबसे सही जवाब तय करना बहुत ज़रूरी है. ऐप्लिकेशन, उपयोगकर्ता को गड़बड़ी के डायलॉग दिखा सकता है. इसके अलावा, वह वेब रिसीवर से कनेक्शन खत्म करने का फ़ैसला भी ले सकता है.