Media Session API로 미디어 알림 및 재생 컨트롤 맞춤설정

하드웨어 미디어 키와 통합하고 미디어 알림을 맞춤설정하는 방법 등을 알아봅니다.

프랑수아 보퍼트
프랑수아 보퍼트

사용자에게 브라우저에서 현재 재생 중인 음악을 알려주고 브라우저를 실행한 페이지로 돌아가지 않고도 콘텐츠를 제어할 수 있도록 Media Session API가 도입되었습니다. 이를 통해 웹 개발자는 맞춤 미디어 알림의 메타데이터, 재생, 일시중지, 찾기, 트랙 변경과 같은 미디어 이벤트, 화상 회의 이벤트(마이크/음소거 해제, 카메라 켜기/끄기, 끊기)를 통해 이 환경을 맞춤설정할 수 있습니다. 이러한 맞춤설정은 데스크톱 미디어 허브, 모바일의 미디어 알림, 웨어러블 기기 등 여러 상황에서 사용할 수 있습니다. 이 도움말에서는 이러한 맞춤설정에 대해 설명하겠습니다.

미디어 세션 컨텍스트 스크린샷
데스크톱의 미디어 허브, 모바일의 미디어 알림, 웨어러블 기기

Media Session API 정보

Media Session API는 여러 가지 이점과 기능을 제공합니다.

  • 하드웨어 미디어 키가 지원됩니다.
  • 미디어 알림은 모바일, 데스크톱, 페어링된 웨어러블 기기에 맞춤설정됩니다.
  • 미디어 허브는 데스크톱에서 사용할 수 있습니다.
  • 잠금 화면 미디어 컨트롤은 ChromeOS 및 휴대기기에서 사용할 수 있습니다.
  • PIP 모드 창 컨트롤은 오디오 재생, 화상 회의, 슬라이드 발표에 사용할 수 있습니다.
  • 모바일에서 어시스턴트 통합을 사용할 수 있습니다.

브라우저 지원

  • 73
  • 79
  • 82
  • 15

소스

이에 대한 이해를 돕기 위해 몇 가지 예를 들어보겠습니다.

예 1: 사용자가 키보드의 '다음 트랙' 미디어 키를 누르면 웹 개발자는 브라우저가 포그라운드에 있든 백그라운드에 있든 이 사용자 작업을 처리할 수 있습니다.

예 2: 기기 화면이 잠겨 있는 동안 사용자가 웹에서 팟캐스트를 듣는 경우 사용자는 잠금 화면 미디어 컨트롤에서 '뒤로 탐색' 아이콘을 누를 수 있습니다. 그러면 웹 개발자가 재생 시간을 몇 초 뒤로 이동할 수 있습니다.

예 3: 사용자에게 오디오를 재생하는 탭이 있다면 데스크톱의 미디어 허브에서 재생을 쉽게 중지하여 웹 개발자가 상태를 지울 수 있도록 할 수 있습니다.

예 4: 사용자가 영상 통화 중인 경우 PIP 모드 창에서 '마이크 전환' 컨트롤을 눌러 웹사이트의 마이크 데이터 수신을 중지할 수 있습니다.

이 작업은 모두 MediaSession 인터페이스와 MediaMetadata 인터페이스라는 두 가지 다른 인터페이스를 통해 실행됩니다. 첫 번째 화면에서는 사용자가 재생 중인 항목을 제어할 수 있습니다. 두 번째는 제어해야 할 항목을 MediaSession에 알리는 방법입니다.

아래 이미지는 설명을 위해 이러한 인터페이스가 특정 미디어 컨트롤(이 경우 모바일의 미디어 알림)과 어떤 관련이 있는지 보여줍니다.

미디어 세션 인터페이스 이미지
휴대기기의 미디어 알림 분석

사용자에게 지금 재생 중인 노래 알리기

웹사이트에서 오디오 또는 동영상을 재생하면 사용자에게 자동으로 모바일 알림 표시줄이나 데스크톱의 미디어 허브에 미디어 알림이 표시됩니다. 브라우저는 문서의 제목과 찾을 수 있는 가장 큰 아이콘 이미지를 사용하여 적절한 정보를 표시하기 위해 최선을 다합니다. Media Session API를 사용하면 아래와 같이 제목, 아티스트 이름, 앨범 이름, 아트워크와 같은 풍부한 미디어 메타데이터로 미디어 알림을 맞춤설정할 수 있습니다.

미디어 지속 시간이 5초 이상일 때만 Chrome에서 미디어 알림을 표시하기 위해 '전체' 오디오 포커스를 요청합니다. 이렇게 하면 요란한 소리와 같은 부수적인 소리가 알림을 표시하지 않습니다.

