יצירת מקלט אינטרנט מותאם אישית

1. סקירה כללית

הלוגו של Google Cast

בקודלאב הזה תלמדו איך ליצור אפליקציית מקלט אינטרנט בהתאמה אישית להפעלת תוכן במכשירים שתומכים ב-Cast.

מה זה Google Cast?

Google Cast מאפשר למשתמשים להעביר תוכן מהנייד לטלוויזיה. לאחר מכן, המשתמשים יכולים להשתמש במכשיר הנייד או בדפדפן Chrome במחשב כשלט רחוק להפעלת מדיה בטלוויזיה.

Google Cast SDK מאפשר לאפליקציה לשלוט במכשירים שתומכים ב-Google Cast (לדוגמה, טלוויזיה או מערכת סאונד). ערכת ה-SDK של Cast מספקת את רכיבי ממשק המשתמש הנדרשים על סמך רשימת המשימות לעיצוב של Google Cast.

רשימת המשימות לעיצוב של Google Cast נועדה להפוך את חוויית המשתמש ב-Cast לפשוטה ולצפויה בכל הפלטפורמות הנתמכות. מידע נוסף זמין כאן.

מה אנחנו הולכים ליצור?

בסיום הקודלאב הזה תהיה לכם אפליקציית HTML5 שתופעל כמקלט בהתאמה אישית משלכם, שתוכל להציג תוכן וידאו במכשירים שתומכים ב-Cast.

מה תלמדו

  • איך מתכוננים לפיתוח מקלט.
  • העקרונות הבסיסיים של מקלט עם תמיכה ב-Cast על סמך מסגרת האפליקציות של Cast.
  • איך לקבל סרטון שהופעל אליו Cast.
  • איך משלבים את יומן ניפוי הבאגים.
  • איך מבצעים אופטימיזציה של המקלט למסכים חכמים.

מה נדרש

  • דפדפן Google Chrome בגרסה העדכנית ביותר.
  • שירות אירוח HTTPS, כמו Firebase Hosting או ngrok.
  • מכשיר Google Cast, כמו Chromecast או Android TV, עם הגדרת גישה לאינטרנט.
  • טלוויזיה או צג עם כניסת HDMI.

ניסיון

  • נדרש ידע קודם בפיתוח אתרים.
  • נדרש גם ידע קודם על צפייה בטלוויזיה :)

איך תוכלו להשתמש במדריך הזה?

לקריאה בלבד לקריאת התרגילים ולהשלמת התרגילים

מה מידת הניסיון שלך בפיתוח אפליקציות אינטרנט?

מתחילים בינוניים מתקדמים

איזה דירוג מגיע לדעתך לחוויית הצפייה בטלוויזיה?

מתחילים בינוניים מומחים

2. קבלת קוד לדוגמה

אפשר להוריד את כל הקוד לדוגמה למחשב...

ופורקים את קובץ ה-ZIP שהורדתם.

3. פריסה מקומית של המקבל

כדי שתוכלו להשתמש במקלט האינטרנט עם מכשיר Cast, הוא צריך להיות מתארח במקום שבו מכשיר ה-Cast יכול להגיע אליו. אם כבר יש לכם שרת זמין שתומך ב-HTTPS, תוכלו לדלג על ההוראות הבאות ולכתוב את כתובת ה-URL, כי תצטרכו אותה בקטע הבא.

אם אין לכם שרת זמין לשימוש, תוכלו להשתמש ב-אירוח ב-Firebase או ב-ngrok.

הפעלת השרת

אחרי שמגדירים את השירות הרצוי, עוברים אל app-start ומפעילים את השרת.

שימו לב לכתובת ה-URL של המקבל שמתארח. תשתמשו בו בקטע הבא.

4. רישום אפליקציה ב-Cast Console

כדי להפעיל מקלט בהתאמה אישית, כפי שנוצר ב-codelab הזה, במכשירי Chromecast, צריך לרשום את האפליקציה. אחרי שתירשמו את האפליקציה, תקבלו מזהה אפליקציה שבו האפליקציה השולחת צריכה להשתמש כדי לבצע קריאות ל-API, למשל כדי להפעיל אפליקציית מקלט.

תמונה של מסוף הפיתוח של Google Cast SDK עם הלחצן 'הוספת אפליקציה חדשה' מודגש

יש ללחוץ על 'הוספת אפליקציה חדשה'

