আপনার Android অ্যাপে Cast ইন্টিগ্রেট করুন

Android Sender SDK ব্যবহার করে আপনার Android প্রেরক অ্যাপে কীভাবে Google Cast সহায়তা যোগ করবেন তা এই ডেভেলপার গাইডে বর্ণনা করা হয়েছে।

মোবাইল ডিভাইস বা ল্যাপটপ হল প্রেরক যা প্লেব্যাক কন্ট্রোল করে এবং Google Cast ডিভাইস হল প্রাপক যা টিভিতে কন্টেন্ট দেখায়।

প্রেরক ফ্রেমওয়ার্ক বলতে Cast ক্লাস লাইব্রেরি বাইনারি এবং রানটাইমে প্রেরকের কাছে উপলভ্য সংশ্লিষ্ট রিসোর্সকে বোঝায়। প্রেরক অ্যাপ বা Cast অ্যাপ বলতে এমন অ্যাপকে বোঝায় যা প্রেরকের ডিভাইসেও চলছে। ওয়েব রিসিভার অ্যাপ বলতে Cast-চালু ডিভাইসে চলা HTML অ্যাপ্লিকেশনকে বোঝায়।

প্রেরক ফ্রেমওয়ার্ক, ইভেন্ট সম্পর্কে প্রেরক অ্যাপকে জানাতে এবং Cast অ্যাপ লাইফ সাইকেলের বিভিন্ন স্টেটের মধ্যে ট্রানজিশন করতে অ্যাসিঙ্ক্রোনাস কলব্যাক ডিজাইন ব্যবহার করে।

অ্যাপ ফ্লো

নিম্নলিখিত ধাপগুলি প্রেরক Android অ্যাপের জন্য সাধারণ হাই-লেভেল এক্সিকিউশন ফ্লো বর্ণনা করে:

  • Cast ফ্রেমওয়ার্ক Activity লাইফসাইকেলের উপর ভিত্তি করে অটোমেটিক MediaRouter ডিভাইস ডিসকভারি শুরু করে।
  • ব্যবহারকারী 'কাস্ট করুন' বোতামে ক্লিক করলে, ফ্রেমওয়ার্ক, খুঁজে পাওয়া কাস্ট ডিভাইসের তালিকা সহ কাস্ট ডায়ালগ দেখায়।
  • ব্যবহারকারী কোনও কাস্ট ডিভাইস বেছে নিলে, ফ্রেমওয়ার্ক কাস্ট ডিভাইসে ওয়েব রিসিভার অ্যাপ লঞ্চ করার চেষ্টা করে।
  • ফ্রেমওয়ার্ক, প্রেরক অ্যাপে কলব্যাক ইনভোক করে এটি কনফার্ম করে যে Web Receiver অ্যাপ লঞ্চ করা হয়েছে।
  • ফ্রেমওয়ার্ক প্রেরক ও Web রিসিভার অ্যাপের মধ্যে একটি কমিউনিকেশন চ্যানেল তৈরি করে।
  • ওয়েব রিসিভারে মিডিয়া প্লেব্যাক লোড ও কন্ট্রোল করতে ফ্রেমওয়ার্ক কমিউনিকেশন চ্যানেল ব্যবহার করে।
  • ফ্রেমওয়ার্ক প্রেরক ও ওয়েব রিসিভারের মধ্যে মিডিয়া প্লেব্যাক স্টেট সিঙ্ক্রোনাইজ করে: ব্যবহারকারী প্রেরক UI অ্যাকশন নিলে, ফ্রেমওয়ার্ক সেইসব মিডিয়া কন্ট্রোল অনুরোধ ওয়েব রিসিভারকে পাঠায় এবং ওয়েব রিসিভার মিডিয়া স্ট্যাটাস আপডেট পাঠালে, ফ্রেমওয়ার্ক প্রেরক UI-এর স্টেট আপডেট করে।
  • ব্যবহারকারী কাস্ট ডিভাইস থেকে ডিসকানেক্ট করার জন্য কাস্ট বোতামে ক্লিক করলে, ফ্রেমওয়ার্ক প্রেরক অ্যাপকে ওয়েব রিসিভার থেকে ডিসকানেক্ট করে দেবে।

