Menyesuaikan notifikasi media dan kontrol pemutaran dengan Media Session API

Cara mengintegrasikan dengan tombol media hardware, menyesuaikan notifikasi media, dan lainnya.

François Beaufort
François Beaufort

Untuk memberi tahu pengguna apa yang sedang diputar di browser dan mengontrolnya tanpa kembali ke halaman yang meluncurkannya, Media Session API telah diperkenalkan. Dengan API ini, developer web dapat menyesuaikan pengalaman ini melalui metadata di notifikasi media kustom, peristiwa media seperti memutar, menjeda, mencari, melacak perubahan, dan peristiwa konferensi video seperti membisukan/membunyikan mikrofon, mengaktifkan/menonaktifkan kamera, dan menutup. Penyesuaian ini tersedia dalam beberapa konteks, termasuk hub media desktop, notifikasi media di perangkat seluler, dan bahkan di perangkat wearable. Saya akan menjelaskan penyesuaian ini dalam artikel ini.

Screenshot konteks Sesi Media.
Pusat media di desktop, notifikasi media di perangkat seluler, dan perangkat wearable.

Tentang Media Session API

Media session API memberikan beberapa manfaat dan kemampuan:

  • Mendukung tombol media hardware.
  • Notifikasi media disesuaikan di ponsel, desktop, dan perangkat wearable yang disambungkan.
  • Media hub tersedia di desktop.
  • Kontrol media layar kunci tersedia di ChromeOS dan perangkat seluler.
  • Kontrol jendela Picture-in-Picture tersedia untuk pemutaran audio, konferensi video, dan mempresentasikan slide.
  • Tersedia integrasi Asisten di perangkat seluler.

Dukungan Browser

  • 73
  • 79
  • 82
  • 15

Sumber

Beberapa contoh akan menggambarkan beberapa poin ini.

Contoh 1: Jika pengguna menekan tombol media "track berikutnya" pada keyboard, developer web dapat menangani tindakan pengguna ini, baik saat browser berada di latar depan maupun di latar belakang.

Contoh 2: Jika pengguna mendengarkan podcast di web saat layar perangkat terkunci, mereka masih bisa menekan ikon "mundurkan" dari kontrol media layar kunci sehingga developer web memundurkan waktu pemutaran selama beberapa detik.

Contoh 3: Jika pengguna memiliki tab yang memutar audio, mereka dapat dengan mudah menghentikan pemutaran dari media hub di desktop sehingga developer web memiliki kesempatan untuk menghapus statusnya.

Contoh 4: Jika pengguna sedang melakukan panggilan video, mereka dapat menekan kontrol "alihkan mikrofon" di jendela Picture-in-Picture untuk menghentikan situs agar tidak menerima data mikrofon.

Semuanya dilakukan melalui dua antarmuka yang berbeda: antarmuka MediaSession dan antarmuka MediaMetadata. Yang pertama memungkinkan pengguna mengontrol apa pun yang sedang diputar. Yang kedua adalah cara memberi tahu MediaSession apa yang perlu dikontrol.

Sebagai ilustrasi, gambar di bawah ini menunjukkan hubungan antarmuka ini dengan kontrol media tertentu, dalam hal ini notifikasi media di perangkat seluler.

Ilustrasi antarmuka Sesi Media.
Anatomi notifikasi media di perangkat seluler.

Beri tahu pengguna media yang sedang diputar

Saat situs memutar audio atau video, pengguna otomatis mendapatkan notifikasi media di baki notifikasi di perangkat seluler, atau di hub media di desktop. Browser melakukan yang terbaik untuk menampilkan informasi yang sesuai dengan menggunakan judul dokumen dan gambar ikon terbesar yang dapat ditemukannya. Dengan Media Session API, Anda dapat menyesuaikan notifikasi media dengan beberapa metadata media yang lebih lengkap seperti judul, nama artis, nama album, dan karya seni seperti yang ditunjukkan di bawah ini.

Chrome meminta fokus audio "penuh" untuk menampilkan notifikasi media hanya jika durasi media adalah setidaknya 5 detik. Hal ini memastikan bahwa suara insidental seperti bunyi notifikasi tidak menampilkan notifikasi.

// 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.
}

