إنشاء جهاز استقبال ويب مخصص

‫1. نظرة عامة

شعار Google Cast

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

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

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

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

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

ما الذي سنقوم بإنشائه؟

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

أهداف الدورة التعليمية

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

المتطلبات

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

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

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

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

قراءة المحتوى فقط قراءة المحتوى وإكمال التمارين

ما هو تقييمك لتجربتك في إنشاء تطبيقات ويب؟

مبتدئ متوسط متمكّن

كيف تقيّم تجربتك في مشاهدة التلفزيون؟

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

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

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

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

3- نشر تطبيق الاستقبال محليًا

لكي تتمكّن من استخدام تطبيق استقبال الويب مع جهاز البث، يجب استضافته في مكان يمكن لجهاز البث الوصول إليه. إذا كان لديك خادم متاح يدعم بروتوكول HTTPS، تخطَّ التعليمات التالية ودوِّن عنوان URL، لأنّك ستحتاج إليه في القسم التالي.

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

تشغيل الخادم

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

دوِّن عنوان URL الخاص بجهاز الاستقبال المستضاف. ستستخدمه في القسم التالي.

4. تسجيل تطبيق في Cast Play Console

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

صورة لـ Google Cast SDK Developer Console مع تمييز الزر "إضافة تطبيق جديد"

انقر على "إضافة تطبيق جديد".

صورة لشاشة "تطبيق جهاز استقبال جديد" مع تمييز الخيار "جهاز استقبال مخصّص"

اختَر "جهاز استقبال مخصّص"، وهو ما سننشئه.

صورة لشاشة "جهاز استقبال مخصّص جديد" تعرض عنوان URL يكتبه أحد المستخدمين في حقل "عنوان URL لتطبيق جهاز الاستقبال"

أدخِل تفاصيل جهاز الاستقبال الجديد، وتأكَّد من استخدام عنوان URL الذي حصلت عليه.

في القسم الأخير. دوِّن رقم تعريف التطبيق المخصّص لجهاز الاستقبال الجديد.

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

صورة لواجهة Google Cast SDK Play Console مع تمييز الزر "إضافة جهاز جديد"

انقر على "إضافة جهاز جديد".

صورة لمربّع الحوار "إضافة جهاز استقبال البث"

أدخِل الرقم التسلسلي المطبوع على الجزء الخلفي من جهاز Cast وأدخِل اسمًا وصفيًا له. يمكنك أيضًا العثور على الرقم التسلسلي من خلال مشاركة شاشتك في Chrome عند الوصول إلى Play Console لـ Google Cast SDK.

ستستغرق العملية من 5 إلى 15 دقيقة قبل أن يصبح جهاز الاستقبال والجهاز جاهزَين للاختبار. بعد الانتظار لمدة تتراوح بين 5 و15 دقيقة، عليك إعادة تشغيل جهاز البث.

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

شعار Google Chrome

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

في المتصفّح، افتح أداة "التحكّم والسيطرة" (CaC).

صورة لعلامة التبويب "عناصر التحكّم في Cast Connect وأداة تسجيل البيانات" في أداة "التحكّم والقيادة" (CaC)

  1. من المفترض أن تظهر لك "أداة تكلفة اكتساب العملاء".
  2. استخدِم رقم تعريف جهاز الاستقبال التلقائي "CC1AD845" وانقر على الزر "ضبط معرّف التطبيق".
  3. انقر على زر "البث" في أعلى يمين الشاشة واختَر جهاز Google Cast.

صورة لعلامة التبويب "أدوات Cast والربط والتسجيل" في أداة "التحكّم والإدارة" (CaC) تشير إلى أنّها مرتبطة بتطبيق "جهاز استقبال"

  1. انتقِل إلى علامة التبويب "تحميل الوسائط" في أعلى الصفحة.

صورة لعلامة التبويب "تحميل الوسائط" في أداة القيادة والتحكّم (CaC)

  1. انقر على الزر "التحميل حسب المحتوى" لتشغيل فيديو نموذجي.
  2. سيبدأ تشغيل الفيديو على جهاز Google Cast لعرض الشكل الأساسي لوظائف جهاز الاستقبال باستخدام "جهاز الاستقبال التلقائي".

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

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

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

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

  1. اختَر الدليل رمز المجلدapp-start من ملف تنزيل الرمز النموذجي.
  2. فتح js/receiver.js وindex.html

يُرجى العِلم أنّه أثناء العمل على هذا الدرس العملي، من المفترض أن يرصد http-server التغييرات التي تجريها. إذا لاحظت عدم حدوث ذلك، حاوِل إيقاف http-server وإعادة تشغيله.

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