Google Cast Android SDK-তে থাকা সব ক্লাস, পদ্ধতি ও ইভেন্টের বিস্তারিত তালিকা পেতে, Android-এর জন্য Google Cast Sender API রেফারেন্স দেখুন। আপনার Android অ্যাপে Cast যোগ করার ধাপগুলি নিম্নলিখিত বিভাগে উল্লেখ করা হয়েছে।

Android ম্যানিফেস্ট কনফিগার করুন

আপনার অ্যাপের AndroidManifest.xml ফাইলে Cast SDK-এর জন্য নিম্নলিখিত এলিমেন্ট কনফিগার করতে হবে:

uses-sdk

Cast SDK কাজ করে এমন ন্যূনতম ও টার্গেট Android API লেভেল সেট করুন। বর্তমানে ন্যূনতম API লেভেল হল ২৪ এবং টার্গেট API লেভেল হল ৩৫।

<uses-sdk
        android:minSdkVersion="24"
        android:targetSdkVersion="35" />

android:theme

ন্যূনতম Android SDK ভার্সনের উপর ভিত্তি করে আপনার অ্যাপের থিম সেট করুন। যেমন, আপনি নিজের থিম প্রয়োগ না করলে, আপনাকে Theme.AppCompat-এর একটি ভ্যারিয়েন্ট ব্যবহার করতে হবে যখন আপনি প্রি-ললিপপ ন্যূনতম Android SDK ভার্সনকে টার্গেট করছেন।

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

Cast Context ইনিশিয়ালাইজ করা

ফ্রেমওয়ার্কে একটি গ্লোবাল সিঙ্গেলটন অবজেক্ট, CastContext, আছে যা ফ্রেমওয়ার্কের সব ইন্টার‍্যাকশন সমন্বয় করে।

আপনার অ্যাপকে OptionsProvider ইন্টারফেস প্রয়োগ করতে হবে যাতে CastContext সিঙ্গেলটনকে ইনিশিয়ালাইজ করার জন্য প্রয়োজনীয় বিকল্প প্রদান করা যায়। OptionsProvider-এ CastOptions-এর একটি ইনস্ট্যান্স রয়েছে যাতে ফ্রেমওয়ার্কের আচরণকে প্রভাবিত করে এমন বিকল্প রয়েছে। এর মধ্যে সবচেয়ে গুরুত্বপূর্ণ হল Web Receiver অ্যাপ্লিকেশন আইডি, যা ডিসকভারি ফলাফল ফিল্টার করতে এবং কোনও Cast সেশন শুরু হলে Web Receiver অ্যাপ লঞ্চ করতে ব্যবহৃত হয়।

Kotlin
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 অলসভাবে ইনিশিয়ালাইজ করা হয়।

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

কাস্ট UX উইজেট

