تفعيل تطبيق البث من خلال Android TV

1- نظرة عامة

شعار Google Cast

سيعلّمك هذا الدرس التطبيقي حول الترميز كيفية تعديل تطبيق حالي على Android TV لإتاحة الإرسال والتواصل من تطبيقات الإرسال الحالية.

ما المقصود بتكنولوجيا Google Cast وCast Connect؟

يتيح Google Cast للمستخدمين إرسال المحتوى من جهاز جوّال إلى جهاز تلفزيون. تتألف جلسة Google Cast النموذجية من مكوّنين هما: المرسل وتطبيق المستلم. تبدأ تطبيقات المُرسِل، مثل تطبيق الجوّال أو موقع ويب، مثل YouTube.com، في تشغيل تطبيق مستقبِل Cast والتحكم فيه. تطبيقات جهاز استقبال الإرسال هي تطبيقات HTML 5 التي تعمل على أجهزة Chromecast وAndroid TV.

يتم تخزين كل أجزاء الحالة تقريبًا في جلسة الإرسال على تطبيق المستقبِل. عند تحديث الحالة، على سبيل المثال في حالة تحميل عنصر وسائط جديد، يتم بث حالة الوسائط لجميع المرسلين. تحتوي عمليات البث هذه على الحالة الحالية لجلسة البث. تستخدم تطبيقات المرسل حالة الوسائط هذه لعرض معلومات التشغيل في واجهة المستخدم.

يعتمد Cast Cast على هذه البنية الأساسية، حيث يعمل تطبيق Android TV كجهاز استقبال. تسمح مكتبة Cast Connect لتطبيق Android TV بتلقي الرسائل وبث حالة الوسائط كما لو كانت تطبيقًا لجهاز استقبال البث.

ما الذي سنبنيه؟

عند الانتهاء من هذا الدرس التطبيقي حول الترميز، ستتمكّن من استخدام تطبيقات "إرسال الإرسال" لإرسال الفيديوهات إلى تطبيق Android TV. ويمكن أيضًا لتطبيق Android TV التواصل مع تطبيقات المُرسِل من خلال بروتوكول الإرسال.

ما ستتعرَّف عليه

  • كيفية إضافة مكتبة Cast Connect إلى نموذج تطبيق ATV.
  • كيفية توصيل مُرسِل Cast وتشغيل تطبيق ATV.
  • كيفية بدء تشغيل الوسائط على تطبيق ATV من تطبيق "إرسال الإرسال".
  • كيفية إرسال حالة الوسائط من تطبيق ATV إلى تطبيقات "إرسال المُرسِل".

المتطلبات

2- الحصول على نموذج الشفرة

يمكنك تنزيل كل نماذج الشفرة إلى جهاز الكمبيوتر...

وفكّ ضغط الملف المضغوط الذي تم تنزيله.

3. تشغيل نموذج التطبيق

لنرى أولاً كيف يبدو نموذج التطبيق المكتمل. يستخدم تطبيق Android TV واجهة مستخدم Leanback ومشغل الفيديو الأساسي. ويمكن للمستخدم اختيار فيديو من قائمة يتم تشغيلها بعد ذلك على التلفزيون عند اختياره. وباستخدام تطبيق المُرسِل المتوافق مع الأجهزة الجوّالة، يمكن للمستخدم أيضًا إرسال فيديو إلى تطبيق Android TV.

صورة لسلسلة من الصور المصغّرة للفيديو (يتم تمييز إحداها) تظهر على سطح الفيديو في وضع معاينة الفيديو، وتظهر الكلمات "Cast Cast" في الجزء العلوي الأيسر

تسجيل أجهزة مطوّري البرامج

لتفعيل إمكانات Cast Connect لتطوير التطبيقات، يجب تسجيل الرقم التسلسلي لـ Chromecast المدمج في جهاز Android TV الذي ستستخدمه في وحدة تحكم مطوّري برامج Cast. يمكنك العثور على الرقم التسلسلي من خلال الانتقال إلى الإعدادات > الإعدادات المفضّلة للجهاز > Chromecast Built-in > الرقم التسلسلي على Android TV. لاحظ أن هذا الرقم يختلف عن الرقم التسلسلي للجهاز الفعلي ويجب الحصول عليه من الطريقة الموضحة أعلاه.

