הוספת תכונות ליבה למקלט האינטרנט המותאם אישית

בדף הזה מופיעים קטעי קוד ותיאורים של התכונות הזמינות לאפליקציית Custom Web Receiver.

  1. רכיב cast-media-player שמייצג את ממשק המשתמש המובנה של הנגן שסופק עם Web Receiver.
  2. סגנון מותאם אישית שדומה ל-CSS לרכיב cast-media-player, כדי לסגנן רכיבים שונים של ממשק המשתמש, כמו background-image,‏ splash-image ו-font-family.
  3. רכיב סקריפט לטעינה של מסגרת Web Receiver.
  4. קוד JavaScript לניתוב הודעות ולטיפול באירועים.
  5. להוסיף את הסרטון לתור להפעלה אוטומטית.
  6. אפשרויות להגדרת ההפעלה.
  7. אפשרויות להגדרת ההקשר של Web Receiver.
  8. אפשרויות להגדרת פקודות שנתמכות באפליקציית Web Receiver.
  9. קריאה ל-JavaScript כדי להפעיל את אפליקציית Web Receiver.

הגדרות ואפשרויות של אפליקציה

הגדרת האפליקציה

CastReceiverContext היא הכיתה החיצונית ביותר שחשופה למפתח, והיא מנהלת את טעינת הספריות הבסיסיות ומטפלת בהפעלה של Web Receiver SDK. ה-SDK כולל ממשקי API שמאפשרים למפתחי אפליקציות להגדיר את ה-SDK דרך CastReceiverOptions. ההגדרות האלה נבדקות פעם אחת בכל הפעלה של האפליקציה, והן מועברות ל-SDK כשמגדירים את הפרמטר האופציונלי בקריאה ל-start.

הדוגמה הבאה מראה איך לשנות את התנהגות ברירת המחדל לזיהוי אם חיבור של שולח עדיין פעיל. כשמרכז הקבלה באינטרנט לא מצליח לתקשר עם שולח במשך maxInactivity שניות, נשלח אירוע SENDER_DISCONNECTED. ההגדרה שבהמשך מבטלת את הזמן הקצוב לתפוגה. האפשרות הזו יכולה להיות שימושית כשמנפים באגים, כי היא מונעת מהאפליקציה Web Receiver לסגור את הסשן של Chrome Remote Debugger כשאין שולחים מחוברים במצב IDLE.

const context = cast.framework.CastReceiverContext.getInstance();
const options = new cast.framework.CastReceiverOptions();
options.maxInactivity = 3600; // Development only
context.start(options);

הגדרת הנגן

כשאתם טוענים תוכן, ה-Web Receiver SDK מספק דרך להגדיר משתני הפעלה כמו פרטי DRM, הגדרות של ניסיונות חוזרים ומטפלי בקשות באמצעות cast.framework.PlaybackConfig. PlayerManager מטפל במידע הזה, והוא נבדק בזמן יצירת השחקנים. הנגנים נוצרים בכל פעם שטעינה חדשה מועברת ל-Web Receiver SDK. שינויים ב-PlaybackConfig אחרי היצירה של הנגן נבדקים בטעינה הבאה של התוכן. ערכת ה-SDK מספקת את השיטות הבאות לשינוי הערך של PlaybackConfig.

  • CastReceiverOptions.playbackConfig כדי לשנות את אפשרויות ברירת המחדל של ההגדרות בזמן האתחול של CastReceiverContext.
  • PlayerManager.getPlaybackConfig() כדי לקבל את ההגדרה הנוכחית.
  • PlayerManager.setPlaybackConfig() כדי לשנות את ההגדרה הנוכחית. ההגדרה הזו חלה על כל הטעינות הבאות, או עד שמשנים אותה שוב.
  • PlayerManager.setMediaPlaybackInfoHandler() כדי להחיל הגדרות נוספות רק על פריט המדיה שנטען, נוסף על ההגדרות הנוכחיות. הטיפול נקרא ממש לפני יצירת הנגן. השינויים שיבוצעו כאן לא יהיו קבועים ולא ייכללו בשאילתות ל-getPlaybackConfig(). כשפריט המדיה הבא נטען, הטיפול הזה נקרא שוב.

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