Cast ফ্রেমওয়ার্ক এমন উইজেট প্রদান করে যা Cast ডিজাইন চেকলিস্টের সাথে সামঞ্জস্যপূর্ণ:

  • ইন্ট্রোডাক্টরি ওভারলে: ফ্রেমওয়ার্ক একটি কাস্টম ভিউ প্রদান করে, IntroductoryOverlay, যা ব্যবহারকারীকে দেখানো হয় যাতে প্রথমবার রিসিভার উপলভ্য হলে তিনি কাস্ট বোতামের দিকে মনোযোগ দেন। Sender অ্যাপ শীর্ষকের টেক্সট ও পজিশন কাস্টমাইজ করতে পারে।

  • কাস্ট বোতাম: কাস্ট ডিভাইস উপলভ্য থাকুক বা না থাকুক, কাস্ট বোতাম দেখা যাবে। ব্যবহারকারী প্রথমবার 'কাস্ট' বোতামে ক্লিক করলে, একটি কাস্ট ডায়ালগ দেখানো হয় যেখানে খুঁজে পাওয়া ডিভাইসগুলির তালিকা থাকে। ডিভাইস কানেক্ট করা থাকাকালীন ব্যবহারকারী কাস্ট বোতামে ক্লিক করলে, এটি বর্তমান মিডিয়া মেটাডেটা (যেমন, শিরোনাম, রেকর্ডিং স্টুডিওর নাম এবং থাম্বনেল ছবি) দেখায় অথবা ব্যবহারকারীকে কাস্ট ডিভাইস থেকে ডিসকানেক্ট করার অনুমতি দেয়। "কাস্ট বোতাম" কখনও কখনও "কাস্ট আইকন" হিসেবে উল্লেখ করা হয়।

  • মিনি কন্ট্রোলার: ব্যবহারকারী কন্টেন্ট কাস্ট করার সময় বর্তমান কন্টেন্ট পৃষ্ঠা থেকে নেভিগেট করে সेंडर অ্যাপের অন্য স্ক্রিনে চলে গেলে, স্ক্রিনের নিচে মিনি কন্ট্রোলার দেখানো হয়। এর ফলে ব্যবহারকারী বর্তমানে কাস্ট করা মিডিয়ার মেটাডেটা দেখতে এবং প্লেব্যাক নিয়ন্ত্রণ করতে পারেন।

  • এক্সপ্যান্ডেড কন্ট্রোলার: ব্যবহারকারী কন্টেন্ট কাস্ট করার সময়, মিডিয়া বিজ্ঞপ্তি বা মিনি কন্ট্রোলারে ক্লিক করলে, এক্সপ্যান্ডেড কন্ট্রোলার চালু হয়, যা বর্তমানে চলা মিডিয়া মেটাডেটা দেখায় এবং মিডিয়া প্লেব্যাক কন্ট্রোল করার জন্য একাধিক বোতাম প্রদান করে।

  • বিজ্ঞপ্তি: শুধুমাত্র Android-এ উপলভ্য। ব্যবহারকারী কন্টেন্ট কাস্ট করার সময় প্রেরক অ্যাপ থেকে বেরিয়ে গেলে, একটি মিডিয়া বিজ্ঞপ্তি দেখানো হয়। এতে বর্তমানে কাস্ট করা মিডিয়ার মেটাডেটা ও প্লেব্যাক কন্ট্রোল দেখা যায়।

  • লক স্ক্রিন: শুধুমাত্র Android-এ। ব্যবহারকারী কন্টেন্ট কাস্ট করার সময় লক স্ক্রিনে নেভিগেট করলে (অথবা ডিভাইসের সময়সীমা শেষ হয়ে গেলে), মিডিয়া লক স্ক্রিন কন্ট্রোল দেখানো হয় যা বর্তমানে কাস্ট করা মিডিয়া মেটাডেটা এবং প্লেব্যাক কন্ট্রোল দেখায়।

আপনার অ্যাপে কীভাবে এইসব উইজেট যোগ করবেন তার বিবরণ নিম্নলিখিত গাইডে দেওয়া আছে।

কাস্ট করার বোতাম যোগ করুন

সেকেন্ডারি ডিভাইসে মিডিয়া ডিসপ্লে ও প্লেব্যাক চালু করার জন্য Android MediaRouter API ডিজাইন করা হয়েছে। যেসব Android অ্যাপ MediaRouter API ব্যবহার করে, সেগুলির ইউজার ইন্টারফেসে কাস্ট করার বোতাম থাকতে হবে, যাতে ব্যবহারকারীরা কাস্ট ডিভাইসের মতো সেকেন্ডারি ডিভাইসে মিডিয়া চালানোর জন্য মিডিয়া রুট বেছে নিতে পারেন।