يبدأ تطبيق المستقبِل جلسة البث ويبقى في وضع الاستعداد إلى أن يصل طلب LOAD (أي الأمر بتشغيل جزء من الوسائط) من جهاز الإرسال.

يتألف التطبيق من طريقة عرض رئيسية واحدة، محدّدة في index.html، وملف JavaScript واحد باسم js/receiver.js يحتوي على جميع التعليمات البرمجية اللازمة لتشغيل جهاز الاستقبال.

index.html

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

receiver.js

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

7. جهاز استقبال البث الأساسي

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

الإعداد

أضِف الرمز التالي إلى index.html في العنوان:

<head>
  ...

  <script src="//www.gstatic.com/cast/sdk/libs/caf_receiver/v3/cast_receiver_framework.js"></script>
</head>

أضِف الرمز التالي إلى index.html <body> قبل <footer> loading receiver.js, لتوفير مساحة لحزمة تطوير البرامج (SDK) الخاصة بجهاز الاستقبال لعرض واجهة المستخدم التلقائية لجهاز الاستقبال التي يتم شحنها مع النص البرمجي الذي أضفته للتو.

<cast-media-player></cast-media-player>

الآن، علينا إعداد حزمة تطوير البرامج (SDK) في js/receiver.js، والتي تتضمّن ما يلي:

  • الحصول على مرجع إلى CastReceiverContext، نقطة الدخول الأساسية إلى حزمة تطوير البرامج (SDK) الكاملة الخاصة بجهاز الاستقبال
  • تخزين مرجع إلى PlayerManager، وهو العنصر الذي يتعامل مع التشغيل ويزوّدك بكلّ نقاط الربط التي تحتاج إليها لإضافة منطق مخصّص
  • إعداد حزمة تطوير البرامج (SDK) من خلال استدعاء start() على CastReceiverContext

أضِف ما يلي إلى js/receiver.js.

const context = cast.framework.CastReceiverContext.getInstance();
const playerManager = context.getPlayerManager();

context.start();

8. إرسال محتوى فيديو "أساسي"

لأغراض هذا الدرس التطبيقي، استخدِم "أداة CaC" لتجربة جهاز الاستقبال الجديد.

وجِّه متصفّح الويب إلى أداة "التحكّم والإدارة" (CaC).

صورة لعلامة التبويب &quot;عناصر التحكّم في Cast Connect وأداة تسجيل البيانات&quot; في أداة &quot;التحكّم والقيادة&quot; (CaC)

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

بثّ الوسائط

على مستوى عالٍ، لتشغيل الوسائط على جهاز بث، يجب اتّباع الخطوات التالية:

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

في هذه المحاولة الأساسية الأولى، سنملأ MediaInfo بعنوان URL لمادة عرض قابلة للتشغيل (مخزّنة في MediaInfo.contentUrl).

يستخدم المرسِل الحقيقي معرّف وسائط خاصًا بالتطبيق في MediaInfo.contentId. يستخدم جهاز الاستقبال contentId كمعرّف لإجراء طلبات مناسبة من واجهة برمجة التطبيقات الخلفية لحلّ عنوان URL الفعلي للأصل وتعيينه على MediaInfo.contentUrl.. سيتولّى جهاز الاستقبال أيضًا مهامًا مثل الحصول على ترخيص إدارة الحقوق الرقمية أو إدخال معلومات حول فواصل الإعلانات.

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

صورة لعلامة التبويب &quot;عناصر التحكّم في Cast Connect وLogger &quot; في أداة &quot;التحكّم والإدارة&quot; (CaC) تشير إلى أنّها مرتبطة بتطبيق Receiver

انتقِل إلى علامة التبويب "تحميل الوسائط" (Load Media) وانقر على الزر "تحميل حسب المحتوى" (Load by Content). من المفترض أن يبدأ جهاز الاستقبال في تشغيل المحتوى النموذجي.

صورة لعلامة التبويب &quot;تحميل الوسائط&quot; في أداة القيادة والتحكّم (CaC)

وبالتالي، تعالج حزمة تطوير البرامج (SDK) الخاصة بجهاز الاستقبال ما يلي:

  • بدء جلسة Cast
  • التعامل مع طلبات LOAD الواردة من المُرسِلين والتي تتضمّن مواد عرض قابلة للتشغيل
  • قدِّم واجهة مستخدم أساسية جاهزة للعرض على الشاشة الكبيرة.

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

9- التكامل مع واجهة برمجة تطبيقات خارجية

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