תמונה של המסך 'אפליקציה חדשה של המקבל' שבה האפשרות 'מקלט מותאם אישית' מודגשת

בוחרים באפשרות 'Custom Receiver' (מקלט מותאם אישית). זה מה שאנחנו יוצרים.

תמונה של המסך 'New Custom Receiver' (מקלט מותאם אישית חדש) שמוצגת בה כתובת URL שמישהו מקלידים בשדה 'Receiver Application URL' (כתובת ה-URL של אפליקציית המקלט)

צריך להזין את הפרטים של המקבל החדש ולהשתמש בכתובת ה-URL שאליה הגעת

בקטע האחרון. צריך לרשום את מזהה האפליקציה שהוקצה למכשיר המקלט החדש.

לפני הפרסום, צריך גם לרשום את מכשיר Google Cast כדי שיהיה לו גישה לאפליקציית המקלט. לאחר פרסום אפליקציית המקבל, היא תהיה זמינה לכל מכשירי Google Cast. לצורך ה-Codelab הזה, מומלץ לעבוד עם אפליקציית מקלט שלא פורסמה.

תמונה של Google Cast SDK Console שבו מופיע הלחצן 'הוספת מכשיר חדש'

לוחצים על 'הוספת מכשיר חדש'.

תמונה של תיבת הדו-שיח 'הוספת מכשיר מקלט להעברה (cast)'

מזינים את המספר הסידורי שמודפס על גב מכשיר ההעברה (cast) ומעניקים לו שם תיאורי. אפשר גם למצוא את המספר הסידורי על ידי העברה (cast) של המסך ב-Chrome כשנכנסים אל Google Cast SDK Developer Console.

יחלפו 5 עד 15 דקות עד שהמקלט והמכשיר יהיו מוכנים לבדיקה. אחרי שממתינים 5 עד 15 דקות, צריך להפעיל מחדש את מכשיר ה-Cast.

5. הרצת האפליקציה לדוגמה

הלוגו של Google Chrome

בזמן שאנחנו ממתינים לאפליקציית המקלט החדשה שלנו שתהיה מוכנה לבדיקה, נראה איך נראית אפליקציית מקלט לדוגמה שהושלמו בה כל הפעולות. המקלט שנבנה יוכל להפעיל מדיה באמצעות סטרימינג בקצב העברת נתונים אדפטיבי (אנחנו נשתמש בתוכן לדוגמה שמקודד ל-Dynamic Adaptive Streaming over HTTP (DASH)).

פותחים את הכלי לניהול (CaC) בדפדפן.

תמונה של הכרטיסייה 'Cast Connect & Logger Controls' בכלי Command and Control (CaC)

  1. אמור להופיע הכלי שלנו לניהול הרשאות גישה.
  2. משתמשים במזהה הנמען לדוגמה 'CC1AD845' שמוגדר כברירת מחדל ולוחצים על הלחצן 'הגדרת מזהה האפליקציה'.
  3. לוחצים על הלחצן להפעלת Cast בפינה הימנית העליונה ובוחרים את מכשיר ה-Google Cast.

תמונה של הכרטיסייה 'Cast Connect & Logger Controls' של כלי הפקודה והבקרה (CaC), שמציין שהוא מחובר לאפליקציית מקלט

  1. עוברים לכרטיסייה 'טעינת מדיה' בחלק העליון.

תמונה של הכרטיסייה 'טעינה של מדיה' בכלי Command and Control (CaC)

  1. לוחצים על הלחצן 'טעינה לפי תוכן' כדי להפעיל סרטון לדוגמה.
  2. הסרטון יתחיל לפעול במכשיר Google Cast כדי להראות איך נראית הפונקציונליות הבסיסית של מקלט באמצעות מקלט ברירת המחדל.

6. הכנת פרויקט ההתחלה

אנחנו צריכים להוסיף תמיכה ב-Google Cast לאפליקציית ההתחלה שהורדתם. הנה כמה מונחים של Google Cast שנשתמש בהם ב-Codelab הזה:

  • אפליקציית שולח פועלת במכשיר נייד או במחשב נייד,
  • אפליקציית מקלט פועלת במכשיר Google Cast.

עכשיו אתם מוכנים להמשיך לפתח את הפרויקט באמצעות עורך הטקסט המועדף עליכם:

  1. בוחרים את הספרייה סמל של תיקייהapp-start מתוך הורדת הקוד לדוגמה.
  2. פתיחת js/receiver.js ו-index.html