ফ্রেমওয়ার্কের মাধ্যমে Cast button হিসেবে MediaRouteButton যোগ করা খুব সহজ হয়ে যায়। প্রথমে আপনাকে মেনু আইটেম বা MediaRouteButton xml ফাইলে যোগ করতে হবে যা আপনার মেনুকে সংজ্ঞায়িত করে এবং ফ্রেমওয়ার্কের সাথে কানেক্ট করতে 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" />
Kotlin
// 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>
Kotlin
// 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 শুরু করার সময়, প্রেরক অ্যাপ Web Receiver অ্যাপ্লিকেশন আইডি নির্দিষ্ট করে এবং ঐচ্ছিকভাবে supportedNamespaces-এ CastOptions সেট করার মাধ্যমে নেমস্পেস ফিল্টারিংয়ের অনুরোধ করতে পারে। CastContext ইন্টার্নালি MediaRouter-এর রেফারেন্স হোল্ড করে এবং নিম্নলিখিত শর্তে ডিসকভারি প্রসেস শুরু করবে:

  • ডিভাইস খোঁজার লেটেন্সি ও ব্যাটারির ব্যবহার ব্যালেন্স করার জন্য ডিজাইন করা অ্যালগরিদমের ভিত্তিতে, প্রেরক অ্যাপ ফোরগ্রাউন্ডে এলে মাঝে মাঝে অটোমেটিক খোঁজা শুরু হবে।
  • কাস্ট ডায়ালগ খোলা আছে।
  • Cast SDK একটি Cast সেশন ফিরিয়ে আনার চেষ্টা করছে।

Cast ডায়ালগ বন্ধ করা হলে বা প্রেরক অ্যাপ ব্যাকগ্রাউন্ডে চলে গেলে, ডিসকভারি প্রসেস বন্ধ হয়ে যাবে।

Kotlin
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, Cast সেশনের ধারণা নিয়ে আসে, যার প্রতিষ্ঠা কোনও ডিভাইসে কানেক্ট করা, Web Receiver অ্যাপ লঞ্চ (বা যোগ দেওয়া), সেই অ্যাপে কানেক্ট করা এবং মিডিয়া কন্ট্রোল চ্যানেল শুরু করার ধাপগুলিকে একত্রিত করে। Cast সেশন ও Web Receiver লাইফ সাইকেল সম্পর্কে আরও জানতে, Web Receiver অ্যাপ্লিকেশন লাইফ সাইকেল গাইড দেখুন।

সেশনগুলি SessionManager ক্লাস দ্বারা পরিচালিত হয়, যা আপনার অ্যাপ CastContext.getSessionManager()-এর মাধ্যমে অ্যাক্সেস করতে পারে। Session ক্লাসের সাবক্লাস দিয়ে আলাদা আলাদা সেশন দেখানো হয়। যেমন, CastSession কাস্ট ডিভাইসের সেশনকে বোঝায়। আপনার অ্যাপ SessionManager.getCurrentCastSession()-এর মাধ্যমে বর্তমানে অ্যাক্টিভ Cast সেশন অ্যাক্সেস করতে পারবে।

আপনার অ্যাপ সেশন ইভেন্ট মনিটর করার জন্য SessionManagerListener ক্লাস ব্যবহার করতে পারে, যেমন তৈরি করা, সাসপেন্ড করা, আবার চালু করা এবং বন্ধ করা। সেশন চালু থাকাকালীন অস্বাভাবিক/আকস্মিক বন্ধ হয়ে গেলে ফ্রেমওয়ার্ক অটোমেটিক আবার চালু করার চেষ্টা করে।

MediaRouterডায়ালগ থেকে ব্যবহারকারীর জেসচারের প্রতিক্রিয়া হিসেবে সেশন অটোমেটিক তৈরি ও বন্ধ করা হয়।

কাস্ট শুরু করার সময় হওয়া সমস্যা আরও ভালোভাবে বুঝতে, অ্যাপ CastContext#getCastReasonCodeForCastStatusCode(int) ব্যবহার করে সেশন শুরু করার সময় হওয়া সমস্যাকে CastReasonCodes-এ কনভার্ট করতে পারে। মনে রাখবেন, কিছু সেশন শুরু হওয়ার সময় হওয়া সমস্যা (যেমন, CastReasonCodes#CAST_CANCELLED) ইচ্ছাকৃত আচরণ এবং এটি সমস্যা হিসেবে লগ করা উচিত নয়।

সেশনের স্টেট পরিবর্তন সম্পর্কে আপনাকে সচেতন থাকতে হলে, আপনি SessionManagerListener প্রয়োগ করতে পারেন। এই উদাহরণে Activity-এ a CastSession-এর উপলভ্যতা শোনা হয়।