// After media (video or audio) starts playing
await document.querySelector("video").play();

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://via.placeholder.com/96',   sizes: '96x96',   type: 'image/png' },
      { src: 'https://via.placeholder.com/128', sizes: '128x128', type: 'image/png' },
      { src: 'https://via.placeholder.com/192', sizes: '192x192', type: 'image/png' },
      { src: 'https://via.placeholder.com/256', sizes: '256x256', type: 'image/png' },
      { src: 'https://via.placeholder.com/384', sizes: '384x384', type: 'image/png' },
      { src: 'https://via.placeholder.com/512', sizes: '512x512', type: 'image/png' },
    ]
  });

  // TODO: Update playback state.
}

재생이 끝나면 알림이 자동으로 사라지므로 미디어 세션을 '해제'할 필요가 없습니다. 하지만 다음 재생이 시작될 때 navigator.mediaSession.metadata가 사용된다는 점에 유의하세요. 따라서 미디어 재생 소스가 변경될 때 관련 정보가 미디어 알림에 표시되도록 하는 것이 중요합니다.

미디어 메타데이터와 관련하여 몇 가지 주의할 사항이 있습니다.

  • 알림 아트워크 배열은 blob URL과 데이터 URL을 지원합니다.
  • 정의된 아트워크가 없고 적절한 크기의 아이콘 이미지 (<link rel=icon>를 사용하여 지정됨)가 있는 경우 미디어 알림에서 이 이미지를 사용합니다.
  • Android용 Chrome의 알림 아트워크 대상 크기는 512x512입니다. 저사양 기기의 경우에는 256x256입니다.
  • 미디어 HTML 요소의 title 속성은 '지금 재생 중' macOS 위젯에서 사용됩니다.
  • 미디어 리소스가 삽입된 경우 (예: iframe) Media Session API 정보는 삽입된 컨텍스트에서 설정해야 합니다. 아래 스니펫을 참조하세요.
<iframe id="iframe">
  <video>...</video>
</iframe>
<script>
  iframe.contentWindow.navigator.mediaSession.metadata = new MediaMetadata({
    title: 'Never Gonna Give You Up',
    ...
  });
</script>

사용자가 재생 중인 콘텐츠를 제어하도록 허용

미디어 세션 작업은 사용자가 현재 미디어 재생과 상호작용할 때 웹사이트에서 사용자를 위해 처리할 수 있는 작업 (예: '재생' 또는 '일시중지')입니다. 작업은 이벤트와 유사하며 거의 동일하게 작동합니다. 이벤트와 마찬가지로 작업은 적절한 객체(이 경우 MediaSession 인스턴스)에 핸들러를 설정하여 구현됩니다. 일부 작업은 사용자가 헤드셋, 다른 원격 기기, 키보드에서 버튼을 누르거나 미디어 알림과 상호작용할 때 트리거됩니다.

Windows 10의 미디어 알림 스크린샷
Windows 10의 맞춤설정된 미디어 알림

일부 미디어 세션 작업은 지원되지 않을 수 있으므로 설정할 때 try…catch 블록을 사용하는 것이 좋습니다.

const actionHandlers = [
  ['play',          () => { /* ... */ }],
  ['pause',         () => { /* ... */ }],
  ['previoustrack', () => { /* ... */ }],
  ['nexttrack',     () => { /* ... */ }],
  ['stop',          () => { /* ... */ }],
  ['seekbackward',  (details) => { /* ... */ }],
  ['seekforward',   (details) => { /* ... */ }],
  ['seekto',        (details) => { /* ... */ }],
  /* Video conferencing actions */
  ['togglemicrophone', () => { /* ... */ }],
  ['togglecamera',     () => { /* ... */ }],
  ['hangup',           () => { /* ... */ }],
  /* Presenting slides actions */
  ['previousslide', () => { /* ... */ }],
  ['nextslide',     () => { /* ... */ }],
];

for (const [action, handler] of actionHandlers) {
  try {
    navigator.mediaSession.setActionHandler(action, handler);
  } catch (error) {
    console.log(`The media session action "${action}" is not supported yet.`);
  }
}

미디어 세션 작업 핸들러 설정 해제는 null로 설정하기만 하면 됩니다.

try {
  // Unset the "nexttrack" action handler at the end of a playlist.
  navigator.mediaSession.setActionHandler('nexttrack', null);
} catch (error) {
  console.log(`The media session action "nexttrack" is not supported yet.`);
}

설정된 미디어 세션 작업 핸들러는 미디어 재생 시에도 유지됩니다. 이벤트를 처리하면 브라우저가 기본 동작 실행을 중지하고 웹사이트에서 미디어 작업을 지원한다는 신호로 이를 사용한다는 점을 제외하면 이벤트 리스너 패턴과 유사합니다. 따라서 적절한 작업 핸들러가 설정되지 않으면 미디어 작업 컨트롤이 표시되지 않습니다.

