1. نظرة عامة

سيعلّمك هذا الدرس التطبيقي حول الترميز كيفية تعديل تطبيق فيديو حالي على الويب لبث المحتوى على جهاز يتيح استخدام Google Cast.
ما هي تكنولوجيا Google Cast؟
تتيح تكنولوجيا Google Cast للمستخدمين بث المحتوى من جهاز جوّال إلى التلفزيون. يمكن للمستخدمين بعد ذلك استخدام أجهزتهم الجوّالة كوحدة تحكّم عن بُعد لتشغيل الوسائط على التلفزيون.
تتيح لك حزمة تطوير البرامج (SDK) الخاصة بتكنولوجيا Google Cast توسيع نطاق تطبيقك للتحكّم في تلفزيون أو نظام صوت. تتيح لك حزمة تطوير البرامج (SDK) الخاصة بـ Cast إضافة عناصر واجهة المستخدم اللازمة استنادًا إلى قائمة تدقيق تصميم Google Cast.
يتم توفير قائمة التحقّق من تصميم Google Cast لتكون تجربة المستخدم في Cast بسيطة ويمكن توقّعها على جميع الأنظمة الأساسية المتوافقة.
ما الذي سنقوم بإنشائه؟
عند الانتهاء من هذا الدرس التطبيقي حول الترميز، سيكون لديك تطبيق فيديو على الويب في Chrome يمكنه بث الفيديوهات إلى جهاز بث.
أهداف الدورة التعليمية
- كيفية إضافة حزمة تطوير البرامج (SDK) الخاصة بـ Google Cast إلى تطبيق فيديو نموذجي.
- كيفية إضافة زر "البث" لاختيار جهاز Google Cast
- كيفية الربط بجهاز البث وتشغيل تطبيق استقبال الوسائط
- كيفية بث فيديو
- كيفية دمج Cast Connect
المتطلبات
- أحدث إصدار من متصفّح Google Chrome
- خدمة استضافة HTTPS، مثل استضافة Firebase أو ngrok
- جهاز بث، مثل Chromecast أو Android TV، تم إعداده للوصول إلى الإنترنت.
- تلفزيون أو شاشة مزوَّدان بمنفذ إدخال HDMI
- يجب توفّر جهاز Chromecast with Google TV لاختبار عملية الدمج مع Cast Connect، ولكنّه اختياري لبقية Codelab. إذا لم يكن لديك حساب، يمكنك تخطّي خطوة إضافة دعم Cast Connect في نهاية هذا البرنامج التعليمي.
تجربة الاستخدام
- يجب أن تكون لديك معرفة سابقة بتطوير الويب.
- ستحتاج أيضًا إلى معرفة سابقة بمشاهدة التلفزيون :)
كيف ستستخدم هذا البرنامج التعليمي؟
ما هو تقييمك لتجربتك في إنشاء تطبيقات ويب؟
كيف تقيّم تجربتك في مشاهدة التلفزيون؟
2. الحصول على الرمز النموذجي
يمكنك تنزيل كل الرموز النموذجية على جهاز الكمبيوتر...
وفكّ ضغط ملف ZIP الذي تم تنزيله.
3- تشغيل نموذج التطبيق

لنبدأ بالاطّلاع على الشكل الذي سيبدو عليه نموذج التطبيق المكتمل. التطبيق هو مشغّل فيديو أساسي. يمكن للمستخدم اختيار فيديو من قائمة ثم تشغيله على الجهاز أو بثه إلى جهاز بث متوافق مع Google Cast.
لاستخدام النموذج المكتمل، يجب استضافته.
إذا لم يكن لديك خادم متاح للاستخدام، يمكنك استخدام استضافة Firebase أو ngrok.
تشغيل الخادم
بعد إعداد الخدمة التي تختارها، انتقِل إلى app-done وابدأ تشغيل الخادم.
في المتصفّح، انتقِل إلى عنوان URL الخاص بالنموذج الذي استضافته.
- من المفترض أن يظهر تطبيق الفيديو.
- انقر على زر "البث" واختَر جهاز Google Cast.
- اختَر فيديو، ثم انقر على زر التشغيل.
- سيبدأ تشغيل الفيديو على جهاز البث Google Cast.

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

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