تنفّذ التطبيقات ذلك عادةً للأسباب التالية:

  • قد لا يعرف المرسِل عنوان URL للمحتوى.
  • تم تصميم تطبيق Cast للتعامل مع المصادقة أو منطق الأنشطة التجارية الأخرى أو طلبات البيانات من واجهة برمجة التطبيقات مباشرةً على جهاز الاستقبال.

يتم تنفيذ هذه الوظيفة بشكل أساسي في الطريقة PlayerManager setMessageInterceptor(). يتيح لك ذلك اعتراض الرسائل الواردة حسب النوع وتعديلها قبل أن تصل إلى معالج الرسائل الداخلي في حزمة SDK. في هذا القسم، سنتعامل مع طلبات LOAD حيث سننفّذ ما يلي:

  • اقرأ طلب LOAD الوارد وcontentId المخصّص له.
  • أرسِل طلب GET إلى واجهة برمجة التطبيقات للبحث عن مادة العرض القابلة للبث حسب contentId.
  • عدِّل طلب LOAD باستخدام عنوان URL الخاص بالبث.
  • عدِّل العنصر MediaInformation لضبط مَعلمات نوع البث.
  • إحالة الطلب إلى حزمة SDK لتشغيل المحتوى، أو رفض الأمر إذا لم نتمكّن من البحث عن الوسائط المطلوبة

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

نموذج واجهة برمجة التطبيقات

انتقِل بمتصفّحك إلى https://storage.googleapis.com/cpe-sample-media/content.json وألقِ نظرة على كتالوج الفيديو النموذجي. يتضمّن المحتوى عناوين URL لصور الملصقات بتنسيق png بالإضافة إلى كل من بث DASH وبث HLS. تشير مجموعات بث DASH وHLS إلى مصادر الفيديو والصوت التي تم فصلها والمخزّنة في حاويات mp4 مجزّأة.

{
  "bbb": {
    "author": "The Blender Project",
    "description": "Grumpy Bunny is grumpy",
    "poster": "https://[...]/[...]/BigBuckBunny/images/screenshot1.png",
    "stream": {
      "dash": "https://[...]/[...]/BigBuckBunny/BigBuckBunny_master.mpd",
      "hls": "https://[...]/[...]/BigBuckBunny/BigBuckBunny_master.m3u8",
    "title": "Big Buck Bunny"
  },
  "fbb_ad": {
    "author": "Google Inc.",
    "description": "Introducing Chromecast. The easiest way to enjoy [...]",
    "poster": "https://[...]/[...]/ForBiggerBlazes/images/screenshot8.png",
    "stream": {
      "dash": "https://[...]/[...]/ForBiggerBlazes/ForBiggerBlazes.mpd",
      "hls": "https://[...]/[...]/ForBiggerBlazes/ForBiggerBlazes.m3u8",
    "title": "For Bigger Blazes"
  },

  [...]

}

في الخطوة التالية، سنربط مفتاح كل إدخال (على سبيل المثال، bbb, fbb_ad ) بعنوان URL الخاص بالبث بعد أن يتم استدعاء المستلِم بطلب LOAD.

اعتراض طلب LOAD

في هذه الخطوة، سننشئ أداة اعتراض تحميل تتضمّن دالة تُرسل طلب XHR إلى ملف JSON المستضاف. بعد الحصول على ملف JSON، سنحلّل المحتوى ونضبط البيانات الوصفية. في الأقسام التالية، سنخصّص المَعلمات MediaInformation لتحديد نوع المحتوى.

أضِف الرمز التالي إلى ملف js/receiver.js، قبل استدعاء context.start() مباشرةً.

function makeRequest (method, url) {
  return new Promise(function (resolve, reject) {
    let xhr = new XMLHttpRequest();
    xhr.open(method, url);
    xhr.onload = function () {
      if (this.status >= 200 && this.status < 300) {
        resolve(JSON.parse(xhr.response));
      } else {
        reject({
          status: this.status,
          statusText: xhr.statusText
        });
      }
    };
    xhr.onerror = function () {
      reject({
        status: this.status,
        statusText: xhr.statusText
      });
    };
    xhr.send();
  });
}

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD,
    request => {
      return new Promise((resolve, reject) => {
        // Fetch content repository by requested contentId
        makeRequest('GET', 'https://storage.googleapis.com/cpe-sample-media/content.json').then(function (data) {
          let item = data[request.media.contentId];
          if(!item) {
            // Content could not be found in repository
            reject();
          } else {
            // Add metadata
            let metadata = new
               cast.framework.messages.GenericMediaMetadata();
            metadata.title = item.title;
            metadata.subtitle = item.author;

            request.media.metadata = metadata;

            // Resolve request
            resolve(request);
          }
        });
      });
    });

سيوضّح القسم التالي كيفية ضبط السمة media لطلب التحميل لمحتوى DASH.

استخدام محتوى Sample API DASH

بعد أن أعددنا أداة اعتراض التحميل، سنحدّد نوع المحتوى للمستلِم. ستوفّر هذه المعلومات للمستلِم عنوان URL لقائمة التشغيل الرئيسية ونوع MIME الخاص بالبث. أضِف الرمز التالي إلى ملف js/receiver.js في Promise() أداة اعتراض LOAD:

...
playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD,
    request => {
      return new Promise((resolve, reject) => {
          ...
          } else {
            // Adjusting request to make requested content playable
            request.media.contentUrl = item.stream.dash;
            request.media.contentType = 'application/dash+xml';
            ...
          }
        });
      });
    });