const playbackConfig = new cast.framework.PlaybackConfig();
playbackConfig.manifestRequestHandler = requestInfo => {
  requestInfo.withCredentials = true;
};
context.start({playbackConfig: playbackConfig});

בדוגמה הבאה מוסבר איך לשנות את PlaybackConfig באמצעות ה-getter וה-setter שסופקו ב-PlayerManager. ההגדרה מאפשרת לנגן להמשיך את הפעלת התוכן אחרי טעינה של מקטע אחד.

const playerManager =
    cast.framework.CastReceiverContext.getInstance().getPlayerManager();
const playbackConfig = (Object.assign(
            new cast.framework.PlaybackConfig(), playerManager.getPlaybackConfig()));
playbackConfig.autoResumeNumberOfSegments = 1;
playerManager.setPlaybackConfig(playbackConfig);

הדוגמה הבאה מראה איך לשנות את הערך של PlaybackConfig לבקשת טעינה ספציפית באמצעות ה-handler של פרטי ההפעלה של המדיה. הטיפול גורם להפעלה של השיטה getLicenseUrlForMedia שמופעלת באפליקציה, כדי לקבל את הערך של licenseUrl מה-contentId של הפריט הנוכחי.

playerManager.setMediaPlaybackInfoHandler((loadRequestData, playbackConfig) => {
  const mediaInformation = loadRequestData.media;
  playbackConfig.licenseUrl = getLicenseUrlForMedia(mediaInformation.contentId);

  return playbackConfig;
});

Event listener

ערכת ה-SDK של Web Receiver מאפשרת לאפליקציית Web Receiver לטפל באירועים של הנגן. למעקב אחר אירועים נדרש פרמטר cast.framework.events.EventType (או מערך של הפרמטרים האלה) שמציין את האירועים שצריכים להפעיל את המעקב. מערכי cast.framework.events.EventType מוגדרים מראש ששימושיים לניפוי באגים מופיעים ב-cast.framework.events.category. פרמטר האירוע מספק מידע נוסף על האירוע.

לדוגמה, אם רוצים לדעת מתי מתבצע שידור של שינוי ב-mediaStatus, אפשר להשתמש בלוגיקה הבאה כדי לטפל באירוע:

const playerManager =
    cast.framework.CastReceiverContext.getInstance().getPlayerManager();
playerManager.addEventListener(
    cast.framework.events.EventType.MEDIA_STATUS, (event) => {
      // Write your own event handling code, for example
      // using the event.mediaStatus value
});

תיעוד הודעות

ערכת ה-SDK של Web Receiver מאפשרת לאפליקציית Web Receiver ליירט הודעות ולבצע בהן קוד מותאם אישית. ניתוח ההודעות מקבל פרמטר cast.framework.messages.MessageType שמציין את סוג ההודעה שצריך ליירט.

המתווך צריך להחזיר את הבקשה ששונתה או Promise שמתפרק עם ערך הבקשה ששונה. החזרת הערך null תמנע את הקריאה ל-handler של ההודעות שמוגדר כברירת מחדל. פרטים נוספים זמינים במאמר טעינה של מדיה.

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

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

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD, loadRequestData => {
      const error = new cast.framework.messages.ErrorData(
                      cast.framework.messages.ErrorType.LOAD_FAILED);
      if (!loadRequestData.media) {
        error.reason = cast.framework.messages.ErrorReason.INVALID_PARAM;
        return error;
      }

      if (!loadRequestData.media.entity) {
        return loadRequestData;
      }

      return thirdparty.fetchAssetAndAuth(loadRequestData.media.entity,
                                          loadRequestData.credentials)
        .then(asset => {
          if (!asset) {
            throw cast.framework.messages.ErrorReason.INVALID_REQUEST;
          }

          loadRequestData.media.contentUrl = asset.url;
          loadRequestData.media.metadata = asset.metadata;
          loadRequestData.media.tracks = asset.tracks;
          return loadRequestData;
        }).catch(reason => {
          error.reason = reason; // cast.framework.messages.ErrorReason
          return error;
        });
    });

context.start();

טיפול בשגיאות