app-startمن عملية تنزيل رمزك النموذجي. - شغِّل التطبيق باستخدام الخادم واستكشِف واجهة المستخدم.
يُرجى العِلم أنّه أثناء العمل على هذا الدرس التطبيقي حول الترميز، عليك إعادة استضافة النموذج على الخادم حسب الخدمة.
تصميم التطبيقات
يجلب التطبيق قائمة بالفيديوهات من خادم ويب بعيد ويقدّم قائمة للمستخدم لتصفّحها. يمكن للمستخدمين اختيار فيديو للاطّلاع على التفاصيل أو تشغيله على الجهاز الجوّال.
يتألف التطبيق من طريقة عرض رئيسية واحدة، يتم تحديدها في index.html ووحدة التحكّم الرئيسية، CastVideos.js.
index.html
يحدد ملف HTML هذا جميع عناصر واجهة المستخدم تقريبًا لتطبيق الويب.
هناك بضعة أقسام من طرق العرض، لدينا div#main_video الذي يحتوي على عنصر الفيديو. في ما يتعلق بعنصر div الخاص بالفيديو، لدينا div#media_control الذي يحدّد جميع عناصر التحكّم في عنصر الفيديو. أسفل ذلك، يظهر media_info الذي يعرض تفاصيل الفيديو المعروض. أخيرًا، يعرض العنصر carousel قائمة بالفيديوهات في عنصر div.
يعمل الملف index.html أيضًا على بدء تشغيل حزمة تطوير البرامج (SDK) الخاصة بـ Cast، ويطلب من الدالة CastVideos تحميلها.
يتم تحديد معظم المحتوى الذي سيتم ملء هذه العناصر به وإدراجه والتحكّم فيه في CastVideos.js. لذا، دعونا نلقي نظرة على ذلك.
CastVideos.js
يدير هذا النص البرمجي كل منطق تطبيق Cast Videos على الويب. يتم تضمين قائمة الفيديوهات والبيانات الوصفية المرتبطة بها والمحدّدة في CastVideos.js في عنصر باسم mediaJSON.
هناك بعض الأقسام الرئيسية التي تتولّى معًا إدارة الفيديو وتشغيله محليًا وعن بُعد. بشكل عام، هذا تطبيق ويب بسيط إلى حدّ ما.
CastPlayer هي الفئة الرئيسية التي تدير التطبيق بأكمله، وتعمل على إعداد المشغّل واختيار الوسائط وربط الأحداث بـ PlayerHandler لتشغيل الوسائط. CastPlayer.prototype.initializeCastPlayer هي الطريقة التي يتم من خلالها إعداد جميع وظائف Cast. يُبدّل CastPlayer.prototype.switchPlayer الحالة بين اللاعبين المحليين واللاعبين عن بُعد. يتم استخدام CastPlayer.prototype.setupLocalPlayer وCastPlayer.prototype.setupRemotePlayer لتهيئة اللاعبين المحليين والبعيدين.
PlayerHandler هو الصف المسؤول عن إدارة تشغيل الوسائط. هناك عدد من الطرق الأخرى المسؤولة عن تفاصيل إدارة الوسائط وتشغيلها.
الأسئلة الشائعة
5. إضافة زر الإرسال