بعد إكمال هذه الخطوة، يمكنك الانتقال إلى "تجربة التحميل" لمحاولة التحميل باستخدام محتوى DASH. إذا أردت اختبار التحميل باستخدام محتوى HLS بدلاً من ذلك، اطّلِع على الخطوة التالية.

استخدام محتوى HLS الخاص بواجهة برمجة التطبيقات التجريبية

يتضمّن نموذج واجهة برمجة التطبيقات محتوى HLS بالإضافة إلى DASH. بالإضافة إلى ضبط contentType كما فعلنا في الخطوة السابقة، سيتطلّب طلب التحميل بعض الخصائص الإضافية من أجل استخدام عناوين URL الخاصة بواجهة برمجة التطبيقات النموذجية لبروتوكول HLS. وعندما يتم ضبط جهاز الاستقبال لتشغيل بث HLS، يكون نوع الحاوية التلقائي المتوقّع هو بث النقل (TS). نتيجةً لذلك، سيحاول جهاز الاستقبال فتح عيّنات من بث MP4 بتنسيق TS إذا تم تعديل السمة contentUrl فقط. في طلب التحميل، يجب تعديل الكائن MediaInformation باستخدام خصائص إضافية لكي يعرف جهاز الاستقبال أنّ نوع المحتوى هو MP4 وليس TS. أضِف الرمز التالي إلى ملف js/receiver.js في أداة اعتراض التحميل لتعديل السمتَين contentUrl وcontentType. أضِف أيضًا السمتَين HlsSegmentFormat وHlsVideoSegmentFormat.

...
playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD,
    request => {
      return new Promise((resolve, reject) => {
          ...
          } else {
            // Adjusting request to make requested content playable
            request.media.contentUrl = item.stream.hls;
            request.media.contentType = 'application/x-mpegurl';
            request.media.hlsSegmentFormat = cast.framework.messages.HlsSegmentFormat.FMP4;
            request.media.hlsVideoSegmentFormat = cast.framework.messages.HlsVideoSegmentFormat.FMP4;
            ...
          }
        });
      });
    });

تجربة الميزة

افتح أداة "التحكّم والسيطرة" (CaC) مرة أخرى واضبط معرّف التطبيق على معرّف تطبيق جهاز الاستقبال. اختَر جهازك باستخدام زر "البث".

انتقِل إلى علامة التبويب "تحميل الوسائط". في هذه المرة، احذف النص في حقل "عنوان URL للمحتوى" بجانب الزر "التحميل حسب المحتوى"، ما سيؤدي إلى إجبار تطبيقنا على إرسال طلب LOAD يتضمّن فقط المرجع contentId إلى الوسائط الخاصة بنا.

صورة لعلامة التبويب &quot;تحميل الوسائط&quot; في أداة القيادة والتحكّم (CaC)

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

انقر على الزر "التحميل حسب المحتوى" لمعرفة ما إذا كان يتم تشغيل الوسائط بشكل صحيح. يمكنك تغيير معرّف Content ID إلى معرّف آخر في ملف content.json.

10. التحسين للشاشات الذكية

الشاشات الذكية هي أجهزة تتضمّن وظيفة اللمس وتسمح لتطبيقات الاستقبال بتوفير عناصر تحكّم تعمل باللمس.

يوضّح هذا القسم كيفية تحسين تطبيق الاستقبال عند تشغيله على الشاشات الذكية، وكيفية تخصيص عناصر التحكّم في المشغّل.

الوصول إلى عناصر التحكّم في واجهة المستخدم

يمكن الوصول إلى عنصر "عناصر التحكّم في واجهة المستخدم" للشاشات الذكية باستخدام cast.framework.ui.Controls.GetInstance(). أضِف الرمز التالي إلى ملف js/receiver.js فوق context.start():

...

// Optimizing for smart displays
const touchControls = cast.framework.ui.Controls.getInstance();

context.start();