صورة لشاشة Android TV تعرض شاشة "Chromecast Built-in" ورقم الإصدار والرقم التسلسلي

بدون التسجيل، لن يعمل Cast Connect إلا للتطبيقات التي تم تثبيتها من متجر Google Play لأسباب أمنية. بعد 15 دقيقة من بدء عملية التسجيل، أعد تشغيل الجهاز.

تثبيت تطبيق المُرسِل الذي يعمل بنظام التشغيل Android

لاختبار إرسال الطلبات من جهاز جوّال، قدّمنا تطبيقًا بسيطًا للمُرسِل يُسمى "إرسال الفيديوهات" كملف mobile-sender-0629.apk في ملف zip للرمز المصدر. سنستفيد من ADB لتثبيت ملف APK. وإذا سبق لك تثبيت إصدار مختلف من مقاطع فيديو Cast، فالرجاء إزالة هذا الإصدار من جميع الملفات الشخصية الموجودة على الجهاز قبل المتابعة.

  1. مكِّن خيارات المطورين وتصحيح أخطاء USB على هاتف Android.
  2. وصِّل كابل بيانات USB لتوصيل هاتف Android بكمبيوتر التطوير.
  3. ثبِّت mobile-sender-0629.apk على هاتف Android.

صورة لنافذة طرفية تُشغِّل أمر adb install لتثبيت mobile-sender.apk

  1. يمكنك العثور على تطبيق المُرسِل إرسال الفيديوهات على هاتف Android. رمز تطبيق المُرسِل للفيديوهات

صورة لتطبيق "إرسال الفيديوهات" الذي يعمل على شاشة هاتف Android

تثبيت تطبيق Android TV

توضح التعليمات التالية كيفية فتح نموذج التطبيق المكتمل وتشغيله في Android Studio:

  1. حدد استيراد المشروع على شاشة الترحيب أو خيارات القائمة ملف > جديد > استيراد المشروع....
  2. اختَر الدليل رمز المجلدapp-done من مجلد الرمز النموذجي وانقر على "حسنًا".
  3. انقر على ملف > مشروع مزامنة "استوديو تطبيقات Android" مع زر Gradle مزامنة المشروع مع ملفات Gradle.
  4. مكِّن خيارات المطورين وتصحيح أخطاء USB على جهاز Android TV.
  5. يمكنك توصيل ADB مع جهاز Android TV، ومن المفترض أن يظهر الجهاز في Android Studio. صورة تعرض جهاز Android TV الذي يظهر في شريط أدوات Android Studio
  6. انقر على الزر زر تشغيل استوديو Android، مثلث أخضر يشير إلى اليمينتشغيل، من المفترض أن يظهر تطبيق ATV الذي يحمل اسم Cast Connect Codelab بعد بضع ثوانٍ.

هيا نشغِّل Cast Connect باستخدام تطبيق ATV

  1. انتقل إلى شاشة Android TV الرئيسية.
  2. افتح تطبيق مُرسِل فيديوهات Cast من هاتفك الذي يعمل بنظام التشغيل Android. انقر على زر الإرسال رمز زر الإرسال واختَر جهاز ATV.
  3. سيتم تشغيل تطبيق Cast Code Codelab ATV على جهاز ATV، وسيشير زر الإرسال في المُرسِل إلى أنّه متّصل بـ رمز زر الإرسال مع قلب الألوان.
  4. اختَر فيديو من تطبيق ATV وسيبدأ تشغيل الفيديو على ATV.
  5. على هاتفك الجوّال، تظهر الآن وحدة تحكّم مصغّرة في الجزء السفلي من تطبيق المُرسِل. ويمكنك استخدام زر التشغيل/الإيقاف المؤقت للتحكم في التشغيل.
  6. اختَر فيديو من الهاتف الجوّال وشغِّله. سيبدأ تشغيل الفيديو على ATV وسيتم عرض وحدة التحكم الموسعة على مرسل الجوال.
  7. يمكنك قفل هاتفك وعند فتح قفله، من المفترض أن ترى إشعارًا على شاشة القفل للتحكم في تشغيل الوسائط أو إيقاف الإرسال.

صورة لقسم من شاشة هاتف Android مع مشغّل مصغّر يشغّل فيديو

