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

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

  1. רכיב cast-media-player שמייצג את ממשק המשתמש המובנה של הנגן שמסופק עם Web Receiver.
  2. סגנון מותאם אישית שדומה ל-CSS לרכיב cast-media-player, כדי לסגנן רכיבים שונים בממשק המשתמש, כמו background-image, splash-image ו-font-family.
  3. רכיב script לטעינת מסגרת 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.

בדוגמה הבאה אפשר לראות איך מבטלים את התנהגות ברירת המחדל של זיהוי אם החיבור של השולח עדיין פעיל. אם Web Receiver לא מצליח לתקשר עם השולח במשך 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, הגדרות ניסיון חוזר ו-handlers של בקשות באמצעות cast.framework.PlaybackConfig. המידע הזה מטופל על ידי PlayerManager ומוערך בזמן יצירת השחקנים. שחקנים נוצרים בכל פעם שמועברת טעינה חדשה אל Web Receiver SDK. שינויים ב-PlaybackConfig אחרי שהשחקן נוצר מוערכים בטעינת התוכן הבאה. ערכת ה-SDK מספקת את ה-methods הבאות לשינוי PlaybackConfig.

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

בדוגמה הבאה אפשר לראות איך מגדירים את PlaybackConfig כשמפעילים את CastReceiverContext. ההגדרה מבטלת את הבקשות היוצאות לקבלת קובצי מניפסט. ה-handler מציין שבקשות Access-Control של 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 של פרטי הפעלת מדיה. ה-handler מפעיל את ה-method getLicenseUrlForMedia שהוטמעה באפליקציה כדי לקבל את licenseUrl מ-contentId של הפריט הנוכחי.

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

  return playbackConfig;
});

רכיב event listener

‫Web Receiver SDK מאפשר לאפליקציית Web Receiver לטפל באירועים של נגן. רכיב event listener מקבל פרמטר cast.framework.events.EventType (או מערך של פרמטרים כאלה) שמציין את האירועים שאמורים להפעיל את רכיב event listener. מערכים שהוגדרו מראש של 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
});

יירוט הודעות

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

ה-interceptor צריך להחזיר את הבקשה ששונתה או 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();

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

כשמתרחשות שגיאות ב-message interceptor, אפליקציית 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

אלה כמה מההבדלים העיקריים בין חסימת הודעות לבין רכיב event listener:

  • רכיב event listener לא מאפשר לשנות את נתוני הבקשה.
  • השימוש הכי טוב ברכיב 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 של תוכן שאפשר להפעיל (בדומה לערך של מאפיין 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 ובמכשירים המחוברים לתצוגה ולשמע.

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

בדוגמה הזו נבדק אם מכשיר Web Receiver יכול להפעיל 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();

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

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

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

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

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

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

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

כדי למנוע הפעלה של פקודת מדיה במכשיר עם 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, כמו האזנה לדיבור של המשתמש או מענה לו, הודעה של NOT_IN_FOCUS FocusState נשלחת לאפליקציית Web Receiver כשהפעילות מתחילה. כשמסיימים את הפעילות, נשלחת הודעה נוספת עם 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, תפעיל כתוביות באנגלית", הערך של isSuggestedLanguage מוגדר כ-false.

מטא-נתונים ושימוש בהעברה קולית

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

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

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

הפעלת החלפת רמקול

כדי להטמיע העברת סטרימינג ב-Web Receiver:

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

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

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

אפשר לבטל את בקשת הטעינה שנוצרה על ידי Web Receiver ב-SESSION_STATE message interceptor, אם צריך. אם רוצים להוסיף נתונים מותאמים אישית לבקשת הטעינה, מומלץ להוסיף אותם ל-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 interceptor של ההודעה.

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;
    });

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

ה-Web Receiver תומך בטעינה מראש של פריטי מדיה אחרי פריט ההפעלה הנוכחי בתור.

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

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

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

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

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

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

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

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

קטע קוד ל-Web Receiver להאזנה להודעות מותאמות אישית משולחים מחוברים:

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.

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

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

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

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

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