Dengan Media Session API yang baru, kini Anda dapat menyesuaikan notifikasi media dengan memberikan metadata untuk media yang diputar oleh aplikasi web Anda. Hal ini juga memungkinkan Anda menangani peristiwa terkait media, seperti mencari atau melacak perubahan yang mungkin berasal dari notifikasi atau kunci media. Tertarik? Coba contoh Sesi Media resmi.
Media Session API didukung di Chrome 57 (versi beta pada Februari 2017, stabil pada Maret 2017).
Berikan yang kuinginkan
Anda sudah tahu Media Session API dan baru kembali untuk menyalin dan menempelkan tanpa perlu malu dengan kode boilerplate? Jadi ini dia.
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://dummyimage.com/96x96', sizes: '96x96', type: 'image/png' },
{ src: 'https://dummyimage.com/128x128', sizes: '128x128', type: 'image/png' },
{ src: 'https://dummyimage.com/192x192', sizes: '192x192', type: 'image/png' },
{ src: 'https://dummyimage.com/256x256', sizes: '256x256', type: 'image/png' },
{ src: 'https://dummyimage.com/384x384', sizes: '384x384', type: 'image/png' },
{ src: 'https://dummyimage.com/512x512', sizes: '512x512', type: 'image/png' },
]
});
navigator.mediaSession.setActionHandler('play', function() {});
navigator.mediaSession.setActionHandler('pause', function() {});
navigator.mediaSession.setActionHandler('seekbackward', function() {});
navigator.mediaSession.setActionHandler('seekforward', function() {});
navigator.mediaSession.setActionHandler('previoustrack', function() {});
navigator.mediaSession.setActionHandler('nexttrack', function() {});
}
Memahami kode
Ayo main Persona
Tambahkan elemen <audio>
sederhana ke halaman web Anda dan tetapkan beberapa sumber media sehingga
browser dapat memilih sumber media yang paling efektif.
<audio controls>
<source src="audio.mp3" type="audio/mp3"/>
<source src="audio.ogg" type="audio/ogg"/>
</audio>
Seperti yang mungkin Anda ketahui, autoplay
dinonaktifkan untuk elemen audio di Chrome
untuk Android, yang berarti kita harus menggunakan metode play()
elemen
audio. Metode ini harus dipicu oleh gestur pengguna seperti sentuhan atau
klik mouse.
Artinya, memproses peristiwa pointerup
, click
, dan touchend
. Dengan kata lain, pengguna harus mengklik tombol sebelum aplikasi web Anda benar-benar dapat membuat derau.
playButton.addEventListener('pointerup', function(event) {
let audio = document.querySelector('audio');
// User interacted with the page. Let's play audio...
audio.play()
.then(_ => { /* Set up media session... */ })
.catch(error => { console.log(error) });
});
Jika Anda tidak ingin memutar audio tepat setelah interaksi pertama, sebaiknya
gunakan metode load()
elemen audio. Ini adalah salah satu cara bagi browser untuk melacak apakah pengguna berinteraksi dengan elemen. Perlu
diketahui bahwa tindakan ini juga dapat membantu memperlancar pemutaran karena konten sudah
dimuat.
let audio = document.querySelector('audio');
welcomeButton.addEventListener('pointerup', function(event) {
// User interacted with the page. Let's load audio...
<strong>audio.load()</strong>
.then(_ => { /* Show play button for instance... */ })
.catch(error => { console.log(error) });
});
// Later...
playButton.addEventListener('pointerup', function(event) {
<strong>audio.play()</strong>
.then(_ => { /* Set up media session... */ })
.catch(error => { console.log(error) });
});
Menyesuaikan notifikasi
Saat aplikasi web memutar audio, Anda sudah dapat melihat notifikasi media di baki notifikasi. Di Android, Chrome melakukan yang terbaik untuk menampilkan informasi yang sesuai dengan menggunakan judul dokumen dan gambar ikon terbesar yang dapat ditemukannya.
Menetapkan metadata
Mari kita lihat cara menyesuaikan notifikasi media ini dengan menyetel beberapa metadata sesi media seperti judul, artis, nama album, dan karya seni dengan Media Session API.
// When audio starts playing...
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://dummyimage.com/96x96', sizes: '96x96', type: 'image/png' },
{ src: 'https://dummyimage.com/128x128', sizes: '128x128', type: 'image/png' },
{ src: 'https://dummyimage.com/192x192', sizes: '192x192', type: 'image/png' },
{ src: 'https://dummyimage.com/256x256', sizes: '256x256', type: 'image/png' },
{ src: 'https://dummyimage.com/384x384', sizes: '384x384', type: 'image/png' },
{ src: 'https://dummyimage.com/512x512', sizes: '512x512', type: 'image/png' },
]
});
}
Setelah pemutaran selesai, Anda tidak perlu "merilis" sesi media karena
notifikasi akan otomatis menghilang. Perlu diingat bahwa navigator.mediaSession.metadata
saat ini akan digunakan saat pemutaran dimulai. Oleh karena itu,
Anda perlu memperbaruinya untuk memastikan Anda selalu menampilkan informasi
yang relevan dalam notifikasi media.
Lagu sebelumnya / lagu berikutnya
Jika aplikasi web Anda menyediakan playlist, Anda mungkin ingin mengizinkan pengguna membuka playlist langsung dari notifikasi media dengan beberapa ikon "Lagu Sebelumnya" dan "Lagu Berikutnya".
let audio = document.createElement('audio');
let playlist = ['audio1.mp3', 'audio2.mp3', 'audio3.mp3'];
let index = 0;
navigator.mediaSession.setActionHandler('previoustrack', function() {
// User clicked "Previous Track" media notification icon.
index = (index - 1 + playlist.length) % playlist.length;
playAudio();
});
navigator.mediaSession.setActionHandler('nexttrack', function() {
// User clicked "Next Track" media notification icon.
index = (index + 1) % playlist.length;
playAudio();
});
function playAudio() {
audio.src = playlist[index];
audio.play()
.then(_ => { /* Set up media session... */ })
.catch(error => { console.log(error); });
}
playButton.addEventListener('pointerup', function(event) {
playAudio();
});
Perhatikan bahwa pengendali tindakan media akan tetap ada. Ini sangat mirip dengan pola pemroses peristiwa, hanya saja penanganan suatu peristiwa berarti browser berhenti melakukan perilaku default apa pun dan menggunakannya sebagai sinyal bahwa aplikasi web Anda mendukung media action tersebut. Oleh karena itu, kontrol tindakan media tidak akan ditampilkan kecuali Anda menetapkan pengendali tindakan yang tepat.
Ngomong-ngomong, membatalkan penetapan pengendali tindakan media semudah menetapkannya ke null
.
Mundur / cari maju
Media Session API memungkinkan Anda menampilkan ikon notifikasi media "Seek Backward" dan "Seek Forward" jika ingin mengontrol jumlah waktu yang dilewati.
let skipTime = 10; // Time to skip in seconds
navigator.mediaSession.setActionHandler('seekbackward', function() {
// User clicked "Seek Backward" media notification icon.
audio.currentTime = Math.max(audio.currentTime - skipTime, 0);
});
navigator.mediaSession.setActionHandler('seekforward', function() {
// User clicked "Seek Forward" media notification icon.
audio.currentTime = Math.min(audio.currentTime + skipTime, audio.duration);
});
Memutar / menjeda
Ikon "Putar/Jeda" selalu ditampilkan di notifikasi media dan peristiwa terkait akan otomatis ditangani oleh browser. Jika perilaku default tidak berhasil, karena alasan tertentu, Anda masih dapat menangani peristiwa media "Putar" dan "Jeda".
navigator.mediaSession.setActionHandler('play', function() {
// User clicked "Play" media notification icon.
// Do something more than just playing current audio...
});
navigator.mediaSession.setActionHandler('pause', function() {
// User clicked "Pause" media notification icon.
// Do something more than just pausing current audio...
});
Notifikasi di mana saja
Hal yang menarik tentang Media Session API adalah baki notifikasi bukan satu-satunya tempat metadata dan kontrol media terlihat. Notifikasi media disinkronkan secara otomatis ke perangkat wearable yang disambungkan. Dan itu juga muncul di layar kunci.
Putar musik dengan nyaman saat offline
Aku tahu apa yang kamu pikirkan sekarang. Pekerja layanan siap menolong.
Benar, tetapi yang terpenting, Anda ingin memastikan semua item dalam checklist ini telah dicentang:
- Semua file media dan poster ditayangkan dengan header HTTP
Cache-Control
yang sesuai. Hal ini akan memungkinkan browser meng-cache dan menggunakan kembali resource yang diambil sebelumnya. Lihat Checklist penyimpanan dalam cache. - Pastikan semua file media dan poster ditayangkan dengan
header HTTP
Allow-Control-Allow-Origin: *
. Tindakan ini akan memungkinkan aplikasi web pihak ketiga mengambil dan menggunakan respons HTTP dari server web Anda.
Strategi penyimpanan dalam cache pekerja layanan
Mengenai file media, saya merekomendasikan strategi "Cache, fallback to network" sederhana seperti yang diilustrasikan oleh Jake Archibald.
Untuk poster, saya akan sedikit lebih spesifik dan memilih pendekatan di bawah ini:
- Poster
If
sudah ada di cache, tayangkan dari cache Else
mengambil karya seni dari jaringan- Pengambilan
If
berhasil, tambahkan poster jaringan ke cache dan tayangkan Else
menayangkan poster penggantian dari cache
- Pengambilan
Dengan demikian, notifikasi media akan selalu memiliki ikon poster yang bagus meskipun browser tidak dapat mengambilnya. Berikut cara menerapkannya:
const FALLBACK_ARTWORK_URL = 'fallbackArtwork.png';
addEventListener('install', event => {
self.skipWaiting();
event.waitUntil(initArtworkCache());
});
function initArtworkCache() {
caches.open('artwork-cache-v1')
.then(cache => cache.add(FALLBACK_ARTWORK_URL));
}
addEventListener('fetch', event => {
if (/artwork-[0-9]+\.png$/.test(event.request.url)) {
event.respondWith(handleFetchArtwork(event.request));
}
});
function handleFetchArtwork(request) {
// Return cache request if it's in the cache already, otherwise fetch
// network artwork.
return getCacheArtwork(request)
.then(cacheResponse => cacheResponse || getNetworkArtwork(request));
}
function getCacheArtwork(request) {
return caches.open('artwork-cache-v1')
.then(cache => cache.match(request));
}
function getNetworkArtwork(request) {
// Fetch network artwork.
return fetch(request)
.then(networkResponse => {
if (networkResponse.status !== 200) {
return Promise.reject('Network artwork response is not valid');
}
// Add artwork to the cache for later use and return network response.
addArtworkToCache(request, networkResponse.clone())
return networkResponse;
})
.catch(error => {
// Return cached fallback artwork.
return getCacheArtwork(new Request(FALLBACK_ARTWORK_URL))
});
}
function addArtworkToCache(request, response) {
return caches.open('artwork-cache-v1')
.then(cache => cache.put(request, response));
}
Izinkan pengguna mengontrol cache
Karena pengguna menggunakan konten dari aplikasi web Anda, file media dan karya seni dapat memerlukan banyak ruang di perangkat mereka. Anda bertanggung jawab untuk menunjukkan seberapa banyak cache yang digunakan dan memberi pengguna kemampuan untuk menghapusnya. Untungnya, kami dapat melakukannya dengan mudah menggunakan Cache API.
// Here's how I'd compute how much cache is used by artwork files...
caches.open('artwork-cache-v1')
.then(cache => cache.matchAll())
.then(responses => {
let cacheSize = 0;
let blobQueue = Promise.resolve();
responses.forEach(response => {
let responseSize = response.headers.get('content-length');
if (responseSize) {
// Use content-length HTTP header when possible.
cacheSize += Number(responseSize);
} else {
// Otherwise, use the uncompressed blob size.
blobQueue = blobQueue.then(_ => response.blob())
.then(blob => { cacheSize += blob.size; blob.close(); });
}
});
return blobQueue.then(_ => {
console.log('Artwork cache is about ' + cacheSize + ' Bytes.');
});
})
.catch(error => { console.log(error); });
// And here's how to delete some artwork files...
const artworkFilesToDelete = ['artwork1.png', 'artwork2.png', 'artwork3.png'];
caches.open('artwork-cache-v1')
.then(cache => Promise.all(artworkFilesToDelete.map(artwork => cache.delete(artwork))))
.catch(error => { console.log(error); });
Catatan penerapan
- Chrome untuk Android meminta fokus audio "penuh" untuk menampilkan notifikasi media hanya jika durasi file media adalah setidaknya 5 detik.
- Poster notifikasi mendukung URL blob dan URL data.
- Jika tidak ada karya seni yang ditentukan dan ada gambar ikon dengan ukuran yang diinginkan, notifikasi media akan menggunakannya.
- Ukuran poster notifikasi di Chrome untuk Android adalah
512x512
. Untuk perangkat kelas bawah, nilainya adalah256x256
. - Tutup notifikasi media dengan
audio.src = ''
. - Karena Web Audio API tidak meminta Fokus Audio Android karena alasan historis, satu-satunya cara untuk membuatnya berfungsi dengan Media Session API adalah dengan menghubungkan
elemen
<audio>
sebagai sumber input ke Web Audio API. Semoga Web AudioFocus API yang diusulkan akan memperbaiki situasi ini dalam waktu dekat. - Panggilan Sesi Media akan memengaruhi notifikasi media hanya jika panggilan tersebut berasal dari frame yang sama dengan resource media. Lihat cuplikan di bawah.
<iframe id="iframe">
<audio>...</audio>
</iframe>
<script>
iframe.contentWindow.navigator.mediaSession.metadata = new MediaMetadata({
title: 'Never Gonna Give You Up',
...
});
</script>
Dukungan
Pada saat ini ditulis, Chrome untuk Android adalah satu-satunya platform yang mendukung Media Session API. Informasi terbaru lebih lanjut tentang status penerapan browser dapat ditemukan di Status Platform Chrome.
Contoh & demo
Lihat contoh Sesi Media Chrome resmi kami yang menampilkan Blender Foundation dan karya Jan Morgenstern.
Referensi
Spesifikasi Sesi Media: wicg.github.io/mediasession
Masalah Spesifikasi: github.com/WICG/mediasession/issues
Bug Chrome: crbug.com