إذا لم تستخدم العنصر <cast-media-player>، عليك ضبط touchScreenOptimizedApp في CastReceiverOptions. في هذا الدرس التطبيقي، سنستخدم العنصر <cast-media-player>.

context.start({ touchScreenOptimizedApp: true });

يتم تعيين أزرار التحكّم التلقائية لكلّ خانة استنادًا إلى MetadataType وMediaStatus.supportedMediaCommands.

عناصر التحكّم في الفيديو

بالنسبة إلى MetadataType.MOVIE وMetadataType.TV_SHOW وMetadataType.GENERIC، سيتم عرض عنصر "عناصر تحكّم واجهة المستخدم" للشاشات الذكية كما هو موضّح في المثال أدناه.

صورة لفيديو يتم تشغيله مع عناصر تحكّم في واجهة المستخدم تظهر في الأعلى

  1. --playback-logo-image
  2. MediaMetadata.subtitle
  3. MediaMetadata.title
  4. MediaStatus.currentTime
  5. MediaInformation.duration
  6. ControlsSlot.SLOT_SECONDARY_1: ControlsButton.QUEUE_PREV
  7. ControlsSlot.SLOT_PRIMARY_1: ControlsButton.SEEK_BACKWARD_30
  8. PLAY/PAUSE
  9. ControlsSlot.SLOT_PRIMARY_2: ControlsButton.SEEK_FORWARD_30
  10. ControlsSlot.SLOT_SECONDARY_2: ControlsButton.QUEUE_NEXT

عناصر التحكّم في الصوت

بالنسبة إلى MetadataType.MUSIC_TRACK، سيتم عرض عنصر "عناصر التحكّم في واجهة المستخدم" الخاص بالشاشات الذكية على النحو التالي:

صورة لموسيقى يتم تشغيلها مع عناصر تحكّم في واجهة المستخدم مدمجة في الأعلى

  1. --playback-logo-image
  2. MusicTrackMediaMetadata.albumName
  3. MusicTrackMediaMetadata.title
  4. MusicTrackMediaMetadata.albumArtist
  5. MusicTrackMediaMetadata.images[0]
  6. MediaStatus.currentTime
  7. MediaInformation.duration
  8. ControlsSlot.SLOT_SECONDARY_1: ControlsButton.NO_BUTTON
  9. ControlsSlot.SLOT_PRIMARY_1: ControlsButton.QUEUE_PREV
  10. PLAY/PAUSE
  11. ControlsSlot.SLOT_PRIMARY_2: ControlsButton.QUEUE_NEXT
  12. ControlsSlot.SLOT_SECONDARY_2: ControlsButton.NO_BUTTON

تعديل أوامر الوسائط المتوافقة

يحدّد عنصر "عناصر التحكّم في واجهة المستخدم" أيضًا ما إذا كان سيتم عرض ControlsButton استنادًا إلى MediaStatus.supportedMediaCommands.

عندما تكون قيمة supportedMediaCommands مساوية ALL_BASIC_MEDIA، سيتم عرض تخطيط عناصر التحكّم التلقائي كما يلي:

صورة لعناصر التحكّم في مشغّل الوسائط: شريط التقدّم وزر &quot;تشغيل&quot; وزرّا &quot;تخطّي للأمام&quot; و&quot;تخطّي للخلف&quot; مفعّلان

عندما تكون قيمة supportedMediaCommands مساوية ALL_BASIC_MEDIA | QUEUE_PREV | QUEUE_NEXT، سيتم عرض تخطيط عناصر التحكّم التلقائي كما يلي:

صورة لعناصر التحكّم في مشغّل الوسائط: شريط التقدّم وزر &quot;تشغيل&quot; وزرّا &quot;التقديم السريع&quot; و&quot;الترجيع&quot; وزرّا &quot;إضافة الأغنية السابقة إلى قائمة الانتظار&quot; و&quot;إضافة الأغنية التالية إلى قائمة الانتظار&quot;

عندما تكون قيمة supportedMediaCommands مساوية PAUSE | QUEUE_PREV | QUEUE_NEXT، سيظهر تنسيق عناصر التحكّم التلقائي كما يلي:

صورة لعناصر التحكّم في مشغّل الوسائط: شريط التقدّم وزر &quot;تشغيل&quot; وزرّا &quot;إضافة إلى قائمة التشغيل السابقة&quot; و&quot;إضافة إلى قائمة التشغيل التالية&quot; مفعّلان

عندما تتوفّر مسارات النص، سيظهر زر مقاطع الترجمة والشرح دائمًا في SLOT_1.

