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

1- نظرة عامة

شعار Google Cast

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

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

المتطلبات

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

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

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

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

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

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

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

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

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

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

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

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

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

صورة نافذة طرفية تنفِّذ أمر تثبيت أداة adb لتثبيت mobile-sender.jpg

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

يتم إرسال أمر التحميل من خلال هدف يتضمن اسم الحزمة الذي حددته في Play Console. يجب إضافة فلتر الأهداف المحدّد مسبقًا التالي في تطبيق 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 للتعامل مع 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; مثلث أخضر يشير إلى اليمين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/docs/android_tv_ ستتلقىr.