এই পৃষ্ঠায় একটি অ্যান্ড্রয়েড টিভি রিসিভার অ্যাপ কাস্টমাইজ করার জন্য উপলব্ধ ফিচারগুলোর কোড স্নিপেট এবং বিবরণ রয়েছে।
লাইব্রেরি কনফিগার করা
আপনার অ্যান্ড্রয়েড টিভি অ্যাপে কাস্ট কানেক্ট এপিআই উপলব্ধ করতে:
- আপনার অ্যাপ্লিকেশন মডিউল ডিরেক্টরির ভিতরে
build.gradleফাইলটি খুলুন। - যাচাই করুন যে
google()তালিকাভুক্তrepositoriesঅন্তর্ভুক্ত আছে।repositories { google() } - আপনার অ্যাপের জন্য নির্ধারিত ডিভাইসের ধরনের ওপর নির্ভর করে, লাইব্রেরিগুলোর সর্বশেষ সংস্করণ আপনার ডিপেন্ডেন্সিতে যোগ করুন:
- For Android Receiver app:
dependencies { implementation 'com.google.android.gms:play-services-cast-tv:21.1.1' implementation 'com.google.android.gms:play-services-cast:22.3.0' }
- অ্যান্ড্রয়েড প্রেরক অ্যাপের জন্য:
dependencies { implementation 'com.google.android.gms:play-services-cast:21.1.1' implementation 'com.google.android.gms:play-services-cast-framework:22.3.0' }
- For Android Receiver app:
- পরিবর্তনগুলি সংরক্ষণ করুন এবং টুলবারে থাকা
Sync Project with Gradle Filesবোতামে ক্লিক করুন।
- নিশ্চিত করুন যে আপনার
Podfilegoogle-cast-sdk4.8.4 বা তার উচ্চতর সংস্করণকে টার্গেট করছে। - আইওএস ১৫ বা উচ্চতর সংস্করণ লক্ষ্য করুন। আরও বিস্তারিত জানতে রিলিজ নোট দেখুন।
platform: ios, '15' def target_pods pod 'google-cast-sdk', '~>4.8.4' end
- ক্রোমিয়াম ব্রাউজার সংস্করণ M87 বা তার উচ্চতর সংস্করণ প্রয়োজন।
- আপনার প্রজেক্টে ওয়েব সেন্ডার এপিআই লাইব্রেরিটি যোগ করুন।
<script src="//www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"></script>
AndroidX প্রয়োজনীয়তা
Google Play Services-এর নতুন সংস্করণগুলো ব্যবহারের জন্য অ্যাপটিকে androidx নেমস্পেস ব্যবহার করার জন্য আপডেট করা আবশ্যক। AndroidX-এ স্থানান্তরের জন্য নির্দেশাবলী অনুসরণ করুন।
অ্যান্ড্রয়েড টিভি অ্যাপ—পূর্বশর্ত
আপনার অ্যান্ড্রয়েড টিভি অ্যাপে কাস্ট কানেক্ট সমর্থন করার জন্য, আপনাকে অবশ্যই একটি মিডিয়া সেশন থেকে ইভেন্ট তৈরি এবং সমর্থন করতে হবে। আপনার মিডিয়া সেশন থেকে প্রাপ্ত ডেটা আপনার মিডিয়ার স্ট্যাটাসের জন্য প্রাথমিক তথ্য—যেমন, অবস্থান, প্লেব্যাক অবস্থা ইত্যাদি—প্রদান করে। এছাড়াও, কোনো প্রেরকের কাছ থেকে পজের মতো নির্দিষ্ট বার্তা পেলে তা জানানোর জন্য কাস্ট কানেক্ট লাইব্রেরি আপনার মিডিয়া সেশন ব্যবহার করে।
মিডিয়া সেশন এবং কীভাবে একটি মিডিয়া সেশন শুরু করতে হয় সে সম্পর্কে আরও তথ্যের জন্য, "মিডিয়া সেশন নিয়ে কাজ করার নির্দেশিকা" দেখুন।
মিডিয়া সেশন জীবনচক্র
প্লেব্যাক শুরু হলে আপনার অ্যাপের একটি মিডিয়া সেশন তৈরি করা উচিত এবং যখন এটি আর নিয়ন্ত্রণ করা যাবে না, তখন তা রিলিজ করা উচিত। উদাহরণস্বরূপ, যদি আপনার অ্যাপটি একটি ভিডিও অ্যাপ হয়, তবে ব্যবহারকারী যখন প্লেব্যাক অ্যাক্টিভিটি থেকে বেরিয়ে যাবেন—অন্যান্য কন্টেন্ট ব্রাউজ করার জন্য 'ব্যাক' নির্বাচন করে অথবা অ্যাপটিকে ব্যাকগ্রাউন্ডে পাঠিয়ে—তখন সেশনটি রিলিজ করা উচিত। যদি আপনার অ্যাপটি একটি মিউজিক অ্যাপ হয়, তবে যখন আপনার অ্যাপটি আর কোনো মিডিয়া প্লে করবে না, তখন এটি রিলিজ করা উচিত।
সেশনের অবস্থা আপডেট করা হচ্ছে
আপনার মিডিয়া সেশনের ডেটা আপনার প্লেয়ারের স্ট্যাটাস অনুযায়ী হালনাগাদ রাখা উচিত। উদাহরণস্বরূপ, যখন প্লেব্যাক পজ করা হয়, তখন আপনার প্লেব্যাক স্টেট এবং সাপোর্টেড অ্যাকশনগুলোও আপডেট করা উচিত। নিচের সারণিগুলোতে সেই স্টেটগুলোর একটি তালিকা দেওয়া হলো, যেগুলো হালনাগাদ রাখার দায়িত্ব আপনার।
মিডিয়ামেটাডেটাকম্প্যাট
| মেটাডেটা ক্ষেত্র | বর্ণনা |
|---|---|
| মেটাডেটা_কী_শিরোনাম (আবশ্যক) | গণমাধ্যমের শিরোনাম। |
| মেটাডেটা_কী_ডিসপ্লে_সাবটাইটেল | উপশিরোনামটি। |
| মেটাডেটা_কী_ডিসপ্লে_আইকন_ইউআরআই | আইকন ইউআরএল। |
| মেটাডেটা_কী_সময়কাল (প্রয়োজনীয়) | মিডিয়ার সময়কাল। |
| মেটাডেটা_কী_মিডিয়া_ইউআরআই | কন্টেন্ট আইডি। |
| মেটাডেটা_কী_শিল্পী | শিল্পী। |
| মেটাডেটা_কী_অ্যালবাম | অ্যালবামটি। |
প্লেব্যাকস্টেটকম্প্যাট
| প্রয়োজনীয় পদ্ধতি | বর্ণনা |
|---|---|
| setActions() | সমর্থিত মিডিয়া কমান্ডগুলো সেট করে। |
| setState() | খেলার অবস্থা এবং বর্তমান অবস্থান নির্ধারণ করুন। |
মিডিয়াসেশনকম্প্যাট
| প্রয়োজনীয় পদ্ধতি | বর্ণনা |
|---|---|
| setRepeatMode() | পুনরাবৃত্তি মোড সেট করে। |
| setShuffleMode() | শাফেল মোড সেট করে। |
| setMetadata() | মিডিয়া মেটাডেটা সেট করে। |
| setPlaybackState() | প্লেব্যাক অবস্থা নির্ধারণ করে। |
private fun updateMediaSession() { val metadata = MediaMetadataCompat.Builder() .putString(MediaMetadataCompat.METADATA_KEY_TITLE, "title") .putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, "subtitle") .putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON_URI, mMovie.getCardImageUrl()) .build() val playbackState = PlaybackStateCompat.Builder() .setState( PlaybackStateCompat.STATE_PLAYING, player.getPosition(), player.getPlaybackSpeed(), System.currentTimeMillis() ) .build() mediaSession.setMetadata(metadata) mediaSession.setPlaybackState(playbackState) }
private void updateMediaSession() {
MediaMetadataCompat metadata =
new MediaMetadataCompat.Builder()
.putString(MediaMetadataCompat.METADATA_KEY_TITLE, "title")
.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, "subtitle")
.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON_URI,mMovie.getCardImageUrl())
.build();
PlaybackStateCompat playbackState =
new PlaybackStateCompat.Builder()
.setState(
PlaybackStateCompat.STATE_PLAYING,
player.getPosition(),
player.getPlaybackSpeed(),
System.currentTimeMillis())
.build();
mediaSession.setMetadata(metadata);
mediaSession.setPlaybackState(playbackState);
}পরিবহন নিয়ন্ত্রণ পরিচালনা
আপনার অ্যাপে মিডিয়া সেশন ট্রান্সপোর্ট কন্ট্রোল কলব্যাক প্রয়োগ করা উচিত। নিচের সারণিতে দেখানো হয়েছে যে তাদের কী কী ট্রান্সপোর্ট কন্ট্রোল অ্যাকশন পরিচালনা করতে হবে:
MediaSessionCompat.কলব্যাক
| কর্ম | বর্ণনা |
|---|---|
| onPlay() | জীবনবৃত্তান্ত |
| onPause() | বিরতি |
| onSeekTo() | একটি পদের সন্ধান করুন |
| onStop() | Stop the current media |
class MyMediaSessionCallback : MediaSessionCompat.Callback() { override fun onPause() { // Pause the player and update the play state. ... } override fun onPlay() { // Resume the player and update the play state. ... } override fun onSeekTo (long pos) { // Seek and update the play state. ... } ... } mediaSession.setCallback( MyMediaSessionCallback() );
public MyMediaSessionCallback extends MediaSessionCompat.Callback { public void onPause() { // Pause the player and update the play state. ... } public void onPlay() { // Resume the player and update the play state. ... } public void onSeekTo (long pos) { // Seek and update the play state. ... } ... } mediaSession.setCallback(new MyMediaSessionCallback());
কাস্ট সমর্থন কনফিগার করা
যখন কোনো প্রেরক অ্যাপ্লিকেশন থেকে একটি লঞ্চ রিকোয়েস্ট পাঠানো হয়, তখন একটি অ্যাপ্লিকেশন নেমস্পেস সহ একটি ইন্টেন্ট তৈরি হয়। আপনার অ্যাপ্লিকেশনটি এটি হ্যান্ডেল করার এবং টিভি অ্যাপটি চালু হলে CastReceiverContext অবজেক্টের একটি ইনস্ট্যান্স তৈরি করার জন্য দায়ী। টিভি অ্যাপটি চলার সময় কাস্টের সাথে ইন্টারঅ্যাক্ট করার জন্য CastReceiverContext অবজেক্টটি প্রয়োজন হয়। এই অবজেক্টটি আপনার টিভি অ্যাপ্লিকেশনকে যেকোনো সংযুক্ত প্রেরকের কাছ থেকে আসা কাস্ট মিডিয়া মেসেজ গ্রহণ করতে সক্ষম করে।
অ্যান্ড্রয়েড টিভি সেটআপ
একটি লঞ্চ ইন্টেন্ট ফিল্টার যোগ করা
যে অ্যাক্টিভিটিতে আপনি আপনার প্রেরক অ্যাপ থেকে লঞ্চ ইন্টেন্টটি পরিচালনা করতে চান, সেখানে একটি নতুন ইন্টেন্ট ফিল্টার যোগ করুন:
<activity android:name="com.example.activity">
<intent-filter>
<action android:name="com.google.android.gms.cast.tv.action.LAUNCH" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
প্রাপক বিকল্প প্রদানকারী নির্দিষ্ট করুন
CastReceiverOptions প্রদান করার জন্য আপনাকে একটি ReceiverOptionsProvider ইমপ্লিমেন্ট করতে হবে:
class MyReceiverOptionsProvider : ReceiverOptionsProvider { override fun getOptions(context: Context?): CastReceiverOptions { return CastReceiverOptions.Builder(context) .setStatusText("My App") .build() } }
public class MyReceiverOptionsProvider implements ReceiverOptionsProvider { @Override public CastReceiverOptions getOptions(Context context) { return new CastReceiverOptions.Builder(context) .setStatusText("My App") .build(); } }
তারপর আপনার AndroidManifest এ অপশন প্রোভাইডারটি নির্দিষ্ট করুন:
<meta-data
android:name="com.google.android.gms.cast.tv.RECEIVER_OPTIONS_PROVIDER_CLASS_NAME"
android:value="com.example.mysimpleatvapplication.MyReceiverOptionsProvider" />
CastReceiverContext ইনিশিয়ালাইজ করার সময় CastReceiverOptions সরবরাহ করার জন্য ReceiverOptionsProvider ব্যবহৃত হয়।
কাস্ট রিসিভার প্রসঙ্গ
আপনার অ্যাপ তৈরি করার সময় CastReceiverContext ইনিশিয়ালাইজ করুন:
override fun onCreate() { CastReceiverContext.initInstance(this) ... }
@Override public void onCreate() { CastReceiverContext.initInstance(this); ... }
আপনার অ্যাপ ফোরগ্রাউন্ডে এলে CastReceiverContext চালু করুন:
CastReceiverContext.getInstance().start()
CastReceiverContext.getInstance().start();
ভিডিও অ্যাপ বা যে অ্যাপগুলো ব্যাকগ্রাউন্ড প্লেব্যাক সমর্থন করে না, সেগুলোর ক্ষেত্রে অ্যাপটি ব্যাকগ্রাউন্ডে যাওয়ার পর CastReceiverContext এ stop() কল করুন:
// Player has stopped. CastReceiverContext.getInstance().stop()
// Player has stopped. CastReceiverContext.getInstance().stop();
এছাড়াও, যদি আপনার অ্যাপ ব্যাকগ্রাউন্ডে প্লে করা সমর্থন করে, তাহলে ব্যাকগ্রাউন্ডে প্লে হওয়া বন্ধ হলে CastReceiverContext এর উপর stop() কল করুন।
CastReceiverContext.start() এবং CastReceiverContext.stop() কলগুলো পরিচালনা করার জন্য আমরা আপনাকে androidx.lifecycle লাইব্রেরির LifecycleObserver ব্যবহার করার জন্য দৃঢ়ভাবে সুপারিশ করছি, বিশেষ করে যদি আপনার নেটিভ অ্যাপে একাধিক অ্যাক্টিভিটি থাকে। এর ফলে, যখন আপনি বিভিন্ন অ্যাক্টিভিটি থেকে start() এবং stop() কল করেন, তখন সৃষ্ট রেস কন্ডিশন এড়ানো যায়।
// Create a LifecycleObserver class. class MyLifecycleObserver : DefaultLifecycleObserver { override fun onStart(owner: LifecycleOwner) { // App prepares to enter foreground. CastReceiverContext.getInstance().start() } override fun onStop(owner: LifecycleOwner) { // App has moved to the background or has terminated. CastReceiverContext.getInstance().stop() } } // Add the observer when your application is being created. class MyApplication : Application() { fun onCreate() { super.onCreate() // Initialize CastReceiverContext. CastReceiverContext.initInstance(this /* android.content.Context */) // Register LifecycleObserver ProcessLifecycleOwner.get().lifecycle.addObserver( MyLifecycleObserver()) } }
// Create a LifecycleObserver class. public class MyLifecycleObserver implements DefaultLifecycleObserver { @Override public void onStart(LifecycleOwner owner) { // App prepares to enter foreground. CastReceiverContext.getInstance().start(); } @Override public void onStop(LifecycleOwner owner) { // App has moved to the background or has terminated. CastReceiverContext.getInstance().stop(); } } // Add the observer when your application is being created. public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); // Initialize CastReceiverContext. CastReceiverContext.initInstance(this /* android.content.Context */); // Register LifecycleObserver ProcessLifecycleOwner.get().getLifecycle().addObserver( new MyLifecycleObserver()); } }
// In AndroidManifest.xml set MyApplication as the application class
<application
...
android:name=".MyApplication">
মিডিয়াসেশনকে মিডিয়াম্যানেজারের সাথে সংযুক্ত করা
যখন আপনি একটি MediaSession তৈরি করেন, তখন আপনাকে CastReceiverContext কে বর্তমান MediaSession টোকেনটিও প্রদান করতে হবে, যাতে এটি জানতে পারে কোথায় কমান্ড পাঠাতে হবে এবং মিডিয়া প্লেব্যাকের অবস্থা পুনরুদ্ধার করতে হবে।
val mediaManager: MediaManager = receiverContext.getMediaManager() mediaManager.setSessionCompatToken(currentMediaSession.getSessionToken())
MediaManager mediaManager = receiverContext.getMediaManager(); mediaManager.setSessionCompatToken(currentMediaSession.getSessionToken());
নিষ্ক্রিয় প্লেব্যাকের কারণে যখন আপনি আপনার MediaSession রিলিজ করবেন, তখন MediaManager এ একটি null টোকেন সেট করতে হবে:
myPlayer.stop() mediaSession.release() mediaManager.setSessionCompatToken(null)
myPlayer.stop(); mediaSession.release(); mediaManager.setSessionCompatToken(null);
আপনার অ্যাপ যদি ব্যাকগ্রাউন্ডে থাকাকালীন মিডিয়া প্লে করা সমর্থন করে, তাহলে অ্যাপটি ব্যাকগ্রাউন্ডে চলে গেলে CastReceiverContext.stop() কল করার পরিবর্তে, এটি শুধুমাত্র তখনই কল করা উচিত যখন আপনার অ্যাপটি ব্যাকগ্রাউন্ডে থাকবে এবং আর কোনো মিডিয়া প্লে হবে না। উদাহরণস্বরূপ:
class MyLifecycleObserver : DefaultLifecycleObserver { ... // App has moved to the background. override fun onPause(owner: LifecycleOwner) { mIsBackground = true myStopCastReceiverContextIfNeeded() } } // Stop playback on the player. private fun myStopPlayback() { myPlayer.stop() myStopCastReceiverContextIfNeeded() } // Stop the CastReceiverContext when both the player has // stopped and the app has moved to the background. private fun myStopCastReceiverContextIfNeeded() { if (mIsBackground && myPlayer.isStopped()) { CastReceiverContext.getInstance().stop() } }
public class MyLifecycleObserver implements DefaultLifecycleObserver { ... // App has moved to the background. @Override public void onPause(LifecycleOwner owner) { mIsBackground = true; myStopCastReceiverContextIfNeeded(); } } // Stop playback on the player. private void myStopPlayback() { myPlayer.stop(); myStopCastReceiverContextIfNeeded(); } // Stop the CastReceiverContext when both the player has // stopped and the app has moved to the background. private void myStopCastReceiverContextIfNeeded() { if (mIsBackground && myPlayer.isStopped()) { CastReceiverContext.getInstance().stop(); } }
কাস্ট কানেক্টের সাথে এক্সোপ্লেয়ার ব্যবহার করা
আপনি যদি Exoplayer ব্যবহার করেন, তাহলে ম্যানুয়ালি পরিবর্তনগুলো ট্র্যাক করার পরিবর্তে MediaSessionConnector ব্যবহার করে সেশন এবং প্লেব্যাক অবস্থাসহ সমস্ত সম্পর্কিত তথ্য স্বয়ংক্রিয়ভাবে বজায় রাখতে পারেন।
MediaSessionConnector.MediaButtonEventHandler ব্যবহার করে setMediaButtonEventHandler(MediaButtonEventHandler) কল করার মাধ্যমে MediaButton-এর ইভেন্টগুলো হ্যান্ডেল করা যায়, যেগুলো অন্যথায় ডিফল্টভাবে MediaSessionCompat.Callback দ্বারা হ্যান্ডেল করা হয়।
আপনার অ্যাপে MediaSessionConnector ইন্টিগ্রেট করতে, নিম্নলিখিতটি আপনার প্লেয়ার অ্যাক্টিভিটি ক্লাসে অথবা যেখানে আপনি আপনার মিডিয়া সেশন পরিচালনা করেন সেখানে যোগ করুন:
class PlayerActivity : Activity() { private var mMediaSession: MediaSessionCompat? = null private var mMediaSessionConnector: MediaSessionConnector? = null private var mMediaManager: MediaManager? = null override fun onCreate(savedInstanceState: Bundle?) { ... mMediaSession = MediaSessionCompat(this, LOG_TAG) mMediaSessionConnector = MediaSessionConnector(mMediaSession!!) ... } override fun onStart() { ... mMediaManager = receiverContext.getMediaManager() mMediaManager!!.setSessionCompatToken(currentMediaSession.getSessionToken()) mMediaSessionConnector!!.setPlayer(mExoPlayer) mMediaSessionConnector!!.setMediaMetadataProvider(mMediaMetadataProvider) mMediaSession!!.isActive = true ... } override fun onStop() { ... mMediaSessionConnector!!.setPlayer(null) mMediaSession!!.release() mMediaManager!!.setSessionCompatToken(null) ... } }
public class PlayerActivity extends Activity { private MediaSessionCompat mMediaSession; private MediaSessionConnector mMediaSessionConnector; private MediaManager mMediaManager; @Override protected void onCreate(Bundle savedInstanceState) { ... mMediaSession = new MediaSessionCompat(this, LOG_TAG); mMediaSessionConnector = new MediaSessionConnector(mMediaSession); ... } @Override protected void onStart() { ... mMediaManager = receiverContext.getMediaManager(); mMediaManager.setSessionCompatToken(currentMediaSession.getSessionToken()); mMediaSessionConnector.setPlayer(mExoPlayer); mMediaSessionConnector.setMediaMetadataProvider(mMediaMetadataProvider); mMediaSession.setActive(true); ... } @Override protected void onStop() { ... mMediaSessionConnector.setPlayer(null); mMediaSession.release(); mMediaManager.setSessionCompatToken(null); ... } }
প্রেরক অ্যাপ সেটআপ
কাস্ট কানেক্ট সমর্থন সক্রিয় করুন
আপনার প্রেরক অ্যাপটি Cast Connect সমর্থন সহ আপডেট করার পরে, আপনি LaunchOptions এ androidReceiverCompatible ফ্ল্যাগটিকে true সেট করে এর প্রস্তুতি ঘোষণা করতে পারেন।
play-services-cast-framework সংস্করণ 19.0.0 বা তার উচ্চতর সংস্করণ প্রয়োজন।
androidReceiverCompatible ফ্ল্যাগটি LaunchOptions এ (যা CastOptions এর একটি অংশ) সেট করা হয়:
class CastOptionsProvider : OptionsProvider { override fun getCastOptions(context: Context?): CastOptions { val launchOptions: LaunchOptions = Builder() .setAndroidReceiverCompatible(true) .build() return CastOptions.Builder() .setLaunchOptions(launchOptions) ... .build() } }
public class CastOptionsProvider implements OptionsProvider { @Override public CastOptions getCastOptions(Context context) { LaunchOptions launchOptions = new LaunchOptions.Builder() .setAndroidReceiverCompatible(true) .build(); return new CastOptions.Builder() .setLaunchOptions(launchOptions) ... .build(); } }
google-cast-sdk সংস্করণ v4.4.8 বা তার উচ্চতর সংস্করণ প্রয়োজন।
androidReceiverCompatible ফ্ল্যাগটি GCKLaunchOptions এ (যা GCKCastOptions এর একটি অংশ) সেট করা হয়:
let options = GCKCastOptions(discoveryCriteria: GCKDiscoveryCriteria(applicationID: kReceiverAppID)) ... let launchOptions = GCKLaunchOptions() launchOptions.androidReceiverCompatible = true options.launchOptions = launchOptions GCKCastContext.setSharedInstanceWith(options)
ক্রোমিয়াম ব্রাউজার সংস্করণ M87 বা তার উচ্চতর সংস্করণ প্রয়োজন।
const context = cast.framework.CastContext.getInstance(); const castOptions = new cast.framework.CastOptions(); castOptions.receiverApplicationId = kReceiverAppID; castOptions.androidReceiverCompatible = true; context.setOptions(castOptions);
কাস্ট ডেভেলপার কনসোল সেটআপ
অ্যান্ড্রয়েড টিভি অ্যাপ কনফিগার করুন
আপনার কাস্ট অ্যাপ আইডির সাথে যুক্ত করতে, কাস্ট ডেভেলপার কনসোলে আপনার অ্যান্ড্রয়েড টিভি অ্যাপের প্যাকেজ নামটি যোগ করুন।

ডেভেলপার ডিভাইস নিবন্ধন করুন
ডেভেলপমেন্টের জন্য আপনি যে অ্যান্ড্রয়েড টিভি ডিভাইসটি ব্যবহার করতে চলেছেন, সেটির সিরিয়াল নম্বরটি কাস্ট ডেভেলপার কনসোলে রেজিস্টার করুন।

নিরাপত্তাজনিত কারণে, নিবন্ধন ছাড়া কাস্ট কানেক্ট শুধুমাত্র গুগল প্লে স্টোর থেকে ইনস্টল করা অ্যাপগুলোর জন্যই কাজ করবে।
কাস্ট ডেভেলপমেন্টের জন্য কাস্ট বা অ্যান্ড্রয়েড টিভি ডিভাইস নিবন্ধন করার বিষয়ে আরও তথ্যের জন্য, নিবন্ধন পৃষ্ঠাটি দেখুন।
মিডিয়া লোড হচ্ছে
আপনি যদি আপনার অ্যান্ড্রয়েড টিভি অ্যাপে ইতিমধ্যেই ডিপ লিঙ্ক সাপোর্ট প্রয়োগ করে থাকেন, তাহলে আপনার অ্যান্ড্রয়েড টিভি ম্যানিফেস্টেও একটি অনুরূপ ডেফিনিশন কনফিগার করা থাকা উচিত:
<activity android:name="com.example.activity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="https"/>
<data android:host="www.example.com"/>
<data android:pathPattern=".*"/>
</intent-filter>
</activity>
প্রেরকের উপর সত্তা দ্বারা লোড করুন
প্রেরকদের ক্ষেত্রে, লোড অনুরোধের মিডিয়া তথ্যে entity সেট করার মাধ্যমে আপনি ডিপ লিঙ্কটি পাস করতে পারেন:
val mediaToLoad = MediaInfo.Builder("some-id") .setEntity("https://example.com/watch/some-id") ... .build() val loadRequest = MediaLoadRequestData.Builder() .setMediaInfo(mediaToLoad) .setCredentials("user-credentials") ... .build() remoteMediaClient.load(loadRequest)
MediaInfo mediaToLoad = new MediaInfo.Builder("some-id") .setEntity("https://example.com/watch/some-id") ... .build(); MediaLoadRequestData loadRequest = new MediaLoadRequestData.Builder() .setMediaInfo(mediaToLoad) .setCredentials("user-credentials") ... .build(); remoteMediaClient.load(loadRequest);
let mediaInfoBuilder = GCKMediaInformationBuilder(entity: "https://example.com/watch/some-id") ... mediaInformation = mediaInfoBuilder.build() let mediaLoadRequestDataBuilder = GCKMediaLoadRequestDataBuilder() mediaLoadRequestDataBuilder.mediaInformation = mediaInformation mediaLoadRequestDataBuilder.credentials = "user-credentials" ... let mediaLoadRequestData = mediaLoadRequestDataBuilder.build() remoteMediaClient?.loadMedia(with: mediaLoadRequestData)
ক্রোমিয়াম ব্রাউজার সংস্করণ M87 বা তার উচ্চতর সংস্করণ প্রয়োজন।
let mediaInfo = new chrome.cast.media.MediaInfo('some-id"', 'video/mp4'); mediaInfo.entity = 'https://example.com/watch/some-id'; ... let request = new chrome.cast.media.LoadRequest(mediaInfo); request.credentials = 'user-credentials'; ... cast.framework.CastContext.getInstance().getCurrentSession().loadMedia(request);
আপনার ডিপ লিঙ্ক এবং ডেভেলপার কনসোলে নির্ধারণ করা প্যাকেজের নাম সহ একটি ইন্টেন্টের মাধ্যমে লোড কমান্ডটি পাঠানো হয়।
প্রেরকের কাছে ATV পরিচয়পত্র সেট করা হচ্ছে
এমনটা হতে পারে যে আপনার ওয়েব রিসিভার অ্যাপ এবং অ্যান্ড্রয়েড টিভি অ্যাপ ভিন্ন ভিন্ন ডিপ লিঙ্ক এবং credentials সমর্থন করে (উদাহরণস্বরূপ, যদি আপনি দুটি প্ল্যাটফর্মে প্রমাণীকরণ ভিন্নভাবে পরিচালনা করেন)। এর সমাধান করতে, আপনি অ্যান্ড্রয়েড টিভির জন্য বিকল্প entity এবং credentials প্রদান করতে পারেন:
val mediaToLoad = MediaInfo.Builder("some-id") .setEntity("https://example.com/watch/some-id") .setAtvEntity("myscheme://example.com/atv/some-id") ... .build() val loadRequest = MediaLoadRequestData.Builder() .setMediaInfo(mediaToLoad) .setCredentials("user-credentials") .setAtvCredentials("atv-user-credentials") ... .build() remoteMediaClient.load(loadRequest)
MediaInfo mediaToLoad = new MediaInfo.Builder("some-id") .setEntity("https://example.com/watch/some-id") .setAtvEntity("myscheme://example.com/atv/some-id") ... .build(); MediaLoadRequestData loadRequest = new MediaLoadRequestData.Builder() .setMediaInfo(mediaToLoad) .setCredentials("user-credentials") .setAtvCredentials("atv-user-credentials") ... .build(); remoteMediaClient.load(loadRequest);
let mediaInfoBuilder = GCKMediaInformationBuilder(entity: "https://example.com/watch/some-id") mediaInfoBuilder.atvEntity = "myscheme://example.com/atv/some-id" ... mediaInformation = mediaInfoBuilder.build() let mediaLoadRequestDataBuilder = GCKMediaLoadRequestDataBuilder() mediaLoadRequestDataBuilder.mediaInformation = mediaInformation mediaLoadRequestDataBuilder.credentials = "user-credentials" mediaLoadRequestDataBuilder.atvCredentials = "atv-user-credentials" ... let mediaLoadRequestData = mediaLoadRequestDataBuilder.build() remoteMediaClient?.loadMedia(with: mediaLoadRequestData)
ক্রোমিয়াম ব্রাউজার সংস্করণ M87 বা তার উচ্চতর সংস্করণ প্রয়োজন।
let mediaInfo = new chrome.cast.media.MediaInfo('some-id"', 'video/mp4'); mediaInfo.entity = 'https://example.com/watch/some-id'; mediaInfo.atvEntity = 'myscheme://example.com/atv/some-id'; ... let request = new chrome.cast.media.LoadRequest(mediaInfo); request.credentials = 'user-credentials'; request.atvCredentials = 'atv-user-credentials'; ... cast.framework.CastContext.getInstance().getCurrentSession().loadMedia(request);
ওয়েব রিসিভার অ্যাপটি চালু করা হলে, এটি লোড রিকোয়েস্টে entity এবং credentials ব্যবহার করে। তবে আপনার অ্যান্ড্রয়েড টিভি অ্যাপটি চালু করা হলে, এসডিকে আপনার atvEntity এবং atvCredentials (যদি নির্দিষ্ট করা থাকে) দিয়ে entity এবং credentials ওভাররাইড করে দেয়।
কন্টেন্ট আইডি বা মিডিয়া কিউ ডেটা দ্বারা লোড করা হচ্ছে
আপনি যদি entity বা atvEntity ব্যবহার না করেন এবং আপনার মিডিয়া ইনফরমেশনে কন্টেন্ট আইডি বা কন্টেন্ট ইউআরএল ব্যবহার করেন অথবা আরও বিস্তারিত মিডিয়া লোড রিকোয়েস্ট ডেটা ব্যবহার করেন, তাহলে আপনাকে আপনার অ্যান্ড্রয়েড টিভি অ্যাপে নিম্নলিখিত প্রিডিফাইন্ড ইন্টেন্ট ফিল্টারটি যোগ করতে হবে:
<activity android:name="com.example.activity">
<intent-filter>
<action android:name="com.google.android.gms.cast.tv.action.LOAD"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
প্রেরকের দিকে, এনটিটি অনুযায়ী লোড করার মতোই, আপনি আপনার কন্টেন্টের তথ্য দিয়ে একটি লোড রিকোয়েস্ট তৈরি করে load() কল করতে পারেন।
val mediaToLoad = MediaInfo.Builder("some-id").build() val loadRequest = MediaLoadRequestData.Builder() .setMediaInfo(mediaToLoad) .setCredentials("user-credentials") ... .build() remoteMediaClient.load(loadRequest)
MediaInfo mediaToLoad = new MediaInfo.Builder("some-id").build(); MediaLoadRequestData loadRequest = new MediaLoadRequestData.Builder() .setMediaInfo(mediaToLoad) .setCredentials("user-credentials") ... .build(); remoteMediaClient.load(loadRequest);
let mediaInfoBuilder = GCKMediaInformationBuilder(contentId: "some-id") ... mediaInformation = mediaInfoBuilder.build() let mediaLoadRequestDataBuilder = GCKMediaLoadRequestDataBuilder() mediaLoadRequestDataBuilder.mediaInformation = mediaInformation mediaLoadRequestDataBuilder.credentials = "user-credentials" ... let mediaLoadRequestData = mediaLoadRequestDataBuilder.build() remoteMediaClient?.loadMedia(with: mediaLoadRequestData)
ক্রোমিয়াম ব্রাউজার সংস্করণ M87 বা তার উচ্চতর সংস্করণ প্রয়োজন।
let mediaInfo = new chrome.cast.media.MediaInfo('some-id"', 'video/mp4'); ... let request = new chrome.cast.media.LoadRequest(mediaInfo); ... cast.framework.CastContext.getInstance().getCurrentSession().loadMedia(request);
লোড অনুরোধ পরিচালনা করা
আপনার অ্যাক্টিভিটিতে এই লোড রিকোয়েস্টগুলো হ্যান্ডেল করার জন্য, অ্যাক্টিভিটি লাইফসাইকেল কলব্যাকগুলোতে ইন্টেন্টগুলো হ্যান্ডেল করতে হবে:
class MyActivity : Activity() { override fun onStart() { super.onStart() val mediaManager = CastReceiverContext.getInstance().getMediaManager() // Pass the intent to the SDK. You can also do this in onCreate(). if (mediaManager.onNewIntent(intent)) { // If the SDK recognizes the intent, you should early return. return } // If the SDK doesn't recognize the intent, you can handle the intent with // your own logic. ... } // For some cases, a new load intent triggers onNewIntent() instead of // onStart(). override fun onNewIntent(intent: Intent) { val mediaManager = CastReceiverContext.getInstance().getMediaManager() // Pass the intent to the SDK. You can also do this in onCreate(). if (mediaManager.onNewIntent(intent)) { // If the SDK recognizes the intent, you should early return. return } // If the SDK doesn't recognize the intent, you can handle the intent with // your own logic. ... } }
public class MyActivity extends Activity { @Override protected void onStart() { super.onStart(); MediaManager mediaManager = CastReceiverContext.getInstance().getMediaManager(); // Pass the intent to the SDK. You can also do this in onCreate(). if (mediaManager.onNewIntent(getIntent())) { // If the SDK recognizes the intent, you should early return. return; } // If the SDK doesn't recognize the intent, you can handle the intent with // your own logic. ... } // For some cases, a new load intent triggers onNewIntent() instead of // onStart(). @Override protected void onNewIntent(Intent intent) { MediaManager mediaManager = CastReceiverContext.getInstance().getMediaManager(); // Pass the intent to the SDK. You can also do this in onCreate(). if (mediaManager.onNewIntent(intent)) { // If the SDK recognizes the intent, you should early return. return; } // If the SDK doesn't recognize the intent, you can handle the intent with // your own logic. ... } }
MediaManager যদি ইন্টেন্টটিকে একটি লোড ইন্টেন্ট হিসেবে শনাক্ত করে, তবে এটি ইন্টেন্টটি থেকে একটি MediaLoadRequestData অবজেক্ট সংগ্রহ করে এবং MediaLoadCommandCallback.onLoad() মেথডটি কল করে। লোড রিকোয়েস্টটি হ্যান্ডেল করার জন্য আপনাকে এই মেথডটি ওভাররাইড করতে হবে। MediaManager.onNewIntent() কল করার আগেই কলব্যাকটি রেজিস্টার করতে হবে (এটি কোনো Activity বা Application-এর onCreate() মেথডে করার পরামর্শ দেওয়া হয়)।
class MyActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val mediaManager = CastReceiverContext.getInstance().getMediaManager() mediaManager.setMediaLoadCommandCallback(MyMediaLoadCommandCallback()) } } class MyMediaLoadCommandCallback : MediaLoadCommandCallback() { override fun onLoad( senderId: String?, loadRequestData: MediaLoadRequestData ): Task{ return Tasks.call { // Resolve the entity into your data structure and load media. val mediaInfo = loadRequestData.getMediaInfo() if (!checkMediaInfoSupported(mediaInfo)) { // Throw MediaException to indicate load failure. throw MediaException( MediaError.Builder() .setDetailedErrorCode(DetailedErrorCode.LOAD_FAILED) .setReason(MediaError.ERROR_REASON_INVALID_REQUEST) .build() ) } myFillMediaInfo(MediaInfoWriter(mediaInfo)) myPlayerLoad(mediaInfo.getContentUrl()) // Update media metadata and state (this clears all previous status // overrides). castReceiverContext.getMediaManager() .setDataFromLoad(loadRequestData) ... castReceiverContext.getMediaManager().broadcastMediaStatus() // Return the resolved MediaLoadRequestData to indicate load success. return loadRequestData } } private fun myPlayerLoad(contentURL: String) { myPlayer.load(contentURL) // Update the MediaSession state. val playbackState: PlaybackStateCompat = Builder() .setState( player.getState(), player.getPosition(), System.currentTimeMillis() ) ... .build() mediaSession.setPlaybackState(playbackState) }
public class MyActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); MediaManager mediaManager = CastReceiverContext.getInstance().getMediaManager(); mediaManager.setMediaLoadCommandCallback(new MyMediaLoadCommandCallback()); } } public class MyMediaLoadCommandCallback extends MediaLoadCommandCallback { @Override public TaskonLoad(String senderId, MediaLoadRequestData loadRequestData) { return Tasks.call(() -> { // Resolve the entity into your data structure and load media. MediaInfo mediaInfo = loadRequestData.getMediaInfo(); if (!checkMediaInfoSupported(mediaInfo)) { // Throw MediaException to indicate load failure. throw new MediaException( new MediaError.Builder() .setDetailedErrorCode(DetailedErrorCode.LOAD_FAILED) .setReason(MediaError.ERROR_REASON_INVALID_REQUEST) .build()); } myFillMediaInfo(new MediaInfoWriter(mediaInfo)); myPlayerLoad(mediaInfo.getContentUrl()); // Update media metadata and state (this clears all previous status // overrides). castReceiverContext.getMediaManager() .setDataFromLoad(loadRequestData); ... castReceiverContext.getMediaManager().broadcastMediaStatus(); // Return the resolved MediaLoadRequestData to indicate load success. return loadRequestData; }); } private void myPlayerLoad(String contentURL) { myPlayer.load(contentURL); // Update the MediaSession state. PlaybackStateCompat playbackState = new PlaybackStateCompat.Builder() .setState( player.getState(), player.getPosition(), System.currentTimeMillis()) ... .build(); mediaSession.setPlaybackState(playbackState); }
লোড ইন্টেন্টটি প্রসেস করার জন্য, আপনি ইন্টেন্টটিকে আমাদের সংজ্ঞায়িত ডেটা স্ট্রাকচারগুলিতে (লোড রিকোয়েস্টের জন্য MediaLoadRequestData ) পার্স করতে পারেন।
মিডিয়া কমান্ড সমর্থন করা
মৌলিক প্লেব্যাক নিয়ন্ত্রণ সমর্থন
বেসিক ইন্টিগ্রেশন কমান্ডের মধ্যে সেই কমান্ডগুলো অন্তর্ভুক্ত রয়েছে যেগুলো মিডিয়া সেশনের সাথে সামঞ্জস্যপূর্ণ। এই কমান্ডগুলো মিডিয়া সেশন কলব্যাকের মাধ্যমে জানানো হয়। এটি সমর্থন করার জন্য আপনাকে মিডিয়া সেশনে একটি কলব্যাক রেজিস্টার করতে হবে (হয়তো আপনি ইতিমধ্যেই এটি করছেন)।
private class MyMediaSessionCallback : MediaSessionCompat.Callback() { override fun onPause() { // Pause the player and update the play state. myPlayer.pause() } override fun onPlay() { // Resume the player and update the play state. myPlayer.play() } override fun onSeekTo(pos: Long) { // Seek and update the play state. myPlayer.seekTo(pos) } ... } mediaSession.setCallback(MyMediaSessionCallback())
private class MyMediaSessionCallback extends MediaSessionCompat.Callback { @Override public void onPause() { // Pause the player and update the play state. myPlayer.pause(); } @Override public void onPlay() { // Resume the player and update the play state. myPlayer.play(); } @Override public void onSeekTo(long pos) { // Seek and update the play state. myPlayer.seekTo(pos); } ... } mediaSession.setCallback(new MyMediaSessionCallback());
সহায়ক কাস্ট নিয়ন্ত্রণ কমান্ড
কিছু Cast কমান্ড আছে যা MediaSession এ পাওয়া যায় না, যেমন skipAd() বা setActiveMediaTracks() । এছাড়াও, কিছু কিউ কমান্ড এখানে প্রয়োগ করা প্রয়োজন, কারণ Cast কিউ MediaSession কিউ-এর সাথে পুরোপুরি সামঞ্জস্যপূর্ণ নয়।
class MyMediaCommandCallback : MediaCommandCallback() { override fun onSkipAd(requestData: RequestData?): Task<Void?> { // Skip your ad ... return Tasks.forResult(null) } } val mediaManager = CastReceiverContext.getInstance().getMediaManager() mediaManager.setMediaCommandCallback(MyMediaCommandCallback())
public class MyMediaCommandCallback extends MediaCommandCallback { @Override public TaskonSkipAd(RequestData requestData) { // Skip your ad ... return Tasks.forResult(null); } } MediaManager mediaManager = CastReceiverContext.getInstance().getMediaManager(); mediaManager.setMediaCommandCallback(new MyMediaCommandCallback());
সমর্থিত মিডিয়া কমান্ডগুলি নির্দিষ্ট করুন
আপনার কাস্ট রিসিভারের মতোই, আপনার অ্যান্ড্রয়েড টিভি অ্যাপেও কোন কমান্ডগুলো সমর্থিত তা নির্দিষ্ট করে দেওয়া উচিত, যাতে প্রেরকরা নির্দিষ্ট UI কন্ট্রোল চালু বা বন্ধ করতে পারেন। MediaSession এর অংশ এমন কমান্ডগুলোর জন্য, PlaybackStateCompat এ কমান্ডগুলো উল্লেখ করুন। অতিরিক্ত কমান্ডগুলো MediaStatusModifier এ উল্লেখ করতে হবে।
// Set media session supported commands val playbackState: PlaybackStateCompat = PlaybackStateCompat.Builder() .setActions(PlaybackStateCompat.ACTION_PLAY or PlaybackStateCompat.ACTION_PAUSE) .setState(PlaybackStateCompat.STATE_PLAYING) .build() mediaSession.setPlaybackState(playbackState) // Set additional commands in MediaStatusModifier val mediaManager = CastReceiverContext.getInstance().getMediaManager() mediaManager.getMediaStatusModifier() .setMediaCommandSupported(MediaStatus.COMMAND_QUEUE_NEXT)
// Set media session supported commands PlaybackStateCompat playbackState = new PlaybackStateCompat.Builder() .setActions(PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PAUSE) .setState(PlaybackStateCompat.STATE_PLAYING) .build(); mediaSession.setPlaybackState(playbackState); // Set additional commands in MediaStatusModifier MediaManager mediaManager = CastReceiverContext.getInstance().getMediaManager(); mediaManager.getMediaStatusModifier() .setMediaCommandSupported(MediaStatus.COMMAND_QUEUE_NEXT);
অসমর্থিত বোতামগুলি লুকান
যদি আপনার অ্যান্ড্রয়েড টিভি অ্যাপ শুধুমাত্র সাধারণ মিডিয়া নিয়ন্ত্রণ সমর্থন করে কিন্তু আপনার ওয়েব রিসিভার অ্যাপ আরও উন্নত নিয়ন্ত্রণ সমর্থন করে, তাহলে অ্যান্ড্রয়েড টিভি অ্যাপে কাস্ট করার সময় আপনার প্রেরক অ্যাপটি যেন সঠিকভাবে কাজ করে তা নিশ্চিত করা উচিত। উদাহরণস্বরূপ, যদি আপনার অ্যান্ড্রয়েড টিভি অ্যাপ প্লেব্যাক রেট পরিবর্তন করা সমর্থন না করে কিন্তু আপনার ওয়েব রিসিভার অ্যাপ তা করে, তাহলে আপনার প্রতিটি প্ল্যাটফর্মে সমর্থিত অ্যাকশনগুলো সঠিকভাবে সেট করা উচিত এবং নিশ্চিত করা উচিত যে আপনার প্রেরক অ্যাপটি UI সঠিকভাবে রেন্ডার করছে।
মিডিয়া স্ট্যাটাস পরিবর্তন করা
ট্র্যাক, বিজ্ঞাপন, লাইভ এবং কিউইং-এর মতো উন্নত ফিচারগুলো সমর্থন করার জন্য, আপনার অ্যান্ড্রয়েড টিভি অ্যাপকে এমন অতিরিক্ত তথ্য সরবরাহ করতে হয় যা MediaSession মাধ্যমে নিশ্চিত করা যায় না।
এই কাজটি করার জন্য আমরা আপনাকে MediaStatusModifier ক্লাসটি প্রদান করি। MediaStatusModifier সর্বদা সেই MediaSession উপর কাজ করবে যা আপনি CastReceiverContext এ সেট করেছেন।
MediaStatus তৈরি এবং সম্প্রচার করতে :
val mediaManager: MediaManager = castReceiverContext.getMediaManager() val statusModifier: MediaStatusModifier = mediaManager.getMediaStatusModifier() statusModifier .setLiveSeekableRange(seekableRange) .setAdBreakStatus(adBreakStatus) .setCustomData(customData) mediaManager.broadcastMediaStatus()
MediaManager mediaManager = castReceiverContext.getMediaManager();
MediaStatusModifier statusModifier = mediaManager.getMediaStatusModifier();
statusModifier
.setLiveSeekableRange(seekableRange)
.setAdBreakStatus(adBreakStatus)
.setCustomData(customData);
mediaManager.broadcastMediaStatus(); আমাদের ক্লায়েন্ট লাইব্রেরি MediaSession থেকে মূল MediaStatus গ্রহণ করবে, আপনার অ্যান্ড্রয়েড টিভি অ্যাপ একটি MediaStatus মডিফায়ারের মাধ্যমে অতিরিক্ত স্ট্যাটাস নির্দিষ্ট করতে এবং স্ট্যাটাস ওভাররাইড করতে পারবে।
কিছু স্টেট এবং মেটাডেটা MediaSession এবং MediaStatusModifier উভয় স্থানেই সেট করা যায়। আমরা দৃঢ়ভাবে সুপারিশ করি যে আপনি এগুলো শুধুমাত্র MediaSession এই সেট করুন। আপনি চাইলে মডিফায়ার ব্যবহার করে MediaSession এর স্টেটগুলোকে ওভাররাইড করতে পারেন—তবে এটি নিরুৎসাহিত করা হয়, কারণ মডিফায়ারের স্ট্যাটাসের অগ্রাধিকার MediaSession এর দেওয়া মানের চেয়ে সবসময় বেশি থাকে।
পাঠানোর আগে মিডিয়া স্ট্যাটাস আটকানো
ওয়েব রিসিভার SDK-এর মতোই, পাঠানোর আগে যদি আপনি কিছু চূড়ান্ত পরিবর্তন করতে চান, তাহলে প্রেরিতব্য MediaStatus প্রসেস করার জন্য একটি MediaStatusInterceptor নির্দিষ্ট করে দিতে পারেন। পাঠানোর আগে MediaStatus টিকে নিয়ন্ত্রণ করার জন্য আমরা একটি MediaStatusWriter পাস করে থাকি।
mediaManager.setMediaStatusInterceptor(object : MediaStatusInterceptor { override fun intercept(mediaStatusWriter: MediaStatusWriter) { // Perform customization. mediaStatusWriter.setCustomData(JSONObject("{data: \"my Hello\"}")) } })
mediaManager.setMediaStatusInterceptor(new MediaStatusInterceptor() { @Override public void intercept(MediaStatusWriter mediaStatusWriter) { // Perform customization. mediaStatusWriter.setCustomData(new JSONObject("{data: \"my Hello\"}")); } });
ব্যবহারকারীর পরিচয়পত্র পরিচালনা করা
আপনার অ্যান্ড্রয়েড টিভি অ্যাপটি হয়তো শুধুমাত্র নির্দিষ্ট কিছু ব্যবহারকারীকে অ্যাপ সেশন চালু করতে বা তাতে যোগ দিতে অনুমতি দিতে পারে। উদাহরণস্বরূপ, একজন প্রেরককে শুধুমাত্র তখনই অ্যাপ সেশন চালু করতে বা তাতে যোগ দিতে অনুমতি দিন, যদি:
- প্রেরক অ্যাপটি এটিভি অ্যাপের মতো একই অ্যাকাউন্ট এবং প্রোফাইলে লগ ইন করা আছে।
- প্রেরক অ্যাপটি একই অ্যাকাউন্টে লগ ইন করা আছে, কিন্তু এটিভি অ্যাপের থেকে ভিন্ন প্রোফাইলে।
যদি আপনার অ্যাপ একাধিক বা বেনামী ব্যবহারকারীকে সামলাতে পারে, তবে আপনি যেকোনো অতিরিক্ত ব্যবহারকারীকে ATV সেশনে যোগদানের অনুমতি দিতে পারেন। যদি ব্যবহারকারী তার পরিচয়পত্র প্রদান করে, তবে আপনার ATV অ্যাপকে সেই পরিচয়পত্রগুলো পরিচালনা করতে হবে, যাতে তার অগ্রগতি এবং অন্যান্য ব্যবহারকারীর ডেটা সঠিকভাবে ট্র্যাক করা যায়।
যখন আপনার প্রেরক অ্যাপটি আপনার অ্যান্ড্রয়েড টিভি অ্যাপ চালু করে বা তাতে যোগদান করে, তখন প্রেরক অ্যাপটির উচিত সেশনে যোগদানকারী ব্যক্তির পরিচয়পত্র প্রদান করা।
কোনো প্রেরক আপনার অ্যান্ড্রয়েড টিভি অ্যাপ চালু করে তাতে যোগ দেওয়ার আগে, প্রেরকের ক্রেডেনশিয়ালগুলো অনুমোদিত কিনা তা দেখার জন্য আপনি একটি লঞ্চ চেকার নির্দিষ্ট করে দিতে পারেন। যদি তা না হয়, তাহলে কাস্ট কানেক্ট এসডিকে আপনার ওয়েব রিসিভারটি চালু করার বিকল্প ব্যবস্থা গ্রহণ করে।
প্রেরক অ্যাপ লঞ্চ ক্রেডেনশিয়াল ডেটা
প্রেরকের দিকে, সেশনে কে যোগদান করছে তা বোঝানোর জন্য আপনি CredentialsData নির্দিষ্ট করতে পারেন।
credentials হলো একটি স্ট্রিং যা ব্যবহারকারী দ্বারা সংজ্ঞায়িত করা যেতে পারে, যতক্ষণ পর্যন্ত আপনার এটিভি অ্যাপ এটি বুঝতে পারে। credentialsType নির্ধারণ করে যে CredentialsData কোন প্ল্যাটফর্ম থেকে আসছে অথবা এটি একটি কাস্টম মানও হতে পারে। ডিফল্টরূপে, এটি যে প্ল্যাটফর্ম থেকে পাঠানো হচ্ছে, সেই প্ল্যাটফর্মেই সেট করা থাকে।
CredentialsData শুধুমাত্র আপনার Android TV অ্যাপ চালু করার বা যোগদানের সময় পাঠানো হয়। আপনি যদি সংযুক্ত থাকা অবস্থায় এটি আবার সেট করেন, তবে এটি আপনার Android TV অ্যাপে পাঠানো হবে না। সংযুক্ত থাকা অবস্থায় যদি আপনার প্রেরক প্রোফাইল পরিবর্তন করে, তবে আপনি হয় সেশনে থাকতে পারেন, অথবা যদি আপনার মনে হয় নতুন প্রোফাইলটি সেশনের সাথে সামঞ্জস্যপূর্ণ নয়, তাহলে SessionManager.endCurrentCastSession(boolean stopCasting) কল করতে পারেন।
প্রতিটি প্রেরকের CredentialsData পেতে, CastReceiverContext এর getSenders ব্যবহার করে SenderInfo , getCastLaunchRequest() ব্যবহার করে CastLaunchRequest এবং তারপর getCredentialsData() ব্যবহার করা যেতে পারে।
play-services-cast-framework সংস্করণ 19.0.0 বা তার উচ্চতর সংস্করণ প্রয়োজন।
CastContext.getSharedInstance().setLaunchCredentialsData( CredentialsData.Builder() .setCredentials("{\"userId\": \"abc\"}") .build() )
CastContext.getSharedInstance().setLaunchCredentialsData(
new CredentialsData.Builder()
.setCredentials("{\"userId\": \"abc\"}")
.build()); এর জন্য google-cast-sdk সংস্করণ v4.8.4 বা তার উচ্চতর সংস্করণ প্রয়োজন।
Can be called anytime after the options are set: GCKCastContext.setSharedInstanceWith(options) .
GCKCastContext.sharedInstance().setLaunch( GCKCredentialsData(credentials: "{\"userId\": \"abc\"}")
ক্রোমিয়াম ব্রাউজার সংস্করণ M87 বা তার উচ্চতর সংস্করণ প্রয়োজন।
অপশনগুলো সেট করার পর যেকোনো সময় কল করা যেতে পারে: cast.framework.CastContext.getInstance().setOptions(options); ।
let credentialsData = new chrome.cast.CredentialsData("{\"userId\": \"abc\"}"); cast.framework.CastContext.getInstance().setLaunchCredentialsData(credentialsData);
এটিভি লঞ্চ অনুরোধ পরীক্ষক বাস্তবায়ন করা হচ্ছে
যখন কোনো প্রেরক অ্যাপ চালু করতে বা যোগদান করতে চেষ্টা করে, তখন CredentialsData আপনার Android TV অ্যাপে পাঠানো হয়। এই অনুরোধটি অনুমোদন বা প্রত্যাখ্যান করার জন্য আপনি একটি LaunchRequestChecker প্রয়োগ করতে পারেন।
যদি কোনো অনুরোধ প্রত্যাখ্যান করা হয়, তাহলে এটিভি অ্যাপে সরাসরি চালু হওয়ার পরিবর্তে ওয়েব রিসিভার লোড হয়। যদি আপনার এটিভি চালু বা যোগদানের অনুরোধকারী ব্যবহারকারীকে সামলাতে না পারে, তবে আপনার অনুরোধটি প্রত্যাখ্যান করা উচিত। উদাহরণস্বরূপ, অনুরোধকারী ব্যবহারকারীর পরিবর্তে অন্য কোনো ব্যবহারকারী এটিভি অ্যাপে লগ ইন করা আছেন এবং আপনার অ্যাপটি ক্রেডেনশিয়াল পরিবর্তনের বিষয়টি সামলাতে পারছে না, অথবা বর্তমানে এটিভি অ্যাপে কোনো ব্যবহারকারী লগ ইন করা নেই।
অনুরোধটি অনুমোদিত হলে, ATV অ্যাপটি চালু হয়। কোনো ব্যবহারকারী ATV অ্যাপে লগ ইন করা না থাকলে অথবা ব্যবহারকারীর মধ্যে অমিল থাকলে, আপনার অ্যাপটি লোড রিকোয়েস্ট পাঠাতে সমর্থন করে কি না, তার উপর নির্ভর করে আপনি এই আচরণটি কাস্টমাইজ করতে পারেন। এই আচরণটি LaunchRequestChecker এ সম্পূর্ণরূপে কাস্টমাইজযোগ্য।
CastReceiverOptions.LaunchRequestChecker ইন্টারফেসটি ইমপ্লিমেন্ট করে এমন একটি ক্লাস তৈরি করুন:
class MyLaunchRequestChecker : LaunchRequestChecker { override fun checkLaunchRequestSupported(launchRequest: CastLaunchRequest): Task{ return Tasks.call { myCheckLaunchRequest( launchRequest ) } } } private fun myCheckLaunchRequest(launchRequest: CastLaunchRequest): Boolean { val credentialsData = launchRequest.getCredentialsData() ?: return false // or true if you allow anonymous users to join. // The request comes from a mobile device, e.g. checking user match. return if (credentialsData.credentialsType == CredentialsData.CREDENTIALS_TYPE_ANDROID) { myCheckMobileCredentialsAllowed(credentialsData.getCredentials()) } else false // Unrecognized credentials type. }
public class MyLaunchRequestChecker implements CastReceiverOptions.LaunchRequestChecker { @Override public TaskcheckLaunchRequestSupported(CastLaunchRequest launchRequest) { return Tasks.call(() -> myCheckLaunchRequest(launchRequest)); } } private boolean myCheckLaunchRequest(CastLaunchRequest launchRequest) { CredentialsData credentialsData = launchRequest.getCredentialsData(); if (credentialsData == null) { return false; // or true if you allow anonymous users to join. } // The request comes from a mobile device, e.g. checking user match. if (credentialsData.getCredentialsType().equals(CredentialsData.CREDENTIALS_TYPE_ANDROID)) { return myCheckMobileCredentialsAllowed(credentialsData.getCredentials()); } // Unrecognized credentials type. return false; }
তারপর আপনার ReceiverOptionsProvider এ এটি সেট করুন:
class MyReceiverOptionsProvider : ReceiverOptionsProvider { override fun getOptions(context: Context?): CastReceiverOptions { return CastReceiverOptions.Builder(context) ... .setLaunchRequestChecker(MyLaunchRequestChecker()) .build() } }
public class MyReceiverOptionsProvider implements ReceiverOptionsProvider { @Override public CastReceiverOptions getOptions(Context context) { return new CastReceiverOptions.Builder(context) ... .setLaunchRequestChecker(new MyLaunchRequestChecker()) .build(); } }
LaunchRequestChecker এ true নির্বাচন করলে ATV অ্যাপ চালু হয় এবং false নির্বাচন করলে আপনার Web Receiver অ্যাপ চালু হয়।
কাস্টম বার্তা পাঠানো ও গ্রহণ করা
Cast প্রোটোকল আপনাকে প্রেরক এবং আপনার প্রাপক অ্যাপ্লিকেশনের মধ্যে কাস্টম স্ট্রিং বার্তা পাঠাতে দেয়। আপনার CastReceiverContext ইনিশিয়ালাইজ করার আগে, বার্তা পাঠানোর জন্য আপনাকে অবশ্যই একটি নেমস্পেস (চ্যানেল) রেজিস্টার করতে হবে।
অ্যান্ড্রয়েড টিভি—কাস্টম নেমস্পেস নির্দিষ্ট করুন
সেটআপের সময় আপনাকে আপনার CastReceiverOptions এ সমর্থিত নেমস্পেসগুলি নির্দিষ্ট করতে হবে:
class MyReceiverOptionsProvider : ReceiverOptionsProvider { override fun getOptions(context: Context?): CastReceiverOptions { return CastReceiverOptions.Builder(context) .setCustomNamespaces( Arrays.asList("urn:x-cast:com.example.cast.mynamespace") ) .build() } }
public class MyReceiverOptionsProvider implements ReceiverOptionsProvider { @Override public CastReceiverOptions getOptions(Context context) { return new CastReceiverOptions.Builder(context) .setCustomNamespaces( Arrays.asList("urn:x-cast:com.example.cast.mynamespace")) .build(); } }
অ্যান্ড্রয়েড টিভি—বার্তা পাঠানো
// If senderId is null, then the message is broadcasted to all senders. CastReceiverContext.getInstance().sendMessage( "urn:x-cast:com.example.cast.mynamespace", senderId, customString)
// If senderId is null, then the message is broadcasted to all senders. CastReceiverContext.getInstance().sendMessage( "urn:x-cast:com.example.cast.mynamespace", senderId, customString);
অ্যান্ড্রয়েড টিভি—কাস্টম নেমস্পেস বার্তা গ্রহণ করুন
class MyCustomMessageListener : MessageReceivedListener { override fun onMessageReceived( namespace: String, senderId: String?, message: String ) { ... } } CastReceiverContext.getInstance().setMessageReceivedListener( "urn:x-cast:com.example.cast.mynamespace", new MyCustomMessageListener());
class MyCustomMessageListener implements CastReceiverContext.MessageReceivedListener { @Override public void onMessageReceived( String namespace, String senderId, String message) { ... } } CastReceiverContext.getInstance().setMessageReceivedListener( "urn:x-cast:com.example.cast.mynamespace", new MyCustomMessageListener());