يعرض تطبيق يتيح استخدام Google Cast زر البث في عنصر الفيديو. يؤدي النقر على زر "البث" إلى عرض قائمة بأجهزة البث التي يمكن للمستخدم اختيارها. إذا كان المستخدم يشغّل المحتوى محليًا على جهاز الإرسال، يؤدي اختيار جهاز بث إلى بدء التشغيل أو استئنافه على جهاز البث هذا. في أي وقت أثناء جلسة البث، يمكن للمستخدم النقر على زر البث وإيقاف بث تطبيقك إلى جهاز البث. يجب أن يتمكّن المستخدم من الاتصال بجهاز البث أو قطع الاتصال به أثناء تصفّح أي شاشة في تطبيقك، كما هو موضّح في قائمة التحقّق من تصميم Google Cast.
التهيئة
يتطلّب مشروع البدء نفس التبعيات والإعدادات التي استخدمتها في نموذج التطبيق المكتمل، ولكن هذه المرة استضِف محتوى app-start.
في المتصفّح، انتقِل إلى عنوان URL الخاص بالنموذج الذي استضفته.https
تذكَّر أنّه عند إجراء تغييرات، عليك إعادة استضافة العيّنة على الخادم حسب الخدمة.
الإعداد
يحتوي إطار عمل Cast على عنصر فردي عام، وهو CastContext، الذي ينسّق جميع أنشطة إطار العمل. يجب إعداد هذا العنصر في وقت مبكر من مراحل نشاط التطبيق، ويتم عادةً استدعاؤه من دالة ردّ تم تعيينها إلى window['__onGCastApiAvailable']، ويتم استدعاؤها بعد تحميل حزمة تطوير البرامج (SDK) الخاصة بـ Cast، وتكون متاحة للاستخدام. في هذه الحالة، يتم استدعاء CastContext في CastPlayer.prototype.initializeCastPlayer، والذي يتم استدعاؤه من دالة معاودة الاتصال المذكورة أعلاه.
يجب توفير عنصر JSON options عند تهيئة 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، علينا الآن إضافة زر "البث" للسماح للمستخدم باختيار جهاز بث. توفّر حزمة تطوير البرامج (SDK) لتطبيق Cast مكوّن زر البث باسم 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.
بثّ الوسائط
بشكل عام، إذا أردت تشغيل وسائط على جهاز البث، يجب اتّباع الخطوات التالية:
- أنشئ عنصر
MediaInfoJSONمن حزمة تطوير البرامج (SDK) الخاصة بـ Cast التي تصمّم عنصر وسائط. - يتصل المستخدم بجهاز البث لتشغيل تطبيق الاستقبال.
- حمِّل العنصر
MediaInfoفي جهاز الاستقبال وشغِّل المحتوى. - تتبُّع حالة الوسائط
- إرسال أوامر التشغيل إلى جهاز الاستقبال استنادًا إلى تفاعلات المستخدم
تتمثّل الخطوة الأولى في ربط عنصر بآخر، حيث إنّ MediaInfo هو عنصر تفهمه حزمة تطوير البرامج (SDK) الخاصة بـ Cast، وmediaJSON هو عملية تغليف تطبيقنا لعنصر وسائط، ويمكننا بسهولة ربط mediaJSON بـ MediaInfo. لقد أكملنا الخطوة 2 في القسم السابق. يمكن تنفيذ الخطوة 3 بسهولة باستخدام Cast SDK.
يميز نموذج التطبيق CastPlayer بالفعل بين التشغيل المحلي والتشغيل عن بُعد في الطريقة switchPlayer:
if (cast && cast.framework) {
if (this.remotePlayer.isConnected) {
//...
ليس من المهم في هذا الدرس التطبيقي حول الترميز أن تفهم بالضبط طريقة عمل جميع نماذج منطق اللاعب. ومع ذلك، من المهم أن تعرف أنّه يجب تعديل مشغّل الوسائط في تطبيقك ليكون على دراية بكل من التشغيل المحلي والتشغيل عن بُعد.
في الوقت الحالي، يكون مشغّل الفيديو المحلي دائمًا في حالة التشغيل المحلية لأنّه لا يعرف أي شيء عن حالات البث بعد. علينا تعديل واجهة المستخدم استنادًا إلى عمليات نقل الحالة التي تحدث في إطار عمل Cast. على سبيل المثال، إذا بدأنا البث، علينا إيقاف التشغيل المحلي وإيقاف بعض عناصر التحكّم. وبالمثل، إذا أوقفنا البث عندما نكون في وحدة التحكّم في العرض هذه، علينا الانتقال إلى التشغيل المحلي. للتعامل مع ذلك، علينا الاستماع إلى الأحداث المختلفة التي ينشئها إطار عمل Cast.
إدارة جلسة البث
بالنسبة إلى إطار عمل Cast، تجمع جلسة 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();
};
جارٍ تحميل الوسائط
في Cast SDK، يوفّر كلّ من 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 ليكون متوافقًا
من أجل تشغيل تطبيق Android TV، المعروف أيضًا باسم Android Receiver، يجب ضبط العلامة androidReceiverCompatible على "صحيح" في العنصر CastOptions.
أضِف الرمز التالي إلى CastVideos.js في الدالة initializeCastPlayer:
var options = {};
...
options.androidReceiverCompatible = true;
cast.framework.CastContext.getInstance().setOptions(options);
ضبط بيانات اعتماد الإطلاق
من جهة المُرسِل، يمكنك تحديد CredentialsData لتمثيل المستخدم الذي ينضم إلى الجلسة. credentials هي سلسلة يمكن للمستخدم تحديدها، طالما أنّ تطبيق Android TV يمكنه فهمها. لا يتم تمرير 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":
- ابحث عن عنوان IP لجهاز Android TV. عادةً ما يكون متاحًا ضمن الإعدادات > الشبكة والإنترنت > (اسم الشبكة التي يتصل بها جهازك). على اليسار، ستظهر التفاصيل وعنوان IP لجهازك على الشبكة.
- استخدِم عنوان IP الخاص بجهازك للاتصال به عبر ADB باستخدام الوحدة الطرفية:
$ adb connect <device_ip_address>:5555
- من نافذة الوحدة الطرفية، انتقِل إلى مجلد المستوى الأعلى لعينات الدرس التطبيقي حول الترميز التي نزّلتها في بداية هذا الدرس. على سبيل المثال:
$ cd Desktop/chrome_codelab_src
- ثبِّت ملف .apk في هذا المجلد على Android TV من خلال تنفيذ الأمر التالي:
$ adb -s <device_ip_address>:5555 install android-tv-app.apk
- من المفترض أن يظهر لك الآن تطبيق باسم بثّ الفيديوهات في قائمة تطبيقاتك على جهاز Android TV.
- نفِّذ رمز مرسل الويب المعدَّل وأنشئ جلسة بث مع جهاز Android TV باستخدام رمز البث أو من خلال النقر على
Cast..من القائمة المنسدلة في متصفّح Chrome. من المفترض أن يؤدي ذلك إلى تشغيل تطبيق Android TV على جهاز استقبال Android وأن يسمح لك بالتحكّم في التشغيل باستخدام جهاز التحكّم عن بُعد في Android TV.
8. تهانينا
أصبحت الآن تعرف كيفية تفعيل ميزة "الإرسال" في تطبيق فيديو باستخدام أدوات واجهة المستخدم الخاصة بحزمة تطوير البرامج (SDK) الخاصة بميزة "الإرسال" في تطبيق ويب على Chrome.
لمزيد من التفاصيل، يُرجى الاطّلاع على دليل المطوّرين Web Sender.