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

1. نظرة عامة

شعار Google Cast

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

ما هو Google Cast و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 من تطبيق مُرسِل بث
  • كيفية إرسال حالة الوسائط من تطبيق ATV إلى تطبيقات إرسال الوسائط عبر البث

المتطلبات

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

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

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

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

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

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

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

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

صورة لشاشة Android TV تعرض شاشة "Google Cast" ورقم الإصدار والرقم التسلسلي

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

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

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

  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. انقر على ملف > زر "مزامنة المشروع مع Gradle" في "استوديو تطبيقات Android" مزامنة المشروع مع ملفات Gradle.
  4. فعِّل خيارات المطوّرين وميزة "تصحيح أخطاء الجهاز عبر USB" على جهاز Android TV.
  5. اربط جهاز Android TV بجهاز Android Debug Bridge، ومن المفترض أن يظهر الجهاز في Android Studio. صورة تعرض جهاز Android TV يظهر على شريط أدوات Android Studio
  6. انقر على الزر زر التشغيل في "استوديو Android"، وهو مثلث أخضر يشير إلى اليمينتشغيل، ومن المفترض أن يظهر تطبيق ATV باسم Cast Connect Codelab بعد بضع ثوانٍ.

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

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

صورة لجزء من شاشة هاتف Android مع مشغّل فيديو صغير

4. إعداد مشروع البدء

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

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

التبعيات

عدِّل ملف 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 هو عنصر وحيد لتنسيق جميع تفاعلات Cast. يجب تنفيذ واجهة 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. من جهاز الإرسال، انقر على زر البث رمز زر البث واختَر جهاز Android TV. سيظهر لك أنّه تم تشغيل تطبيق ATV على جهاز ATV وأنّ حالة زرّ البث متصلة.

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

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

7- إتاحة طلبات التحكّم في البث

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

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

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

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

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- تهانينا

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

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