Saat pemutaran berakhir, Anda tidak perlu "melepaskan" sesi media karena notifikasi akan otomatis menghilang. Perlu diingat bahwa navigator.mediaSession.metadata akan digunakan saat pemutaran berikutnya dimulai. Itulah sebabnya penting untuk memperbaruinya saat sumber pemutaran media berubah untuk memastikan informasi yang relevan ditampilkan dalam notifikasi media.

Ada beberapa hal yang perlu diperhatikan mengenai metadata media.

  • Array karya seni notifikasi mendukung URL blob dan URL data.
  • Jika tidak ada poster yang ditentukan dan ada gambar ikon (ditentukan menggunakan <link rel=icon>) pada ukuran yang diinginkan, notifikasi media akan menggunakannya.
  • Ukuran target poster notifikasi di Chrome untuk Android adalah 512x512. Untuk perangkat kelas bawah, nilainya adalah 256x256.
  • Atribut title elemen HTML media digunakan di widget macOS "Now Playing".
  • Jika resource media disematkan (misalnya dalam iframe), informasi Media Session API harus ditetapkan dari konteks tersemat. Lihat cuplikan di bawah.
<iframe id="iframe">
  <video>...</video>
</iframe>
<script>
  iframe.contentWindow.navigator.mediaSession.metadata = new MediaMetadata({
    title: 'Never Gonna Give You Up',
    ...
  });
</script>

Anda juga dapat menambahkan informasi segmen individual, seperti judul bagian, stempel waktunya, dan gambar screenshot ke metadata media. Hal ini memungkinkan pengguna untuk menjelajahi konten media.

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' },
    ]
  }]
});
Informasi segmen ditampilkan di notifikasi media ChromeOS.
Notifikasi media yang menampilkan bab di ChromeOS.

Izinkan pengguna mengontrol media yang sedang diputar

Tindakan sesi media adalah tindakan (misalnya "putar" atau "jeda") yang dapat ditangani situs untuk pengguna saat mereka berinteraksi dengan pemutaran media saat ini. Tindakan analog dengan dan berfungsi hampir sama seperti peristiwa. Seperti peristiwa, tindakan diimplementasikan dengan menyetel pengendali pada objek yang sesuai, yaitu instance MediaSession. Beberapa tindakan dipicu saat pengguna menekan tombol dari headset, perangkat jarak jauh lainnya, keyboard, atau berinteraksi dengan notifikasi media.

Screenshot notifikasi media di Windows 10.
Notifikasi media yang disesuaikan di Windows 10.

Karena beberapa tindakan sesi media mungkin tidak didukung, sebaiknya gunakan blok try…catch saat menyetelnya.

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

