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

1- نظرة عامة

شعار Google Cast

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

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

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

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

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

ما الذي سنبنيه؟

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

ما ستتعرَّف عليه

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

المتطلبات

التجربة

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

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

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

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

مبتدئ متوسط مختص

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

مبتدئ متوسط مختص

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

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

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

3. نشر جهاز الاستقبال محليًا

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

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

تشغيل الخادم

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

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

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

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

صورة لوحدة تحكّم المطوّرين في حزمة Google Cast SDK يظهر فيها الزر "إضافة تطبيق جديد" مميّزًا

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

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

حدد "Custom Replyr (مستلم مخصص)"، فهذا هو ما نصممه.

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

أدخل تفاصيل المُستلِم الجديد، واحرص على استخدام عنوان URL الذي انتهى المطاف به

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

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

صورة لوحدة تحكّم المطوّرين في حزمة تطوير البرامج (SDK) لتكنولوجيا Google Cast مع تمييز الزر "إضافة جهاز جديد"

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

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

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

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

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

شعار Google Chrome

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

في متصفّحك، افتح أداة Command and Control (CaC).

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

  1. من المفترض أن ترى أداة CaC.
  2. استخدم نموذج رقم تعريف المستلم لنموذج "CC1AD845" التلقائي، ثم انقر على الزر "ضبط رقم تعريف التطبيق".
  3. انقر على زر البث في أعلى يمين الشاشة، ثم اختر جهاز Google 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" وإعادة تشغيله.

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

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

يتكون التطبيق من عرض رئيسي واحد، تم تحديده في index.html وملف JavaScript واحد يُسمى js/receiver.js والذي يحتوي على كل المنطق لجعل جهاز الاستقبال يعمل بشكل صحيح.

index.html

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

receiver.js

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

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

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

وجِّه متصفّح الويب إلى أداة Command and Control (CaC).

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

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

بث الوسائط

على مستوى عالٍ، يجب تنفيذ ما يلي لتشغيل الوسائط على جهاز بث:

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

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

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

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

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

انتقل إلى علامة التبويب "تحميل الوسائط" وانقر على الزر "تحميل حسب المحتوى". من المفترض أن يبدأ المُستلِم تشغيل عيّنة المحتوى.

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

لذا، تكون أدوات SDK لجهاز الاستقبال جاهزة للاستخدام:

  • جارٍ إعداد جلسة البث
  • معالجة طلبات "LOAD" الواردة من المُرسِلين الذين لديهم مواد عرض قابلة للتشغيل
  • توفير واجهة مستخدم أساسية للمشغّل جاهزة للعرض على الشاشة الكبيرة.

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

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

تماشيًا مع الطريقة التي يتفاعل بها معظم المطوّرين مع أجهزة استقبال البث في التطبيقات الفعلية، سنعدّل جهاز الاستقبال للتعامل مع طلبات 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.

اعتراض طلب التحميل

سننشئ في هذه الخطوة أداة اعتراض التحميل تحتوي على دالة تُجري طلب 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.

استخدام نموذج محتوى DASH لواجهة برمجة التطبيقات

الآن وبعد أن أعددنا معترض التحميل، سنحدد نوع المحتوى للمستلم. ستوفّر هذه المعلومات للمستلم عنوان URL لقائمة التشغيل الرئيسية ونوع MIME لمجموعة البث. أضف الرمز التالي إلى ملف js/replyr.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/replyr.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;

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

صورة عناصر التحكّم في مشغّل الوسائط: تم تفعيل شريط التقدّم والزر &quot;تشغيل&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. تفعيل ميزة "تصفّح الوسائط" على الشاشات الذكية

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

BrowseContent

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

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

  1. BrowseContent.title
  2. BrowseContent.items

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

استخدِم targetAspectRatio property لاختيار أفضل نسبة عرض إلى ارتفاع لمواد عرض الصور. متوافقة مع ثلاث نِسَب عرض إلى ارتفاع متوافقة مع حزمة تطوير البرامج (SDK) لمعيار CAF: 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) لجهاز استقبال البث خيارًا آخر للمطوّرين يتيح لهم تصحيح الأخطاء في تطبيقات المُستلِم بسهولة من خلال استخدام CastDebugLogger API وأداة Command and Control (CaC) المصاحبة لالتقاط السجلات.

الإعداد

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

<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، واستخدام مستويات مختلفة من المسجِّل لتسجيل بيانات الأحداث. تستخدم الإعدادات 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 API إنشاء رسائل السجلّ التي تظهر على سطح تصحيح أخطاء المُستلِم بألوان مختلفة. تتوفر طرق السجل التالية، مرتبة بترتيب من الأولوية القصوى إلى الأدنى:

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

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

لعرض السجلّات أثناء العمل، أضِف السجلّات إلى أداة اعتراض 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,
};

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

يوفّر مسجّل تصحيح أخطاء البث تراكبًا لتصحيح الأخطاء على جهاز الاستقبال لعرض رسائل السجلّ المخصّصة على جهاز البث. استخدِم 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. تهانينا

تعرف الآن كيفية إنشاء تطبيق مخصص لجهاز استقبال الويب باستخدام حزمة تطوير البرامج (SDK) لجهاز Google Cast.

ولمزيد من التفاصيل، يُرجى الاطّلاع على دليل المطوِّر حول أجهزة استقبال الويب.