Kotlin
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)
    }
}
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 ডিভাইস, স্ট্রিম ট্রান্সফারে সোর্স বা ডেস্টিনেশন হিসেবে কাজ করতে পারে।

স্ট্রিম ট্রান্সফার বা এক্সপ্যানশনের সময় নতুন ডেস্টিনেশন ডিভাইস পেতে, Cast.Listener রেজিস্টার করুন CastSession#addCastListener ব্যবহার করে। তারপরে onDeviceNameChanged কলব্যাক চলাকালীন CastSession#getCastDevice() কল করুন।

আরও তথ্যের জন্য ওয়েব রিসিভারে স্ট্রিম ট্রান্সফার দেখুন।

অটোমেটিক আবার কানেক্ট করা

ফ্রেমওয়ার্ক এমন একটি ReconnectionService প্রদান করে যা প্রেরক অ্যাপ চালু করতে পারে। এর ফলে অনেক সূক্ষ্ম কঠিন পরিস্থিতিতে রিকানেকশন ম্যানেজ করা যায়, যেমন:

  • ওয়াই-ফাই সাময়িকভাবে বন্ধ হয়ে গেলে তা থেকে রিকভার করা
  • ডিভাইস স্লিপ মোড থেকে রিকভার করা
  • অ্যাপ ব্যাকগ্রাউন্ডে চলে যাওয়ার সমস্যা থেকে বেরিয়ে আসা
  • অ্যাপ ক্র্যাশ করলে ডেটা ফিরিয়ে আনা

এই পরিষেবা সাধারণত চালু করা থাকে এবং CastOptions.Builder থেকে বন্ধ করা যায়।

আপনার gradle ফাইলে অটো-মার্জ চালু করা থাকলে, এই পরিষেবা আপনার অ্যাপের ম্যানিফেস্টে অটোমেটিক মার্জ করা যেতে পারে।

মিডিয়া সেশন থাকলে ফ্রেমওয়ার্ক পরিষেবা শুরু করবে এবং মিডিয়া সেশন শেষ হলে পরিষেবা বন্ধ করে দেবে।

মিডিয়া কন্ট্রোল কীভাবে কাজ করে

Cast 2.x থেকে Cast ফ্রেমওয়ার্ক RemoteMediaPlayer ক্লাসটি সরিয়ে দিয়ে নতুন ক্লাস RemoteMediaClient যোগ করেছে। এটি আরও সুবিধাজনক API-এর সেটে একই ফাংশনালিটি প্রদান করে এবং GoogleApiClient-এ পাস করার প্রয়োজন হয় না।

আপনার অ্যাপ যখন মিডিয়া নেমস্পেস কাজ করে এমন কোনও ওয়েব রিসিভার অ্যাপের সাথে CastSession কানেক্ট করে, তখন ফ্রেমওয়ার্ক অটোমেটিক RemoteMediaClient-এর একটি ইনস্ট্যান্স তৈরি করে; আপনার অ্যাপ CastSession ইনস্ট্যান্সে getRemoteMediaClient() মেথড কল করে এটি অ্যাক্সেস করতে পারে।

Web Receiver-কে অনুরোধ করা RemoteMediaClient-এর সব পদ্ধতি একটি PendingResult অবজেক্ট রিটার্ন করে যা সেই অনুরোধ ট্র্যাক করতে ব্যবহার করা যেতে পারে।

এটি আশা করা হয় যে RemoteMediaClient-এর ইনস্ট্যান্স আপনার অ্যাপের বিভিন্ন অংশ এবং ফ্রেমওয়ার্কের কিছু ইন্টার্নাল কম্পোনেন্ট যেমন, পারসিস্টেন্ট মিনি কন্ট্রোলার ও বিজ্ঞপ্তি পরিষেবা শেয়ার করতে পারে। সেই জন্য, এই ইনস্ট্যান্স RemoteMediaClient.Listener-এর একাধিক ইনস্ট্যান্স রেজিস্ট্রেশন করার সুবিধা দেয়।

মিডিয়া মেটাডেটা সেট করা