כשמתרחשות שגיאות במעכב ההודעות, אפליקציית Web Receiver אמורה להחזיר את הערכים המתאימים של cast.framework.messages.ErrorType ושל cast.framework.messages.ErrorReason.

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD, loadRequestData => {
      const error = new cast.framework.messages.ErrorData(
                      cast.framework.messages.ErrorType.LOAD_CANCELLED);
      if (!loadRequestData.media) {
        error.reason = cast.framework.messages.ErrorReason.INVALID_PARAM;
        return error;
      }

      ...

      return fetchAssetAndAuth(loadRequestData.media.entity,
                               loadRequestData.credentials)
        .then(asset => {
          ...
          return loadRequestData;
        }).catch(reason => {
          error.reason = reason; // cast.framework.messages.ErrorReason
          return error;
        });
    });

עיקור הודעות לעומת event listener

הנה כמה הבדלים מרכזיים בין ניתוב הודעות לבין מאזין לאירועים:

  • מאזין לאירועים לא מאפשר לשנות את נתוני הבקשה.
  • רכיב מעקב אירועים הכי מתאים להפעלת ניתוח נתונים או פונקציה מותאמת אישית.
playerManager.addEventListener(cast.framework.events.category.CORE,
    event => {
        console.log(event);
    });
  • יירוט הודעות מאפשר להאזין להודעה, ליירט אותה ולשנות את נתוני הבקשה עצמם.
  • מומלץ להשתמש באינטרסקציה עם הודעות כדי לטפל בלוגיקה מותאמת אישית לגבי נתוני הבקשה.

טעינה של מדיה

MediaInformation מספק מאפיינים רבים לטעינה של מדיה בהודעת cast.framework.messages.MessageType.LOAD, כולל entity, ‏contentUrl ו-contentId.

  • entity הוא המאפיין המומלץ לשימוש בהטמעה שלכם, גם באפליקציית השולח וגם באפליקציית הנמען. הנכס הוא כתובת URL של קישור עמוק שיכולה להיות פלייליסט או תוכן מדיה. האפליקציה צריכה לנתח את כתובת ה-URL הזו ולאכלס לפחות אחד משני השדות האחרים.
  • השדה contentUrl תואם לכתובת ה-URL שניתן להפעיל, שבה הנגן ישתמש כדי לטעון את התוכן. לדוגמה, כתובת ה-URL הזו יכולה להפנות למניפסט DASH.
  • השדה contentId יכול להיות כתובת URL של תוכן שניתן להפעלה (בדומה לכתובת ה-URL של נכס contentUrl) או מזהה ייחודי של התוכן או הפלייליסט שנטענים. אם משתמשים בנכס הזה כמזהה, האפליקציה צריכה לאכלס כתובת URL שניתן להפעיל אותה ב-contentUrl.

מומלץ להשתמש ב-entity כדי לאחסן את הפרמטרים האמיתיים של המזהה או המפתח, ולהשתמש ב-contentUrl לכתובת ה-URL של המדיה. דוגמה לכך מופיעה בקטע הקוד הבא, שבו הערך entity נמצא בבקשה LOAD והערך contentUrl שניתן להפעלה מאוחזר:

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

      if (!loadRequestData.media.entity) {
        // Copy the value from contentId for legacy reasons if needed
        loadRequestData.media.entity = loadRequestData.media.contentId;
      }

      return thirdparty.fetchAssetAndAuth(loadRequestData.media.entity,
                                          loadRequestData.credentials)
        .then(asset => {
          loadRequestData.media.contentUrl = asset.url;
          ...
          return loadRequestData;
        });
    });

יכולות המכשיר

השיטה getDeviceCapabilities מספקת מידע על המכשיר במכשיר Cast המחובר ועל מכשיר הווידאו או האודיו שמחובר אליו. השיטה getDeviceCapabilities מספקת מידע על תמיכה ב-Google Assistant, ב-Bluetooth ובמסך ובמכשירי האודיו המחוברים.

השיטה הזו מחזירה אובייקט שאפשר לשלוח אליו שאילתה על ידי העברת אחד מה-enums שצוינו כדי לקבל את יכולת המכשיר ל-enum הזה. המאפיינים של הממשק המוגדר מופיעים בקובץ cast.framework.system.DeviceCapabilities.

בדוגמה הזו בודקים אם מכשיר מקלט האינטרנט מסוגל להפעיל HDR ו-DolbyVision‏ (DV) באמצעות המקשים IS_HDR_SUPPORTED ו-IS_DV_SUPPORTED, בהתאמה.

