এই ডেভেলপার নির্দেশিকাটি বর্ণনা করে যে কীভাবে Android Sender SDK ব্যবহার করে আপনার Android Sender অ্যাপে Google Cast সমর্থন যোগ করবেন।
মোবাইল ডিভাইস বা ল্যাপটপ হল প্রেরক যা প্লেব্যাক নিয়ন্ত্রণ করে, এবং Google Cast ডিভাইস হল রিসিভার যা টিভিতে সামগ্রী প্রদর্শন করে।
প্রেরক কাঠামো বলতে প্রেরকের রানটাইমে উপস্থিত কাস্ট ক্লাস লাইব্রেরি বাইনারি এবং সংশ্লিষ্ট রিসোর্সগুলিকে বোঝায়। প্রেরক অ্যাপ বা কাস্ট অ্যাপ বলতে প্রেরকের উপর চলমান একটি অ্যাপকেও বোঝায়। ওয়েব রিসিভার অ্যাপ বলতে কাস্ট-সক্ষম ডিভাইসে চলমান HTML অ্যাপ্লিকেশনকে বোঝায়।
প্রেরক ফ্রেমওয়ার্কটি প্রেরক অ্যাপকে ইভেন্ট সম্পর্কে অবহিত করতে এবং কাস্ট অ্যাপের জীবনচক্রের বিভিন্ন অবস্থার মধ্যে রূপান্তর করতে একটি অ্যাসিঙ্ক্রোনাস কলব্যাক ডিজাইন ব্যবহার করে।
অ্যাপ প্রবাহ
নিম্নলিখিত ধাপগুলি একটি প্রেরক অ্যান্ড্রয়েড অ্যাপের জন্য সাধারণ উচ্চ-স্তরের কার্যকরকরণ প্রবাহ বর্ণনা করে:
- কাস্ট ফ্রেমওয়ার্কটি
Activityলাইফসাইকেলের উপর ভিত্তি করে স্বয়ংক্রিয়ভাবেMediaRouterডিভাইস আবিষ্কার শুরু করে। - যখন ব্যবহারকারী কাস্ট বোতামে ক্লিক করেন, তখন ফ্রেমওয়ার্কটি আবিষ্কৃত কাস্ট ডিভাইসের তালিকা সহ কাস্ট ডায়ালগ উপস্থাপন করে।
- যখন ব্যবহারকারী একটি কাস্ট ডিভাইস নির্বাচন করেন, তখন ফ্রেমওয়ার্কটি কাস্ট ডিভাইসে ওয়েব রিসিভার অ্যাপ চালু করার চেষ্টা করে।
- ওয়েব রিসিভার অ্যাপটি চালু হয়েছে কিনা তা নিশ্চিত করার জন্য ফ্রেমওয়ার্কটি প্রেরক অ্যাপে কলব্যাক আহ্বান করে।
- এই কাঠামোটি প্রেরক এবং ওয়েব রিসিভার অ্যাপের মধ্যে একটি যোগাযোগ চ্যানেল তৈরি করে।
- ফ্রেমওয়ার্কটি ওয়েব রিসিভারে মিডিয়া প্লেব্যাক লোড এবং নিয়ন্ত্রণ করতে যোগাযোগ চ্যানেল ব্যবহার করে।
- এই ফ্রেমওয়ার্কটি প্রেরক এবং ওয়েব রিসিভারের মধ্যে মিডিয়া প্লেব্যাক অবস্থাকে সিঙ্ক্রোনাইজ করে: যখন ব্যবহারকারী প্রেরক UI অ্যাকশন করে, তখন ফ্রেমওয়ার্কটি সেই মিডিয়া নিয়ন্ত্রণ অনুরোধগুলি ওয়েব রিসিভারের কাছে প্রেরণ করে এবং যখন ওয়েব রিসিভার মিডিয়া স্ট্যাটাস আপডেট পাঠায়, তখন ফ্রেমওয়ার্কটি প্রেরক UI এর অবস্থা আপডেট করে।
- যখন ব্যবহারকারী কাস্ট ডিভাইস থেকে সংযোগ বিচ্ছিন্ন করতে কাস্ট বোতামে ক্লিক করেন, তখন ফ্রেমওয়ার্কটি ওয়েব রিসিভার থেকে প্রেরক অ্যাপটিকে সংযোগ বিচ্ছিন্ন করে দেবে।
Google Cast Android SDK-তে সমস্ত ক্লাস, পদ্ধতি এবং ইভেন্টের একটি বিস্তৃত তালিকার জন্য, Android এর জন্য Google Cast Sender API রেফারেন্স দেখুন। নিম্নলিখিত বিভাগগুলিতে আপনার Android অ্যাপে Cast যোগ করার পদক্ষেপগুলি অন্তর্ভুক্ত রয়েছে।
অ্যান্ড্রয়েড ম্যানিফেস্ট কনফিগার করুন
আপনার অ্যাপের AndroidManifest.xml ফাইলের জন্য আপনাকে Cast SDK-এর জন্য নিম্নলিখিত উপাদানগুলি কনফিগার করতে হবে:
ব্যবহার-এসডিকে
Cast SDK-তে সমর্থিত সর্বনিম্ন এবং লক্ষ্য Android API স্তরগুলি সেট করুন। বর্তমানে সর্বনিম্ন API স্তর 23 এবং লক্ষ্য হল API স্তর 34।
<uses-sdk
android:minSdkVersion="23"
android:targetSdkVersion="34" />
অ্যান্ড্রয়েড: থিম
আপনার অ্যাপের থিমটি ন্যূনতম Android SDK সংস্করণের উপর ভিত্তি করে সেট করুন। উদাহরণস্বরূপ, যদি আপনি নিজের থিমটি বাস্তবায়ন না করেন, তাহলে ললিপপের পূর্বে থাকা ন্যূনতম Android SDK সংস্করণটিকে লক্ষ্য করার সময় আপনার Theme.AppCompat এর একটি রূপ ব্যবহার করা উচিত।
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Theme.AppCompat" >
...
</application>
কাস্ট প্রসঙ্গটি শুরু করুন
ফ্রেমওয়ার্কটিতে একটি গ্লোবাল সিঙ্গেলটন অবজেক্ট রয়েছে, CastContext , যা ফ্রেমওয়ার্কের সমস্ত ইন্টারঅ্যাকশন সমন্বয় করে।
CastContext সিঙ্গেলটন শুরু করার জন্য প্রয়োজনীয় বিকল্পগুলি সরবরাহ করার জন্য আপনার অ্যাপটিকে OptionsProvider ইন্টারফেসটি বাস্তবায়ন করতে হবে। OptionsProvider CastOptions এর একটি উদাহরণ প্রদান করে যার মধ্যে এমন বিকল্প রয়েছে যা ফ্রেমওয়ার্কের আচরণকে প্রভাবিত করে। এর মধ্যে সবচেয়ে গুরুত্বপূর্ণ হল ওয়েব রিসিভার অ্যাপ্লিকেশন আইডি, যা আবিষ্কারের ফলাফল ফিল্টার করতে এবং কাস্ট সেশন শুরু হওয়ার সময় ওয়েব রিসিভার অ্যাপ চালু করতে ব্যবহৃত হয়।
class CastOptionsProvider : OptionsProvider { override fun getCastOptions(context: Context): CastOptions { return Builder() .setReceiverApplicationId(context.getString(R.string.app_id)) .build() } override fun getAdditionalSessionProviders(context: Context): List<SessionProvider>? { return null } }
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); } }
কাস্ট ইউএক্স উইজেটস
কাস্ট ফ্রেমওয়ার্কটি কাস্ট ডিজাইন চেকলিস্ট মেনে চলা উইজেটগুলি সরবরাহ করে:
ইন্ট্রোডাক্টরি ওভারলে : ফ্রেমওয়ার্কটি একটি কাস্টম ভিউ,
IntroductoryOverlayপ্রদান করে, যা ব্যবহারকারীকে দেখানো হয় যাতে প্রথমবার রিসিভার উপলব্ধ হলে কাস্ট বোতামের দিকে মনোযোগ আকর্ষণ করা যায়। প্রেরক অ্যাপটি টেক্সট এবং শিরোনাম টেক্সটের অবস্থান কাস্টমাইজ করতে পারে।কাস্ট বোতাম : কাস্ট ডিভাইসের প্রাপ্যতা নির্বিশেষে কাস্ট বোতামটি দৃশ্যমান। ব্যবহারকারী যখন প্রথম কাস্ট বোতামে ক্লিক করেন, তখন একটি কাস্ট ডায়ালগ প্রদর্শিত হয় যা আবিষ্কৃত ডিভাইসগুলির তালিকা করে। ডিভাইসটি সংযুক্ত থাকাকালীন ব্যবহারকারী যখন কাস্ট বোতামে ক্লিক করেন, তখন এটি বর্তমান মিডিয়া মেটাডেটা (যেমন শিরোনাম, রেকর্ডিং স্টুডিওর নাম এবং একটি থাম্বনেইল চিত্র) প্রদর্শন করে অথবা ব্যবহারকারীকে কাস্ট ডিভাইস থেকে সংযোগ বিচ্ছিন্ন করার অনুমতি দেয়। "কাস্ট বোতাম" কে কখনও কখনও "কাস্ট আইকন" বলা হয়।
মিনি কন্ট্রোলার : যখন ব্যবহারকারী কন্টেন্ট কাস্ট করেন এবং বর্তমান কন্টেন্ট পৃষ্ঠা বা প্রসারিত কন্ট্রোলার থেকে প্রেরক অ্যাপের অন্য স্ক্রিনে নেভিগেট করেন, তখন স্ক্রিনের নীচে মিনি কন্ট্রোলারটি প্রদর্শিত হয় যাতে ব্যবহারকারী বর্তমানে কাস্টিং মিডিয়া মেটাডেটা দেখতে এবং প্লেব্যাক নিয়ন্ত্রণ করতে পারেন।
এক্সপেন্ডেড কন্ট্রোলার : ব্যবহারকারী যখন কন্টেন্ট কাস্ট করেন, তখন যদি তারা মিডিয়া নোটিফিকেশন বা মিনি কন্ট্রোলারে ক্লিক করেন, তাহলে এক্সপেন্ডেড কন্ট্রোলারটি চালু হয়, যা বর্তমানে চলমান মিডিয়া মেটাডেটা প্রদর্শন করে এবং মিডিয়া প্লেব্যাক নিয়ন্ত্রণ করার জন্য বেশ কয়েকটি বোতাম প্রদান করে।
বিজ্ঞপ্তি : শুধুমাত্র অ্যান্ড্রয়েড। যখন ব্যবহারকারী কন্টেন্ট কাস্ট করেন এবং প্রেরক অ্যাপ থেকে দূরে সরে যান, তখন একটি মিডিয়া বিজ্ঞপ্তি প্রদর্শিত হয় যা বর্তমানে কাস্ট করা মিডিয়া মেটাডেটা এবং প্লেব্যাক নিয়ন্ত্রণগুলি দেখায়।
লক স্ক্রিন : শুধুমাত্র অ্যান্ড্রয়েড। যখন ব্যবহারকারী কন্টেন্ট কাস্ট করেন এবং লক স্ক্রিনে নেভিগেট করেন (অথবা ডিভাইসের সময়সীমা শেষ হয়ে যায়), তখন একটি মিডিয়া লক স্ক্রিন নিয়ন্ত্রণ প্রদর্শিত হয় যা বর্তমানে কাস্ট করা মিডিয়া মেটাডেটা এবং প্লেব্যাক নিয়ন্ত্রণগুলি দেখায়।
নিম্নলিখিত নির্দেশিকাটিতে আপনার অ্যাপে এই উইজেটগুলি কীভাবে যুক্ত করবেন তার বর্ণনা রয়েছে।
একটি কাস্ট বোতাম যোগ করুন
অ্যান্ড্রয়েড MediaRouter এপিআইগুলি সেকেন্ডারি ডিভাইসে মিডিয়া প্রদর্শন এবং প্লেব্যাক সক্ষম করার জন্য ডিজাইন করা হয়েছে। MediaRouter এপিআই ব্যবহারকারী অ্যান্ড্রয়েড অ্যাপগুলির ব্যবহারকারী ইন্টারফেসের অংশ হিসাবে একটি কাস্ট বোতাম অন্তর্ভুক্ত করা উচিত, যাতে ব্যবহারকারীরা কাস্ট ডিভাইসের মতো সেকেন্ডারি ডিভাইসে মিডিয়া চালানোর জন্য একটি মিডিয়া রুট নির্বাচন করতে পারেন।
এই ফ্রেমওয়ার্কটি Cast button হিসেবে MediaRouteButton যোগ করা খুব সহজ করে তোলে। প্রথমে আপনাকে xml ফাইলে একটি মেনু আইটেম অথবা 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; } }
সেশন ম্যানেজমেন্ট কিভাবে কাজ করে
কাস্ট এসডিকে একটি কাস্ট সেশনের ধারণাটি উপস্থাপন করে, যার প্রতিষ্ঠায় একটি ডিভাইসের সাথে সংযোগ স্থাপন, একটি ওয়েব রিসিভার অ্যাপ চালু করা (অথবা যোগদান করা), সেই অ্যাপের সাথে সংযোগ স্থাপন এবং একটি মিডিয়া নিয়ন্ত্রণ চ্যানেল শুরু করার ধাপগুলি একত্রিত করা হয়। কাস্ট সেশন এবং ওয়েব রিসিভার লাইফ সাইকেল সম্পর্কে আরও তথ্যের জন্য ওয়েব রিসিভার অ্যাপ্লিকেশন লাইফ সাইকেল গাইড দেখুন।
সেশনগুলি SessionManager ক্লাস দ্বারা পরিচালিত হয়, যা আপনার অ্যাপ CastContext.getSessionManager() এর মাধ্যমে অ্যাক্সেস করতে পারে। পৃথক সেশনগুলি Session ক্লাসের উপশ্রেণী দ্বারা প্রতিনিধিত্ব করা হয়। উদাহরণস্বরূপ, CastSession Cast ডিভাইস সহ সেশনগুলি উপস্থাপন করে। আপনার অ্যাপ SessionManager.getCurrentCastSession() এর মাধ্যমে বর্তমানে সক্রিয় Cast সেশন অ্যাক্সেস করতে পারে।
আপনার অ্যাপটি 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 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); } }
স্ট্রিম ট্রান্সফার
স্ট্রিম ট্রান্সফারের ভিত্তি হল সেশন স্টেট সংরক্ষণ করা, যেখানে ব্যবহারকারীরা ভয়েস কমান্ড, গুগল হোম অ্যাপ বা স্মার্ট ডিসপ্লে ব্যবহার করে বিদ্যমান অডিও এবং ভিডিও স্ট্রিমগুলি বিভিন্ন ডিভাইসে স্থানান্তর করতে পারেন। মিডিয়া একটি ডিভাইসে (উৎস) প্লে করা বন্ধ করে অন্যটিতে (গন্তব্যস্থলে) চলতে থাকে। সর্বশেষ ফার্মওয়্যার সহ যেকোনো কাস্ট ডিভাইস স্ট্রিম ট্রান্সফারে সোর্স বা গন্তব্যস্থল হিসেবে কাজ করতে পারে।
স্ট্রিম ট্রান্সফার বা এক্সপেনশনের সময় নতুন গন্তব্য ডিভাইস পেতে, CastSession#addCastListener ব্যবহার করে একটি Cast.Listener নিবন্ধন করুন। তারপর onDeviceNameChanged কলব্যাকের সময় CastSession#getCastDevice() কল করুন।
আরও তথ্যের জন্য ওয়েব রিসিভারে স্ট্রিম ট্রান্সফার দেখুন।
স্বয়ংক্রিয় পুনঃসংযোগ
এই ফ্রেমওয়ার্কটি একটি ReconnectionService প্রদান করে যা প্রেরক অ্যাপ দ্বারা অনেক সূক্ষ্ম কোণার ক্ষেত্রে পুনঃসংযোগ পরিচালনা করতে সক্ষম করা যেতে পারে, যেমন:
- ওয়াইফাইয়ের অস্থায়ী ক্ষতি থেকে সেরে উঠুন
- ডিভাইস স্লিপ থেকে পুনরুদ্ধার করুন
- অ্যাপের ব্যাকগ্রাউন্ডিং থেকে পুনরুদ্ধার করুন
- অ্যাপ ক্র্যাশ হলে পুনরুদ্ধার করুন
এই পরিষেবাটি ডিফল্টরূপে চালু থাকে এবং CastOptions.Builder এ বন্ধ করা যেতে পারে।
আপনার gradle ফাইলে অটো-মার্জ সক্ষম থাকলে এই পরিষেবাটি স্বয়ংক্রিয়ভাবে আপনার অ্যাপের ম্যানিফেস্টে মার্জ করা যেতে পারে।
মিডিয়া সেশনের সময় ফ্রেমওয়ার্কটি পরিষেবাটি শুরু করবে এবং মিডিয়া সেশন শেষ হলে এটি বন্ধ করে দেবে।
মিডিয়া কন্ট্রোল কীভাবে কাজ করে
কাস্ট ফ্রেমওয়ার্কটি কাস্ট 2.x থেকে RemoteMediaPlayer ক্লাসকে বাদ দিয়ে একটি নতুন ক্লাস RemoteMediaClient পক্ষে, যা আরও সুবিধাজনক API-এর একটি সেটে একই কার্যকারিতা প্রদান করে এবং একটি GoogleApiClient-এ পাস করা এড়ায়।
যখন আপনার অ্যাপটি মিডিয়া নেমস্পেস সমর্থন করে এমন একটি ওয়েব রিসিভার অ্যাপের সাহায্যে একটি CastSession স্থাপন করে, তখন ফ্রেমওয়ার্ক দ্বারা স্বয়ংক্রিয়ভাবে RemoteMediaClient এর একটি ইনস্ট্যান্স তৈরি হবে; আপনার অ্যাপটি CastSession ইনস্ট্যান্সে getRemoteMediaClient() পদ্ধতিতে কল করে এটি অ্যাক্সেস করতে পারে।
RemoteMediaClient এর সকল পদ্ধতি যা ওয়েব রিসিভারে অনুরোধ জারি করে, একটি PendingResult অবজেক্ট ফেরত দেবে যা সেই অনুরোধটি ট্র্যাক করতে ব্যবহার করা যেতে পারে।
আশা করা হচ্ছে যে RemoteMediaClient এর ইনস্ট্যান্সটি আপনার অ্যাপের একাধিক অংশ এবং প্রকৃতপক্ষে ফ্রেমওয়ার্কের কিছু অভ্যন্তরীণ উপাদান, যেমন persistent mini controllers এবং notification service দ্বারা শেয়ার করা হতে পারে। সেই লক্ষ্যে, এই ইনস্ট্যান্সটি RemoteMediaClient.Listener এর একাধিক ইনস্ট্যান্সের নিবন্ধন সমর্থন করে।
মিডিয়া মেটাডেটা সেট করুন
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 পান, তারপর MediaInfo সেই RemoteMediaClient এ লোড করুন। ওয়েব রিসিভারে চলমান একটি মিডিয়া প্লেয়ার অ্যাপ চালানো, বিরতি দেওয়া এবং অন্যথায় নিয়ন্ত্রণ করতে 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 এর বর্তমান ইনস্ট্যান্সটি পান। এই ইনস্ট্যান্সে HDR টিভি ফর্ম্যাটের ধরণ এবং পিক্সেলে ডিসপ্লের উচ্চতা এবং প্রস্থ রয়েছে। 4K ফর্ম্যাটের ভেরিয়েন্টগুলি ধ্রুবক HDR_TYPE_* দ্বারা নির্দেশিত হয়।
একাধিক ডিভাইসে রিমোট কন্ট্রোল বিজ্ঞপ্তি
যখন একজন ব্যবহারকারী কাস্টিং করবেন, তখন একই নেটওয়ার্কের অন্যান্য অ্যান্ড্রয়েড ডিভাইসগুলি প্লেব্যাক নিয়ন্ত্রণ করার জন্য একটি বিজ্ঞপ্তি পাবে। যাদের ডিভাইসে এই ধরনের বিজ্ঞপ্তি পাওয়া যাবে তারা Google > Google Cast > Show remote control notifications -এ সেটিংস অ্যাপে গিয়ে সেই ডিভাইসের জন্য সেগুলি বন্ধ করতে পারবেন। (বিজ্ঞপ্তিগুলিতে সেটিংস অ্যাপের একটি শর্টকাট অন্তর্ভুক্ত রয়েছে।) আরও বিস্তারিত জানার জন্য, Cast remote control notifications দেখুন।
মিনি কন্ট্রোলার যোগ করুন
কাস্ট ডিজাইন চেকলিস্ট অনুসারে, একটি প্রেরক অ্যাপের একটি স্থায়ী নিয়ন্ত্রণ প্রদান করা উচিত যা মিনি কন্ট্রোলার নামে পরিচিত, যা ব্যবহারকারী যখন বর্তমান কন্টেন্ট পৃষ্ঠা থেকে প্রেরক অ্যাপের অন্য অংশে নেভিগেট করেন তখন প্রদর্শিত হওয়া উচিত। মিনি কন্ট্রোলারটি বর্তমান কাস্ট সেশনের ব্যবহারকারীকে একটি দৃশ্যমান অনুস্মারক প্রদান করে। মিনি কন্ট্রোলারে ট্যাপ করে, ব্যবহারকারী কাস্ট পূর্ণ-স্ক্রিন সম্প্রসারিত নিয়ন্ত্রক দৃশ্যে ফিরে যেতে পারেন।
ফ্রেমওয়ার্কটিতে একটি কাস্টম ভিউ, মিনিকন্ট্রোলারফ্রেগমেন্ট রয়েছে, যা আপনি প্রতিটি অ্যাক্টিভিটির লেআউট ফাইলের নীচে যোগ করতে পারেন যেখানে আপনি মিনি কন্ট্রোলারটি দেখাতে চান।
<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 স্বয়ংক্রিয়ভাবে মিনি কন্ট্রোলারে প্লে/পজ বোতামের জায়গায় একটি প্লে/স্টপ বোতাম প্রদর্শন করে।
এই কাস্টম ভিউয়ের শিরোনাম এবং সাবটাইটেলের টেক্সট উপস্থিতি সেট করতে এবং বোতামগুলি নির্বাচন করতে, কাস্টমাইজ মিনি কন্ট্রোলার দেখুন।
প্রসারিত নিয়ামক যোগ করুন
গুগল কাস্ট ডিজাইন চেকলিস্টের জন্য একটি প্রেরক অ্যাপকে কাস্ট করা মিডিয়ার জন্য একটি বর্ধিত নিয়ামক সরবরাহ করতে হবে। বর্ধিত নিয়ামকটি মিনি নিয়ামকের একটি পূর্ণ স্ক্রিন সংস্করণ।
Cast SDK এক্সপেন্ডেড কন্ট্রোলারের জন্য একটি উইজেট প্রদান করে যার নাম ExpandedControllerActivity । এটি একটি অ্যাবস্ট্রাক্ট ক্লাস যা আপনাকে 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 প্রসারিত করে।
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 স্বয়ংক্রিয়ভাবে প্রসারিত কন্ট্রোলারে প্লে/পজ বোতামের জায়গায় একটি প্লে/স্টপ বোতাম প্রদর্শন করে।
থিম ব্যবহার করে চেহারা সেট করতে, কোন বোতামগুলি প্রদর্শন করবেন তা চয়ন করুন এবং কাস্টম বোতাম যুক্ত করুন, কাস্টমাইজ এক্সপেন্ডেড কন্ট্রোলার দেখুন।
ভলিউম নিয়ন্ত্রণ
ফ্রেমওয়ার্কটি স্বয়ংক্রিয়ভাবে প্রেরক অ্যাপের ভলিউম পরিচালনা করে। ফ্রেমওয়ার্কটি স্বয়ংক্রিয়ভাবে প্রেরক এবং ওয়েব রিসিভার অ্যাপগুলিকে সিঙ্ক্রোনাইজ করে যাতে প্রেরক UI সর্বদা ওয়েব রিসিভার দ্বারা নির্দিষ্ট ভলিউম রিপোর্ট করে।
ভৌত বোতাম ভলিউম নিয়ন্ত্রণ
অ্যান্ড্রয়েডে, জেলি বিন বা তার পরবর্তী যেকোনো ডিভাইসের জন্য, প্রেরক ডিভাইসের ফিজিক্যাল বোতামগুলি ডিফল্টরূপে ওয়েব রিসিভারে কাস্ট সেশনের ভলিউম পরিবর্তন করতে ব্যবহার করা যেতে পারে।
জেলি বিনের আগে ভৌত বোতামের ভলিউম নিয়ন্ত্রণ
জেলি বিনের চেয়ে পুরনো অ্যান্ড্রয়েড ডিভাইসে ওয়েব রিসিভার ডিভাইসের ভলিউম নিয়ন্ত্রণ করতে ফিজিক্যাল ভলিউম কী ব্যবহার করতে, প্রেরক অ্যাপটিকে তাদের Activities-এ 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); } }
বিজ্ঞপ্তি এবং লক স্ক্রিনে মিডিয়া নিয়ন্ত্রণ যোগ করুন
শুধুমাত্র অ্যান্ড্রয়েডে, 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();
বিজ্ঞপ্তি এবং লক স্ক্রিন থেকে মিডিয়া নিয়ন্ত্রণ দেখানো ডিফল্টরূপে চালু থাকে এবং CastMediaOptions.Builder এ null দিয়ে setNotificationOptions কল করে এটি অক্ষম করা যেতে পারে। বর্তমানে, বিজ্ঞপ্তি চালু থাকা পর্যন্ত লক স্ক্রিন বৈশিষ্ট্যটি চালু থাকে।
// ... 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 স্বয়ংক্রিয়ভাবে বিজ্ঞপ্তি নিয়ন্ত্রণে প্লে/পজ বোতামের জায়গায় একটি প্লে/স্টপ বোতাম প্রদর্শন করে কিন্তু লক স্ক্রিন নিয়ন্ত্রণে নয়।
দ্রষ্টব্য : ললিপপ-পূর্ববর্তী ডিভাইসগুলিতে লক স্ক্রিন নিয়ন্ত্রণগুলি প্রদর্শন করতে, RemoteMediaClient স্বয়ংক্রিয়ভাবে আপনার পক্ষ থেকে অডিও ফোকাসের অনুরোধ করবে।
ত্রুটিগুলি পরিচালনা করুন
প্রেরক অ্যাপগুলির জন্য সমস্ত ত্রুটি কলব্যাক পরিচালনা করা এবং কাস্ট জীবনচক্রের প্রতিটি পর্যায়ে সর্বোত্তম প্রতিক্রিয়া নির্ধারণ করা খুবই গুরুত্বপূর্ণ। অ্যাপটি ব্যবহারকারীকে ত্রুটি সংলাপ প্রদর্শন করতে পারে অথবা ওয়েব রিসিভারের সাথে সংযোগ বিচ্ছিন্ন করার সিদ্ধান্ত নিতে পারে।