صورة لعناصر التحكّم في مشغّل الوسائط: شريط التقدّم وزر &quot;تشغيل&quot; وزرّا &quot;تخطّي للأمام&quot; و&quot;تخطّي للخلف&quot; وزرّا &quot;وضع في قائمة الانتظار قبل&quot; و&quot;وضع في قائمة الانتظار بعد&quot; وزرّ &quot;الترجمة والشرح&quot; مفعّل

لتغيير قيمة supportedMediaCommands بشكلٍ ديناميكي بعد بدء سياق جهاز الاستقبال، يمكنك طلب PlayerManager.setSupportedMediaCommands لإلغاء القيمة. يمكنك أيضًا إضافة أمر جديد باستخدام addSupportedMediaCommands أو إزالة أمر حالي باستخدام removeSupportedMediaCommands.

تخصيص أزرار التحكّم

يمكنك تخصيص عناصر التحكّم باستخدام PlayerDataBinder. أضِف الرمز التالي إلى ملف js/receiver.js أسفل عناصر التحكّم باللمس لضبط الفتحة الأولى لعناصر التحكّم:

...

// Optimizing for smart displays
const touchControls = cast.framework.ui.Controls.getInstance();
const playerData = new cast.framework.ui.PlayerData();
const playerDataBinder = new cast.framework.ui.PlayerDataBinder(playerData);

playerDataBinder.addEventListener(
  cast.framework.ui.PlayerDataEventType.MEDIA_CHANGED,
  (e) => {
    if (!e.value) return;

    // Clear default buttons and re-assign
    touchControls.clearDefaultSlotAssignments();
    touchControls.assignButton(
      cast.framework.ui.ControlsSlot.SLOT_PRIMARY_1,
      cast.framework.ui.ControlsButton.SEEK_BACKWARD_30
    );
  });

context.start();

11. تنفيذ ميزة تصفّح الوسائط على الشاشات الذكية

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

BrowseContent

في ما يلي مثال على واجهة المستخدم BrowseContent وسماتها:

صورة لواجهة مستخدم BrowseContent تعرض صورتَين مصغّرتَين لفيديو وجزءًا من صورة مصغّرة ثالثة

  1. BrowseContent.title
  2. BrowseContent.items

نسبة العرض إلى الارتفاع

استخدِم targetAspectRatio property لاختيار أفضل نسبة عرض إلى ارتفاع لمواد عرض الصور. تتيح حزمة تطوير البرامج (SDK) الخاصة بـ CAF Receiver ثلاث نسب عرض إلى ارتفاع: SQUARE_1_TO_1 وPORTRAIT_2_TO_3 وLANDSCAPE_16_TO_9.

BrowseItem

استخدِم BrowseItem لعرض العنوان والعنوان الفرعي والمدة والصورة لكل عنصر:

صورة لواجهة مستخدم BrowseContent تعرض صورتَين مصغّرتَين لفيديو وجزءًا من صورة مصغّرة ثالثة

  1. BrowseItem.image
  2. BrowseItem.duration
  3. BrowseItem.title
  4. BrowseItem.subtitle

ضبط بيانات "تصفّح الوسائط"

يمكنك تقديم قائمة بالمحتوى الإعلامي لتصفّحه من خلال استدعاء setBrowseContent. أضِف الرمز التالي إلى ملف js/receiver.js أسفل playerDataBinder وفي متتبِّع الأحداث MEDIA_CHANGED لضبط عناصر التصفّح بعنوان "التالي".

// Optimizing for smart displays
const touchControls = cast.framework.ui.Controls.getInstance();
const playerData = new cast.framework.ui.PlayerData();
const playerDataBinder = new cast.framework.ui.PlayerDataBinder(playerData);

...

let browseItems = getBrowseItems();

function getBrowseItems() {
  let browseItems = [];
  makeRequest('GET', 'https://storage.googleapis.com/cpe-sample-media/content.json')
  .then(function (data) {
    for (let key in data) {
      let item = new cast.framework.ui.BrowseItem();
      item.entity = key;
      item.title = data[key].title;
      item.subtitle = data[key].description;
      item.image = new cast.framework.messages.Image(data[key].poster);
      item.imageType = cast.framework.ui.BrowseImageType.MOVIE;
      browseItems.push(item);
    }
  });
  return browseItems;
}

let browseContent = new cast.framework.ui.BrowseContent();
browseContent.title = 'Up Next';
browseContent.items = browseItems;
browseContent.targetAspectRatio = cast.framework.ui.BrowseImageAspectRatio.LANDSCAPE_16_TO_9;

playerDataBinder.addEventListener(
  cast.framework.ui.PlayerDataEventType.MEDIA_CHANGED,
  (e) => {
    if (!e.value) return;

    ....

    // Media browse
    touchControls.setBrowseContent(browseContent);
  });