const context = cast.framework.CastReceiverContext.getInstance();
context.addEventListener(cast.framework.system.EventType.READY, () => {
  const deviceCapabilities = context.getDeviceCapabilities();
  if (deviceCapabilities &&
      deviceCapabilities[cast.framework.system.DeviceCapabilities.IS_HDR_SUPPORTED]) {
    // Write your own event handling code, for example
    // using the deviceCapabilities[cast.framework.system.DeviceCapabilities.IS_HDR_SUPPORTED] value
  }
  if (deviceCapabilities &&
      deviceCapabilities[cast.framework.system.DeviceCapabilities.IS_DV_SUPPORTED]) {
    // Write your own event handling code, for example
    // using the deviceCapabilities[cast.framework.system.DeviceCapabilities.IS_DV_SUPPORTED] value
  }
});
context.start();

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

משתמשים יכולים לקיים אינטראקציה עם אפליקציית מקלט האינטרנט שלכם דרך אפליקציות של שולחים (אינטרנט, Android ו-iOS), פקודות קוליות במכשירים עם Assistant מובנית, פקדי מגע במסכים חכמים ושלטים מרחוק במכשירי Android TV. ‏Cast SDK מספק ממשקי API שונים שמאפשרים לאפליקציית Web Receiver לטפל באינטראקציות האלה, לעדכן את ממשק המשתמש של האפליקציה באמצעות מצבי פעולות של משתמשים, ולשלוח את השינויים לעדכון שירותי הקצה העורפי, אם רוצים.

פקודות מדיה נתמכות

מצבי אמצעי הבקרה בממשק המשתמש מוגדרים על ידי MediaStatus.supportedMediaCommands בשלטים המורחבים של מכשירי iOS ו-Android לשליחה, באפליקציות של מכשירים מקבלים ובאפליקציות של שלטים מרחוק שפועלות במכשירי מגע, ובאפליקציות של מכשירים מקבלים במכשירי Android TV. כשמפעילים בנכס Command ביטבי מסוים, הלחצנים שקשורים לפעולה הזו מופעלים. אם לא מגדירים את הערך, הלחצן יושבת. אפשר לשנות את הערכים האלה במקלט האינטרנט באופן הבא:

  1. שימוש ב-PlayerManager.setSupportedMediaCommands כדי להגדיר את Commands הספציפי
  2. הוספת פקודה חדשה באמצעות addSupportedMediaCommands
  3. הסרת פקודה קיימת באמצעות removeSupportedMediaCommands.
playerManager.setSupportedMediaCommands(cast.framework.messages.Command.SEEK |
  cast.framework.messages.Command.PAUSE);

כשהצד המקבל יכין את הקובץ MediaStatus המעודכן, הוא יכלול את השינויים בנכס supportedMediaCommands. כשהסטטוס יישלח, האפליקציות המקושרות לשליחה יעדכנו את הלחצנים בממשק המשתמש שלהן בהתאם.

מידע נוסף על פקודות מדיה נתמכות ועל מכשירים מגע זמין במדריך Accessing UI controls.

ניהול מצבי הפעולות של המשתמשים

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

  • מגדירים את MediaInformation userActionStates עם העדפות המשתמש בזמן טעינת פריט מדיה.
  • ליירט הודעות USER_ACTION ולקבוע את הפעולה המבוקשת.
  • מעדכנים את MediaInformation UserActionState כדי לעדכן את ממשק המשתמש.

קטע הקוד הבא מיירט את הבקשה LOAD ומאכלס את MediaInformation של LoadRequestData. במקרה כזה, המשתמש אוהב את התוכן שנטען.

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.LOAD, (loadRequestData) => {
      const userActionLike = new cast.framework.messages.UserActionState(
          cast.framework.messages.UserAction.LIKE);
      loadRequestData.media.userActionStates = [userActionLike];

      return loadRequestData;
    });

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

playerManager.setMessageInterceptor(cast.framework.messages.MessageType.USER_ACTION,
  (userActionRequestData) => {
    // Obtain the media information of the current content to associate the action to.
    let mediaInfo = playerManager.getMediaInformation();

    // If there is no media info return an error and ignore the request.
    if (!mediaInfo) {
        console.error('Not playing media, user action is not supported');
        return new cast.framework.messages.ErrorData(messages.ErrorType.BAD_REQUEST);
    }

    // Reach out to backend services to store user action modifications. See sample below.
    return sendUserAction(userActionRequestData, mediaInfo)

    // Upon response from the backend, update the client's UserActionState.
    .then(backendResponse => updateUserActionStates(backendResponse))

    // If any errors occurred in the backend return them to the cast receiver.
    .catch((error) => {
      console.error(error);
      return error;
    });
});

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