הערה: במהלך העבודה ב-codelab הזה, http-server אמור לזהות את השינויים שתבצעו. אם היא לא מופיעה, אפשר לנסות למחוק את הפעילות של http-server ולהפעיל אותה מחדש.

עיצוב אפליקציות

אפליקציית המכשיר המקבל מפעילה את סשן ההעברה (cast) וממתינה לקבלת בקשת 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, הפעלה של טיפול באובייקט ומתן כל ה-הוקים (hooks) הדרושים לך כדי לחבר לוגיקה מותאמת אישית משלך
  • אתחול ה-SDK באמצעות קריאה ל-start() ב-CastReceiverContext

מוסיפים את הפרטים הבאים ל-js/receiver.js.

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

context.start();

8. העברה (cast) של תוכן וידאו 'בסיסי'

במסגרת Codelab הזה, נשתמש בכלי CaC כדי לנסות את המקלט החדש.

פותחים את דפדפן האינטרנט ומפנים אותו אל הכלי Command and Control (CaC).

תמונה של הכרטיסייה &#39;Cast Connect ו-Logger Controls&#39; בכלי Command and Control (CaC)

חשוב להחליף את מזהה האפליקציה שלכם כפי שרשום בשדה קודם, וללחוץ על 'הגדרת מזהה האפליקציה'. כך הכלי יורה להשתמש במכשיר הקולט כשמתחילים את סשן ההעברה (cast).

העברת מדיה

ככלל, כדי להפעיל מדיה במכשיר Cast צריכים להתקיים התנאים הבאים:

  1. השולח יוצר אובייקט JSON מסוג MediaInfo מ-Cast SDK, שמתאר פריט מדיה.
  2. השולח מתחבר למכשיר Cast כדי להפעיל את אפליקציית המקלט.
  3. המקבל טוען את האובייקט MediaInfo באמצעות בקשת LOAD כדי להפעיל את התוכן.
  4. הנמען עוקב אחרי מצב המדיה ומנטר אותו.
  5. השולח שולח פקודות הפעלה למקבל כדי לשלוט בהפעלה על סמך אינטראקציות של המשתמש עם האפליקציה של השולח.

בניסיון הבסיסי הראשון הזה, נאכלס את MediaInfo בכתובת URL של נכס שניתן להפעלה (ששמור ב-MediaInfo.contentUrl).

שולח בעולם האמיתי משתמש במזהה מדיה ספציפי לאפליקציה ב-MediaInfo.contentId. המקבל משתמש ב-contentId כמזהה כדי לבצע קריאות מתאימות ל-API בקצה העורפי כדי לפענח את כתובת ה-URL של הנכס בפועל ולהגדיר אותה לערך MediaInfo.contentUrl. המקבל יטפל גם במשימות כמו רכישה של רישיון DRM או החדרת מידע על הפסקות למודעות.

בקטע הבא נרחיב את המקלט כדי לבצע פעולה כזו. בינתיים, לוחצים על סמל ההעברה (Cast) ובוחרים את המכשיר כדי לפתוח את המקלט.

תמונה של הכרטיסייה &#39;Cast Connect & Logger Controls&#39; בכלי לניהול (CaC) שמציינת שהוא מחובר לאפליקציית מקלט

עוברים לכרטיסייה 'טעינת מדיה' ולוחצים על הלחצן 'טעינת תוכן'. השקע אמור להתחיל להפעיל את תוכן הדוגמה.

תמונה של הכרטיסייה &#39;טעינה של מדיה&#39; בכלי Command and Control (CaC)

לאחר מכן, ה-SDK של המקלט מטפל בנושאים הבאים:

  • איפוס הסשן של ה-Cast
  • טיפול בבקשות LOAD נכנסות משולחים שמכילות נכסים שניתן להפעיל
  • לספק ממשק משתמש בסיסי של נגן שאפשר להציג במסך הגדול.

מומלץ לבדוק את הכלי ל-CAC ואת הקוד שלו לפני שממשיכים לקטע הבא, שבו נרחיב את המקלט שלנו כדי לתקשר עם ממשק API לדוגמה פשוט כדי למלא בקשות LOAD נכנסות משולחים.

9. שילוב עם ממשק API חיצוני

