تفعيل بث تطبيق ويب

1. نظرة عامة

شعار Google Cast

يشرح لك هذا الدرس التطبيقي حول الترميز كيفية تعديل تطبيق فيديو حالي على الويب لبث محتوى إلى جهاز يعمل بتكنولوجيا Google Cast.

ما هي تكنولوجيا Google Cast؟

تسمح تكنولوجيا Google Cast للمستخدمين ببث المحتوى من جهاز جوّال إلى تلفزيون. ويمكن للمستخدمين بعد ذلك استخدام أجهزتهم الجوّالة كجهاز تحكّم عن بُعد لتشغيل الوسائط على التلفزيون.

تتيح لك حزمة تطوير البرامج (SDK) لنظام Google Cast توسيع نطاق تطبيقك للتحكّم في التلفزيون أو نظام الصوت. تتيح لك حزمة تطوير البرامج (SDK) لأجهزة البث إضافة مكوّنات واجهة المستخدم اللازمة استنادًا إلى قائمة التحقّق من تصميم Google Cast.

يتم توفير قائمة التحقّق من تصميم Google Cast لجعل تجربة المستخدم في Cast بسيطة ويمكن توقّعها على جميع المنصات المتوافقة.

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

عند الانتهاء من هذا الدرس التطبيقي، سيكون لديك تطبيق فيديو على الويب من Chrome سيتمكن من إرسال مقاطع الفيديو إلى جهاز Google Cast.

المُعطيات

  • كيفية إضافة حزمة تطوير البرامج (SDK) لتكنولوجيا Google Cast إلى نموذج فيديو
  • كيفية إضافة زر البث لاختيار جهاز Google Cast
  • كيفية الاتصال بجهاز بث وتشغيل جهاز استقبال وسائط
  • كيفية بث فيديو
  • كيفية دمج Cast Connect

المتطلبات

  • أحدث إصدار من متصفّح Google Chrome
  • خدمة استضافة HTTPS مثل استضافة Firebase أو ngrok
  • جهاز Google Cast، مثل Chromecast أو Android TV تم ضبطه للوصول إلى الإنترنت
  • تلفزيون أو شاشة مزوّدة بمنفذ إدخال HDMI.
  • يجب توفُّر جهاز Chromecast مع Google TV لاختبار عملية دمج Cast Connect، ولكنّه اختياري لبقية خطوات Codelab. إذا لم يكن لديك حساب، يمكنك تخطّي خطوة إضافة ميزة Cast Connect في نهاية هذا الدليل التعليمي.

تجربة الاستخدام

  • يجب أن تكون لديك معرفة سابقة بتطوير الويب.
  • ستحتاج أيضًا إلى معرفة سابقة بمشاهدة التلفزيون :)

كيف ستستخدم هذا البرنامج التعليمي؟

قراءته فقط قراءته وإكمال التمارين

ما مدى رضاك عن تجربتك في إنشاء تطبيقات الويب؟

مبتدئ متوسط متقدّم

ما مدى رضاك عن تجربة مشاهدة التلفزيون؟

مبتدئ متوسط متقدّم

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

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

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

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

شعار Google Chrome

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

لاستخدام النموذج المكتمل، يجب استضافته.

إذا لم يكن لديك خادم متاح للاستخدام، يمكنك استخدام استضافة Firebase أو ngrok.

تشغيل الخادم

بعد إعداد الخدمة التي تريدها، انتقِل إلى app-done وابدأ تشغيل الخادم.

في المتصفّح، انتقِل إلى عنوان URL https للنموذج الذي استضفته.

  1. من المفترض أن يظهر تطبيق الفيديو.
  2. انقر على زر البث واختَر جهاز Google Cast.
  3. اختَر فيديو، ثم انقر على زر التشغيل.
  4. سيبدأ تشغيل الفيديو على جهاز Google Cast.

صورة فيديو يتم تشغيله على جهاز بث

انقر على زر الإيقاف المؤقت في عنصر الفيديو لإيقاف الفيديو مؤقتًا على جهاز الاستقبال. انقر على زر التشغيل في عنصر الفيديو لمواصلة تشغيله مرة أخرى.

انقر على زر البث لإيقاف البث على جهاز Google Cast.

قبل أن ننتقل، قم بإيقاف الخادم.

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

صورة فيديو يتم تشغيله على جهاز بث