function sendUserAction(userActionRequestData, mediaInfo) {
  return new Promise((resolve, reject) => {
    switch (userActionRequestData.userAction) {
      // Handle user action changes supported by the backend.
      case cast.framework.messages.UserAction.LIKE:
      case cast.framework.messages.UserAction.DISLIKE:
      case cast.framework.messages.UserAction.FOLLOW:
      case cast.framework.messages.UserAction.UNFOLLOW:
      case cast.framework.messages.UserAction.FLAG:
      case cast.framework.messages.UserAction.SKIP_AD:
        let backendResponse = {userActionRequestData: userActionRequestData, mediaInfo: mediaInfo};
        setTimeout(() => {resolve(backendResponse)}, 1000);
        break;
      // Reject all other user action changes.
      default:
        reject(
          new cast.framework.messages.ErrorData(cast.framework.messages.ErrorType.INVALID_REQUEST));
    }
  });
}

קטע הקוד הבא מקבל את UserActionRequestData ומוסיף או מסיר את UserActionState מ-MediaInformation. עדכון הערך של UserActionState ב-MediaInformation משנה את המצב של הלחצן שמשויך לפעולה המבוקשת. השינוי הזה יבואו לידי ביטוי בממשק המשתמש של אמצעי הבקרה במסך החכם, באפליקציית השלט הרחוק ובממשק המשתמש של Android TV. הוא גם מופץ באמצעות הודעות MediaStatus יוצאות כדי לעדכן את ממשק המשתמש של הבקר המורחב לשולחים ב-iOS וב-Android.

function updateUserActionStates(backendResponse) {
  // Unwrap the backend response.
  let mediaInfo = backendResponse.mediaInfo;
  let userActionRequestData = backendResponse.userActionRequestData;

  // If the current item playing has changed, don't update the UserActionState for the current item.
  if (playerManager.getMediaInformation().entity !== mediaInfo.entity) {
    return;
  }

  // Check for existing userActionStates in the MediaInformation.
  // If none, initialize a new array to populate states with.
  let userActionStates = mediaInfo.userActionStates || [];

  // Locate the index of the UserActionState that will be updated in the userActionStates array.
  let index = userActionStates.findIndex((currUserActionState) => {
    return currUserActionState.userAction == userActionRequestData.userAction;
  });

  if (userActionRequestData.clear) {
    // Remove the user action state from the array if cleared.
    if (index >= 0) {
      userActionStates.splice(index, 1);
    }
    else {
      console.warn("Could not find UserActionState to remove in MediaInformation");
    }
  } else {
    // Add the UserActionState to the array if enabled.
    userActionStates.push(
      new cast.framework.messages.UserActionState(userActionRequestData.userAction));
  }

  // Update the UserActionState array and set the new MediaInformation
  mediaInfo.userActionStates = userActionStates;
  playerManager.setMediaInformation(mediaInfo, true);
  return;
}

פקודות קוליות

הפקודות הבאות לגבי מדיה נתמכות כרגע ב-Web Receiver SDK למכשירים עם Assistant מובנית. הטמעות ברירת המחדל של הפקודות האלה נמצאות ב-cast.framework.PlayerManager.

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

פקודות מדיה נתמכות באמצעות הקול

כדי למנוע הפעלה של פקודת מדיה על ידי פקודת קול במכשיר עם Assistant מובנית, צריך קודם להגדיר את פקודות המדיה הנתמכות שאתם מתכננים לתמוך בהן. לאחר מכן, צריך לאכוף את הפקודות האלה על ידי הפעלת הנכס CastReceiverOptions.enforceSupportedCommands. ממשק המשתמש של משתמשי Cast SDK ומכשירים עם תמיכה במגע ישתנה כך שישקף את ההגדרות האלה. אם הדגל לא מופעל, הפקודות הקוליות הנכנסות יבוצעו.

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

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

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

context.start({
  enforceSupportedCommands: true,
  supportedCommands: cast.framework.messages.Command.PAUSE
});

