Medya bildirimlerini özelleştirin ve oynatma listelerini yönetin

François Beaufort
François Beaufort

Yepyeni Media Session API ile artık web uygulamanızın oynattığı medya için meta veri sağlayarak medya bildirimlerini özelleştirebilirsiniz. Ayrıca, arama yapma veya bildirimlerden ya da medya tuşlarından gelmiş olabilecek değişiklikleri takip etme gibi medyayla ilgili etkinlikleri yönetmenize de olanak tanır. Heyecanlandınız mı? Resmi Medya Oturumu örneklerini deneyin.

Media Session API, Chrome 57'de (Şubat 2017'de beta, Mart 2017'de kararlı durumda) desteklenmektedir.

Medya Oturumu Özetleri;
Fotoğraf , Michael Alø-Nielsen / CC BY 2.0

İstediğimi ver

Media Session API'yi zaten biliyorsunuz ve mahcup olmazsanız standart kodları kopyalayıp yapıştırmak için geri mi geliyorsunuz? İşte burada.

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() {});
}

Kodu inceleyin

Hadi oynayalım 🎷

Web sayfanıza basit bir <audio> öğesi ekleyin ve tarayıcının en uygun olanı seçebilmesi için birkaç medya kaynağı atayın.

<audio controls>
    <source src="audio.mp3" type="audio/mp3"/>
    <source src="audio.ogg" type="audio/ogg"/>
</audio>

Bildiğiniz gibi autoplay, Android için Chrome'da ses öğeleri için devre dışı bırakılmıştır. Bu, ses öğesinin play() yöntemini kullanmak zorunda olduğumuz anlamına gelir. Bu yöntem, dokunma veya fare tıklaması gibi bir kullanıcı hareketi ile tetiklenmelidir. Yani pointerup, click ve touchend etkinliklerinin dinlenmesi gerekir. Diğer bir deyişle, web uygulamanızın gürültü çıkarması için önce kullanıcının bir düğmeyi tıklaması gerekir.

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

İlk etkileşimden hemen sonra ses çalmak istemiyorsanız ses öğesinin load() yöntemini kullanmanızı öneririz. Bu, tarayıcının, kullanıcının öğeyle etkileşimde bulunup bulunmadığını takip etmesinin bir yoludur. İçerik zaten yüklenmiş olacağından, bu işlemin oynatmanın sorunsuz şekilde ilerlemesine de yardımcı olabileceğini unutmayın.

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

Bildirimi özelleştirme

Web uygulamanız ses çalarken, bildirim tepsisinde duran bir medya bildirimi görebilirsiniz. Android'de Chrome, dokümanın başlığını ve bulunabileceği en büyük simge resmini kullanarak uygun bilgileri göstermek için elinden geleni yapar.

Medya oturumu olmadan
Medya oturumu olmadan
Medya oturumunda
Medya oturumuyla

Meta veriyi ayarla

Medya Oturumu API'sı ile başlık, sanatçı, albüm adı ve poster gibi bazı medya oturumu meta verilerini ayarlayarak bu medya bildirimini nasıl özelleştireceğimize bakalım.

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

Oynatma tamamlandığında bildirim otomatik olarak kaybolacağı için medya oturumunu "bırakmanız" gerekmez. Herhangi bir oynatma başladığında mevcut navigator.mediaSession.metadata kullanılacağını unutmayın. Bu nedenle, medya bildiriminde her zaman alakalı bilgiler gösterdiğinizden emin olmak için bildirimi güncellemeniz gerekir.

Önceki parça / sonraki parça

Web uygulamanız bir şarkı listesi sağlıyorsa kullanıcının bazı "Önceki Parça" ve "Sonraki Parça" simgeleriyle, doğrudan medya bildiriminden oynatma listenizde gezinmesine izin vermek isteyebilirsiniz.

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

Medya işlemi işleyicilerin kullanılmaya devam edeceğini unutmayın. Bu, etkinlik işleyici kalıbına çok benzer. Tek fark, bir etkinliğin işlenmesinin, tarayıcının herhangi bir varsayılan davranışı yapmayı durdurması ve bunu web uygulamanızın medya işlemini desteklediğine dair bir sinyal olarak kullanması anlamına gelir. Bu nedenle, doğru işlem işleyiciyi ayarlamadığınız sürece medya işlemi kontrolleri gösterilmez.

Bu arada, bir medya işlemi işleyicinin ayarını kaldırmak onu null adlı kullanıcıya atamak kadar kolay.

Geri sar / ileri sar

Media Session API'si, atlanan süreyi kontrol etmek istiyorsanız "Geri sar" ve "İleriye sar" medya bildirimi simgelerini göstermenize olanak tanır.

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

Oynatma / duraklatma

"Oynat/Duraklat" simgesi medya bildiriminde her zaman gösterilir ve ilgili etkinlikler tarayıcı tarafından otomatik olarak işlenir. Herhangi bir nedenle varsayılan davranış işe yaramazsa "Oynat" ve "Duraklat" medya etkinliklerini yine de işleyebilirsiniz.

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