4. إعداد المشروع الافتتاحي

الآن وبعد التحقُّق من دمج Cast Connect المكتمل للتطبيق، علينا إضافة الدعم إلى Cast Connect إلى التطبيق الذي تم تنزيله. أصبحت الآن جاهزًا للبدء في إنجاز المشروع الأول باستخدام Android Studio:

  1. حدد استيراد المشروع على شاشة الترحيب أو خيارات القائمة ملف > جديد > استيراد المشروع....
  2. اختَر الدليل رمز المجلدapp-start من مجلد الرمز النموذجي وانقر على "حسنًا".
  3. انقر على ملف > مشروع مزامنة "استوديو Android" مع زر Gradle مزامنة المشروع مع ملفات Gradle.
  4. اختَر جهاز ATV وانقر على الزر زر التشغيل في "استوديو Android" على شكل مثلث أخضر يشير إلى اليمينتشغيل لتشغيل التطبيق واستكشاف واجهة المستخدم. شريط أدوات Android Studio يعرض جهاز Android TV الذي تم اختياره

صورة لسلسلة من الصور المصغّرة للفيديو (يتم تمييز إحداها) تظهر على سطح الفيديو في وضع معاينة الفيديو، وتظهر الكلمات "Cast Cast" في الجزء العلوي الأيسر

تصميم التطبيقات

يوفر التطبيق قائمة بمقاطع الفيديو التي يمكن للمستخدم تصفحها. يمكن للمستخدمين اختيار فيديو لتشغيله على Android TV. يتكون التطبيق من نشاطين أساسيين: MainActivity وPlaybackActivity.

MainActivity

يحتوي هذا النشاط على جزء (MainFragment). تم ضبط قائمة الفيديوهات والبيانات الوصفية المرتبطة بها في فئة MovieList، ويتم استدعاء طريقة setupMovies() لإنشاء قائمة تحتوي على Movie كائنات.

يشير الكائن Movie إلى كيان فيديو يتضمّن عنوانًا ووصفًا وصورًا مصغّرة رائعة وعنوان URL للفيديو. يتم ربط كل عنصر Movie بـ CardPresenter لتقديم صورة مصغّرة للفيديو مع عنوان واستوديو وتمريرها إلى ArrayObjectAdapter.

عند اختيار عنصر، يتم تمرير الكائن Movie المقابل إلى PlaybackActivity.

نشاط التشغيل

يتضمن هذا النشاط جزءًا (PlaybackVideoFragment) يستضيف VideoView مع ExoPlayer، وبعض عناصر التحكّم في الوسائط، ومساحة نصية لعرض وصف الفيديو المختار، ويسمح للمستخدم بتشغيل الفيديو على Android TV. ويمكن للمستخدم استخدام وحدة التحكم عن بُعد لتشغيل مقاطع الفيديو أو إيقافها مؤقتًا أو طلب تشغيل مقاطع الفيديو.

المتطلبات الأساسية لجهاز Cast Connect

يستخدم Cast Connect إصدارات جديدة من خدمات Google Play تتطلب تحديث تطبيق ATV لكي يستخدم مساحة الاسم AndroidX.

لإتاحة استخدام Cast Connect في تطبيق Android TV، يجب إنشاء أحداث من جلسة وسائط وتقديم الدعم لها. تنشئ مكتبة Cast Connect حالة الوسائط استنادًا إلى حالة جلسة الوسائط. ويتم أيضًا استخدام جلسة الوسائط من خلال مكتبة Cast Connect للإشارة إلى أنها تلقت رسائل معينة من أحد المُرسِلين، مثل الإيقاف المؤقت.

5. تهيئة دعم الإرسال

العناصر التابعة

يُرجى تحديث ملف التطبيق build.gradle لتضمين تبعيات المكتبة اللازمة:

dependencies {
    ....

    // Cast Connect libraries
    implementation 'com.google.android.gms:play-services-cast-tv:20.0.0'
    implementation 'com.google.android.gms:play-services-cast:21.1.0'
}

عليك مزامنة المشروع للتأكّد من إنشاء المشروع بدون أخطاء.

الإعداد

CastReceiverContext هي كائن فردي لتنسيق جميع تفاعلات الإرسال. يجب تنفيذ واجهة ReceiverOptionsProvider لتوفير CastReceiverOptions عند إعداد CastReceiverContext.