אפשר להחיל לוגיקה נפרדת לכל פקודה שרוצים להגביל. מסירים את הדגל enforceSupportedCommands, וכל הודעה נכנסת עם פקודה שרוצים להגביל יכולה להיפריע. כאן אנחנו מפריעים לבקשה שמספקת ה-SDK, כדי שהפקודות SEEK שהונפקו למכשירים עם Assistant לא יפעילו חיפוש באפליקציית Web Receiver.

אם האפליקציה לא תומכת בפקודות מדיה מסוימות, צריך להחזיר את הסיבה המתאימה לשגיאה, למשל NOT_SUPPORTED.

playerManager.setMessageInterceptor(cast.framework.messages.MessageType.SEEK,
  seekData => {
    // Block seeking if the SEEK supported media command is disabled
    if (!(playerManager.getSupportedMediaCommands() & cast.framework.messages.Command.SEEK)) {
      let e = new cast.framework.messages.ErrorData(cast.framework.messages.ErrorType
      .INVALID_REQUEST);
      e.reason = cast.framework.messages.ErrorReason.NOT_SUPPORTED;
      return e;
    }

    return seekData;
  });

מעבר לרקע מפעילות קולית

אם פלטפורמת Cast מעבירה את הצליל של האפליקציה לרקע בגלל פעילות של Assistant, כמו האזנה לדיבור של המשתמש או מענה אוטומטי, נשלחת לאפליקציית Web Receiver הודעת FocusState עם הערך NOT_IN_FOCUS כשהפעילות מתחילה. כשהפעילות מסתיימת, נשלחת הודעה נוספת עם IN_FOCUS. בהתאם לאפליקציה ולמדיה שמופעלת, יכול להיות שתרצו להשהות את המדיה כשהערך של FocusState הוא NOT_IN_FOCUS על ידי ניתוב הודעות מסוג FOCUS_STATE.

לדוגמה, חוויית משתמש טובה היא להשהות את ההפעלה של ספר האודיו אם Assistant מגיבה לשאילתת משתמש.

playerManager.setMessageInterceptor(cast.framework.messages.MessageType.FOCUS_STATE,
  focusStateRequestData => {
    // Pause content when the app is out of focus. Resume when focus is restored.
    if (focusStateRequestData.state == cast.framework.messages.FocusState.NOT_IN_FOCUS) {
      playerManager.pause();
    } else {
      playerManager.play();
    }

    return focusStateRequestData;
  });

שפת הכתוביות שצוינה באמצעות הקול

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

לדוגמה, השדה isSuggestedLanguage מוגדר כ-true לפקודה "Ok Google, turn captions on", כי השפה נקבעה לפי השפה שבה נאמרה הפקודה. אם השפה מופיעה בבקשה מפורשת, כמו "Ok Google, turn on English captions", הערך של isSuggestedLanguage מוגדר כ-false.

מטא-נתונים והעברה קולית (cast)

כברירת מחדל, פקודות הקול מטופלות על ידי מקלט האינטרנט, אבל חשוב לוודא שהמטא-נתונים של התוכן שלכם מלאים ומדויקים. כך אפשר לוודא שהפקודות הקוליות מטופלות כראוי על ידי Assistant, והמטא-נתונים מוצגים כראוי בממשקים מסוגים חדשים, כמו אפליקציית Google Home ומסכים חכמים כמו Google Home Hub.

העברת סטרימינג

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

תהליך האירועים להעברת שידור הוא:

  1. במכשיר המקור:
    1. ההפעלה של המדיה מופסקת.
    2. אפליקציית Web Receiver מקבלת פקודה לשמירת מצב המדיה הנוכחי.
    3. אפליקציית Web Receiver מושבתת.
  2. במכשיר היעד:
    1. אפליקציית Web Receiver נטענת.
    2. אפליקציית Web Receiver מקבלת פקודה לשחזור מצב המדיה השמור.
    3. המדיה תמשיך לפעול.

אלמנטים של מצב המדיה כוללים:

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

הפעלת העברת סטרימינג

