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

1. نظرة عامة

شعار Google Cast

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

ما المقصود بتكنولوجيا Google Cast؟

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

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

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

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

الإعداد

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

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

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

الإعداد

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

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

عند تطوير تطبيقك الخاص الذي يعمل بتكنولوجيا Google Cast، عليك التسجيل كمطوِّر لتكنولوجيا Google 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- بث محتوى الفيديو

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

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

بث الوسائط

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

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

تمثل الخطوة 1 ارتباط كائن بآخر؛ MediaInfo هو شيء تفهمه حزمة تطوير البرامج (SDK) الخاصة بالبث، وmediaJSON هو تغليف تطبيقنا لعنصر وسائط. يمكننا بسهولة ربط mediaJSON بـ MediaInfo. لقد أكملنا الخطوة 2 في القسم السابق. يسهل تنفيذ الخطوة الثالثة باستخدام حزمة تطوير البرامج (SDK) الخاصة بالبث.

يميّز نموذج التطبيق CastPlayer حاليًا بين التشغيل المحلي والتشغيل عن بُعد بالطريقة switchPlayer:

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

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

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

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

بالنسبة إلى إطار عمل Google 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();
};

أخيرًا، يمكنك إضافة طريقة للتعامل مع أي رسائل خطأ في البث:

/**
 * 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 على البنية الأساسية للبث، ويعمل تطبيق Android TV كوحدة استقبال.

التبعيات

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

ضبط توافق جهاز استقبال Android

لتشغيل تطبيق Android TV، الذي يُشار إليه أيضًا باسم "مستقبل Android"، نحتاج إلى ضبط علامة androidReceiverCompatible على "صحيح" في كائن 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);
...

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

إذا كان تطبيق "استقبال الويب" وتطبيق 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 TV والسماح لك بالتحكّم في التشغيل باستخدام جهاز التحكّم عن بُعد في Android TV.

8. تهانينا

تعرفت الآن على كيفية تمكين تطبيق فيديو باستخدام Cast SDK على تطبيق ويب Chrome.

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