سيؤدي النقر على عنصر تصفّح الوسائط إلى تشغيل أداة الاعتراض LOAD. أضِف الرمز التالي إلى أداة اعتراض LOAD لربط request.media.contentId بـ request.media.entity من عنصر تصفّح الوسائط:

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD,
    request => {
      ...

      // Map contentId to entity
      if (request.media && request.media.entity) {
        request.media.contentId = request.media.entity;
      }

      return new Promise((resolve, reject) => {
            ...
        });
    });

يمكنك أيضًا ضبط العنصر BrowseContent على null لإزالة واجهة مستخدم "تصفّح الوسائط".

12. تصحيح أخطاء تطبيقات المستقبِل

توفّر حزمة تطوير البرامج (SDK) لتطبيق Cast Receiver خيارًا آخر للمطوّرين لتصحيح أخطاء تطبيقات الاستقبال بسهولة من خلال استخدام واجهة برمجة التطبيقات CastDebugLogger وأداة مصاحبة للتحكّم والسيطرة (CaC) لتسجيل السجلات.

الإعداد

لدمج واجهة برمجة التطبيقات، أضِف نص برمجي للمصدر CastDebugLogger في ملف index.html. يجب تعريف المصدر في علامة <head> بعد تعريف حزمة تطوير البرامج (SDK) الخاصة بـ Cast Receiver.

<head>
  ...
  <script src="//www.gstatic.com/cast/sdk/libs/caf_receiver/v3/cast_receiver_framework.js"></script>
  <!-- Cast Debug Logger -->
  <script src="//www.gstatic.com/cast/sdk/libs/devtools/debug_layer/caf_receiver_logger.js"></script>
</head>

في js/receiver.js أعلى الملف وأسفل playerManager، أضِف الرمز التالي لاسترداد مثيل CastDebugLogger وتفعيل أداة تسجيل البيانات:

const context = cast.framework.CastReceiverContext.getInstance();
const playerManager = context.getPlayerManager();

// Debug Logger
const castDebugLogger = cast.debug.CastDebugLogger.getInstance();
const LOG_TAG = 'MyAPP.LOG';

// Enable debug logger and show a 'DEBUG MODE' overlay at top left corner.
context.addEventListener(cast.framework.system.EventType.READY, () => {
  if (!castDebugLogger.debugOverlayElement_) {
      castDebugLogger.setEnabled(true);
  }
});

عند تفعيل أداة تسجيل تصحيح الأخطاء، سيظهر على جهاز الاستقبال تراكب يعرض DEBUG MODE.

صورة لفيديو يتم تشغيله مع ظهور الرسالة &quot;وضع تصحيح الأخطاء&quot; على خلفية حمراء في أعلى يمين الإطار

تسجيل أحداث اللاعب

باستخدام CastDebugLogger، يمكنك بسهولة تسجيل أحداث اللاعبين التي يتم تشغيلها بواسطة حزمة تطوير البرامج (SDK) الخاصة بـ CAF Receiver واستخدام مستويات تسجيل مختلفة لتسجيل بيانات الأحداث. يستخدِم إعداد loggerLevelByEvents كلاً من cast.framework.events.EventType وcast.framework.events.category لتحديد الأحداث التي سيتم تسجيلها.

أضِف الرمز التالي أسفل تعريف castDebugLogger لتسجيل الوقت الذي يتم فيه تشغيل حدث CORE أو بث تغيير mediaStatus:

// Debug Logger
const castDebugLogger = cast.debug.CastDebugLogger.getInstance();

// Enable debug logger and show a 'DEBUG MODE' overlay at top left corner.
context.addEventListener(cast.framework.system.EventType.READY, () => {
  if (!castDebugLogger.debugOverlayElement_) {
      castDebugLogger.setEnabled(true);
  }
});

// Set verbosity level for Core events.
castDebugLogger.loggerLevelByEvents = {
  'cast.framework.events.category.CORE': cast.framework.LoggerLevel.INFO,
  'cast.framework.events.EventType.MEDIA_STATUS': cast.framework.LoggerLevel.DEBUG
}

رسائل السجلّ والعلامات المخصّصة

تتيح واجهة برمجة التطبيقات CastDebugLogger إنشاء رسائل سجلّ تظهر على طبقة تصحيح أخطاء جهاز الاستقبال بألوان مختلفة. تتوفّر طرق السجلّ التالية، وهي مُدرَجة بالترتيب من الأولوية القصوى إلى الأولوية الدنيا:

  • castDebugLogger.error(custom_tag, message);
  • castDebugLogger.warn(custom_tag, message);
  • castDebugLogger.info(custom_tag, message);
  • castDebugLogger.debug(custom_tag, message);