نحتاج إلى إتاحة استخدام Google Cast في تطبيق البدء الذي نزّلته. في ما يلي بعض مصطلحات Google Cast التي سنستخدمها في هذا الدرس التطبيقي حول الترميز:

  • تشغيل تطبيق المرسِل على جهاز جوّال أو كمبيوتر محمول،
  • تشغيل تطبيق مستلِم على جهاز Google Cast

أنت الآن جاهز لتطوير المشروع الأساسي باستخدام محرِّر النصوص المفضّل لديك:

  1. اختَر الدليل رمز المجلدapp-start من تنزيل نموذج الرمز.
  2. شغِّل التطبيق باستخدام خادمك واستكشف واجهة المستخدم.

ملاحظة: أثناء العمل على هذا الدرس التطبيقي حول الترميز، ستحتاج إلى إعادة استضافة النموذج على الخادم اعتمادًا على الخدمة.

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

يُجلب التطبيق قائمة بالفيديوهات من خادم ويب عن بُعد ويقدّم قائمة للمستخدم لتصفّحها. ويمكن للمستخدمين اختيار فيديو للاطّلاع على التفاصيل أو تشغيله محليًا على الجهاز الجوّال.

ويتكون التطبيق من طريقة عرض رئيسية واحدة، تم تحديدها في index.html ووحدة التحكّم الرئيسية، CastVideos.js..

index.html

يوضح ملف html هذا كل واجهة المستخدم تقريبًا لتطبيق الويب.

هناك أقسام قليلة من المشاهدات، لدينا div#main_video، الذي يحتوي على عنصر الفيديو. في ما يتعلّق بقسم الفيديو، لدينا div#media_control الذي يحدّد جميع عناصر التحكّم في عنصر الفيديو. أسفل ذلك، تظهر العلامة media_info التي تعرض تفاصيل الفيديو المعروض. أخيرًا، يعرض div‏ carousel قائمة بالفيديوهات في div.

يعمل ملف index.html أيضًا على تشغيل حزمة تطوير البرامج (SDK) لـ Cast، ويطلب من دالة CastVideos تحميل البيانات.

يتم تحديد معظم المحتوى الذي سيعبئ هذه العناصر وإدراجه والتحكّم فيه في CastVideos.js. لذا، دعونا نلقِ نظرة على ذلك.

CastVideos.js

يدير هذا النص البرمجي كلّ المنطق الخاص بتطبيق الويب Cast Videos. وتتضمّن قائمة الفيديوهات والبيانات الوصفية المرتبطة بها والمحدّدة في CastVideos.js عنصرًا باسم mediaJSON.

هناك عدد قليل من الأقسام الرئيسية المسؤولة عن إدارة الفيديو وتشغيله محليًا وعن بُعد. بشكل عام، هذا تطبيق ويب بسيط إلى حدٍ ما.

CastPlayer هي الفئة الرئيسية التي تدير التطبيق بالكامل وتتولى إعداد المشغّل واختيار الوسائط وربط الأحداث بـ "PlayerHandler" لتشغيل الوسائط. CastPlayer.prototype.initializeCastPlayer هي الطريقة التي يتم فيها إعداد جميع وظائف البث. CastPlayer.prototype.switchPlayer للتبديل بين حالة اللاعبين المحليين واللاعبين عن بُعد يتم إعداد المشغّلات المحلية والبعيدة عن بُعد من خلال CastPlayer.prototype.setupLocalPlayer وCastPlayer.prototype.setupRemotePlayer.

PlayerHandler هي الفئة المسؤولة عن إدارة تشغيل الوسائط. هناك عدد من الطرق الأخرى المسؤولة عن تفاصيل إدارة الوسائط وتشغيلها.

الأسئلة الشائعة

5- إضافة زرّ "البث"

صورة لتطبيق يعمل بتكنولوجيا Google Cast

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

الإعداد

يتطلّب مشروع البدء الإعدادات والتبعيات نفسها التي استخدمتها في نموذج التطبيق المكتمل، ولكن هذه المرة يستضيف محتوى app-start.

في المتصفِّح، انتقِل إلى عنوان URL https للعيّنة التي استضافتها.

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

الإعداد

