בעזרת ה-Media Session API, אפשר להתאים אישית את ההתראות של המדיה ואת פקדי ההפעלה

איך לשלב את מקשי המדיה עם מקשי החומרה, להתאים אישית את התראות המדיה ועוד.

François Beaufort
François Beaufort

כדי לאפשר למשתמשים לדעת מה מופעל כרגע בדפדפן ולשלוט בו מבלי לחזור לדף שבו הוא הופעל, הוספנו את ה-Media Session API. הוא מאפשר למפתחי אתרים להתאים אישית את החוויה הזו באמצעות מטא-נתונים בהתראות מדיה מותאמות אישית, אירועי מדיה כמו הפעלה, השהיה, חיפוש, מעקב, שינוי מעקב ואירועים של שיחות ועידה בווידאו כמו השתקה וביטול השתקה של המיקרופון, הפעלה/כיבוי של המצלמה וניתוק. ההתאמה האישית זמינה במספר הקשרים, כולל מרכזי מדיה במחשב, התראות מדיה בנייד ואפילו במכשירים לבישים. במאמר הזה אסביר על התאמות אישיות אלה.

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

מידע על ה-MediaSession API

ל-Media session API יש מספר יתרונות ויכולות:

תמיכה בדפדפן

  • 73
  • 79
  • 82
  • 15

מקור

ריכזנו כאן כמה דוגמאות כדי להמחיש חלק מהנקודות.

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

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

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

דוגמה 4: כשמשתמשים בשיחות וידאו, הם יכולים ללחוץ על לחצן החלפת המצב של המיקרופון בחלון 'תמונה בתוך תמונה' כדי שהאתר לא יקבל את נתוני המיקרופון.

כל המעקב מתבצע באמצעות שני ממשקים שונים: הממשק MediaSession והממשק MediaMetadata. הראשונה מאפשרת למשתמשים לשלוט במה שמושמע. השנייה היא הדרך שבה אומרים לMediaSession במה צריך לשלוט.

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

איור של הממשקים של סשן מדיה.
המבנה של התראה על מדיה בנייד.

איך ליידע את המשתמשים מה שומעים

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

Chrome מבקש מיקוד אודיו "מלא" כדי להציג התראות מדיה רק כשמשך המדיה הוא 5 שניות לפחות. כך תבטיחו שצלילים מקריים כמו צלצולים לא יציגו התראות.

// After media (video or audio) starts playing
await document.querySelector("video").play();

if ("mediaSession" in navigator) {
  navigator.mediaSession.metadata = new MediaMetadata({
    title: 'Never Gonna Give You Up',
    artist: 'Rick Astley',
    album: 'Whenever You Need Somebody',
    artwork: [
      { src: 'https://via.placeholder.com/96',   sizes: '96x96',   type: 'image/png' },
      { src: 'https://via.placeholder.com/128', sizes: '128x128', type: 'image/png' },
      { src: 'https://via.placeholder.com/192', sizes: '192x192', type: 'image/png' },
      { src: 'https://via.placeholder.com/256', sizes: '256x256', type: 'image/png' },
      { src: 'https://via.placeholder.com/384', sizes: '384x384', type: 'image/png' },
      { src: 'https://via.placeholder.com/512', sizes: '512x512', type: 'image/png' },
    ]
  });

  // TODO: Update playback state.
}

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

יש כמה דברים שחשוב לציין לגבי המטא-נתונים של המדיה.

  • מערך גרפיקה של התראות תומך בכתובות URL של blob ובכתובות URL של נתונים.
  • אם לא הוגדרה גרפיקה ומופיעה תמונת סמל (שצוין באמצעות <link rel=icon>) בגודל הרצוי, הודעות המדיה יוצגו באמצעותה.
  • גודל היעד של גרפיקה להתראות ב-Chrome ל-Android הוא 512x512. במכשירים פחות מתקדמים, המחיר הוא 256x256.
  • המאפיין title של אלמנט ה-HTML של המדיה נמצא בשימוש בווידג'ט של macOS 'מה שומעים עכשיו?'.
  • אם משאב המדיה מוטמע (לדוגמה ב-iframe), יש להגדיר את המידע מ-Media Session API מההקשר המוטמע. מידע נוסף זמין בקטע הקוד שבהמשך.