בהתאם לאופן שבו רוב המפתחים מקיימים אינטראקציה עם מקלטי Cast שלהם באפליקציות בעולם האמיתי, אנחנו הולכים לשנות את המקלט שלנו כדי לטפל בבקשות LOAD שמפנות לתוכן המדיה המיועד לפי מפתח ה-API שלו, במקום לשלוח כתובת URL של נכס שניתן להפעלה.

בדרך כלל האפליקציות עושות זאת כי:

  • יכול להיות שהשולח לא יודע את כתובת ה-URL של התוכן.
  • אפליקציית Cast מיועדת לטיפול באימות, בלוגיקה עסקית אחרת או בקריאות ל-API ישירות במכשיר המקבל.

הפונקציונליות הזו מיושמת בעיקר בשיטה PlayerManager setMessageInterceptor(). כך תוכלו ליירט הודעות נכנסות לפי סוג ולשנות אותן לפני שהן מגיעות למטפל ההודעות הפנימי של ה-SDK. בקטע הזה נדון בבקשות LOAD, שבהן נעשה את הפעולות הבאות:

  • קוראים את הבקשה הנכנסת LOAD ואת contentId המותאם אישית שלה.
  • מריצים קריאה מסוג GET ל-API שלנו כדי לחפש את הנכס שניתן להעביר בסטרימינג לפי contentId שלו.
  • משנים את הבקשה LOAD ומוסיפים את כתובת ה-URL של הסטרימינג.
  • משנים את האובייקט MediaInformation כדי להגדיר את הפרמטרים של סוג הסטרימינג.
  • מעבירים את הבקשה ל-SDK להפעלה, או דוחים את הפקודה אם אין לנו אפשרות לחפש את המדיה המבוקשת.

ה-API לדוגמה שסופק מציג את קטעי ההוק (hooks) של ה-SDK להתאמה אישית של משימות נפוצות של מקלטים, ועדיין מסתמך על חוויה חדשה לגמרי.

Sample API

אפשר להיכנס לכתובת https://storage.googleapis.com/cpe-sample-media/content.json ולעיין בקטלוג הסרטונים לדוגמה שלנו. התוכן כולל כתובות URL של תמונות פוסטרים בפורמט PNG, וגם שידורי DASH ו-HLS. השידורים של DASH ו-HLS מפנים למקורות וידאו ואודיו שעברו ניתוק קודק (demux) ונשמרים במאגרי 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.

שימוש בתוכן DASH לדוגמה של ה-API

עכשיו, אחרי שהכינו את מיירט העומסים, נציין את סוג התוכן לצד המקבל. המידע הזה יספק לנמען את כתובת ה-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 לדוגמה ב-API