כדי להטמיע העברת סטרימינג למקלט האינטרנט:

  1. מעדכנים את הקובץ supportedMediaCommands באמצעות הפקודה STREAM_TRANSFER:
    playerManager.addSupportedMediaCommands(
    cast.framework.messages.Command.STREAM_TRANSFER, true);
  2. אפשר גם לשנות את התנהגות מנטעי ההודעות SESSION_STATE ו-RESUME_SESSION, כפי שמתואר בקטע שמירה על מצב הסשן. משנים את ההגדרות האלה רק אם צריך לשמור נתונים מותאמים אישית כחלק מתמונת המצב של הסשן. אחרת, ההטמעה שמוגדרת כברירת מחדל לשמירת מצבי הסשן תתמוך בהעברת סטרימינג.

שמירה של מצב הסשן

ה-Web Receiver SDK מספק הטמעה שמוגדרת כברירת מחדל לאפליקציות Web Receiver, כדי לשמור על מצבי הסשן. לשם כך, ה-SDK יוצר קובץ snapshot של סטטוס המדיה הנוכחי, ממיר את הסטטוס לבקשת טעינה וממשיך את הסשן באמצעות בקשת הטעינה.

אם צריך, אפשר לשנות את בקשת הטעינה שנוצרה על ידי מקלט האינטרנט במעכב ההודעות SESSION_STATE. אם רוצים להוסיף נתונים מותאמים אישית לבקשת הטעינה, מומלץ להוסיף אותם ל-loadRequestData.customData.

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.SESSION_STATE,
    function (sessionState) {
        // Override sessionState.loadRequestData if needed.
        const newCredentials = updateCredentials_(sessionState.loadRequestData.credentials);
        sessionState.loadRequestData.credentials = newCredentials;

        // Add custom data if needed.
        sessionState.loadRequestData.customData = {
            'membership': 'PREMIUM'
        };

        return sessionState;
    });

אפשר לאחזר את הנתונים המותאמים אישית מ-loadRequestData.customData במעכב ההודעות RESUME_SESSION.

let cred_ = null;
let membership_ = null;

playerManager.setMessageInterceptor(
    cast.framework.messages.MessageType.RESUME_SESSION,
    function (resumeSessionRequest) {
        let sessionState = resumeSessionRequest.sessionState;

        // Modify sessionState.loadRequestData if needed.
        cred_ = sessionState.loadRequestData.credentials;

        // Retrieve custom data.
        membership_ = sessionState.loadRequestData.customData.membership;

        return resumeSessionRequest;
    });

טעינת תוכן מראש

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

פעולת הטעינה מראש מאפשרת להוריד מראש כמה קטעים של הפריטים שצפויים להופיע. ההגדרה מתבצעת בערך preloadTime באובייקט QueueItem (ברירת המחדל היא 20 שניות, אם לא צוין ערך). הזמן מופיע בשניות, ביחס לסוף הפריט שפועל כרגע . רק ערכים חיוביים חוקיים. לדוגמה, אם הערך הוא 10 שניות, הפריט הזה ייטען מראש 10 שניות לפני שהפריט הקודם יסתיים. אם הזמן להעלאה מראש ארוך יותר מהזמן שנותר ל-currentItem, ההעלאה מראש תתבצע בהקדם האפשרי. לכן, אם מציינים ערך גדול מאוד של preload ב-queueItem, אפשר להשיג את האפקט של טעינה מראש של הפריט הבא בכל פעם שאנחנו מפעילים את הפריט הנוכחי. עם זאת, אנחנו משאירים את ההגדרה והבחירה הזו למפתחים, כי הערך הזה יכול להשפיע על רוחב הפס ועל ביצועי הסטרימינג של הפריט הנוכחי שמוצג.

כברירת מחדל, הטעינה מראש תפעל בתוכן HLS, ‏ DASH ו-Smooth streaming.

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

הודעות בהתאמה אישית

החלפת הודעות היא שיטת האינטראקציה העיקרית באפליקציות של Web Receiver.

השולח שולח הודעות לנמען באינטרנט באמצעות ממשקי ה-API של השולח לפלטפורמה שבה הוא פועל (Android,‏ iOS או אינטרנט). לאובייקט האירוע (שמייצג הודעה) שמוענק למאזינים של האירועים יש רכיב נתונים (event.data) שבו הנתונים מקבלים את המאפיינים של סוג האירוע הספציפי.

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