<iframe id="iframe">
  <video>...</video>
</iframe>
<script>
  iframe.contentWindow.navigator.mediaSession.metadata = new MediaMetadata({
    title: 'Never Gonna Give You Up',
    ...
  });
</script>

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

navigator.mediaSession.metadata = new MediaMetadata({
  // title, artist, album, artwork, ...
  chapterInfo: [{
    title: 'Chapter 1',
    startTime: 0,
    artwork: [
      { src: 'https://via.placeholder.com/128', sizes: '128x128', type: 'image/png' },
      { src: 'https://via.placeholder.com/512', sizes: '512x512', type: 'image/png' },
    ]
  }, {
    title: 'Chapter 2',
    startTime: 42,
    artwork: [
      { src: 'https://via.placeholder.com/128', sizes: '128x128', type: 'image/png' },
      { src: 'https://via.placeholder.com/512', sizes: '512x512', type: 'image/png' },
    ]
  }]
});
פרטי הפרק שמוצגים בהתראת מדיה ב-ChromeOS.
התראה במדיה שכוללת פרקים ב-ChromeOS.

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

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

צילום מסך של התראה על מדיה ב-Windows 10.
התראה על מדיה מותאמת אישית ב-Windows 10.

יכול להיות שחלק מהפעולות בסשן מדיה לא נתמכות, לכן מומלץ להשתמש בבלוק try…catch כשמגדירים אותן.

const actionHandlers = [
  ['play',          () => { /* ... */ }],
  ['pause',         () => { /* ... */ }],
  ['previoustrack', () => { /* ... */ }],
  ['nexttrack',     () => { /* ... */ }],
  ['stop',          () => { /* ... */ }],
  ['seekbackward',  (details) => { /* ... */ }],
  ['seekforward',   (details) => { /* ... */ }],
  ['seekto',        (details) => { /* ... */ }],
  /* Video conferencing actions */
  ['togglemicrophone', () => { /* ... */ }],
  ['togglecamera',     () => { /* ... */ }],
  ['hangup',           () => { /* ... */ }],
  /* Presenting slides actions */
  ['previousslide', () => { /* ... */ }],
  ['nextslide',     () => { /* ... */ }],
];

for (const [action, handler] of actionHandlers) {
  try {
    navigator.mediaSession.setActionHandler(action, handler);
  } catch (error) {
    console.log(`The media session action "${action}" is not supported yet.`);
  }
}

ביטול ההגדרה של handler של פעולות שקשורות לסשן מדיה פשוט כמו הגדרה שלו לערך null.

try {
  // Unset the "nexttrack" action handler at the end of a playlist.
  navigator.mediaSession.setActionHandler('nexttrack', null);
} catch (error) {
  console.log(`The media session action "nexttrack" is not supported yet.`);
}

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

צילום מסך של הווידג&#39;ט &#39;מה שומעים עכשיו?&#39; ב-macOS Big Sur.
הווידג'ט 'מה שומעים עכשיו?' ב-macOS Big Sur.

הפעלה / השהיה

הפעולה "play" מציינת שהמשתמש רוצה להמשיך את הפעלת המדיה, אבל "pause" מציין רצון להפסיק אותה באופן זמני.

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

הדפדפן עשוי להתייחס לאתר מסוים כך שלא מפעיל מדיה בזמן חיפוש או טעינה. במקרה כזה, אפשר לשנות את ההתנהגות הזו על ידי הגדרת הערך navigator.mediaSession.playbackState לערך "playing" או "paused" כדי לוודא שממשק המשתמש של האתר יישאר מסונכרן עם פקדי ההתראות של המדיה.