Membatalkan setelan pengendali tindakan sesi media semudah menyetelnya ke 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.`);
}

Setelah disetel, pengendali tindakan sesi media akan tetap ada selama pemutaran media. Ini mirip dengan pola pemroses peristiwa, hanya saja penanganan suatu peristiwa berarti browser berhenti melakukan perilaku default apa pun dan menggunakannya sebagai sinyal bahwa situs mendukung media action tersebut. Oleh karena itu, kontrol tindakan media tidak akan ditampilkan kecuali jika pengendali tindakan yang tepat telah ditetapkan.

Screenshot widget Now Playing di macOS Big Sur.
Widget Now Playing di macOS Big Sur.

Memutar / menjeda

Tindakan "play" menunjukkan bahwa pengguna ingin melanjutkan pemutaran media, sedangkan "pause" menunjukkan keinginan untuk menghentikannya untuk sementara.

Ikon "putar/jeda" selalu ditampilkan dalam notifikasi media dan peristiwa media terkait akan otomatis ditangani oleh browser. Untuk mengganti perilaku defaultnya, tangani tindakan media "putar" dan "jeda" seperti yang ditunjukkan di bawah ini.

Browser dapat mempertimbangkan situs untuk tidak memutar media saat mencari atau memuat misalnya. Dalam hal ini, ganti perilaku ini dengan menyetel navigator.mediaSession.playbackState ke "playing" atau "paused" untuk memastikan UI situs tetap sinkron dengan kontrol notifikasi media.

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

Lagu sebelumnya

Tindakan "previoustrack" menunjukkan bahwa pengguna ingin memulai pemutaran media saat ini dari awal jika pemutaran media memiliki gagasan awal, atau berpindah ke item sebelumnya dalam playlist jika pemutaran media memiliki gagasan tentang playlist.

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

Lagu berikutnya

Tindakan "nexttrack" menunjukkan bahwa pengguna ingin memindahkan pemutaran media ke item berikutnya dalam playlist jika pemutaran media memiliki gagasan playlist.

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

Hentikan

Tindakan "stop" menunjukkan bahwa pengguna ingin menghentikan pemutaran media dan menghapus status jika sesuai.

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

Mundur / maju

Tindakan "seekbackward" menunjukkan bahwa pengguna ingin memundurkan waktu pemutaran media ke belakang untuk jangka waktu yang singkat, sementara "seekforward" menunjukkan keinginan untuk memajukan waktu pemutaran media selama jangka waktu yang singkat. Di kedua kasus, periode yang singkat berarti beberapa detik.

Nilai seekOffset yang diberikan dalam pengendali tindakan adalah waktu dalam detik untuk memindahkan waktu pemutaran media. Jika tidak diberikan (misalnya, undefined), Anda harus menggunakan waktu yang wajar (misalnya 10-30 detik).

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

Cari ke waktu tertentu

Tindakan "seekto" menunjukkan bahwa pengguna ingin memindahkan waktu pemutaran media ke waktu tertentu.

Nilai seekTime yang diberikan dalam pengendali tindakan adalah waktu dalam detik untuk memindahkan waktu pemutaran media.

Boolean fastSeek yang disediakan dalam pengendali tindakan bernilai benar jika tindakan dipanggil beberapa kali sebagai bagian dari suatu urutan dan ini bukan panggilan terakhir dalam urutan tersebut.

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

Menyetel posisi pemutaran

Menampilkan posisi pemutaran media secara akurat dalam notifikasi semudah menyetel status posisi pada waktu yang tepat seperti yang ditunjukkan di bawah ini. Status posisi adalah kombinasi dari kecepatan pemutaran media, durasi, dan waktu saat ini.

Screenshot kontrol media layar kunci di ChromeOS.
Kontrol media layar kunci di ChromeOS.

Durasi harus diberikan dan positif. Posisinya harus positif dan kurang dari durasi. Laju pemutaran harus lebih besar dari 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();
});

Mereset status posisi semudah menyetelnya ke null.

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

Tindakan konferensi video

Saat pengguna melakukan panggilan video ke jendela Picture-in-Picture, browser dapat menampilkan kontrol mikrofon dan kamera, serta untuk menutup telepon. Saat pengguna mengkliknya, situs akan menanganinya melalui tindakan konferensi video di bawah ini. Untuk contohnya, lihat contoh Konferensi Video.

Screenshot kontrol konferensi video di jendela Picture-in-Picture.
Kontrol konferensi video di jendela Picture-in-Picture.

Aktifkan/nonaktifkan mikrofon

Tindakan "togglemicrophone" menunjukkan bahwa pengguna ingin membisukan atau membunyikan mikrofon. Metode setMicrophoneActive(isActive) memberi tahu browser apakah situs saat ini menganggap mikrofon aktif.

let isMicrophoneActive = false;

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

Kamera depan/belakang

Tindakan "togglecamera" menunjukkan bahwa pengguna ingin mengaktifkan atau menonaktifkan kamera aktif. Metode setCameraActive(isActive) menunjukkan apakah browser menganggap situs tersebut aktif.

let isCameraActive = false;

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

Akhiri

Tindakan "hangup" menunjukkan bahwa pengguna ingin mengakhiri panggilan.

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

Mempresentasikan tindakan slide

Saat pengguna menempatkan presentasi slide ke jendela Picture-in-Picture, browser dapat menampilkan kontrol untuk menavigasi slide. Saat pengguna mengkliknya, situs akan menanganinya melalui Media Session API. Untuk contohnya, lihat contoh Presentasi Slide.

Slide sebelumnya

Tindakan "previousslide" menunjukkan bahwa pengguna ingin kembali ke slide sebelumnya saat mempresentasikan slide.

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

Dukungan Browser

  • 111
  • 111
  • x
  • x

Slide berikutnya

Tindakan "nextslide" menunjukkan bahwa pengguna ingin membuka slide berikutnya saat mempresentasikan slide.

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

Dukungan Browser

  • 111
  • 111
  • x
  • x

Contoh

Lihat beberapa contoh Sesi Media yang menampilkan Blender Foundation dan karya Jan Morgenstern.

Screencast yang menggambarkan Media Session API.

Referensi