আপনি কাস্ট করতে চান এমন কোনও মিডিয়া আইটেম সম্পর্কিত তথ্য MediaMetadata ক্লাস দেখায়। নিম্নলিখিত উদাহরণটি কোনও সিনেমার একটি নতুন MediaMetadata ইনস্ট্যান্স তৈরি করে এবং শিরোনাম, সাবটাইটেল ও দুটি ছবি সেট করে।

Kotlin
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 ব্যবহার করুন।

Kotlin
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 ভিডিও ফর্ম্যাট

আপনার মিডিয়া কোন ভিডিও ফর্ম্যাটে আছে তা চেক করতে, getVideoInfo() MediaStatus-এ গিয়ে VideoInfo-এর বর্তমান ইনস্ট্যান্স দেখুন। এই ইনস্ট্যান্সে HDR TV ফর্ম্যাটের ধরন এবং পিক্সেল হিসেবে ডিসপ্লের উচ্চতা ও প্রস্থ থাকে। 4K ফর্ম্যাটের বিভিন্ন ভার্সন ধ্রুবক HDR_TYPE_* দ্বারা চিহ্নিত করা হয়।

একাধিক ডিভাইসে রিমোট কন্ট্রোল বিজ্ঞপ্তি

কোনও ব্যবহারকারী কাস্ট করার সময়, একই নেটওয়ার্কে থাকা অন্যান্য Android ডিভাইস একটি বিজ্ঞপ্তি পাবে, যাতে তারা প্লেব্যাক নিয়ন্ত্রণ করতে পারে। যেসব ডিভাইসে এই ধরনের বিজ্ঞপ্তি আসে, সেগুলির ব্যবহারকারী 'সেটিংস' অ্যাপে গিয়ে Google > Google Cast > রিমোট কন্ট্রোল বিজ্ঞপ্তি দেখুন বিকল্প থেকে বিজ্ঞপ্তি বন্ধ করতে পারবেন। (বিজ্ঞপ্তিতে সেটিংস অ্যাপের শর্টকাট থাকে।) আরও বিবরণের জন্য, কাস্ট রিমোট কন্ট্রোল বিজ্ঞপ্তি দেখুন।

মিনি কন্ট্রোলার যোগ করা

কাস্ট ডিজাইন চেকলিস্ট অনুসারে, প্রেরক অ্যাপকে মিনি কন্ট্রোলার নামে একটি পারসিস্ট্যান্ট কন্ট্রোল প্রদান করতে হবে যা ব্যবহারকারী বর্তমান কন্টেন্ট পৃষ্ঠা থেকে প্রেরক অ্যাপের অন্য অংশে নেভিগেট করলে দেখা যাবে। মিনি কন্ট্রোলার ব্যবহারকারীকে বর্তমান কাস্ট সেশনের একটি দৃশ্যমান রিমাইন্ডার প্রদান করে। মিনি কন্ট্রোলারে ট্যাপ করে, ব্যবহারকারী কাস্টের ফুল-স্ক্রিন এক্সপ্যান্ডেড কন্ট্রোলার ভিউতে ফিরে যেতে পারবেন।

ফ্রেমওয়ার্ক একটি কাস্টম View, 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.gms.cast.framework.media.widget.MiniControllerFragment" />

আপনার প্রেরক অ্যাপ কোনও ভিডিও বা অডিও লাইভ স্ট্রিম চালালে, SDK মিনি কন্ট্রোলারে 'চালান/পজ করুন' বোতামের পরিবর্তে অটোমেটিক 'চালান/বন্ধ করুন' বোতাম দেখায়।

এই কাস্টম ভিউয়ের শীর্ষক ও উপশীর্ষকের টেক্সট কেমন দেখাবে তা সেট করতে, এবং বোতাম বেছে নিতে, মিনি কন্ট্রোলার কাস্টমাইজ করুন দেখুন।

বড় করা কন্ট্রোলার যোগ করা

Google Cast ডিজাইন চেকলিস্টে বলা আছে যে কাস্ট করা মিডিয়ার জন্য প্রেরক অ্যাপকে একটি এক্সপ্যান্ডেড কন্ট্রোলার প্রদান করতে হবে। এক্সপ্যান্ড করা কন্ট্রোলার হল মিনি কন্ট্রোলারের ফুল-স্ক্রিন ভার্সন।

