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

1. نظرة عامة

شعار Google Cast

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

ما هو Google Cast وCast Connect؟

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

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

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

ما الذي سننشئه؟

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

المُعطيات

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

المتطلبات

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

يقدّم التطبيق قائمة بالفيديوهات ليتصفّحها المستخدم. يمكن للمستخدمين اختيار فيديو لتشغيله على 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 عبارة عن كائن مفردة المنتصف لتنسيق جميع تفاعلات البث. يجب تنفيذ واجهة 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- إتاحة طلبات التحكّم في البث

يتيح التطبيق الحالي الآن الأوامر الأساسية المتوافقة مع جلسة وسائط، مثل التشغيل والإيقاف المؤقّت والتقديم/الترجيع. ومع ذلك، هناك بعض أوامر التحكم في البث غير متوفرة في جلسة الوسائط. يجب تسجيل 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.