تفعيل تطبيق Android TV لبثّ المحتوى

1- نظرة عامة

شعار Google Cast

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

ما هو Google Cast وGoogle Cast Connect؟

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

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

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

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

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

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

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

المتطلبات

2. الحصول على الرمز النموذجي

يمكنك تنزيل جميع الرموز النموذجية على الكمبيوتر...

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

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

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

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

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

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

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

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

تثبيت تطبيق المُرسِل على Android

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

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

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

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

صورة لتطبيق مُرسِل فيديوهات البث قيد التشغيل على شاشة هاتف Android

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

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

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

لنلعب تطبيق Cast Connect باستخدام تطبيق ATV.

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

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

4. تجهيز المشروع لبدء المشروع

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

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

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

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

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

MainActivity

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

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

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

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 من جهاز البث الذي يعمل بتكنولوجيا Google Cast، اختَر نشاطًا تريد تشغيله. في هذا الدرس التطبيقي حول الترميز، سنُشغِّل 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;تشغيل&quot; في &quot;استوديو Android&quot;، وهو مثلث أخضر يشير إلى اليمينRun (تشغيل) لنشر التطبيق على جهاز ATV، ثم أغلِق التطبيق ثم ارجع إلى الشاشة الرئيسية ATV. من المرسِل، انقر على زر البث رمز زر البث واختَر جهاز ATV. سيظهر لك تشغيل تطبيق ATV على جهاز ATV وأنّ حالة زر البثّ متصل.

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

يتم إرسال أمر "load" عن طريق أمر intent مع اسم الحزمة الذي حددته في وحدة تحكم المطور. يجب إضافة فلتر الأهداف المحدّد مسبقًا التالي في تطبيق Android TV لتحديد النشاط المستهدف الذي سيتلقّى هذا الهدف. في ملف 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

بعد أن تمّ ضبط النشاط لتلقّي هذا الغرض الذي يحتوي على طلب تحميل، سنحتاج إلى معالجته.

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

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;تشغيل&quot; في &quot;استوديو Android&quot;، وهو مثلث أخضر يشير إلى اليمينRun (تشغيل) لنشر التطبيق على جهاز 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
        })
    }
}

اعتراض حالة الوسائط قبل الإرسال

كما هي الحال في 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 باستخدام مكتبة Cast Connect.

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