Avec la toute nouvelle API Media Session, vous pouvez désormais personnaliser les notifications multimédias en fournissant des métadonnées pour les contenus multimédias lus par votre application Web. Il vous permet également de gérer les événements multimédias tels que la recherche ou les modifications de suivi, qui peuvent provenir de notifications ou de touches multimédias. Ça vous plaît ? Essayez les exemples officiels de sessions multimédias.
L'API Media Session est compatible avec Chrome 57 (bêta en février 2017, stable en mars 2017).
Donne ce que je veux
Vous connaissez déjà l'API Media Session, et vous souhaitez simplement copier-coller du code récurrent sans honte ? Voilà.
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() {});
}
Saisissez le code
Jouons 🎷
Ajoutez un élément <audio>
simple à votre page Web et attribuez plusieurs sources multimédias afin que le navigateur puisse choisir celle qui fonctionne le mieux.
<audio controls>
<source src="audio.mp3" type="audio/mp3"/>
<source src="audio.ogg" type="audio/ogg"/>
</audio>
Comme vous le savez peut-être, autoplay
est désactivé pour les éléments audio sur Chrome pour Android, ce qui signifie que nous devons utiliser la méthode play()
de l'élément audio. Cette méthode doit être déclenchée par un geste de l'utilisateur, comme une pression ou un clic de souris.
Cela implique d'écouter les événements pointerup
, click
et touchend
. En d'autres termes, l'utilisateur doit cliquer sur un bouton pour que votre application Web puisse émettre du bruit.
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) });
});
Si vous ne souhaitez pas lire de contenu audio juste après la première interaction, nous vous recommandons d'utiliser la méthode load()
de l'élément audio. Cela permet au navigateur de savoir si l'utilisateur a interagi avec l'élément. Notez que cela peut également faciliter la lecture, car le contenu sera déjà chargé.
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) });
});
Personnaliser la notification
Lorsque votre application Web lit du contenu audio, une notification multimédia s'affiche déjà dans la barre de notification. Sur Android, Chrome s'efforce d'afficher les informations appropriées en se basant sur le titre du document et la plus grande image d'icône disponible.
Définir les métadonnées
Voyons comment personnaliser cette notification multimédia en définissant certaines métadonnées de session multimédia telles que le titre, l'artiste, le nom de l'album et la pochette avec l'API Media Session.
// 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' },
]
});
}
Une fois la lecture terminée, vous n'avez pas besoin de "libérer" la session multimédia, car la notification disparaît automatiquement. N'oubliez pas que la valeur navigator.mediaSession.metadata
actuelle sera utilisée au début de la lecture. C'est pourquoi vous devez le mettre à jour pour vous assurer de toujours afficher des informations pertinentes dans la notification multimédia.
Titre précédent / suivant
Si votre application Web fournit une playlist, vous pouvez autoriser l'utilisateur à parcourir votre playlist directement à partir de la notification multimédia à l'aide des icônes "Titre précédent" et "Piste suivante".
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();
});
Notez que les gestionnaires d'actions multimédias seront conservés. Ce modèle est très semblable au modèle d'écouteur d'événements, à la différence que la gestion d'un événement signifie que le navigateur cesse d'effectuer tout comportement par défaut et l'utilise comme signal indiquant que votre application Web prend en charge l'action multimédia. Par conséquent, les commandes des actions multimédias ne s'affichent que si vous définissez le gestionnaire d'actions approprié.
À ce propos, il est aussi facile de désactiver un gestionnaire d'actions multimédias que de l'attribuer à null
.
Avancer / Reculer
L'API Media Session vous permet d'afficher les icônes de notification multimédia "Avancer" et "Avancer" si vous souhaitez contrôler la durée d'inactivité.
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);
});
Lecture / Pause
L'icône Lecture/Pause est toujours affichée dans la notification multimédia, et les événements associés sont gérés automatiquement par le navigateur. Si, pour une raison quelconque, le comportement par défaut ne fonctionne pas, vous pouvez toujours gérer les événements multimédias "Lecture" et "Pause".
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...
});
Notifications partout
L'avantage de l'API Media Session est que la barre de notification n'est pas le seul emplacement où les métadonnées et les commandes multimédias sont visibles. La notification multimédia est synchronisée automatiquement avec tout accessoire connecté associé. Et elle apparaît aussi sur les écrans de verrouillage.
Profitez d'une qualité de lecture hors connexion
Je sais ce que vous pensez maintenant. Service worker à la rescousse !
Vrai, mais avant tout, vous devez vous assurer que tous les éléments de cette checklist sont vérifiés:
- Tous les fichiers multimédias et d'illustration sont diffusés avec l'en-tête HTTP
Cache-Control
approprié. Cela permettra au navigateur de mettre en cache et de réutiliser les ressources précédemment récupérées. Consultez la checklist de mise en cache. - Assurez-vous que tous les fichiers multimédias et d'illustration sont diffusés avec l'en-tête HTTP
Allow-Control-Allow-Origin: *
. Cela permettra aux applications Web tierces de récupérer et d'utiliser les réponses HTTP de votre serveur Web.
La stratégie de mise en cache d'un service worker
Concernant les fichiers multimédias, je recommande une stratégie simple "Cache, falling to network" (Mettre en cache, revenir au réseau), comme l'illustre Jake Archibal.
Pour les illustrations, je serais un peu plus précis et choisirais l'approche ci-dessous:
- L'illustration
If
se trouve déjà dans le cache. Diffusez-la à partir du cache. Else
récupère une illustration sur le réseau- La récupération de
If
a réussi. Ajoutez l'illustration de réseau au cache et diffusez-la. Else
diffuse l'illustration de remplacement à partir du cache.
- La récupération de
Ainsi, les notifications multimédias auront toujours une belle icône d'illustration même lorsque le navigateur ne peut pas les récupérer. Voici comment vous pourriez procéder:
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));
}
Autoriser l'utilisateur à contrôler le cache
Comme l'utilisateur utilise le contenu de votre application Web, les fichiers multimédias et d'illustration peuvent prendre beaucoup d'espace sur son appareil. Il vous incombe d'indiquer la quantité de cache utilisée et de permettre aux utilisateurs de le vider. Heureusement pour nous, cela est assez facile avec l'API Cache.
// 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); });
Notes de mise en œuvre
- Chrome pour Android demande le ciblage audio "complet" pour n'afficher les notifications multimédias que si le fichier multimédia dure au moins cinq secondes.
- Les illustrations de notification acceptent les URL blob et les URL de données.
- Si aucune illustration n'est définie et qu'il existe une image d'icône à une taille souhaitée, les notifications multimédias l'utiliseront.
- La taille de l'illustration des notifications dans Chrome pour Android est de
512x512
. Pour les appareils d'entrée de gamme, il s'agit de256x256
. - Ignorer les notifications multimédias avec
audio.src = ''
. - Étant donné que l'API Web Audio ne demande pas la priorité audio Android pour des raisons historiques, le seul moyen de la faire fonctionner avec l'API Media Session consiste à connecter un élément
<audio>
en tant que source d'entrée à l'API Web Audio. Nous espérons que l'API Web AudioFocus proposée permettra d'améliorer la situation dans un avenir proche. - Les appels de session multimédia n'affectent les notifications multimédias que s'ils proviennent du même frame que la ressource multimédia. Consultez l'extrait ci-dessous.
<iframe id="iframe">
<audio>...</audio>
</iframe>
<script>
iframe.contentWindow.navigator.mediaSession.metadata = new MediaMetadata({
title: 'Never Gonna Give You Up',
...
});
</script>
Assistance
Au moment de la rédaction de ce document, Chrome pour Android est la seule plate-forme compatible avec l'API Media Session. Pour obtenir des informations plus récentes sur l'état de la mise en œuvre du navigateur, consultez État de la plate-forme Chrome.
Exemples et démonstrations
Consultez nos exemples officiels de sessions multimédias Chrome, dans lesquelles la Blender Foundation et le travail de Jan Morgenstern sont présentés.
Ressources
Spécification de la session multimédia : wicg.github.io/mediasession
Problèmes de spécifications : github.com/WICG/mediasession/issues
Bugs Chrome : crbug.com