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

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

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

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

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

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

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

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

הגדרת הנגן

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

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

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

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

  return playbackConfig;
});

האזנה לאירוע

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

יירוט הודעות

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

הכלי המיירט צריך להחזיר את הבקשה ששונתה או הבטחה שמסתיימת עם ערך הבקשה שהשתנה. כשמחזירים את 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();

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

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

הדוגמה הזו בודקת אם המכשיר ב-Web Aware יכול להפעיל 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 Aware באמצעות אפליקציות של השולח (אינטרנט, Android ו-iOS), פקודות קוליות במכשירים עם Assistant מובנית, מקשי מגע במסכים חכמים ושלט רחוק במכשירי Android TV. ה-SDK של Cast מספק ממשקי API שונים כדי לאפשר לאפליקציה Web Acceptr לטפל באינטראקציות האלה, לעדכן את ממשק המשתמש של האפליקציה באמצעות מצבים של פעולות משתמש, ואפשר גם לשלוח את השינויים כדי לעדכן את השירותים לקצה העורפי.

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

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

  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 Acceptr SDK במכשירים עם Assistant מובנית. יישומי ברירת המחדל של הפקודות האלה נמצאים ב-cast.framework.PlayerManager.

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

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

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

לדוגמה, אם מאשרים את הגישה ל-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 Acceptr.

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

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

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

העברת השידור

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

זרימת האירועים להעברת סטרימינג היא:

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

הרכיבים של מצב המדיה כוללים:

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

מתבצעת הפעלה של העברת שידור

כדי להטמיע את העברת השידור עבור ה-Web Aware:

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

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

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

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

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

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

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

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

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

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

כל מרחבי השמות מוגדרים על ידי מחרוזת וצריכים להתחיל ב-"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 Acceptr יכולות לעדכן את השולחים לגבי מצב ה-WebReceiver על ידי שליחת הודעות לשולחים מחוברים. אפליקציית Web Aware יכולה לשלוח הודעות באמצעות sendCustomMessage(namespace, senderId, message) ב-CastReceiverContext. מקבל אינטרנט יכול לשלוח הודעות לשולח יחיד, בתגובה להודעה שהתקבלה או עקב שינוי במצב האפליקציה. נוסף על העברת הודעות מנקודה לנקודה (בהגבלה של עד 64kb), שרת האינטרנט יכול גם לשדר הודעות לכל השולחים המחוברים.

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

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

ב-Android TV

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

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

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

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

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

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