أنشئ ملف CastReceiverOptionsProvider.kt وأضِف الصف التالي إلى المشروع:

package com.google.sample.cast.castconnect

import android.content.Context
import com.google.android.gms.cast.tv.ReceiverOptionsProvider
import com.google.android.gms.cast.tv.CastReceiverOptions

class CastReceiverOptionsProvider : ReceiverOptionsProvider {
    override fun getOptions(context: Context): CastReceiverOptions {
        return CastReceiverOptions.Builder(context)
                .setStatusText("Cast Connect Codelab")
                .build()
    }
}

بعد ذلك، حدِّد موفِّر خيارات المستلِم ضمن علامة <application> في ملف AndroidManifest.xml للتطبيق:

<application>
  ...
  <meta-data
    android:name="com.google.android.gms.cast.tv.RECEIVER_OPTIONS_PROVIDER_CLASS_NAME"
    android:value="com.google.sample.cast.castconnect.CastReceiverOptionsProvider" />
</application>

لربط تطبيق ATV من مُرسِل الإرسال، اختَر نشاطًا تريد تشغيله. في هذا الدرس التطبيقي حول الترميز، سنشغّل MainActivity من التطبيق عند بدء جلسة "إرسال". في ملف AndroidManifest.xml، أضِف فلتر الرغبة في الإطلاق في MainActivity.

<activity android:name=".MainActivity">
  ...
  <intent-filter>
    <action android:name="com.google.android.gms.cast.tv.action.LAUNCH" />
    <category android:name="android.intent.category.DEFAULT" />
  </intent-filter>
</activity>

دورة حياة سياق جهاز استقبال البث

يجب أن تبدأ CastReceiverContext عند تشغيل تطبيقك وإيقاف CastReceiverContext عند نقل تطبيقك إلى الخلفية. نقترح استخدام LifecycleObserver من مكتبة androidx.lifecycle لإدارة الاتصال بـ CastReceiverContext.start() وCastReceiverContext.stop()

افتح ملف MyApplication.kt، وهيئ سياق البث من خلال استدعاء initInstance() في طريقة onCreate للتطبيق. في الفئة AppLifeCycleObserver start()، CastReceiverContext عند استئناف التطبيق وstop() عند إيقاف التطبيق مؤقتًا:

package com.google.sample.cast.castconnect

import com.google.android.gms.cast.tv.CastReceiverContext
...

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        CastReceiverContext.initInstance(this)
        ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifecycleObserver())
    }

    class AppLifecycleObserver : DefaultLifecycleObserver {
        override fun onResume(owner: LifecycleOwner) {
            Log.d(LOG_TAG, "onResume")
            CastReceiverContext.getInstance().start()
        }

        override fun onPause(owner: LifecycleOwner) {
            Log.d(LOG_TAG, "onPause")
            CastReceiverContext.getInstance().stop()
        }
    }
}

ربط MediaSession بحساب MediaManager

MediaManager هي خاصية من النوع CastReceiverContext، وتدير حالة الوسائط وتعالج القصد من التحميل وتترجم رسائل مساحة الاسم للوسائط من المرسلين إلى أوامر الوسائط وترسل حالة الوسائط مرة أخرى إلى المرسلين.

عند إنشاء MediaSession، عليك أيضًا تقديم الرمز المميّز الحالي لـ MediaSession إلى MediaManager حتى يعرف الموقع الذي يجب إرسال الأوامر فيه واسترداد حالة تشغيل الوسائط. في ملف PlaybackVideoFragment.kt، تأكَّد من إعداد MediaSession قبل ضبط الرمز المميز على MediaManager.

import com.google.android.gms.cast.tv.CastReceiverContext
import com.google.android.gms.cast.tv.media.MediaManager
...

class PlaybackVideoFragment : VideoSupportFragment() {
    private var castReceiverContext: CastReceiverContext? = null
    ...

    private fun initializePlayer() {
        if (mPlayer == null) {
            ...
            mMediaSession = MediaSessionCompat(getContext(), LOG_TAG)
            ...
            castReceiverContext = CastReceiverContext.getInstance()
            if (castReceiverContext != null) {
                val mediaManager: MediaManager = castReceiverContext!!.getMediaManager()
                mediaManager.setSessionCompatToken(mMediaSession!!.getSessionToken())
            }

        }
    }
}