const video = document.querySelector('video');

navigator.mediaSession.setActionHandler('play', async () => {
  // Resume playback
  await video.play();
});

navigator.mediaSession.setActionHandler('pause', () => {
  // Pause active playback
  video.pause();
});

video.addEventListener('play', () => {
  navigator.mediaSession.playbackState = 'playing';
});

video.addEventListener('pause', () => {
  navigator.mediaSession.playbackState = 'paused';
});

הטראק הקודם

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

navigator.mediaSession.setActionHandler('previoustrack', () => {
  // Play previous track.
});

הטראק הבא

הפעולה "nexttrack" מציינת שהמשתמש רוצה להעביר את הפעלת המדיה לפריט הבא בפלייליסט, אם הפעלת המדיה מבוססת על פלייליסט.

navigator.mediaSession.setActionHandler('nexttrack', () => {
  // Play next track.
});

עצירה

הפעולה "stop" מציינת שהמשתמש רוצה להפסיק את ההפעלה של המדיה ולנקות את המצב במקרה הצורך.

navigator.mediaSession.setActionHandler('stop', () => {
  // Stop playback and clear state if appropriate.
});

הרצה אחורה / קדימה

הפעולה "seekbackward" מציינת שהמשתמש רוצה להעביר את זמן ההפעלה של המדיה אחורה לפרק זמן קצר, ואילו "seekforward" מציינת רצון להעביר את זמן ההפעלה של המדיה קדימה לפרק זמן קצר. בשני המקרים, פרק זמן קצר הוא כמה שניות.

הערך של seekOffset שסופק ב-handler של הפעולות הוא הזמן בשניות, שבו צריך להעביר את זמן ההפעלה של המדיה. אם הוא לא צוין (למשל undefined), צריך להגדיר זמן סביר (למשל 10 עד 30 שניות).

const video = document.querySelector('video');
const defaultSkipTime = 10; /* Time to skip in seconds by default */

navigator.mediaSession.setActionHandler('seekbackward', (details) => {
  const skipTime = details.seekOffset || defaultSkipTime;
  video.currentTime = Math.max(video.currentTime - skipTime, 0);
  // TODO: Update playback state.
});

navigator.mediaSession.setActionHandler('seekforward', (details) => {
  const skipTime = details.seekOffset || defaultSkipTime;
  video.currentTime = Math.min(video.currentTime + skipTime, video.duration);
  // TODO: Update playback state.
});

דילוג למועד ספציפי

הפעולה "seekto" מציינת שהמשתמש רוצה להעביר את זמן ההפעלה של המדיה לזמן ספציפי.

הערך של seekTime שמצוין ב-handler של הפעולות הוא הזמן בשניות, שאליו יש להעביר את זמן ההפעלה של המדיה.

הערך הבוליאני fastSeek שצוין ב-handler של הפעולות הוא TRUE אם הפעולה מופעלת כמה פעמים כחלק מרצף, וזו לא הקריאה האחרונה ברצף הזה.

const video = document.querySelector('video');

navigator.mediaSession.setActionHandler('seekto', (details) => {
  if (details.fastSeek && 'fastSeek' in video) {
    // Only use fast seek if supported.
    video.fastSeek(details.seekTime);
    return;
  }
  video.currentTime = details.seekTime;
  // TODO: Update playback state.
});

הגדרת מיקום ההפעלה

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

צילום מסך של פקדי המדיה במסך הנעילה ב-ChromeOS.
פקדי המדיה של מסך הנעילה ב-ChromeOS.

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

const video = document.querySelector('video');

function updatePositionState() {
  if ('setPositionState' in navigator.mediaSession) {
    navigator.mediaSession.setPositionState({
      duration: video.duration,
      playbackRate: video.playbackRate,
      position: video.currentTime,
    });
  }
}