ממשק ה-API לדוגמה כולל תוכן HLS וגם DASH. בנוסף להגדרת contentType כמו שעשינו בשלב הקודם, בקשת הטעינה תצטרך כמה מאפיינים נוספים כדי להשתמש בכתובות ה-URL של ה-HLS של ממשק ה-API לדוגמה. כשהמקלט מוגדר להפעלת שידורי HLS, סוג ברירת המחדל של מאגר הנתונים הצפוי הוא transport stream‏ (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 לקבצים שלנו.

תמונה של הכרטיסייה &#39;Load Media&#39; של הכלי Command and Control (CaC)

בהנחה שהכול עובד כמו שצריך עם השינויים במקלט, המיירט צריך לעצב את האובייקט MediaInfo כך שה-SDK יכול להפעיל על המסך.

לחץ על הלחצן "טען לפי תוכן" כדי לראות אם המדיה שלך פועלת כראוי. אפשר לשנות את מזהה Content ID למזהה אחר בקובץ content.json.

10. אופטימיזציה למסכים חכמים

מסכים חכמים הם מכשירים עם פונקציונליות מגע שמאפשרת לאפליקציות של מכשירים מקבלים לתמוך באמצעי בקרה מבוססי-מגע.

בקטע הזה מוסבר איך לבצע אופטימיזציה של אפליקציית המקלט כשהיא מופעלת במסכים חכמים, ואיך להתאים אישית את אמצעי הבקרה של הנגן.

גישה לבקרות בממשק המשתמש

אפשר לגשת לאובייקט UI Controls למסכים חכמים באמצעות 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, האובייקט UI Controls למסכים חכמים יוצג כמו בדוגמה הבאה.

תמונה של סרטון שמופעל עם פקדים בממשק המשתמש בשכבת-על מעל

  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, האובייקט של UI Controls במסכים חכמים יוצג כך:

תמונה של מוזיקה שמתנגנת עם פקדי ממשק משתמש שמופיעים מעל התמונה

  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

עדכון הפקודות הנתמכות בנושא מדיה

האובייקט UI Controls קובע גם אם ControlsButton מוצג או לא, על סמך MediaStatus.supportedMediaCommands.

כשהערך של supportedMediaCommands יהיה שווה ל-ALL_BASIC_MEDIA, פריסת הבקרה המוגדרת כברירת מחדל תוצג כך:

תמונה של פקדי נגן המדיה: סרגל ההתקדמות, לחצן ההפעלה, לחצני הדילוג קדימה והדילוג אחורה מופעלים

כשהערך של supportedMediaCommands שווה ל-ALL_BASIC_MEDIA | QUEUE_PREV | QUEUE_NEXT, פריסת אמצעי הבקרה שמוגדרת כברירת מחדל תוצג באופן הבא:

תמונה של פקדים בנגן מדיה: סרגל התקדמות, לחצן &#39;הפעלה&#39;, לחצני &#39;דילוג קדימה&#39; ו &#39;דילוג אחורה&#39;, והלחצנים &#39;הוספה לתור הקודם&#39; ו &#39;הוספה לתור הבא&#39; מופעלים

כשהערך של supportedMediaCommands שווה ל-PAUSE | QUEUE_PREV | QUEUE_NEXT, הפריסה שמוגדרת כברירת מחדל של אמצעי הבקרה תוצג באופן הבא:

תמונה של פקדים של נגן מדיה: סרגל התקדמות, לחצן &#39;הפעלה&#39; והלחצנים &#39;הקודם בתור&#39; ו &#39;הבא בתור&#39; מופעלים

כשיש רצועות טקסט זמינות, לחצן הכתוביות תמיד מוצג ב-SLOT_1.

תמונה של פקדים בנגן מדיה: סרגל התקדמות, לחצן &#39;הפעלה&#39;, לחצני &#39;דילוג קדימה&#39; ו &#39;דילוג אחורה&#39;, לחצני &#39;הקודם בתור&#39; ו &#39;הבא בתור&#39; וגם לחצני &#39;כתוביות&#39; מופעלים

כדי לשנות באופן דינמי את הערך של supportedMediaCommands אחרי שמתחילים הקשר של מקלט, אפשר להפעיל את PlayerManager.setSupportedMediaCommands כדי לשנות את הערך. אפשר גם להוסיף פקודה חדשה באמצעות addSupportedMediaCommands או להסיר פקודה קיימת באמצעות removeSupportedMediaCommands.

התאמה אישית של לחצני הבקרה

אפשר להתאים אישית את אמצעי הבקרה באמצעות PlayerDataBinder. מוסיפים את הקוד הבא לקובץ js/receiver.js מתחת ל-touchControls כדי להגדיר את החריץ הראשון של אמצעי הבקרה:

...

// 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 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

הגדרת נתוני הגלישה ב-Media

ניתן לספק רשימה של תוכן מדיה לגלישה על ידי קריאה ל-setBrowseContent. צריך להוסיף את הקוד הבא לקובץ js/receiver.js מתחת ל-playerDataBinder ול-event listener של MEDIA_CHANGED כדי להגדיר את פריטי העיון עם הכותרת 'Next Next'.

// 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 API וכלי בקרה ובקרה (CaC) נלווה לתיעוד יומנים.

אתחול

כדי לשלב את ה-API, מוסיפים את סקריפט המקור CastDebugLogger לקובץ index.html. צריך להצהיר על המקור בתג <head> אחרי ההצהרה על Cast Receiver 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.

תמונה של סרטון שפועל עם ההודעה &#39;מצב ניפוי באגים&#39; שמופיעה על רקע אדום בפינה הימנית העליונה של המסגרת

רישום ביומן של אירועי שחקנים

באמצעות 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 API אפשר ליצור הודעות ביומן שיופיעו בשכבת-העל של ניפוי הבאגים של המכשיר המקבל בצבעים שונים. שיטות היומנים הבאות זמינות, לפי סדר העדיפות מהגבוהה לנמוכה:

  • 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 מספק שכבת-על לניפוי באגים בנמען כדי להציג את הודעות היומן בהתאמה אישית במכשיר ההעברה (cast). משתמשים ב-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 של Cast WebReceiver.

פרטים נוספים זמינים במדריך למפתחים בנושא Web Receiver.