Mit der brandneuen Media Session API können Sie jetzt Medienbenachrichtigungen anpassen, indem Sie Metadaten für die Medien angeben, die Ihre Webanwendung abspielt. Außerdem können Sie damit medienbezogene Ereignisse verarbeiten, z. B. eine Suche oder Titeländerungen, die über Benachrichtigungen oder Medienschlüssel ausgelöst wurden. Bist du gespannt? Dann sehen Sie sich die offiziellen Media Sessions-Beispiele an.
Die Media Session API wird in Chrome 57 unterstützt (Beta im Februar 2017, stabil im März 2017).
Gib mir, was ich will
Sie kennen die Media Session API bereits und möchten einfach wieder Boilerplate-Code kopieren und einfügen? Hier ist es also.
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() {});
}
In den Code einbauen
Lass uns spielen 🎷
Fügen Sie Ihrer Webseite ein einfaches <audio>
-Element hinzu und weisen Sie mehrere Medienquellen zu, damit der Browser auswählen kann, welche am besten funktioniert.
<audio controls>
<source src="audio.mp3" type="audio/mp3"/>
<source src="audio.ogg" type="audio/ogg"/>
</audio>
Wie du vielleicht weißt, ist autoplay
für Audioelemente in Chrome für Android deaktiviert. Daher müssen wir die play()
-Methode des Audioelements verwenden. Diese Methode muss durch eine Nutzergeste ausgelöst werden, z. B. durch eine Berührung oder einen Mausklick.
Das bedeutet, dass pointerup
-, click
- und touchend
-Ereignisse überwacht werden. Mit anderen Worten: Der Nutzer muss auf eine Schaltfläche klicken, bevor Ihre Webanwendung tatsächlich Geräusche erzeugen kann.
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) });
});
Wenn Sie Audioinhalte nicht direkt nach der ersten Interaktion wiedergeben möchten, empfehlen wir die Verwendung der load()
-Methode des Audioelements. Dies ist eine Möglichkeit für den Browser, zu erfassen, ob der Nutzer mit dem Element interagiert hat. Unter Umständen wird die Wiedergabe dadurch eventuell reibungsloser, da die Inhalte bereits geladen sind.
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) });
});
Benachrichtigung anpassen
Wenn Ihre Web-App Audio wiedergibt, wird bereits eine Medienbenachrichtigung in der Benachrichtigungsleiste angezeigt. Unter Android versucht Chrome, geeignete Informationen anzuzeigen. Dazu werden der Titel des Dokuments und das größte Symbolbild verwendet, das gefunden werden kann.
Metadata festlegen
Sehen wir uns an, wie Sie diese Medienbenachrichtigung anpassen können, indem Sie mit der Media Session API einige Metadaten der Mediensitzung wie Titel, Künstler, Albumname und Artwork festlegen.
// 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' },
]
});
}
Nach der Wiedergabe müssen Sie die Mediensitzung nicht mehr „freigeben“, da die Benachrichtigung automatisch ausgeblendet wird. Hinweis: Beim Start der Wiedergabe wird die aktuelle navigator.mediaSession.metadata
verwendet. Deshalb musst du ihn aktualisieren, damit in den Medienbenachrichtigungen immer relevante Informationen angezeigt werden.
Vorheriger Titel / nächster Titel
Wenn Ihre Webanwendung eine Playlist bereitstellt, können Sie Nutzern die Möglichkeit bieten, direkt von der Medienbenachrichtigung aus durch Ihre Playlist zu navigieren, und zwar mit einigen Symbolen für „Vorheriger Titel“ und „Nächster Titel“.
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();
});
Media Action-Handler bleiben erhalten. Dies ist dem Muster des Event-Listeners sehr ähnlich, außer dass die Verarbeitung eines Ereignisses dazu führt, dass der Browser kein Standardverhalten mehr ausführt und dies als Signal verwendet, dass Ihre Webanwendung die Medienaktion unterstützt. Daher werden Steuerelemente für Medienaktionen nur angezeigt, wenn Sie den richtigen Action-Handler festlegen.
Übrigens ist es genauso einfach, einen Media Action-Handler zu deaktivieren, wie ihn null
zuzuweisen.
Zurück-/Vorwärtsspulen
Mit der Media Session API können Sie die Medienbenachrichtigungssymbole „Zurückspulen“ und „Vorwärts springen“ anzeigen, wenn Sie die übersprungene Zeit steuern möchten.
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);
});
Wiedergabe / Pause
Das Symbol „Wiedergabe/Pause“ wird immer in der Medienbenachrichtigung angezeigt und die zugehörigen Ereignisse werden automatisch vom Browser verarbeitet. Sollte das Standardverhalten aus irgendeinem Grund nicht funktionieren, können Sie Medienereignisse mit den Optionen „Wiedergabe“ und „Pause“ trotzdem verarbeiten.
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...
});
Benachrichtigungen überall
Das Tolle an der Media Session API ist, dass die Benachrichtigungsleiste nicht der einzige Ort ist, an dem Medienmetadaten und Steuerelemente sichtbar sind. Die Medienbenachrichtigungen werden automatisch mit jedem gekoppelten Wearable-Gerät synchronisiert. Auch auf Sperrbildschirmen.
Offline spielen
Ich weiß, was Sie jetzt denken. Service Worker der Rettungsdienst
Richtig, aber in erster Linie möchten Sie sicherstellen, dass alle Punkte in dieser Checkliste geprüft wurden:
- Alle Medien- und Artwork-Dateien werden mit dem entsprechenden
Cache-Control
-HTTP-Header bereitgestellt. Dadurch kann der Browser zuvor abgerufene Ressourcen im Cache speichern und wiederverwenden. Siehe Caching-Checkliste. - Alle Medien- und Artworkdateien müssen mit dem HTTP-Header
Allow-Control-Allow-Origin: *
bereitgestellt werden. Dadurch können Webanwendungen von Drittanbietern HTTP-Antworten von Ihrem Webserver abrufen und verarbeiten.
Die Service Worker-Caching-Strategie
In Bezug auf Mediendateien empfehlen wir eine einfache Strategie des Typs Cache, Fallback auf das Netzwerk, wie von Jake Archibald dargestellt.
Für Artwork würde ich jedoch etwas konkreter sein und den folgenden Ansatz wählen:
If
-Artwork befindet sich bereits im Cache, stelle es aus dem Cache bereitElse
ruft Artwork aus dem Netzwerk ab- Der
If
-Abruf ist erfolgreich. Füge dem Cache Netzwerkgrafiken hinzu und stelle sie bereit. Else
stellt die Fallback-Grafik aus dem Cache bereit
- Der
So haben Medienbenachrichtigungen immer ein schönes Artwork-Symbol, auch wenn der Browser sie nicht abrufen kann. So könnten Sie dies implementieren:
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));
}
Cache durch Nutzer verwalten lassen
Da der Nutzer Inhalte aus Ihrer Web-App nutzt, können Medien- und Grafikdateien auf seinem Gerät viel Speicherplatz einnehmen. Es liegt in Ihrer Verantwortung, zu zeigen, wie viel Cache verwendet wird, und Nutzern die Möglichkeit zu geben, ihn zu leeren. Zum Glück ist dies mit der Cache API ziemlich einfach.
// 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); });
Implementierungshinweise
- Chrome für Android fordert einen vollständigen Audiofokus an, damit Medienbenachrichtigungen nur dann angezeigt werden, wenn die Dauer der Mediendatei mindestens 5 Sekunden beträgt.
- Benachrichtigungsgrafiken unterstützen Blob- und Daten-URLs.
- Wenn kein Artwork definiert ist und ein Symbolbild in einer gewünschten Größe vorhanden ist, wird es in Medienbenachrichtigungen verwendet.
- Die Größe der Benachrichtigungsgrafik in Chrome für Android ist
512x512
. Für Low-End-Geräte ist er256x256
. - Medienbenachrichtigungen mit
audio.src = ''
schließen. - Da die Web Audio API aus historischen Gründen keinen Android Audio Focus anfordert, kann sie nur mit der Media Session API verwendet werden, indem ein
<audio>
-Element als Eingabequelle an die Web Audio API angehängt wird. Wir hoffen, dass die vorgeschlagene Web AudioFocus API die Situation in naher Zukunft verbessern wird. - Mediensitzungsaufrufe wirken sich nur dann auf Medienbenachrichtigungen aus, wenn sie aus demselben Frame wie die Medienressource stammen. Unten sehen Sie das entsprechende Snippet.
<iframe id="iframe">
<audio>...</audio>
</iframe>
<script>
iframe.contentWindow.navigator.mediaSession.metadata = new MediaMetadata({
title: 'Never Gonna Give You Up',
...
});
</script>
Support
Derzeit ist Chrome für Android die einzige Plattform, die die Media Session API unterstützt. Aktuelle Informationen zum Status der Browserimplementierung finden Sie unter Status der Chrome-Plattform.
Beispiele und Demos
Sehen Sie sich unsere offiziellen Beispiele für Chrome Media Sessions mit Blender Foundation und Jan Morgensterns Arbeit an.
Ressourcen
Spezifikation für Mediasitzungen: wicg.github.io/mediasession
Spezifikationsprobleme: github.com/WICG/mediasession/issues
Chrome-Fehler: crbug.com