// When video starts playing, update duration.
await video.play();
updatePositionState();

// When user wants to seek backward, update position.
navigator.mediaSession.setActionHandler('seekbackward', (details) => {
  /* ... */
  updatePositionState();
});

// When user wants to seek forward, update position.
navigator.mediaSession.setActionHandler('seekforward', (details) => {
  /* ... */
  updatePositionState();
});

// When user wants to seek to a specific time, update position.
navigator.mediaSession.setActionHandler('seekto', (details) => {
  /* ... */
  updatePositionState();
});

// When video playback rate changes, update position state.
video.addEventListener('ratechange', (event) => {
  updatePositionState();
});

ניתן לאפס את מצב המיקום בקלות רבה, כמו להגדיר אותו לערך null.

// Reset position state when media is reset.
navigator.mediaSession.setPositionState(null);

פעולות בשיחות ועידה בווידאו

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

צילום מסך של הפקדים לשיחות ועידה בווידאו בחלון &#39;תמונה בתוך תמונה&#39;.
פקדים לשיחות ועידה בווידאו בחלון 'תמונה בתוך תמונה'.

החלפת מצב המיקרופון

הפעולה "togglemicrophone" מציינת שהמשתמש רוצה להשתיק או לבטל את ההשתקה של המיקרופון. השיטה setMicrophoneActive(isActive) מנחה את הדפדפן אם הוא מחשיב כרגע את המיקרופון כפעיל.

let isMicrophoneActive = false;

navigator.mediaSession.setActionHandler('togglemicrophone', () => {
  if (isMicrophoneActive) {
    // Mute the microphone.
  } else {
    // Unmute the microphone.
  }
  isMicrophoneActive = !isMicrophoneActive;
  navigator.mediaSession.setMicrophoneActive(isMicrophoneActive);
});

שנה מצב מצלמה

הפעולה "togglecamera" מציינת שהמשתמש רוצה להפעיל או להשבית את המצלמה הפעילה. השיטה setCameraActive(isActive) מציינת אם הדפדפן מתייחס לאתר פעיל.

let isCameraActive = false;

navigator.mediaSession.setActionHandler('togglecamera', () => {
  if (isCameraActive) {
    // Disable the camera.
  } else {
    // Enable the camera.
  }
  isCameraActive = !isCameraActive;
  navigator.mediaSession.setCameraActive(isCameraActive);
});

ניתוק

הפעולה "hangup" מציינת שהמשתמש רוצה לסיים שיחה.

navigator.mediaSession.setActionHandler('hangup', () => {
  // End the call.
});

הצגת פעולות בשקפים

כשהמשתמש מעביר את המצגת של השקפים לחלון 'תמונה בתוך תמונה', יכול להיות שהדפדפן יציג פקדים לניווט בשקפים. כשהמשתמש לוחץ על המודעות, האתר מטפל בהן דרך ה-MediaSession API. לדוגמה, ראו דוגמה להצגת Slides.

לכרטיס הקודם

הפעולה "previousslide" מציינת שהמשתמש רוצה לחזור לשקף הקודם כשמציגים שקפים.

navigator.mediaSession.setActionHandler('previousslide', () => {
  // Show previous slide.
});

תמיכה בדפדפן

  • 111
  • 111
  • x
  • x

לכרטיס הבא

הפעולה "nextslide" מציינת שהמשתמש רוצה לעבור לשקף הבא כשמציגים שקפים.

navigator.mediaSession.setActionHandler('nextslide', () => {
  // Show next slide.
});

תמיכה בדפדפן

  • 111
  • 111
  • x
  • x

דוגמאות

עיינו בדוגמאות של סשנים של מדיה בהשתתפות Blender Foundation והיצירה של יאן מורגנסטרן.

הקלטת מסך שממחישה את ה-Media Session API.

מקורות מידע