Cast SDK, এক্সপ্যান্ড করা কন্ট্রোলারের জন্য একটি উইজেট প্রদান করে, যাকে ExpandedControllerActivity বলা হয়। এটি একটি অ্যাবস্ট্রাক্ট ক্লাস যা আপনাকে Cast বোতাম যোগ করার জন্য সাবক্লাস করতে হবে।

প্রথমে, বড় করা কন্ট্রোলারের জন্য একটি নতুন মেনু রিসোর্স ফাইল তৈরি করুন যাতে Cast বোতাম থাকে:

<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-এর এক্সটেনশন হিসেবে নতুন ক্লাস তৈরি করুন।

Kotlin
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 পরিবর্তন করুন:

Kotlin
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 পদ্ধতি আপডেট করুন:

Kotlin
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 এক্সপ্যান্ড করা কন্ট্রোলারে প্লে/পজ বোতামের জায়গায় অটোমেটিক প্লে/স্টপ বোতাম দেখায়।

থিম ব্যবহার করে চেহারা সেট করতে, কোন বোতামগুলি দেখাতে হবে তা বেছে নিন, এবং কাস্টম বোতাম যোগ করুন, দেখুন এক্সপ্যান্ড করা কন্ট্রোলার কাস্টমাইজ করুন।

ভলিউম কন্ট্রোল

ফ্রেমওয়ার্ক প্রেরক অ্যাপের ভলিউম অটোমেটিক ম্যানেজ করে। ফ্রেমওয়ার্ক প্রেরক ও ওয়েব রিসিভার অ্যাপ অটোমেটিক সিঙ্ক করে যাতে প্রেরক UI সবসময় ওয়েব রিসিভারের নির্দিষ্ট করা ভলিউম রিপোর্ট করে।

ফিজিক্যাল বোতামের মাধ্যমে ভলিউম কন্ট্রোল

Android-এ, Jelly Bean বা তার পরবর্তী যেকোনও ভার্সন ব্যবহার করা ডিভাইসের জন্য ডিফল্ট হিসেবে Web Receiver-এ Cast সেশনের ভলিউম পরিবর্তন করতে প্রেরক ডিভাইসের ফিজিক্যাল বোতাম ব্যবহার করা যেতে পারে।

Jelly Bean-এর আগের ভার্সনে ফিজিক্যাল বোতামের মাধ্যমে ভলিউম কন্ট্রোল

Jelly Bean-এর থেকে পুরনো Android ডিভাইসে ফিজিক্যাল ভলিউম কী ব্যবহার করে ওয়েব রিসিভার ডিভাইসের ভলিউম কন্ট্রোল করতে, প্রেরক অ্যাপকে তার অ্যাক্টিভিটিতে dispatchKeyEvent ওভাররাইড করতে হবে এবং CastContext.onDispatchVolumeKeyEventBeforeJellyBean() কল করতে হবে:

Kotlin
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 ব্যবহার করা হবে।

Kotlin
// 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-এ নাল ভ্যালু থাকলে এটি বন্ধ করা যায়। বর্তমানে, বিজ্ঞপ্তি চালু থাকলে লক স্ক্রিন ফিচার চালু থাকে।

Kotlin
// ... 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 আপনার হয়ে অটোমেটিক অডিও ফোকাসের অনুরোধ করবে।

সমস্যা ম্যানেজ করা

প্রেরক অ্যাপের জন্য সমস্ত ত্রুটি কলব্যাক ম্যানেজ করা এবং Cast লাইফ সাইকেলের প্রতিটি স্টেজের জন্য সবচেয়ে ভালো উত্তর নির্ধারণ করা খুবই গুরুত্বপূর্ণ। অ্যাপটি ব্যবহারকারীকে ভুল সংক্রান্ত ডায়ালগ দেখাতে পারে অথবা ওয়েব রিসিভারের সাথে কানেকশন বন্ধ করে দিতে পারে।