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

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

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

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

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

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

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

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

הגדרת הנגן

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

האזנה לאירועים

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

לדוגמה, אם רוצים לדעת מתי משודר השינוי ב-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 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();

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

אם מתרחשות שגיאות בכלי ליירוט ההודעות, האפליקציה של מכשיר ה-Web קבלה אמורה להחזיר את הנתונים של 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;
        });
    });

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

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

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

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

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

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

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

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

בפקודות מדיה שהאפליקציה לא תומכת בהן, יש להחזיר סיבה מתאימה לשגיאה, למשל 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 לאפליקציית מקלט האינטרנט כשהפעילות תתחיל. כשהפעילות תסתיים, נשלחת הודעה נוספת עם 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, turntagging on', כי השפה נקבעה לפי השפה שבה הפקודה נאמרה. אם התבקשתם להזין את השפה באופן מפורש, למשל אם אומרים "Ok Google, turn on אנגלית", isSuggestedLanguage מוגדר ל-false.

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

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

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

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

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

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

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

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

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

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

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

מצב הסשן נשמר

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

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

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

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

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

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

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

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

הפעלת Cast להתקני אודיו

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

ב-Android TV

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

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

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

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

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

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