macOS Big Sur의 Now Playing 위젯 스크린샷
macOS Big Sur의 Now Playing 위젯

재생 / 일시중지

"play" 작업은 사용자가 미디어 재생을 다시 시작하고 싶다는 것을 나타내고 "pause"는 일시적으로 중단하고 싶다는 의사를 나타냅니다.

'재생/일시중지' 아이콘은 항상 미디어 알림에 표시되며 관련 미디어 이벤트는 브라우저에서 자동으로 처리합니다. 기본 동작을 재정의하려면 아래와 같이 '재생' 및 '일시중지' 미디어 작업을 처리합니다.

브라우저는 예를 들어 검색하거나 로드할 때 웹사이트가 미디어를 재생하지 않는다고 간주할 수 있습니다. 이 경우 웹사이트 UI가 미디어 알림 컨트롤과 동기화된 상태를 유지하도록 navigator.mediaSession.playbackState"playing" 또는 "paused"로 설정하여 이 동작을 재정의합니다.

const video = document.querySelector('video');

navigator.mediaSession.setActionHandler('play', async () => {
  // Resume playback
  await video.play();
});

navigator.mediaSession.setActionHandler('pause', () => {
  // Pause active playback
  video.pause();
});

video.addEventListener('play', () => {
  navigator.mediaSession.playbackState = 'playing';
});

video.addEventListener('pause', () => {
  navigator.mediaSession.playbackState = 'paused';
});

이전 트랙

"previoustrack" 작업은 미디어 재생에 시작이라는 개념이 있으면 사용자가 현재 미디어 재생을 처음부터 시작하거나 미디어 재생에 재생목록 개념이 있다면 재생목록의 이전 항목으로 이동하려고 함을 나타냅니다.

navigator.mediaSession.setActionHandler('previoustrack', () => {
  // Play previous track.
});

다음 트랙

"nexttrack" 작업은 미디어 재생에 재생목록 개념이 있는 경우 사용자가 미디어 재생을 재생목록의 다음 항목으로 이동하려고 함을 나타냅니다.

navigator.mediaSession.setActionHandler('nexttrack', () => {
  // Play next track.
});

중지

"stop" 작업은 사용자가 미디어 재생을 중지하고 적절한 경우 상태를 삭제하고 싶어 함을 나타냅니다.

navigator.mediaSession.setActionHandler('stop', () => {
  // Stop playback and clear state if appropriate.
});

뒤로 / 앞으로 탐색

"seekbackward" 작업은 사용자가 미디어 재생 시간을 짧게 뒤로 이동하려고 함을 나타내고, "seekforward"는 미디어 재생 시간을 짧게 앞당기고자 함을 나타냅니다. 두 경우 모두 짧은 기간은 몇 초를 의미합니다.

작업 핸들러에 제공된 seekOffset 값은 미디어 재생 시간을 이동하는 시간(초)입니다. 값이 제공되지 않은 경우 (예: undefined) 적절한 시간 (예: 10~30초)을 사용해야 합니다.

const video = document.querySelector('video');
const defaultSkipTime = 10; /* Time to skip in seconds by default */

navigator.mediaSession.setActionHandler('seekbackward', (details) => {
  const skipTime = details.seekOffset || defaultSkipTime;
  video.currentTime = Math.max(video.currentTime - skipTime, 0);
  // TODO: Update playback state.
});

navigator.mediaSession.setActionHandler('seekforward', (details) => {
  const skipTime = details.seekOffset || defaultSkipTime;
  video.currentTime = Math.min(video.currentTime + skipTime, video.duration);
  // TODO: Update playback state.
});

특정 시간 탐색

"seekto" 작업은 사용자가 미디어 재생 시간을 특정 시간으로 이동하려고 함을 나타냅니다.

작업 핸들러에 제공된 seekTime 값은 미디어 재생 시간을 이동할 시간(초)입니다.

작업이 시퀀스의 일부로 여러 번 호출되고 이것이 시퀀스의 마지막 호출이 아닌 경우 작업 핸들러에 제공된 fastSeek 불리언이 true입니다.

const video = document.querySelector('video');

navigator.mediaSession.setActionHandler('seekto', (details) => {
  if (details.fastSeek && 'fastSeek' in video) {
    // Only use fast seek if supported.
    video.fastSeek(details.seekTime);
    return;
  }
  video.currentTime = details.seekTime;
  // TODO: Update playback state.
});

재생 위치 설정