يحتوي إطار عمل Cast على عنصر فردي شامل، وهو CastContext، الذي ينسق جميع أنشطة الإطار. يجب إعداد هذا العنصر في وقت مبكر من دورة حياة التطبيق، ويتم استدعاؤه عادةً من خلال دالة استدعاء مخصّصة لـ window['__onGCastApiAvailable']، ويتم استدعاؤها بعد تحميل حزمة تطوير البرامج (SDK) لتطبيق Cast، وتكون متاحة للاستخدام. في هذه الحالة، يتم استدعاء CastContext في CastPlayer.prototype.initializeCastPlayer، وهو ما يتم استدعاؤه من خلال عملية معاودة الاتصال المذكورة أعلاه.

يجب تقديم كائن options JSON عند إعداد CastContext. تحتوي هذه الفئة على خيارات تؤثر في سلوك إطار العمل. وأهم هذه المعلومات هو معرّف تطبيق المُستلِم، والذي يُستخدَم لفلترة قائمة أجهزة البث المتاحة لعرض الأجهزة القادرة على تشغيل التطبيق المحدّد فقط ولتشغيل تطبيق المُستلِم عند بدء جلسة بث.

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

أضِف الرمز التالي إلى index.html في نهاية القسم body:

<script type="text/javascript" src="https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1"></script>

أضِف الرمز التالي إلى index.html لإعداد تطبيق CastVideos، بالإضافة إلى إعداد CastContext:

<script src="CastVideos.js"></script>
<script type="text/javascript">
var castPlayer = new CastPlayer();
window['__onGCastApiAvailable'] = function(isAvailable) {
  if (isAvailable) {
    castPlayer.initializeCastPlayer();
  }
};
</script>

والآن، نحتاج إلى إضافة طريقة جديدة في CastVideos.js، تتجاوب مع الطريقة التي استدعيناها للتو في index.html. لنضيف طريقة جديدة تُسمى initializeCastPlayer، تُعيِّن الخيارات في CastContext وتهيئ RemotePlayer وRemotePlayerControllers الجديدين:

/**
 * This method sets up the CastContext, and a few other members
 * that are necessary to play and control videos on a Cast
 * device.
 */
CastPlayer.prototype.initializeCastPlayer = function() {

    var options = {};

    // Set the receiver application ID to your own (created in
    // the Google Cast Developer Console), or optionally
    // use the chrome.cast.media.DEFAULT_MEDIA_RECEIVER_APP_ID
    options.receiverApplicationId = 'C0868879';

    // Auto join policy can be one of the following three:
    // ORIGIN_SCOPED - Auto connect from same appId and page origin
    // TAB_AND_ORIGIN_SCOPED - Auto connect from same appId, page origin, and tab
    // PAGE_SCOPED - No auto connect
    options.autoJoinPolicy = chrome.cast.AutoJoinPolicy.ORIGIN_SCOPED;

    cast.framework.CastContext.getInstance().setOptions(options);

    this.remotePlayer = new cast.framework.RemotePlayer();
    this.remotePlayerController = new cast.framework.RemotePlayerController(this.remotePlayer);
    this.remotePlayerController.addEventListener(
        cast.framework.RemotePlayerEventType.IS_CONNECTED_CHANGED,
        this.switchPlayer.bind(this)
    );
};

أخيرًا، نحتاج إلى إنشاء المتغيّرين RemotePlayer وRemotePlayerController:

var CastPlayer = function() {
  //...
  /* Cast player variables */
  /** @type {cast.framework.RemotePlayer} */
  this.remotePlayer = null;
  /** @type {cast.framework.RemotePlayerController} */
  this.remotePlayerController = null;
  //...
};

زر الإرسال

الآن بعد إعداد CastContext، علينا إضافة زر البث للسماح للمستخدم باختيار جهاز بث. توفّر حزمة تطوير البرامج (SDK) الخاصة بالبث مكوّنًا لزر البث يُسمى google-cast-launcher ويحمل معرّف "castbutton"". ويمكن إضافته إلى عنصر الفيديو الخاص بالتطبيق ببساطة عن طريق إضافة button في القسم media_control.

سيظهر عنصر الزر على النحو التالي:

<google-cast-launcher id="castbutton"></google-cast-launcher>

أضِف الرمز التالي إلى index.html في القسم media_control:

<div id="media_control">
  <div id="play"></div>
  <div id="pause"></div>
  <div id="progress_bg"></div>
  <div id="progress"></div>
  <div id="progress_indicator"></div>
  <div id="fullscreen_expand"></div>
  <div id="fullscreen_collapse"></div>
  <google-cast-launcher id="castbutton"></google-cast-launcher>
  <div id="audio_bg"></div>
  <div id="audio_bg_track"></div>
  <div id="audio_indicator"></div>
  <div id="audio_bg_level"></div>
  <div id="audio_on"></div>
  <div id="audio_off"></div>
  <div id="duration">00:00:00</div>
</div>

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

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

6- بث محتوى الفيديو

صورة لتطبيق متوافق مع Cast مع قائمة اختيار أجهزة البث

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

بث الوسائط

بشكل عام، إذا أردت تشغيل محتوى وسائط على جهاز بث، يجب تنفيذ ما يلي:

  1. أنشِئ عنصر MediaInfo JSON من حزمة تطوير البرامج (SDK) لتكنولوجيا Cast لإنشاء نموذج لعنصر وسائط.
  2. يتصل المستخدم بجهاز البث لتشغيل تطبيق المُستلِم.
  3. ما عليك سوى تحميل كائن MediaInfo إلى جهاز الاستقبال وتشغيل المحتوى.
  4. تتبُّع حالة الوسائط
  5. إرسال أوامر التشغيل إلى المستلِم استنادًا إلى تفاعلات المستخدم

تؤدي الخطوة الأولى إلى ربط عنصر بآخر، وMediaInfo هو عنصر يمكن لحزمة تطوير البرامج (SDK) لأجهزة البث فهمه، وmediaJSON هو عنصر يُستخدم في تطبيقنا لتضمين عنصر وسائط، ويمكننا بسهولة ربط mediaJSON بـ MediaInfo. لقد نفّذنا الخطوة 2 في القسم السابق. يسهل تنفيذ الخطوة الثالثة باستخدام حزمة تطوير البرامج (SDK) الخاصة بالبث.

يميز تطبيق CastPlayer التجريبي بين التشغيل على الجهاز والتشغيل عن بُعد في طريقة switchPlayer:

if (cast && cast.framework) {
  if (this.remotePlayer.isConnected) {
    //...

ليس من المهم في هذا الدرس التطبيقي حول الترميز التعرّف بدقة على آلية عمل نموذج منطق المشغّل بالكامل. ومع ذلك، من المهم معرفة أنّه يجب تعديل مشغّل الوسائط في تطبيقك ليتمكّن من رصد كلّ من التشغيل على الجهاز والتشغيل عن بُعد.

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

إدارة جلسة البث

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

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

تتم إدارة جلسات البث من خلال CastSession، والذي يمكن الوصول إليه من خلال cast.framework.CastContext.getInstance().getCurrentSession(). يمكن استخدام عمليات معاودة الاتصال "EventListener" لمراقبة أحداث الجلسة، مثل الإنشاء والتعليق والاستئناف والإنهاء.

في الطلب الحالي، يتم التعامل مع جميع عمليات إدارة الجلسات والحالات نيابةً عنا بطريقة setupRemotePlayer. لنبدأ بإعداد ذلك في تطبيقك من خلال إضافة الرمز التالي إلى CastVideos.js:

/**
 * Set the PlayerHandler target to use the remote player
 */
CastPlayer.prototype.setupRemotePlayer = function () {
    var castSession = cast.framework.CastContext.getInstance().getCurrentSession();

    this.playerHandler.setTarget(playerTarget);

    // Setup remote player volume right on setup
    // The remote player may have had a volume set from previous playback
    if (this.remotePlayer.isMuted) {
        this.playerHandler.mute();
    }
    var currentVolume = this.remotePlayer.volumeLevel * FULL_VOLUME_HEIGHT;
    var p = document.getElementById('audio_bg_level');
    p.style.height = currentVolume + 'px';
    p.style.marginTop = -currentVolume + 'px';

    this.hideFullscreenButton();

    this.playerHandler.play();
};

لا يزال علينا ربط جميع الأحداث من عمليات الاستدعاء ومعالجة جميع الأحداث الواردة. هذه الخطوة سهلة جدًا، لذا لنبدأ بها الآن:

/**
 * Set the PlayerHandler target to use the remote player
 */
CastPlayer.prototype.setupRemotePlayer = function () {
    var castSession = cast.framework.CastContext.getInstance().getCurrentSession();

    // Add event listeners for player changes which may occur outside sender app
    this.remotePlayerController.addEventListener(
        cast.framework.RemotePlayerEventType.IS_PAUSED_CHANGED,
        function() {
            if (this.remotePlayer.isPaused) {
                this.playerHandler.pause();
            } else {
                this.playerHandler.play();
            }
        }.bind(this)
    );

    this.remotePlayerController.addEventListener(
        cast.framework.RemotePlayerEventType.IS_MUTED_CHANGED,
        function() {
            if (this.remotePlayer.isMuted) {
                this.playerHandler.mute();
            } else {
                this.playerHandler.unMute();
            }
        }.bind(this)
    );

    this.remotePlayerController.addEventListener(
        cast.framework.RemotePlayerEventType.VOLUME_LEVEL_CHANGED,
        function() {
            var newVolume = this.remotePlayer.volumeLevel * FULL_VOLUME_HEIGHT;
            var p = document.getElementById('audio_bg_level');
            p.style.height = newVolume + 'px';
            p.style.marginTop = -newVolume + 'px';
        }.bind(this)
    );

    // This object will implement PlayerHandler callbacks with
    // remotePlayerController, and makes necessary UI updates specific
    // to remote playback
    var playerTarget = {};

    playerTarget.play = function () {
        if (this.remotePlayer.isPaused) {
            this.remotePlayerController.playOrPause();
        }

        var vi = document.getElementById('video_image');
        vi.style.display = 'block';
        var localPlayer = document.getElementById('video_element');
        localPlayer.style.display = 'none';
    }.bind(this);

    playerTarget.pause = function () {
        if (!this.remotePlayer.isPaused) {
            this.remotePlayerController.playOrPause();
        }
    }.bind(this);

    playerTarget.stop = function () {
         this.remotePlayerController.stop();
    }.bind(this);

    playerTarget.getCurrentMediaTime = function() {
        return this.remotePlayer.currentTime;
    }.bind(this);

    playerTarget.getMediaDuration = function() {
        return this.remotePlayer.duration;
    }.bind(this);

    playerTarget.updateDisplayMessage = function () {
        document.getElementById('playerstate').style.display = 'block';
        document.getElementById('playerstatebg').style.display = 'block';
        document.getElementById('video_image_overlay').style.display = 'block';
        document.getElementById('playerstate').innerHTML =
            this.mediaContents[ this.currentMediaIndex]['title'] + ' ' +
            this.playerState + ' on ' + castSession.getCastDevice().friendlyName;
    }.bind(this);

    playerTarget.setVolume = function (volumeSliderPosition) {
        // Add resistance to avoid loud volume
        var currentVolume = this.remotePlayer.volumeLevel;
        var p = document.getElementById('audio_bg_level');
        if (volumeSliderPosition < FULL_VOLUME_HEIGHT) {
            var vScale =  this.currentVolume * FULL_VOLUME_HEIGHT;
            if (volumeSliderPosition > vScale) {
                volumeSliderPosition = vScale + (pos - vScale) / 2;
            }
            p.style.height = volumeSliderPosition + 'px';
            p.style.marginTop = -volumeSliderPosition + 'px';
            currentVolume = volumeSliderPosition / FULL_VOLUME_HEIGHT;
        } else {
            currentVolume = 1;
        }
        this.remotePlayer.volumeLevel = currentVolume;
        this.remotePlayerController.setVolumeLevel();
    }.bind(this);

    playerTarget.mute = function () {
        if (!this.remotePlayer.isMuted) {
            this.remotePlayerController.muteOrUnmute();
        }
    }.bind(this);

    playerTarget.unMute = function () {
        if (this.remotePlayer.isMuted) {
            this.remotePlayerController.muteOrUnmute();
        }
    }.bind(this);

    playerTarget.isMuted = function() {
        return this.remotePlayer.isMuted;
    }.bind(this);

    playerTarget.seekTo = function (time) {
        this.remotePlayer.currentTime = time;
        this.remotePlayerController.seek();
    }.bind(this);

    this.playerHandler.setTarget(playerTarget);

    // Setup remote player volume right on setup
    // The remote player may have had a volume set from previous playback
    if (this.remotePlayer.isMuted) {
        this.playerHandler.mute();
    }
    var currentVolume = this.remotePlayer.volumeLevel * FULL_VOLUME_HEIGHT;
    var p = document.getElementById('audio_bg_level');
    p.style.height = currentVolume + 'px';
    p.style.marginTop = -currentVolume + 'px';

    this.hideFullscreenButton();

    this.playerHandler.play();
};

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

في حزمة تطوير البرامج لتكنولوجيا Cast، توفّر RemotePlayer وRemotePlayerController مجموعة من واجهات برمجة التطبيقات المناسبة لإدارة تشغيل الوسائط عن بُعد على المستلِم. بالنسبة إلى CastSession الذي يتيح تشغيل الوسائط، سيتم تلقائيًا إنشاء مثيلَي RemotePlayer وRemotePlayerController من خلال حزمة تطوير البرامج (SDK). ويمكن الوصول إليهما من خلال إنشاء نُسخ من cast.framework.RemotePlayer وcast.framework.RemotePlayerController على التوالي، كما هو موضّح سابقًا في ورشة رموز البرامج.

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

/**
 * Set the PlayerHandler target to use the remote player
 */
CastPlayer.prototype.setupRemotePlayer = function () {
    //...

    playerTarget.load = function (mediaIndex) {
        console.log('Loading...' + this.mediaContents[mediaIndex]['title']);
        var mediaInfo = new chrome.cast.media.MediaInfo(
            this.mediaContents[mediaIndex]['sources'][0], 'video/mp4');

        mediaInfo.metadata = new chrome.cast.media.GenericMediaMetadata();
        mediaInfo.metadata.metadataType = chrome.cast.media.MetadataType.GENERIC;
        mediaInfo.metadata.title = this.mediaContents[mediaIndex]['title'];
        mediaInfo.metadata.images = [
            {'url': MEDIA_SOURCE_ROOT + this.mediaContents[mediaIndex]['thumb']}];

        var request = new chrome.cast.media.LoadRequest(mediaInfo);
        castSession.loadMedia(request).then(
            this.playerHandler.loaded.bind(this.playerHandler),
            function (errorCode) {
                this.playerState = PLAYER_STATE.ERROR;
                console.log('Remote media load error: ' +
                    CastPlayer.getErrorMessage(errorCode));
            }.bind(this));
    }.bind(this);

    //...
};

أضِف الآن طريقة للتبديل بين التشغيل على الجهاز والتشغيل عن بُعد:

/**
 * This is a method for switching between the local and remote
 * players. If the local player is selected, setupLocalPlayer()
 * is run. If there is a cast device connected we run
 * setupRemotePlayer().
 */
CastPlayer.prototype.switchPlayer = function() {
    this.stopProgressTimer();
    this.resetVolumeSlider();
    this.playerHandler.stop();
    this.playerState = PLAYER_STATE.IDLE;
    if (cast && cast.framework) {
        if (this.remotePlayer.isConnected) {
            this.setupRemotePlayer();
            return;
        }
    }
    this.setupLocalPlayer();
};

أخيرًا، أضِف طريقة للتعامل مع أي رسائل خطأ في Cast:

/**
 * Makes human-readable message from chrome.cast.Error
 * @param {chrome.cast.Error} error
 * @return {string} error message
 */
CastPlayer.getErrorMessage = function(error) {
  switch (error.code) {
    case chrome.cast.ErrorCode.API_NOT_INITIALIZED:
      return 'The API is not initialized.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.CANCEL:
      return 'The operation was canceled by the user' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.CHANNEL_ERROR:
      return 'A channel to the receiver is not available.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.EXTENSION_MISSING:
      return 'The Cast extension is not available.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.INVALID_PARAMETER:
      return 'The parameters to the operation were not valid.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.RECEIVER_UNAVAILABLE:
      return 'No receiver was compatible with the session request.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.SESSION_ERROR:
      return 'A session could not be created, or a session was invalid.' +
        (error.description ? ' :' + error.description : '');
    case chrome.cast.ErrorCode.TIMEOUT:
      return 'The operation timed out.' +
        (error.description ? ' :' + error.description : '');
  }
};

الآن، شغِّل التطبيق. اتصل بجهاز البث وابدأ في تشغيل الفيديو. من المفترض أن ترى الفيديو قيد التشغيل على جهاز الاستقبال.

7- إضافة دعم Cast Connect

تسمح مكتبة Cast Connect لتطبيقات المُرسِلين الحالية بالتواصل مع تطبيقات Android TV عبر بروتوكول Cast. يستند Cast Connect إلى البنية الأساسية لنظام Cast، ويعمل تطبيق Android TV كمستلِم.

التبعيات

  • الإصدار M87 أو إصدار أحدث من متصفِّح Chrome

ضبط الإعداد "متوافق مع Android Receiver"

لتشغيل تطبيق Android TV، الذي يُشار إليه أيضًا باسم "مُستلِم Android"، يجب ضبط علامة androidReceiverCompatible على true في عنصر CastOptions.

أضِف الرمز التالي إلى CastVideos.js في الدالة initializeCastPlayer:

var options = {};
...
options.androidReceiverCompatible = true;

cast.framework.CastContext.getInstance().setOptions(options);

ضبط بيانات اعتماد الإطلاق

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

لضبط بيانات اعتماد الإطلاق، يجب تحديد CredentialsData في أي وقت بعد ضبط خيارات التشغيل.

أضِف الرمز التالي إلى فئة CastVideos.js ضمن الدالة initializeCastPlayer:

cast.framework.CastContext.getInstance().setOptions(options);
...
let credentialsData = new chrome.cast.CredentialsData("{\"userId\": \"abc\"}");
cast.framework.CastContext.getInstance().setLaunchCredentialsData(credentialsData);
...

ضبط بيانات الاعتماد عند طلب التحميل

في حال كان تطبيق Web Receiver وتطبيق Android TV يتعاملان مع credentials بشكلٍ مختلف، قد تحتاج إلى تحديد بيانات اعتماد منفصلة لكل منهما. لحلّ هذه المشكلة، أضِف الرمز البرمجي التالي في CastVideos.js ضمن playerTarget.load في الدالة setupRemotePlayer:

...
var request = new chrome.cast.media.LoadRequest(mediaInfo);
request.credentials = 'user-credentials';
request.atvCredentials = 'atv-user-credentials';
...

استنادًا إلى تطبيق المُستلِم الذي يرسِل إليه المُرسِل، ستتعامل حزمة SDK الآن تلقائيًا مع بيانات الاعتماد التي سيتم استخدامها للجلسة الحالية.

اختبار الاتصال بالبث

خطوات تثبيت حزمة APK لنظام التشغيل Android TV على جهاز "‏Chromecast مع Google TV":

  1. ابحث عن عنوان IP لجهاز Android TV. يتوفّر هذا الخيار عادةً ضمن الإعدادات > الشبكة والإنترنت > (اسم الشبكة التي يتصل بها جهازك). على يسار الصفحة، ستظهر التفاصيل وعنوان IP لجهازك على الشبكة.
  2. استخدِم عنوان IP لجهازك للاتصال به عبر ADB باستخدام الوحدة الطرفية:
$ adb connect <device_ip_address>:5555
  1. من النافذة الطرفية، انتقِل إلى مجلد المستوى الأعلى لعيّنات الدروس التطبيقية حول الترميز التي نزّلتها في بداية هذا الدرس التطبيقي حول الترميز. على سبيل المثال:
$ cd Desktop/chrome_codelab_src
  1. ثبِّت ملف apk .في هذا المجلد على Android TV من خلال تنفيذ ما يلي:
$ adb -s <device_ip_address>:5555 install android-tv-app.apk
  1. ستتمكّن الآن من رؤية التطبيق باسم بث الفيديوهات في قائمة تطبيقاتك على جهاز Android TV.
  2. يمكنك تشغيل الرمز المُعدَّل للمُرسِل على الويب وبدء جلسة بث باستخدام جهاز Android TV باستخدام رمز البث أو اختيار Cast.. من القائمة المنسدلة في متصفّح Chrome. من المفترض أن يؤدي ذلك إلى تشغيل تطبيق Android TV على جهاز Android Receiver والسماح لك بالتحكم في التشغيل باستخدام جهاز التحكّم عن بُعد في Android TV.

8. تهانينا

لقد تعرّفت الآن على كيفية تفعيل ميزة "البثّ" في تطبيق فيديو باستخدام التطبيقات المصغّرة لحزمة تطوير البرامج (SDK) لميزة "البثّ" على تطبيق ويب في Chrome.

لمزيد من التفاصيل، يُرجى الاطّلاع على دليل المطوِّر Web Sender.