כל מרחבי השמות מוגדרים על ידי מחרוזת, והם חייבים להתחיל ב-urn:x-cast: ואחריה מחרוזת כלשהי. לדוגמה, "urn:x-cast:com.example.cast.mynamespace".

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

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

const CUSTOM_CHANNEL = 'urn:x-cast:com.example.cast.mynamespace';
context.addCustomMessageListener(CUSTOM_CHANNEL, function(customEvent) {
  // handle customEvent.
});

context.start();

באופן דומה, אפליקציות של Web Receiver יכולות לעדכן את השולחים לגבי המצב של Web Receiver על ידי שליחת הודעות לשולחים מחוברים. אפליקציית Web Receiver יכולה לשלוח הודעות באמצעות sendCustomMessage(namespace, senderId, message) ב-CastReceiverContext. מקלט אינטרנט יכול לשלוח הודעות לשולח מסוים, בתגובה להודעה שהתקבלה או עקב שינוי במצב האפליקציה. בנוסף להעברת הודעות מנקודה לנקודה (עם מגבלה של 64KB), מקלט אינטרנט יכול גם לשדר הודעות לכל השולחים המחוברים.

העברה (cast) למכשירי אודיו

במדריך של Google Cast למכשירי אודיו מוסבר על התמיכה בהפעלת אודיו בלבד.

Android TV

בקטע הזה נסביר איך Google Web Receiver משתמש בנתוני הקלט שלכם להפעלה, ונסביר על תאימות ל-Android TV.

שילוב האפליקציה עם השלט הרחוק

Google Web Receiver שפועל במכשיר Android TV מתרגם קלט ממקורות הבקרה של המכשיר (למשל שלט רחוק נייד) להודעות של הפעלת מדיה שמוגדרות למרחב השמות urn:x-cast:com.google.cast.media, כפי שמתואר בקטע הודעות של הפעלת מדיה. כדי לשלוט בהפעלת המדיה באפליקציה ולאפשר שליטה בסיסית בהפעלה באמצעות מקורות הקלט של Android TV, האפליקציה צריכה לתמוך בהודעות האלה.

הנחיות לתאימות ל-Android TV

ריכזנו כאן כמה המלצות ובעיות נפוצות שחשוב להימנע מהן כדי לוודא שהאפליקציה שלכם תואמת ל-Android TV:

  • חשוב לזכור ששרשור סוכן המשתמש מכיל גם את 'Android' וגם את 'CrKey'. ייתכן שחלק מהאתרים יפנו אוטומטית לאתר לנייד בלבד כי הם מזהים את התווית 'Android'. אל תניחו ש-'Android' במחרוזת של סוכן המשתמש תמיד מציין משתמש בנייד.
  • ייתכן ש-GZIP שקוף ישמש את מקבץ המדיה של Android לאחזור נתונים. חשוב לוודא שנתוני המדיה יכולים להגיב ל-Accept-Encoding: gzip.
  • אירועי מדיה ב-HTML5 ב-Android TV עשויים להתרחש במועדים שונים מאשר ב-Chromecast, וכך יכולות להתגלות בעיות שהיו מוסתרות ב-Chromecast.
  • כשמעדכנים את המדיה, משתמשים באירועים שקשורים למדיה שמופעל על ידי אלמנטים מסוג <audio>/<video>, כמו timeupdate, ‏ pause ו-waiting. מומלץ להימנע משימוש באירועים שקשורים לרשתות, כמו progress,‏ suspend ו-stalled, כי הם נוטים להיות תלויים בפלטפורמה. מידע נוסף על טיפול באירועי מדיה במכשיר המקלט זמין במאמר אירועי מדיה.
  • כשמגדירים את אישורי ה-HTTPS של אתר המקבל, חשוב לכלול אישורי CA ביניים. מומלץ להיכנס אל Qualsys SSL test page כדי לוודא: אם נתיב האישור המהימן של האתר כולל אישור CA שמסומן בתווית 'הורדה נוספת', יכול להיות שהוא לא ייטען בפלטפורמות מבוססות-Android.
  • ב-Chromecast, דף המכשיר המקבל מוצג ברזולוציית גרפיקה של 720p, אבל בפלטפורמות אחרות של העברה (cast), כולל Android TV, יכול להיות שהדף יוצג ברזולוציה של עד 1080p. חשוב לוודא שדף המקבל מתאים את עצמו בצורה חלקה לרזולוציות שונות.