بالنسبة إلى كل طريقة تسجيل، تكون المَعلمة الأولى علامة مخصّصة. يمكن أن تكون هذه السلسلة أي سلسلة تعريفية تجدها ذات معنى. يستخدم CastDebugLogger العلامات لفلترة السجلّات. يتم شرح استخدام العلامات بالتفصيل أدناه. المَعلمة الثانية هي رسالة السجلّ.

لعرض السجلّات أثناء العمل، أضِف سجلّات إلى أداة اعتراض LOAD.

playerManager.setMessageInterceptor(
  cast.framework.messages.MessageType.LOAD,
  request => {
    castDebugLogger.info(LOG_TAG, 'Intercepting LOAD request');

    // Map contentId to entity
    if (request.media && request.media.entity) {
      request.media.contentId = request.media.entity;
    }

    return new Promise((resolve, reject) => {
      // Fetch content repository by requested contentId
      makeRequest('GET', 'https://storage.googleapis.com/cpe-sample-media/content.json')
        .then(function (data) {
          let item = data[request.media.contentId];
          if(!item) {
            // Content could not be found in repository
            castDebugLogger.error(LOG_TAG, 'Content not found');
            reject();
          } else {
            // Adjusting request to make requested content playable
            request.media.contentUrl = item.stream.dash;
            request.media.contentType = 'application/dash+xml';
            castDebugLogger.warn(LOG_TAG, 'Playable URL:', request.media.contentUrl);

            // Add metadata
            let metadata = new cast.framework.messages.MovieMediaMetadata();
            metadata.metadataType = cast.framework.messages.MetadataType.MOVIE;
            metadata.title = item.title;
            metadata.subtitle = item.author;

            request.media.metadata = metadata;

            // Resolve request
            resolve(request);
          }
      });
    });
  });

يمكنك التحكّم في الرسائل التي تظهر على طبقة تصحيح الأخطاء من خلال ضبط مستوى السجلّ في loggerLevelByTags لكل علامة مخصّصة. على سبيل المثال، سيؤدي تفعيل علامة مخصّصة بمستوى السجلّ cast.framework.LoggerLevel.DEBUG إلى عرض جميع الرسائل المُضافة مع رسائل سجلّ الخطأ والتحذير والمعلومات وتصحيح الأخطاء. لن يؤدي تفعيل علامة مخصّصة بالمستوى WARNING إلا إلى عرض رسائل سجلّ الخطأ والتحذير.

إعدادات loggerLevelByTags اختيارية. في حال عدم ضبط علامة مخصّصة لمستوى مسجّل البيانات، ستظهر جميع رسائل السجلّ على طبقة تصحيح الأخطاء.

أضِف الرمز التالي أسفل أداة تسجيل الأحداث CORE:

// Set verbosity level for Core events.
castDebugLogger.loggerLevelByEvents = {
  'cast.framework.events.category.CORE': cast.framework.LoggerLevel.INFO,
  'cast.framework.events.EventType.MEDIA_STATUS': cast.framework.LoggerLevel.DEBUG
}

// Set verbosity level for custom tags.
castDebugLogger.loggerLevelByTags = {
    [LOG_TAG]: cast.framework.LoggerLevel.DEBUG,
};

تراكب تصحيح الأخطاء

توفّر أداة Cast Debug Logger تراكب تصحيح الأخطاء على جهاز الاستقبال لعرض رسائل السجلّ المخصّصة على جهاز البث. استخدِم showDebugLogs لتبديل وضع تصحيح الأخطاء وclearDebugLogs لمحو رسائل السجلّ في وضع تصحيح الأخطاء.

أضِف الرمز التالي لمعاينة طبقة تصحيح الأخطاء على جهاز الاستقبال.

context.addEventListener(cast.framework.system.EventType.READY, () => {
  if (!castDebugLogger.debugOverlayElement_) {
      // Enable debug logger and show a 'DEBUG MODE' overlay at top left corner.
      castDebugLogger.setEnabled(true);

      // Show debug overlay
      castDebugLogger.showDebugLogs(true);

      // Clear log messages on debug overlay
      castDebugLogger.clearDebugLogs();
  }
});

صورة تعرض تراكب تصحيح الأخطاء، وقائمة برسائل سجل تصحيح الأخطاء على خلفية شفافة فوق إطار فيديو

13. تهانينا

أصبحت الآن على دراية بكيفية إنشاء تطبيق مخصّص لجهاز استقبال الويب باستخدام Cast Web Receiver SDK.

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