عند إصدار MediaSession بسبب تشغيل غير نشط، يجب ضبط رمز مميز خالٍ على MediaManager:

private fun releasePlayer() {
    mMediaSession?.release()
    castReceiverContext?.mediaManager?.setSessionCompatToken(null)
    ...
}

لنبدأ تشغيل نموذج التطبيق

انقر على الزر زر التشغيل في &quot;استوديو Android&quot; على شكل مثلث أخضر يشير إلى اليمينتشغيل لنشر التطبيق على جهاز ATV، ثم أغلِق التطبيق وعُد إلى الشاشة الرئيسية ATV. من المُرسِل، انقر على زر الإرسال رمز زر الإرسال واختَر جهاز ATV. سيظهر لك أنّه تمّ تشغيل تطبيق ATV على جهاز ATV وأنّ حالة زر الإرسال متصلة.

6. جارٍ تحميل الوسائط

يتم إرسال أمر التحميل عبر intent باسم الحزمة الذي حدّدته في وحدة تحكم مطوّري البرامج. يجب إضافة فلتر الأهداف المحدّد مسبقًا التالي في تطبيق Android TV لتحديد النشاط المستهدف الذي سيتلقّى هدف intent هذا. في ملف AndroidManifest.xml، أضِف فلتر أهداف التحميل إلى PlayerActivity:

<activity android:name="com.google.sample.cast.castconnect.PlaybackActivity"
          android:launchMode="singleTask"
          android:exported="true">
  <intent-filter>
     <action android:name="com.google.android.gms.cast.tv.action.LOAD"/>
     <category android:name="android.intent.category.DEFAULT" />
  </intent-filter>
</activity>

التعامل مع طلبات التحميل على Android TV

الآن وبعد تهيئة النشاط لاستلام هذه intent التي تحتوي على طلب تحميل، سنحتاج إلى التعامل معه.

يستدعي التطبيق طريقة خاصة تسمى processIntent عند بدء النشاط. تحتوي هذه الطريقة على منطق معالجة الأهداف الواردة. لمعالجة طلب التحميل، سنعدّل هذه الطريقة ونرسل intent إلى مزيد من المعالجة من خلال استدعاء طريقة onNewIntent لمثيل MediaManager. إذا اكتشف MediaManager أن الهدف هو طلب تحميل، فإنه يستخرج الكائن MediaLoadRequestData من intent ويطلب MediaLoadCommandCallback.onLoad(). عدّل طريقة processIntent في ملف PlaybackVideoFragment.kt للتعامل مع intent التي تحتوي على طلب التحميل:

fun processIntent(intent: Intent?) {
    val mediaManager: MediaManager = CastReceiverContext.getInstance().getMediaManager()
    // Pass intent to Cast SDK
    if (mediaManager.onNewIntent(intent)) {
        return
    }

    // Clears all overrides in the modifier.
    mediaManager.getMediaStatusModifier().clear()

    // If the SDK doesn't recognize the intent, handle the intent with your own logic.
    ...
}

بعد ذلك سيتم تمديد الفئة المجردة MediaLoadCommandCallback والتي ستلغي طريقة onLoad() التي تستدعيها MediaManager. تتلقّى هذه الطريقة بيانات طلب التحميل وتحوّلها إلى عنصر Movie. وبعد التحويل، يتم تشغيل الفيلم بواسطة المشغل المحلي. يتم بعد ذلك تحديث MediaManager من خلال MediaLoadRequest وبث MediaStatus إلى المرسِلين المتصلين. أنشئ فئة خاصة متداخلة تسمى MyMediaLoadCommandCallback في الملف PlaybackVideoFragment.kt:

import com.google.android.gms.cast.MediaLoadRequestData
import com.google.android.gms.cast.MediaInfo
import com.google.android.gms.cast.MediaMetadata
import com.google.android.gms.cast.MediaError
import com.google.android.gms.cast.tv.media.MediaException
import com.google.android.gms.cast.tv.media.MediaCommandCallback
import com.google.android.gms.cast.tv.media.QueueUpdateRequestData
import com.google.android.gms.cast.tv.media.MediaLoadCommandCallback
import com.google.android.gms.tasks.Task
import com.google.android.gms.tasks.Tasks
import android.widget.Toast
...