Bildirimler her yerde

Media Session API'nin güzel yanı, bildirim tepsisinin medya meta verilerinin ve kontrollerinin görülebildiği tek yer olmamasıdır. Medya bildirimleri, eşlenmiş herhangi bir giyilebilir cihazla otomatik olarak senkronize edilir. Ayrıca kilit ekranlarında da görünür.

Kilit Ekranı
Kilit Ekranı - Fotoğraf , Michael Alø-Nielsen tarafından / CC BY 2.0
Wear Bildirimi
Wear Bildirimi

İnternete bağlı değilken güzel içerikler oynatın

Şu anda ne düşündüğünüzü biliyorum. Hizmet çalışanı yardım alın!

Doğru ancak her şeyden önce bu kontrol listesindeki tüm öğelerin işaretlendiğinden emin olmanız gerekir:

  • Tüm medya ve çizim dosyaları uygun Cache-Control HTTP üst bilgisiyle sunulur. Bu, tarayıcının önceden getirilen kaynakları önbelleğe alıp yeniden kullanmasına olanak tanır. Önbelleğe alma kontrol listesine bakın.
  • Tüm medya ve çizim dosyalarının Allow-Control-Allow-Origin: * HTTP başlığıyla yayınlandığından emin olun. Böylece üçüncü taraf web uygulamaları, web sunucunuzdaki HTTP yanıtlarını alıp tüketebilir.

Service Worker önbelleğe alma stratejisi

Medya dosyalarıyla ilgili olarak, Jake Archibald tarafından gösterildiği gibi basit bir "Önbellek, ağa geri dönme" stratejisini öneririm.

Ancak poster konusunda biraz daha spesifik olabilirim ve aşağıdaki yaklaşımı seçebilirim:

  • If posteri zaten önbellekte. Önbellekten yayınlayın
  • Else ağdan poster getir
    • If getirme işlemi başarılı oldu, önbelleğe ağ posterini ekleyip yayınlayın
    • Else, önbellekteki yedek posteri yayınla

Bu sayede, tarayıcı bunları alamasa bile medya bildirimlerinde her zaman güzel bir çizim simgesi olur. Bunu şu şekilde uygulayabilirsiniz:

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

Kullanıcının önbelleği kontrol etmesine izin ver

Kullanıcı, web uygulamanızdaki içeriği tükettiğinden medya ve çizim dosyaları cihazında çok fazla yer kaplayabilir. Önbelleğin ne kadar kullanıldığını göstermek ve kullanıcılara önbelleği temizleme olanağı sunmak sizin sorumluluğunuzdadır. Neyse ki bu işlemi Cache API ile yapmak oldukça kolay.

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

Uygulama notları

  • Android için Chrome, medya bildirimlerini yalnızca medya dosyası süresi en az 5 saniye olduğunda göstermek için "tam" ses odağı isteğinde bulunur.
  • Bildirim posteri, blob URL'lerini ve veri URL'lerini destekler.
  • Poster tanımlanmamışsa ve istediğiniz boyutta bir simge resmi varsa medya bildirimleri bunu kullanır.
  • Android için Chrome'da bildirim çizimi boyutu: 512x512. Düşük teknolojili cihazlar için bu değer 256x256.
  • audio.src = '' ile medya bildirimlerini kapatabilirsiniz.
  • Web Audio API, Android Ses Odaklama özelliğini geçmiş nedenlerle istemediğinden Media Session API ile çalışmasının tek yolu Web Audio API'sına giriş kaynağı olarak bir <audio> öğesi bağlamaktır. Teklif edilen Web AudioFocus API'nin yakın gelecekte durumu iyileştireceğini umuyoruz.
  • Medya Oturumu çağrıları, yalnızca medya kaynağıyla aynı çerçeveden gelen medya bildirimlerini etkiler. Aşağıdaki snippet'i inceleyin.
<iframe id="iframe">
  <audio>...</audio>
</iframe>
<script>
  iframe.contentWindow.navigator.mediaSession.metadata = new MediaMetadata({
    title: 'Never Gonna Give You Up',
    ...
  });
</script>

Destek

Bu yazının yazıldığı sırada, Media Session API'yi destekleyen tek platform Android için Chrome'dur. Tarayıcı uygulama durumu hakkında daha güncel bilgileri Chrome Platform Durumu bölümünde bulabilirsiniz.

Örnekler ve demolar

Blender Foundation ve Jan Morgenstern'ın çalışmalarının yer aldığı resmi Chrome Medya Oturumu örneklerimize göz atın.

Kaynaklar

Medya Oturumu Özellikleri: wicg.github.io/mediasession

Teknik Özelliklerle İlgili Sorunlar: github.com/WICG/mediasession/issues

Chrome Hataları: crbug.com