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

1- نظرة عامة

شعار Google Cast

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

ما المقصود بـ Google Cast؟

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

تتيح لك حزمة تطوير البرامج (SDK) لتقنية Google Cast توسيع نطاق تطبيقك للتحكّم في التلفزيون أو نظام الصوت. تتيح لك حزمة تطوير البرامج (SDK) لتقنية Google 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. الحصول على الرمز النموذجي

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

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

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) للبث، ويطلب تحميل الدالة CastVideos.

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

CastVideos.js

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

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

عند تطوير تطبيقك الذي يفعِّل تكنولوجيا Google 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، نحتاج إلى إضافة زر البث للسماح للمستخدم باختيار جهاز البث. توفر حزمة Cast 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. يمكنك إنشاء عنصر JSON على MediaInfo من حزمة تطوير البرامج (SDK) للإرسال والذي ينشئ نموذجًا لعنصر وسائط.
  2. يتصل المستخدم بجهاز البث لتشغيل تطبيق جهاز الاستقبال.
  3. حمِّل الكائن MediaInfo في جهاز الاستقبال وشغِّل المحتوى.
  4. تتبُّع حالة الوسائط
  5. إرسال أوامر التشغيل إلى المتلقي بناءً على تفاعلات المستخدم.

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

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

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

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

في الوقت الحالي، يكون المشغّل المحلي دائمًا في حالة التشغيل المحلية لأنّه لا يعرف أي شيء عن حالات البثّ بعد. نحتاج إلى تحديث واجهة المستخدم استنادًا إلى عمليات انتقال الحالة التي تحدث في إطار عمل Cast. على سبيل المثال، إذا بدأنا البث، يجب إيقاف التشغيل المحلي وإيقاف بعض عناصر التحكّم. وبالمثل، إذا توقّفنا عن البث عندما نكون في وحدة التحكّم في العرض هذه، سنحتاج إلى الانتقال إلى تشغيل المحتوى على الجهاز. لحلّ هذه المشكلة، نحتاج إلى الاستماع إلى الأحداث المختلفة التي أنشأها إطار عمل 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();
};

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

في حزمة تطوير البرامج (SDK) للبث، يوفّر كل من RemotePlayer وRemotePlayerController مجموعة من واجهات برمجة التطبيقات المناسبة لإدارة تشغيل الوسائط عن بُعد على جهاز الاستقبال. بالنسبة إلى CastSession التي تتيح تشغيل الوسائط، ستنشئ حزمة تطوير البرامج (SDK) تلقائيًا مثيلين من RemotePlayer وRemotePlayerController. ويمكن الوصول إليها من خلال إنشاء مثيلَين 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 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';
...

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

اختبار Cast Connect

خطوات تثبيت ملف 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. ثبِّت ملف AP .في هذا المجلد على Android TV من خلال تنفيذ ما يلي:
$ adb -s <device_ip_address>:5555 install android-tv-app.apk
  1. من المفترض أن تتمكن الآن من مشاهدة تطبيق باسم بث الفيديوهات في قائمة تطبيقاتك على جهاز Android TV.
  2. شغِّل رمز الإرسال المحدّث على الويب وأنشِئ جلسة بث من خلال جهاز Android TV باستخدام رمز البث أو اختَر Cast.. من القائمة المنسدلة في متصفّح Chrome. من المفترض أن يؤدي هذا الإجراء الآن إلى تشغيل تطبيق Android TV على جهاز استقبال Android وإتاحة التحكم في التشغيل باستخدام جهاز التحكم بـ Android TV عن بُعد.

8. تهانينا

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

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