private inner class MyMediaLoadCommandCallback :  MediaLoadCommandCallback() {
    override fun onLoad(
        senderId: String?, mediaLoadRequestData: MediaLoadRequestData): Task<MediaLoadRequestData> {
        Toast.makeText(activity, "onLoad()", Toast.LENGTH_SHORT).show()
        return if (mediaLoadRequestData == null) {
            // Throw MediaException to indicate load failure.
            Tasks.forException(MediaException(
                MediaError.Builder()
                    .setDetailedErrorCode(MediaError.DetailedErrorCode.LOAD_FAILED)
                    .setReason(MediaError.ERROR_REASON_INVALID_REQUEST)
                    .build()))
        } else Tasks.call {
            play(convertLoadRequestToMovie(mediaLoadRequestData)!!)
            // Update media metadata and state
            val mediaManager = castReceiverContext!!.mediaManager
            mediaManager.setDataFromLoad(mediaLoadRequestData)
            mediaLoadRequestData
        }
    }
}

private fun convertLoadRequestToMovie(mediaLoadRequestData: MediaLoadRequestData?): Movie? {
    if (mediaLoadRequestData == null) {
        return null
    }
    val mediaInfo: MediaInfo = mediaLoadRequestData.getMediaInfo() ?: return null
    var videoUrl: String = mediaInfo.getContentId()
    if (mediaInfo.getContentUrl() != null) {
        videoUrl = mediaInfo.getContentUrl()
    }
    val metadata: MediaMetadata = mediaInfo.getMetadata()
    val movie = Movie()
    movie.videoUrl = videoUrl
    movie.title = metadata?.getString(MediaMetadata.KEY_TITLE)
    movie.description = metadata?.getString(MediaMetadata.KEY_SUBTITLE)
    if(metadata?.hasImages() == true) {
        movie.cardImageUrl = metadata.images[0].url.toString()
    }
    return movie
}

الآن بعد أن تم تحديد معاودة الاتصال، نحتاج إلى تسجيلها في MediaManager. يجب تسجيل معاودة الاتصال قبل استدعاء MediaManager.onNewIntent(). إضافة setMediaLoadCommandCallback عند إعداد المشغّل:

private fun initializePlayer() {
    if (mPlayer == null) {
        ...
        mMediaSession = MediaSessionCompat(getContext(), LOG_TAG)
        ...
        castReceiverContext = CastReceiverContext.getInstance()
        if (castReceiverContext != null) {
            val mediaManager: MediaManager = castReceiverContext.getMediaManager()
            mediaManager.setSessionCompatToken(mMediaSession.getSessionToken())
            mediaManager.setMediaLoadCommandCallback(MyMediaLoadCommandCallback())
        }
    }
}

لنبدأ تشغيل نموذج التطبيق

انقر على الزر زر التشغيل في &quot;استوديو Android&quot; على شكل مثلث أخضر يشير إلى اليمينتشغيل لنشر التطبيق على جهاز ATV. من المُرسِل، انقر على زر الإرسال رمز زر الإرسال واختَر جهاز ATV. سيتم تشغيل تطبيق ATV على جهاز ATV. اختَر فيديو على جهاز جوّال، وسيبدأ تشغيل الفيديو على ATV. تحقق مما إذا كنت تتلقى إشعارًا على هاتفك يتضمن عناصر التحكم في التشغيل. حاوِل استخدام عناصر التحكّم مثل الإيقاف المؤقت، ويجب إيقاف الفيديو مؤقتًا على جهاز ATV.

7. دعم أوامر التحكم في الإرسال

يتوافق التطبيق الحالي الآن مع الأوامر الأساسية التي تتوافق مع جلسة الوسائط، مثل التشغيل والإيقاف المؤقت والبحث. ومع ذلك، لا تتوفّر بعض أوامر التحكّم في البث في جلسة الوسائط. عليك تسجيل MediaCommandCallback لدعم أوامر التحكّم في البث هذه.

إضافة MyMediaCommandCallback إلى المثيل MediaManager باستخدام setMediaCommandCallback عند إعداد المشغّل:

