Media Session API ใหม่นี้ช่วยให้คุณปรับแต่งการแจ้งเตือนสื่อได้ด้วยการระบุข้อมูลเมตาของสื่อที่เว็บแอปเล่นอยู่ นอกจากนี้ยังช่วยให้คุณจัดการเหตุการณ์ที่เกี่ยวข้องกับสื่อ เช่น การเลือกดูหรือการเปลี่ยนแทร็ก ซึ่งอาจมาจากการแจ้งเตือนหรือแป้นสื่อ น่าสนใจใช่ไหม ลองใช้ตัวอย่างเซสชันสื่ออย่างเป็นทางการ
Chrome 57 รองรับ Media Session API (เบต้าในเดือนกุมภาพันธ์ 2017 และเวอร์ชันเสถียรในเดือนมีนาคม 2017)
โปรดให้สิ่งที่ฉันต้องการ
คุณทราบเกี่ยวกับ Media Session API อยู่แล้วและกลับมาเพื่อคัดลอกและวางโค้ดที่เขียนไว้ล่วงหน้าอย่างไม่ต้องอายใช่ไหม ได้แล้วครับ
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() {});
}
ทำความเข้าใจโค้ด
มาเล่นกันเถอะ 🎷
เพิ่มองค์ประกอบ <audio>
ง่ายๆ ลงในหน้าเว็บและกำหนดแหล่งที่มาของสื่อหลายแหล่งเพื่อให้เบราว์เซอร์เลือกแหล่งที่มาที่ทำงานได้ดีที่สุด
<audio controls>
<source src="audio.mp3" type="audio/mp3"/>
<source src="audio.ogg" type="audio/ogg"/>
</audio>
คุณอาจทราบแล้วว่า autoplay
ถูกปิดใช้สำหรับองค์ประกอบเสียงใน Chrome สำหรับ Android ซึ่งหมายความว่าเราต้องใช้เมธอด play()
ขององค์ประกอบเสียง วิธีการนี้ต้องทริกเกอร์โดยท่าทางสัมผัสของผู้ใช้ เช่น การสัมผัสหรือการคลิกเมาส์
ซึ่งหมายถึงการฟังเหตุการณ์ pointerup
click
และ touchend
กล่าวคือ ผู้ใช้ต้องคลิกปุ่มก่อนเว็บแอปของคุณจึงจะส่งเสียงได้
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) });
});
หากไม่ต้องการให้เล่นเสียงทันทีหลังจากการโต้ตอบครั้งแรก เราขอแนะนำให้คุณใช้เมธอด load()
ขององค์ประกอบเสียง นี่เป็นวิธีหนึ่งสำหรับเบราว์เซอร์ในการติดตามว่าผู้ใช้โต้ตอบกับองค์ประกอบนั้นๆ หรือไม่ โปรดทราบว่าวิธีนี้อาจช่วยให้การเล่นราบรื่นขึ้นด้วยเนื่องจากระบบจะโหลดเนื้อหาไว้แล้ว
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) });
});
ปรับแต่งการแจ้งเตือน
เมื่อเว็บแอปเล่นเสียง คุณจะเห็นว่าการแจ้งเตือนสื่อแสดงอยู่ในถาดการแจ้งเตือนอยู่แล้ว ใน Android ทาง Chrome จะพยายามแสดงข้อมูลที่ถูกต้องโดยใช้ชื่อเอกสารและรูปภาพไอคอนที่ใหญ่ที่สุดที่พบ
ตั้งค่าข้อมูลเมตา
มาดูวิธีปรับแต่งการแจ้งเตือนสื่อนี้ด้วยการตั้งค่าข้อมูลเมตาของเซสชันสื่อ เช่น ชื่อ ศิลปิน ชื่ออัลบั้ม และอาร์ตเวิร์กด้วย 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' },
]
});
}
เมื่อเล่นเสร็จแล้ว คุณไม่จำเป็นต้อง "ปล่อย" เซสชันสื่อ เนื่องจากการแจ้งเตือนจะหายไปโดยอัตโนมัติ โปรดทราบว่าระบบจะใช้ current
navigator.mediaSession.metadata
เมื่อเริ่มเล่น คุณจึงต้องอัปเดตเพื่อให้แน่ใจว่าคุณแสดงข้อมูลที่เกี่ยวข้องในการแจ้งเตือนสื่ออยู่เสมอ
แทร็กก่อนหน้า / ถัดไป
หากเว็บแอปมีเพลย์ลิสต์ คุณอาจต้องการอนุญาตให้ผู้ใช้ไปยังส่วนต่างๆ ของเพลย์ลิสต์ได้โดยตรงจากการแจ้งเตือนสื่อด้วยไอคอน "แทร็กก่อนหน้า" และ "แทร็กถัดไป"
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();
});
โปรดทราบว่าตัวแฮนเดิลการดําเนินการกับสื่อจะยังคงอยู่ รูปแบบนี้คล้ายกับรูปแบบตัวรับฟังเหตุการณ์มาก ยกเว้นการจัดการเหตุการณ์หมายความว่าเบราว์เซอร์จะหยุดทําลักษณะการทำงานเริ่มต้นและใช้เป็นสัญญาณว่าเว็บแอปของคุณรองรับการดำเนินการกับสื่อ ดังนั้น การควบคุมการดําเนินการของสื่อจะไม่แสดง เว้นแต่คุณจะตั้งค่าตัวแฮนเดิลการดําเนินการที่เหมาะสม
นอกจากนี้ การยกเลิกการตั้งค่าตัวแฮนเดิลการดําเนินการของสื่อทําได้ง่ายๆ เพียงกําหนดให้กับ null
กรอกลับ / กรอไปข้างหน้า
Media Session API ช่วยให้คุณแสดงไอคอนการแจ้งเตือนสื่อ "กรอกลับ" และ "กรอไปข้างหน้า" ได้หากต้องการควบคุมระยะเวลาที่ข้าม
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);
});
เล่น/หยุดชั่วคราว
ไอคอน "เล่น/หยุดชั่วคราว" จะแสดงในการแจ้งเตือนสื่อเสมอ และเบราว์เซอร์จะจัดการเหตุการณ์ที่เกี่ยวข้องโดยอัตโนมัติ หากลักษณะการทำงานเริ่มต้นไม่ทำงานด้วยเหตุผลบางอย่าง คุณจะยังคงจัดการเหตุการณ์สื่อ "เล่น" และ "หยุดชั่วคราว" ได้
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...
});
การแจ้งเตือนในทุกที่
สิ่งที่ยอดเยี่ยมเกี่ยวกับ Media Session API คือถาดการแจ้งเตือนไม่ใช่ที่เดียวที่แสดงข้อมูลเมตาและการควบคุมสื่อ การแจ้งเตือนสื่อจะซิงค์กับอุปกรณ์ที่สวมใส่ได้ที่จับคู่ไว้โดยอัตโนมัติ รวมถึงแสดงบนหน้าจอล็อกด้วย
เล่นแบบออฟไลน์ได้
ฉันเข้าใจแล้วว่าตอนนี้คุณกำลังคิดอะไรอยู่ Service Worker ช่วยคุณได้
จริง แต่อันดับแรกและสำคัญที่สุด คุณต้องตรวจสอบว่ารายการทั้งหมดในรายการตรวจสอบนี้ได้รับการตรวจสอบแล้ว
- ไฟล์สื่อและอาร์ตเวิร์กทั้งหมดจะแสดงด้วยส่วนหัว HTTP
Cache-Control
ที่เหมาะสม ซึ่งจะช่วยให้เบราว์เซอร์แคชและนําทรัพยากรที่ดึงข้อมูลไว้ก่อนหน้านี้มาใช้ซ้ำได้ ดูรายการตรวจสอบการแคช - ตรวจสอบว่าไฟล์สื่อและอาร์ตเวิร์กทั้งหมดแสดงด้วยส่วนหัว HTTP ของ
Allow-Control-Allow-Origin: *
ซึ่งจะช่วยให้เว็บแอปของบุคคลที่สามสามารถดึงข้อมูลและใช้การตอบกลับ HTTP จากเว็บเซิร์ฟเวอร์ของคุณได้
กลยุทธ์การแคช Service Worker
สำหรับไฟล์สื่อ เราขอแนะนำให้ใช้กลยุทธ์ "แคช ในกรณีที่ใช้เครือข่ายไม่ได้" แบบง่ายๆ ตามที่ Jake Archibald แสดงไว้
สำหรับอาร์ตเวิร์ก เราขออธิบายให้เจาะจงมากขึ้นและเลือกแนวทางด้านล่างนี้
- อาร์ตเวิร์ก
If
อยู่ในแคชแล้ว ให้แสดงจากแคช Else
ดึงข้อมูลอาร์ตเวิร์กจากเครือข่าย- ดึงข้อมูล
If
สำเร็จแล้ว เพิ่มอาร์ตเวิร์กเครือข่ายลงในแคชและแสดง Else
แสดงอาร์ตเวิร์กสำรองจากแคช
- ดึงข้อมูล
วิธีนี้จะทำให้การแจ้งเตือนสื่อมีไอคอนอาร์ตเวิร์กที่สวยงามเสมอ แม้ว่าเบราว์เซอร์จะดึงข้อมูลอาร์ตเวิร์กไม่ได้ก็ตาม วิธีใช้มีดังนี้
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 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); });
หมายเหตุการติดตั้งใช้งาน
- Chrome สำหรับ Android จะขอโฟกัสเสียง "แบบเต็ม" เพื่อแสดงการแจ้งเตือนสื่อก็ต่อเมื่อไฟล์สื่อมีระยะเวลาอย่างน้อย 5 วินาที
- อาร์ตเวิร์กการแจ้งเตือนรองรับ URL ของข้อมูลและ URL ของไฟล์กลุ่ม
- หากไม่ได้กำหนดอาร์ตเวิร์กไว้และมีรูปภาพไอคอนขนาดที่ต้องการ ระบบจะใช้รูปภาพไอคอนนั้นในการแจ้งเตือนสื่อ
- ขนาดอาร์ตเวิร์กการแจ้งเตือนใน Chrome สำหรับ Android คือ
512x512
สำหรับอุปกรณ์โลว์เอนด์จะเป็น256x256
- ปิดการแจ้งเตือนสื่อด้วย
audio.src = ''
- เนื่องจาก Web Audio API ไม่ได้ขอ Android Audio Focus ด้วยเหตุผลในอดีต วิธีเดียวที่จะทำให้ใช้งานกับ Media Session API ได้คือการเชื่อมต่อองค์ประกอบ
<audio>
เพื่อเป็นแหล่งที่มาของอินพุตไปยัง Web Audio API เราหวังว่า Web AudioFocus API ที่เสนอจะช่วยปรับปรุงสถานการณ์นี้ในอนาคตอันใกล้ - การเรียกเซสชันสื่อจะส่งผลต่อการแจ้งเตือนสื่อเฉพาะในกรณีที่มาจากเฟรมเดียวกับทรัพยากรสื่อ ดูข้อมูลโค้ดด้านล่าง
<iframe id="iframe">
<audio>...</audio>
</iframe>
<script>
iframe.contentWindow.navigator.mediaSession.metadata = new MediaMetadata({
title: 'Never Gonna Give You Up',
...
});
</script>
การสนับสนุน
ในขณะที่เขียน Chrome สำหรับ Android เป็นแพลตฟอร์มเดียวที่รองรับ Media Session API ดูข้อมูลล่าสุดเกี่ยวกับสถานะการใช้งานเบราว์เซอร์ได้ที่สถานะ Chrome Platform
ตัวอย่างเพลงและการสาธิต
ดูตัวอย่างเซสชันสื่ออย่างเป็นทางการของ Chrome ที่มีผลงานของ Blender Foundation และJan Morgenstern
แหล่งข้อมูล
ข้อกำหนดเซสชันสื่อ: wicg.github.io/mediasession
ปัญหาเกี่ยวกับข้อกำหนด: github.com/WICG/mediasession/issues
ข้อบกพร่องของ Chrome: crbug.com