알림에서 미디어 재생 위치를 정확하게 표시하는 것은 아래와 같이 적절한 시간에 위치 상태를 설정하는 것만큼 간단합니다. 위치 상태는 미디어 재생 속도, 지속 시간, 현재 시간의 조합입니다.

ChromeOS의 잠금 화면 미디어 컨트롤 스크린샷
ChromeOS의 잠금 화면 미디어 컨트롤

기간은 양수여야 합니다. 위치는 양수여야 하고 기간보다 짧아야 합니다. 재생 속도는 0보다 커야 합니다.

const video = document.querySelector('video');

function updatePositionState() {
  if ('setPositionState' in navigator.mediaSession) {
    navigator.mediaSession.setPositionState({
      duration: video.duration,
      playbackRate: video.playbackRate,
      position: video.currentTime,
    });
  }
}

// When video starts playing, update duration.
await video.play();
updatePositionState();

// When user wants to seek backward, update position.
navigator.mediaSession.setActionHandler('seekbackward', (details) => {
  /* ... */
  updatePositionState();
});

// When user wants to seek forward, update position.
navigator.mediaSession.setActionHandler('seekforward', (details) => {
  /* ... */
  updatePositionState();
});

// When user wants to seek to a specific time, update position.
navigator.mediaSession.setActionHandler('seekto', (details) => {
  /* ... */
  updatePositionState();
});

// When video playback rate changes, update position state.
video.addEventListener('ratechange', (event) => {
  updatePositionState();
});

위치 상태를 재설정하는 것은 null로 설정하기만 하면 됩니다.

// Reset position state when media is reset.
navigator.mediaSession.setPositionState(null);

화상 회의 작업

사용자가 PIP 모드 창에 영상 통화를 하면 브라우저에 마이크 및 카메라 및 전화 끊기 관련 컨트롤이 표시될 수 있습니다. 사용자가 알림을 클릭하면 웹사이트에서 아래의 화상 회의 작업을 통해 요청을 처리합니다. 예를 보려면 화상 회의 샘플을 참고하세요.

PIP 모드 창에 표시된 화상 회의 제어 스크린샷
PIP 모드 창에서 화상 회의 제어 기능

마이크 전환

"togglemicrophone" 작업은 사용자가 마이크를 음소거하거나 음소거 해제하고 싶어 함을 나타냅니다. setMicrophoneActive(isActive) 메서드는 웹사이트에서 현재 마이크가 활성 상태라고 간주하는지 브라우저에 알립니다.

let isMicrophoneActive = false;

navigator.mediaSession.setActionHandler('togglemicrophone', () => {
  if (isMicrophoneActive) {
    // Mute the microphone.
  } else {
    // Unmute the microphone.
  }
  isMicrophoneActive = !isMicrophoneActive;
  navigator.mediaSession.setMicrophoneActive(isMicrophoneActive);
});

카메라 전환

"togglecamera" 작업은 사용자가 활성 카메라를 켜거나 끄려고 함을 나타냅니다. setCameraActive(isActive) 메서드는 브라우저에서 웹사이트를 활성 상태로 간주하는지 여부를 나타냅니다.

let isCameraActive = false;

navigator.mediaSession.setActionHandler('togglecamera', () => {
  if (isCameraActive) {
    // Disable the camera.
  } else {
    // Enable the camera.
  }
  isCameraActive = !isCameraActive;
  navigator.mediaSession.setCameraActive(isCameraActive);
});

전화 끊기

"hangup" 작업은 사용자가 통화를 종료하려고 함을 나타냅니다.

navigator.mediaSession.setActionHandler('hangup', () => {
  // End the call.
});

슬라이드 작업 표시

사용자가 슬라이드를 PIP 모드 창에 넣으면 브라우저에 슬라이드 탐색을 위한 컨트롤이 표시될 수 있습니다. 사용자가 이를 클릭하면 웹사이트에서 Media Session API를 통해 이를 처리합니다. 예는 Slides 발표 샘플을 참고하세요.

이전 슬라이드

"previousslide" 작업은 사용자가 슬라이드를 표시할 때 이전 슬라이드로 돌아가려고 함을 나타냅니다.

navigator.mediaSession.setActionHandler('previousslide', () => {
  // Show previous slide.
});

브라우저 지원

  • 111
  • 111
  • x
  • x

다음 슬라이드

"nextslide" 작업은 사용자가 슬라이드를 표시할 때 다음 슬라이드로 이동하려고 함을 나타냅니다.

navigator.mediaSession.setActionHandler('nextslide', () => {
  // Show next slide.
});

브라우저 지원

  • 111
  • 111
  • x
  • x

샘플

Blender FoundationJan Morgenstern의 작품이 포함된 몇 가지 미디어 세션 샘플을 확인하세요.

Media Session API를 보여주는 스크린캐스트

자료