private fun initializePlayer() {
    ...
    castReceiverContext = CastReceiverContext.getInstance()
    if (castReceiverContext != null) {
        val mediaManager = castReceiverContext!!.mediaManager
        ...
        mediaManager.setMediaCommandCallback(MyMediaCommandCallback())
    }
}

يمكنك إنشاء فئة MyMediaCommandCallback لإلغاء الطرق، مثل onQueueUpdate() لدعم أوامر التحكّم في البث هذه:

private inner class MyMediaCommandCallback : MediaCommandCallback() {
    override fun onQueueUpdate(
        senderId: String?,
        queueUpdateRequestData: QueueUpdateRequestData
    ): Task<Void> {
        Toast.makeText(getActivity(), "onQueueUpdate()", Toast.LENGTH_SHORT).show()
        // Queue Prev / Next
        if (queueUpdateRequestData.getJump() != null) {
            Toast.makeText(
                getActivity(),
                "onQueueUpdate(): Jump = " + queueUpdateRequestData.getJump(),
                Toast.LENGTH_SHORT
            ).show()
        }
        return super.onQueueUpdate(senderId, queueUpdateRequestData)
    }
}

8. التعامل مع حالة الوسائط

تعديل حالة الوسائط

يحصل Cast Connect على حالة الوسائط الأساسية من جلسة الوسائط. لإتاحة الميزات المتقدّمة، يمكن لتطبيق Android TV تحديد خصائص إضافية للحالة وإلغائها عبر MediaStatusModifier. سيتم تشغيل MediaStatusModifier دائمًا على MediaSession التي عيّنتها في CastReceiverContext.

على سبيل المثال، لتحديد setMediaCommandSupported عند تشغيل استدعاء onLoad:

import com.google.android.gms.cast.MediaStatus
...
private class MyMediaLoadCommandCallback : MediaLoadCommandCallback() {
    fun onLoad(
        senderId: String?,
        mediaLoadRequestData: MediaLoadRequestData
    ): Task<MediaLoadRequestData> {
        Toast.makeText(getActivity(), "onLoad()", Toast.LENGTH_SHORT).show()
        ...
        return Tasks.call({
            play(convertLoadRequestToMovie(mediaLoadRequestData)!!)
            ...
            // Use MediaStatusModifier to provide additional information for Cast senders.
            mediaManager.getMediaStatusModifier()
                .setMediaCommandSupported(MediaStatus.COMMAND_QUEUE_NEXT, true)
                .setIsPlayingAd(false)
            mediaManager.broadcastMediaStatus()
            // Return the resolved MediaLoadRequestData to indicate load success.
            mediaLoadRequestData
        })
    }
}

اعتراض MediaStatus قبل الإرسال

مثل MessageInterceptor لحزمة تطوير البرامج (SDK) الخاصة بمستقبل الويب، يمكنك تحديد MediaStatusWriter في MediaManager لإجراء تعديلات إضافية على MediaStatus قبل بثه إلى المرسلين المتصلين.

على سبيل المثال، يمكنك إعداد بيانات مخصّصة في MediaStatus قبل إرسالها إلى المرسِلين على الأجهزة الجوّالة:

import com.google.android.gms.cast.tv.media.MediaManager.MediaStatusInterceptor
import com.google.android.gms.cast.tv.media.MediaStatusWriter
import org.json.JSONObject
import org.json.JSONException
...

private fun initializePlayer() {
    if (mPlayer == null) {
        ...
        if (castReceiverContext != null) {
            ...
            val mediaManager: MediaManager = castReceiverContext.getMediaManager()
            ...
            // Use MediaStatusInterceptor to process the MediaStatus before sending out.
            mediaManager.setMediaStatusInterceptor(
                MediaStatusInterceptor { mediaStatusWriter: MediaStatusWriter ->
                    try {
                        mediaStatusWriter.setCustomData(JSONObject("{myData: 'CustomData'}"))
                    } catch (e: JSONException) {
                        Log.e(LOG_TAG,e.message,e);
                    }
            })
        }
    }
}        

9. تهانينا

لقد تعرفت الآن على كيفية تفعيل تطبيق Android TV الذي يعمل بتكنولوجيا Google Cast باستخدام مكتبة Cast Connect.

ويمكنك الاطّلاع على دليل مطوّري البرامج للحصول على مزيد من التفاصيل: /cast/docs/android_tv_receiver.