メディアセッション

W3C 作業草案,

この文書の詳細
このバージョン:
https://www.w3.org/TR/2025/WD-mediasession-20250919/
最新公開バージョン:
https://www.w3.org/TR/mediasession/
編集者草案:
https://w3c.github.io/mediasession/
以前のバージョン:
履歴:
https://www.w3.org/standards/history/mediasession/
フィードバック:
GitHub
編集者:
(Google Inc.)
(Apple Inc.)
以前の編集者:
(Google Inc.)
(Google Inc.)
(Google Inc.)
(Opera)
バージョン履歴:
https://github.com/w3c/mediasession/commits

概要

この仕様は、ウェブ開発者がプラットフォームのUI上でカスタマイズされたメディアメタデータを表示したり、利用可能なプラットフォームのメディアコントロールをカスタマイズしたり、キーボードやヘッドセット、リモコンなどのハードウェアキーや、通知領域やモバイルデバイスのロック画面上にあるソフトウェアキーなど、プラットフォームのメディアキーへアクセスできるようにします。

この文書のステータス

このセクションは公開時点での文書のステータスを説明しています。現在のW3C公開文書の一覧や、この技術レポートの最新改訂版は、W3C標準および草案一覧で確認できます。

この仕様へのフィードバックやコメントを歓迎します。 この仕様に関する議論はGitHub Issuesで行うのが望ましいです。あるいは、Media Working Groupのメーリングリストpublic-media-wg@w3.orgアーカイブ)へコメントを送ることもできます。 この草案では、作業グループで今後議論される保留中の課題の一部を強調しています。 これらの課題が有効かどうかを含め、決定はまだなされていません。

この文書はMedia Working Groupによって勧告トラックを用いて作業草案として公開されました。 この文書はW3C勧告となることを意図しています。

作業草案として公開されたことは、W3Cやそのメンバーによる支持を意味するものではありません。

この文書は草案であり、随時更新、置き換え、または廃止される可能性があります。 この文書を進行中の作業以外のものとして引用するのは不適切です。

この文書はW3C特許ポリシーの下で運営されるグループによって作成されました。 W3Cは、グループの成果物に関連して行われた特許開示の公開リストを維持しています。そのページには特許開示の手順も記載されています。ある特定の特許について、必須クレームを含むと信じる実際の知識を持つ者は、W3C特許ポリシー第6節に従いその情報を開示する必要があります。

この文書は2025年8月18日W3Cプロセス文書に従って管理されています。

1. はじめに

このセクションは規範的ではありません。

メディアは今日広く利用されており、Webはメディアコンテンツを消費する主要な手段のひとつです。多くのプラットフォームは通知、メディアコントロールセンター、デバイスのロック画面、ウェアラブルデバイスなど、様々なUI要素上でタイトル、アーティスト、アルバム、アルバムアートなどのメディアメタデータを表示できます。本仕様は、ウェブページがプラットフォームUI上に表示されるメディアメタデータを指定し、プラットフォームUIやメディアキーからのメディアコントロールに応答できるようにすることで、ユーザー体験を向上させることを目的としています。

2. プライバシーの考慮事項

このセクションは規範的ではありません。

この仕様で導入されるAPIは、プライバシーへの影響が非常に低いものです。APIの一部は、ウェブサイトがボタンや他のコントロールを介してユーザーからコマンドを受け取ることを可能にし、時にはユーザーとウェブサイトの間に新たな入力層を導入する場合があります。

2.1. シークレットモード

プライバシー保護のため、シークレットモード時は、ユーザーエージェントはMediaMetadata の情報をシステムと共有する際に注意し、ユーザーに不利益が生じないようにするべきです。この情報を非常に目立つ形で表示することは、シークレットモードで閲覧しているユーザーの意図に反します。利用可能な場合、UI要素はプラットフォームにプライベートとして通知されるべきです。

2.2. メディアセッションアクション

メディアセッションアクションはWebプラットフォームに新たな入力層を公開します。 ユーザーエージェントは、ユーザーのアクションがアクティブなメディアセッションを持つウェブサイトへルーティングされる可能性があることを、ユーザーに認識させるべきです。特に、ヘッドセットやその他のリモートデバイスからのアクションの場合はその傾向が強いです。これらの入力を受け付ける際は、ユーザーエージェントがプラットフォームの慣例に従うことで、ユーザーの理解を促すことが推奨されます。

3. セキュリティの考慮事項

このセクションは規範的ではありません。

この仕様で導入されるAPIは、セキュリティへの影響も非常に低いものです。APIの一部は、ユーザーエージェントが利用できるメタデータをウェブサイトが公開することを可能にします。ユーザーエージェントは当然、このデータを慎重に扱う必要があります。

3.1. ユーザーインターフェースガイドライン

この仕様で導入されるMediaMetadata によって、ウェブサイトは再生中の内容についてより多くの情報を提供できます。ユーザーエージェントはこの情報を、ユーザーエージェント自身やプラットフォーム内のメディア再生に関連するUIで利用することを意図しています。

MediaMetadata はメディア再生の文脈で利用されることが期待されており、なりすましは困難ですが、MediaMetadata にはテキストフィールドや画像フィールドがあるため、悪意のあるウェブサイトが他のウェブサイトの識別情報を偽装しようとする可能性があります。ユーザーエージェントは、メタデータの発信元となるウェブサイトのオリジンを容易に確認できる方法を提供することが推奨されます。

ユーザーエージェントがMediaMetadata に基づいて作成されたUI要素からウェブサイトへ戻る仕組みを提供する場合は、ウェブサイトにそのアクションが気付かれないようにすることが推奨されます。これにより、なりすましの可能性が低くなります。

一般的に、ウェブサイトからの通知表示に関するすべてのセキュリティ上の考慮事項がここにも適用されます。なお、MediaMetadata は通常のWeb通知よりもカスタマイズ性が低いため、なりすましはより困難となります。

4. モデル

4.1. 再生状態

play および pause アクションが正常に機能するために、ユーザーエージェントは閲覧コンテキストアクティブなメディアセッションでメディアを再生しているかどうかを判定できる必要があり、これを推測再生状態と呼びます。推測再生状態を判定する推奨方法は、そのノードドキュメントの閲覧コンテキスト閲覧コンテキストであるメディア要素を監視することです。 閲覧コンテキスト推測再生状態は、 いずれかのメディアが再生可能かつミュートされていない場合は"playing" となり、そうでなければ"paused" となります。その他、WebAudioやプラグイン等の情報も考慮するべきです。

playbackState 属性は、宣言された再生状態閲覧コンテキストから指定します。この状態は推測再生状態と組み合わされて、実際の再生状態が決定され、play およびpause アクションに利用されます。

実際の再生状態 は以下の方法で計算されます:

playbackState 属性は、ページがメディアを一時停止した際に準備ステップを実行したい場合に便利ですが、pause アクションでその準備ステップが中断されることがあります。playbackStateの設定例を参照してください。

アクティブなメディアセッション実際の再生状態が変更された場合、ユーザーエージェントはメディアセッションアクション更新アルゴリズムを実行しなければなりません。

4.2. ルーティング

ユーザーエージェントでは複数のMediaSession オブジェクトが同時に存在する場合があります。なぜなら、複数のタブを開いている場合、各タブにはトップレベルのトラバーサブルや子孫のナビゲーブルが含まれ、各ナビゲーブルMediaSession オブジェクトが存在する可能性があるためです。

ユーザーエージェントはMediaSession オブジェクトのうち最大1つをユーザーに提示する必要があり、これをアクティブなメディアセッションと呼びます。 アクティブなメディアセッションはnullとなる場合もあります。選択はユーザーエージェント次第であり、推奨される基準はユーザー体験の優先です。なお、playbackState 属性はメディアセッションのルーティングには影響しません。これはアクティブなメディアセッションにのみ効力を持ちます。

ユーザーエージェントはオーディオフォーカスを管理することでアクティブなメディアセッションを選択することが推奨されます。タブまたは閲覧コンテキストが現在オーディオを再生中またはユーザーがメディア操作を期待している場合、その状態をオーディオフォーカスがあると言います。AudioFocus APIはこの分野を対象としており、完成次第利用可能です。

アクティブなメディアセッションが変更された場合、ユーザーエージェントはメディアセッションアクション更新アルゴリズムおよびメタデータ更新アルゴリズムを実行しなければなりません。

4.3. メタデータ

アクティブなメディアセッションのメディアメタデータは、プラットフォームの慣例に従ってプラットフォームUIに表示される場合があります。アクティブなメディアセッションが変更された時や、metadataアクティブなメディアセッションに設定した時、ユーザーエージェントはメタデータ更新アルゴリズムを実行しなければなりません。手順は以下の通りです:

  1. アクティブなメディアセッションがnullの場合、プラットフォームに提示しているメディアメタデータを解除し、これらの手順を終了する。
  2. アクティブなメディアセッションmetadata空のメタデータの場合、プラットフォームに提示しているメディアメタデータを解除し、手順を終了する。
  3. プラットフォームに提示するメディアメタデータを、アクティブなメディアセッションmetadata と一致するように更新する。
  4. ユーザーエージェントがアートワーク画像を表示したい場合、画像取得アルゴリズムを実行しなければならない。

画像取得アルゴリズムは以下の通りです:

  1. 他に画像取得アルゴリズムが実行中の場合、既存のアルゴリズム実行インスタンスをキャンセルする。
  2. アクティブなメディアセッションmetadataartwork が空の場合、手順を終了する。
  3. プラットフォームがメディアアートワークの表示をサポートしている場合、metadataartwork からアクティブなメディアセッション優先アートワーク画像を選択する。
  4. 新しいrequestを作成する。このrequestURL優先アートワーク画像srcdestination は "image"、mode は "no-cors"、credentials mode は "include"、 use-URL-credentials flag をセットする。
  5. Fetch requestを実行し、fetchのprocessResponseアルゴリズムとして以下の手順を実行する。
    1. responseをfetchのprocessResponseアルゴリズムに渡されたresponseとする。
    2. responsetype"error"でない場合、 responsebodyを画像としてデコードしようと試みる。
    3. 画像フォーマットがサポートされていれば、プラットフォームUIに表示するアートワークとして画像を使用する。サポートされていなければ画像取得アルゴリズムは失敗し終了する。

画像取得アルゴリズムで画像が取得できない場合、ユーザーエージェントはデフォルト画像をアートワークとして表示するなどのフォールバック動作を行ってもよい。

4.4. アクション

メディアセッションアクションは、ユーザーがMediaSession と対話できるようにページが処理できるアクションです。例えば、ページがいくつかのアクションに対応することで、ユーザーがヘッドセットやその他のリモートデバイスのボタンを押した時にそれらのアクションが発火します。

メディアセッションアクションソースは、メディアセッションアクションを発生させる可能性のあるソースです。このようなソースはプラットフォームや、ユーザーエージェントが作成したUIサーフェスであり得ます。

メディアセッションアクションソースは、オプションでターゲットを持つことができ、これはメディアセッションアクションソースから発生したメディアセッションアクションの受信者となるべきものです。メディアセッションアクションソースターゲットnullの場合、すべてのメディアセッションアクションソースのアクションの受信者はアクティブなメディアセッションとなります。

メディアセッションアクションMediaSessionAction で表され、次のいずれかの値を持つことができます:

  • play: 再生を再開する意図。
  • pause: 現在再生中のメディアを一時停止する意図。
  • seekbackward: 再生時間を短時間(例:数秒)戻す意図。
  • seekforward: 再生時間を短時間(例:数秒)進める意図。
  • previoustrack: 再生に始まりがある場合は最初から再生、またはプレイリストがある場合は前の項目へ移動する意図。
  • nexttrack: プレイリストがある場合は次の項目へ移動する意図。
  • skipad: 現在再生中の広告をスキップする意図。
  • stop: 再生を停止し、必要なら状態をクリアする意図。
  • seekto: 再生時間を特定の時刻へ移動する意図。
  • togglemicrophone: ユーザーのマイクをミュート/ミュート解除する意図。
  • togglecamera: ユーザーのアクティブカメラをオン/オフする意図。
  • togglescreenshare: ユーザーのアクティブ画面共有をオン/オフする意図。
  • hangup: 通話を終了する意図。
  • previousslide: スライドプレゼン時に前のスライドへ戻る意図。
  • nextslide: スライドプレゼン時に次のスライドへ進む意図。
  • enterpictureinpicture: メディアセッションをピクチャインピクチャウィンドウで開く意図。
  • voiceactivity: マイクで音声アクティビティを検出したことをウェブページに通知する意図。

すべてのMediaSessionは、 サポートされるメディアセッションアクションのマップを持ちます。キーはメディアセッションアクション、値はMediaSessionActionHandlerです。

あるMediaSessionに対してactionhandlerパラメータでアクションハンドラー更新アルゴリズムが呼び出された場合、ユーザーエージェントは以下の手順を実行しなければなりません。

  1. handlernullなら、MediaSessionサポートされるメディアセッションアクションからactionを削除し、これらの手順を中断する。
  2. actionMediaSessionサポートされるメディアセッションアクションに追加し、handlerを関連付ける。

サポートされるメディアセッションアクションが変更されたとき、ユーザーエージェントはメディアセッションアクション更新アルゴリズムを実行するべきです。 また、同じイベントループ内で複数のアクションが修正された際にUIのちらつきを避けるため、ユーザーエージェントはタスクをキューしてメディアセッションアクション更新アルゴリズムを実行してもよいです。

ユーザーエージェントがsourceというメディアセッションアクションソースから、actionというメディアセッションアクションが発火された通知を受け取った場合、ユーザーエージェントはタスクをキューし、ユーザーインタラクションタスクソースを使って、以下のメディアセッションアクション処理手順を実行しなければなりません。

  1. sessionsourceターゲットとする。
  2. sessionnullなら、sessionアクティブなメディアセッションに設定する。
  3. sessionnullなら、これらの手順を中断する。
  4. actionssessionサポートされるメディアセッションアクションとする。
  5. actionsactionキーが含まれていなければ、これらの手順を中断する。
  6. handleractionsactionキーに関連付けられているMediaSessionActionHandlerとする。
  7. handlerdetailsパラメータ(MediaSessionActionDetails)で実行する。
  8. sessionに関連する閲覧コンテキスト内でアクティベーション通知手順を実行する。

ユーザーエージェントがヘッドセットのボタン押下など、playpauseの合同コマンドを受け取った場合、タスクをキューし、ユーザーインタラクションタスクソースで以下の手順を実行する。

  1. アクティブなメディアセッションnullなら、この手順を中断する。
  2. actionメディアセッションアクションとする。
  3. アクティブなメディアセッション実際の再生状態playingなら、actionpauseに設定する。
  4. それ以外の場合はactionplayに設定する。
  5. actionメディアセッションアクション処理手順を実行する。

playpauseメディアセッションアクションについて、アクティブなメディアセッションにハンドラが提供されていない場合、ユーザーエージェントがデフォルトハンドラを実装することが推奨されます。

togglemicrophonetogglecameratogglescreensharehangupメディアセッションアクションについても、アクティブなメディアセッションにハンドラが提供されていない場合、ユーザーエージェントがデフォルトハンドラを実装してもよいです。

ユーザーエージェントは、MediaStreamTrackmuted 属性を通じて、マイク・カメラ・画面共有の状態をWebページに公開してもよいです。 その場合、ユーザーエージェントは MediaSessionActionHandler を実行した後、別タスクとして トラックのミュート状態をセットする手順を実行しなければなりません。

voiceactivity アクションソースは常にターゲットを持ち、そのドキュメントは常にlive なマイクMediaStreamTrackを持たなければなりません。 ユーザーエージェントは、MediaSessionActionHandlervoiceactivity に対して、1つ以上のlive MediaStreamTrackを持つマイクから音声活動が検出されたときのみ呼び出さなければなりません。 ユーザーエージェントは、マイクがミュートされておらず、そのマイクに関連するすべてのMediaStreamTrackenabled の場合、音声活動を無視してもよいです。 また、ユーザーエージェントはプライバシーや省電力の観点から、MediaSessionActionHandlervoiceactivity の呼び出し間隔を最小限にすることが推奨されます。

voiceactivity は音声活動の開始のみを示します。例えば、MediaStreamTrack がミュートされている状態でユーザーが話している場合に通知を表示したり、AudioWorklet で音声処理を開始することも可能です。音声活動の終了に対するアクションは定義されていません。 他のアクションがユーザーによって明示的にトリガーされるのに対し、voiceactivity はユーザーエージェントやシステムの音声活動検出アルゴリズムにも依存します。 プライバシーや省電力の理由から、音声活動が終了してすぐに再開された場合、Webページに通知しないこともあります。これは直前のvoiceactivity アクション直後のケースです。

ページは、ユーザーエージェントがサポートされるメディアセッションアクションとして一覧表示し、メディアセッションアクションソースを更新するため、実際にそのアクションを処理できる場合のみMediaSessionActionHandlerを登録するべきです。

メディアセッションアクション更新アルゴリズムが呼び出された場合、ユーザーエージェントは以下の手順を実行しなければなりません。

  1. available actionsメディアセッションアクションの配列にする。
  2. アクティブなメディアセッションがnullの場合、available actionsを空配列にする。
  3. それ以外の場合、available actionsアクティブなメディアセッションサポートされるメディアセッションアクションのキー一覧に設定する。
  4. すべてのメディアセッションアクションソースsourceについて、以下のサブステップを実行する:
    1. オプションで、アクティブなメディアセッションがnullでなければ:
      1. アクティブなメディアセッション実際の再生状態playingなら、playavailable actionsから削除する。
      2. それ以外の場合、pauseavailable actionsから削除する。
    2. sourceがユーザーエージェントが生成したUI要素の場合、利用可能なスペースに比べて多すぎる場合はavailable actionsの要素を一部削除してもよい。
    3. sourceに更新されたavailable actionsのリストを通知する。

4.5. ポジション状態

ユーザーエージェントは、プラットフォームの慣例に応じて、現在の再生位置再生時間 をプラットフォームUIに表示してもよいです。 ポジション状態 は次の要素の組み合わせです:

  • メディアの再生時間(秒単位)。
  • メディアの再生速度(係数)。
  • メディアの最後に報告された再生位置(秒単位)。 これはポジション状態 が作成された時点のメディアの再生位置です。

ポジション状態MediaPositionState で表され、 必ず最後に位置が更新された時刻(秒単位)を保持する必要があります。 これはポジション状態が最後に更新された時刻です。

ポジション状態を判定する推奨方法は、ノードドキュメントの閲覧コンテキストが 閲覧コンテキストであるメディア要素を監視することです。

実際の再生速度は次の方法で算出される係数です:

秒単位の現在の再生位置は次の方法で算出されます:

5. MediaSession インターフェース

[Exposed=Window]
partial interface Navigator {
  [SameObject] readonly attribute MediaSession mediaSession;
};

enum MediaSessionPlaybackState {
  "none",
  "paused",
  "playing"
};

enum MediaSessionAction {
  "play",
  "pause",
  "seekbackward",
  "seekforward",
  "previoustrack",
  "nexttrack",
  "skipad",
  "stop",
  "seekto",
  "togglemicrophone",
  "togglecamera",
  "togglescreenshare",
  "hangup",
  "previousslide",
  "nextslide",
  "enterpictureinpicture",
  "voiceactivity"
};

enum MediaSessionEnterPictureInPictureReason {
  "other",
  "useraction",
  "contentoccluded"
};

callback MediaSessionActionHandler = undefined(MediaSessionActionDetails details);

[Exposed=Window]
interface MediaSession {
  attribute MediaMetadata? metadata;

  attribute MediaSessionPlaybackState playbackState;

  undefined setActionHandler(MediaSessionAction action, MediaSessionActionHandler? handler);

  undefined setPositionState(optional MediaPositionState state = {});

  Promise<undefined> setMicrophoneActive(boolean active);

  Promise<undefined> setCameraActive(boolean active);

  Promise<undefined> setScreenshareActive(boolean active);
};

MediaSession オブジェクトは、あるドキュメントのメディアセッションを表し、ドキュメントが再生やその扱い方に関する情報をユーザーエージェントに伝えることを可能にします。

MediaSession には、metadata オブジェクト(MediaMetadataで表現)を関連付けます。初期値はnullです。

mediaSession 属性は、 MediaSession インスタンスを、Navigator オブジェクトに関連付けて返さなければなりません。

metadata 属性は、 MediaSessionmetadata を反映します。取得時は MediaSessionmetadata を返さなければなりません。設定時は新しい値valueで以下の手順を実行する必要があります:

  1. MediaSessionmetadatanullでない場合は、その media sessionnullに設定する。
  2. MediaSessionmetadatavalueに設定する。
  3. MediaSessionmetadatanullでない場合は、その media sessionを現在のMediaSessionに設定する。
  4. 並行してメタデータ更新アルゴリズムを実行する。

playbackState 属性は、media session宣言された再生状態を表し、セッションがその 閲覧コンテキスト でメディアを再生しているかどうかを宣言します。初期値はnoneです。設定時は、有効な MediaSessionPlaybackState 値ならIDL属性に新しい値を設定しなければなりません。取得時は、最後に設定された有効な値を返す必要があります。 playbackState 属性は、閲覧コンテキストが再生中か一時停止中かを判断するためのヒントです。

playbackState を設定すると、実際の再生状態が変化する可能性があり、 メディアセッションアクション更新アルゴリズムが実行されることがあります。

MediaSessionPlaybackState 列挙型は、 閲覧コンテキストがメディアを再生中かどうかを示すために使われます。値は以下の通りです:

setActionHandler(action, handler) メソッドは、呼び出されるとMediaSessionactionhandlerを使ってアクションハンドラー更新アルゴリズムを実行しなければなりません。

setPositionState(state) メソッドは、 呼び出された時、以下の手順を実行しなければなりません:

setMicrophoneActive(active) メソッドは、 ページが望むマイクキャプチャ状態(例:通話で音声送信していないので「非アクティブ」とみなすなど)をユーザーエージェントに通知します。呼び出すと以下の手順を実行しなければなりません:

  1. documentthis関連グローバルオブジェクト関連付けられたDocumentとする。
  2. captureKindに"microphone"を設定する。
  3. キャプチャ状態更新アルゴリズムdocumentactivecaptureKindで実行した結果を返す。

同様に、setCameraActive(active) メソッドは、ページが望むカメラキャプチャ状態をユーザーエージェントに通知します。呼び出されると以下の手順を実行しなければなりません:

  1. documentthis関連グローバルオブジェクト関連付けられたDocumentとする。
  2. captureKindに"camera"を設定する。
  3. キャプチャ状態更新アルゴリズムdocumentactivecaptureKindで実行した結果を返す。

同様に、setScreenshareActive(active) メソッドは、ページが望む画面共有キャプチャ状態をユーザーエージェントに通知します。呼び出されると以下の手順を実行しなければなりません:

  1. documentthis関連グローバルオブジェクト関連付けられたDocumentとする。
  2. captureKindに"screenshare"を設定する。
  3. キャプチャ状態更新アルゴリズムdocumentactivecaptureKindで実行した結果を返す。

キャプチャ状態更新アルゴリズムは、 documentactivecaptureKindで呼び出された時、以下の手順を実行しなければなりません:

  1. document完全にアクティブでなければ、promiseをInvalidStateErrorで拒否して返す。
  2. activetrueかつdocumentvisibility stateが"visible"でなければ、ユーザーエージェントは promiseを InvalidStateErrorで拒否して返してもよい。
  3. pを新しいpromiseとする。
  4. 並行して、次の手順を実行する:
    1. すべての入力ソース一時停止ポリシーをユーザーエージェントが captureKind型の入力ソースに対してUIで実装している場合はapplyPausePolicytrue、そうでなければfalseとする。
    2. applyPausePolicytrueなら次のサブステップを実行する:
      1. currentlyActive を、ユーザーエージェントが現在 captureKind 型の すべての入力ソースを一時停止している場合は false、それ以外の場合は true とする。
      2. activecurrentlyActive と等しい場合、タスクをキューし、ユーザー操作タスクソースを使って pundefined で解決し、これらの手順を終了する。
      3. activetrue の場合、ユーザーエージェントは進行を待つことができる(例えばユーザーへのプロンプト表示など)。
      4. ユーザーエージェントがキャプチャ状態の更新要求を拒否した場合、タスクをキューし、ユーザー操作タスクソースを使って pNotAllowedError で拒否し、これらの手順を終了する。
    3. ユーザーエージェントのキャプチャ状態UIをcaptureKindactiveに基づき更新する。
    4. タスクをキューし、ユーザーインタラクションタスクソースpundefinedで解決する。
    5. applyPausePolicytrueなら次のサブステップを実行する:
      1. newMutedStateactivefalseならtrue、そうでなければfalseとする。
      2. captureKind型の入力ソースを持つすべてのMediaStreamTrack について、タスクをキューし、ユーザーインタラクションタスクソーストラックのミュート状態を設定する(newMutedState)。
  5. pを返す。

setMicrophoneActive(active)setCameraActive(active) およびsetScreenshareActive(active)メソッドは、ユーザーエージェントの固有のヒューリスティックに基づき拒否されることがあります。特に、ウェブページがマイク・カメラ・画面共有のアクティブ化(ミュート解除)を要求した場合、ユーザーエージェントは一時的なアクティベーションを求めることがあります。また、実際の決定のためにプロンプトなどでユーザー入力を要求する場合もあります。

ユーザーエージェントはメディアセッションアクションのハンドラを呼び出すUIを表示してもよいです。

6. MediaMetadata インターフェース

[Exposed=Window]
interface MediaMetadata {
  constructor(optional MediaMetadataInit init = {});
  attribute DOMString title;
  attribute DOMString artist;
  attribute DOMString album;
  attribute FrozenArray<object> artwork;
  [SameObject] readonly attribute FrozenArray<ChapterInformation> chapterInfo;
};

dictionary MediaMetadataInit {
  DOMString title = "";
  DOMString artist = "";
  DOMString album = "";
  sequence<MediaImage> artwork = [];
  sequence<ChapterInformationInit> chapterInfo = [];
};

MediaMetadata オブジェクトは、MediaSession に関連付けられたメタデータを表し、ユーザーエージェントがカスタマイズされたユーザーインターフェースを提供するために利用できます。

MediaMetadata には、メディアセッションを関連付けることができます。

MediaMetadata には、タイトルアーティストアルバム があり、型はDOMStringです。

MediaMetadata には、アートワーク画像のシーケンスがあり、型はMediaImageです。 また、MediaMetadata には、初期値がundefined 変換済みアートワーク画像が関連付けられます。

MediaMetadata には、 チャプター情報のリストが関連付けられます。

MediaMetadatanullと等しいか、以下のすべての条件を満たす場合、空のメタデータであると言います:

MediaMetadata(init) コンストラクタが呼び出されたとき、以下の手順を実行しなければなりません:

  1. metadataを新しいMediaMetadata オブジェクトとする。
  2. metadatatitleinittitleに設定する。
  3. metadataartistinitartistに設定する。
  4. metadataalbuminitalbumに設定する。
  5. アートワーク変換アルゴリズムinitartworkinputとして実行し、 成功した場合はその結果をmetadataアートワーク画像に設定する。
  6. chaptersChapterInformation型の空のリストとする。
  7. initchapterInfoの各entryについて、 ChapterInformationを作成chaptersに追加する。
  8. metadataチャプター情報chaptersから凍結配列を作成した結果に設定する。
  9. metadataを返す。

アートワーク変換アルゴリズムinputパラメータで呼び出された場合(inputMediaImage型のシーケンス)、ユーザーエージェントは以下の手順を実行しなければなりません:

  1. outputMediaImage型の空のリストとする。
  2. inputMediaImageリスト)の各entryについて、以下の手順を実行する:
    1. imageを新しいMediaImageとする。
    2. baseURLentry settings objectで指定されたAPIのベースURLとする。
    3. Parse entrysrcbaseURLで行い、失敗でなければその値をimagesrcに設定する。失敗なら TypeErrorを投げてこれらの手順を中断する。
    4. imagesizesentrysizesに設定する。
    5. imagetypeentrytypeに設定する。
    6. outputimageを追加する。
  3. outputを結果として返す。

title属性は MediaMetadataタイトルを反映します。取得時は MediaMetadataタイトルを返し、設定時は MediaMetadataタイトルに与えられた値を設定する。

artist属性は MediaMetadataアーティストを反映します。取得時は MediaMetadataアーティストを返し、設定時は MediaMetadataアーティストに与えられた値を設定する。

album属性は MediaMetadataアルバムを反映します。取得時は MediaMetadataアルバムを返し、設定時は MediaMetadataアルバムに与えられた値を設定する。

artwork 属性はMediaMetadataアートワーク画像を反映します。取得時は以下の手順を実行します:

  1. MediaMetadata変換済みアートワーク画像undefinedの場合、以下の手順を実行する:
    1. frozenArtworkをJavaScriptの配列値とする。
    2. MediaMetadataアートワーク画像の各entryについて、以下の手順を実行する:
      1. imageIDLからJavaScriptオブジェクトへの変換結果とする。
      2. SetIntegrityLevel(image, "frozen")を実行し、スクリプトによる偶発的な変更を防ぐ。
      3. frozenArtworkimageを追加する。
    3. SetIntegrityLevel(frozenArtwork, "frozen")を実行する。
    4. MediaMetadata変換済みアートワーク画像frozenArtworkを設定する。
  2. MediaMetadata変換済みアートワーク画像を返す。

設定時は、valueが新しい値として以下の手順を実行する:

  1. convertedArtworkECMAScriptからIDL値への変換valueMediaImage型のシーケンスに変換する。
  2. アートワーク変換アルゴリズムconvertedArtworkで実行し、成功したらその結果をMediaMetadataアートワーク画像に設定する。
  3. MediaMetadata変換済みアートワーク画像undefinedに設定する。

MediaMetadataタイトルアーティストアルバムまたは アートワーク画像が変更された場合、ユーザーエージェントは以下の手順を実行しなければなりません:

  1. インスタンスに関連付けられたメディアセッションがなければ、これらの手順を中断する。
  2. それ以外の場合は、タスクをキューして以下のサブステップを実行する:
    1. インスタンスに関連付けられたメディアセッションがなくなった場合は、これらの手順を中断する。
    2. それ以外の場合は、並行してメタデータ更新アルゴリズムを実行する。

7. ChapterInformation インターフェース

[Exposed=Window]
interface ChapterInformation {
  readonly attribute DOMString title;
  readonly attribute double startTime;
  [SameObject] readonly attribute FrozenArray<MediaImage> artwork;
};

dictionary ChapterInformationInit {
  DOMString title = "";
  double startTime = 0;
  sequence<MediaImage> artwork = [];
};

ChapterInformation オブジェクトは、章ごとのメタデータ(セクションのタイトル、タイムスタンプ、このセクションのスクリーンショット画像データなど)を表し、ユーザーエージェントがカスタマイズされたユーザーインターフェースを提供するために利用できます。

ChapterInformation には、タイトル(DOMString型)が関連付けられます。

ChapterInformation には、 startTime(double型)が関連付けられます。

ChapterInformation には、 アートワーク画像のリストが関連付けられます。

ChapterInformationinitで作成するには、以下の手順を実行します:

  1. chapterInfoを新しいChapterInformation オブジェクトとする。
  2. chapterInfotitleinittitleに設定する。
  3. chapterInfostartTimeinitstartTimeに設定する。 startTimeが負またはdurationより大きい場合、TypeErrorを投げる。
  4. artworkinitartworkを使い アートワーク変換アルゴリズムを実行した結果とする。
  5. chapterInfoアートワーク画像を、 artworkから凍結配列を作成した結果に設定する。
  6. chapterInfoを返す。

title属性は ChapterInformationタイトルを反映します。取得時は ChapterInformationタイトルを返します。

startTime属性は ChapterInformationstartTime(秒単位)を反映します。取得時は ChapterInformationstartTimeを返します。

artwork 属性はChapterInformationアートワーク画像を反映します。取得時は ChapterInformationアートワーク画像を返します。

8. MediaImage 辞書

dictionary MediaImage {
  required USVString src;
  DOMString sizes = "";
  DOMString type = "";
};

MediaImage 辞書のメンバーは、ImageResource ([IMAGE-RESOURCE]) に触発されています。

src 辞書メンバーは、MediaImage オブジェクトのsourceを指定するために使用されます。これはユーザーエージェントが画像データを取得するためのURLです。

sizes 辞書メンバーは、MediaImage オブジェクトのsizesを指定します。 この値はHTML sizes属性の仕様に従い、スペース区切りの一意なトークン集合(ASCII大文字小文字区別なし)で、画像の寸法を表します。 キーワードは "any" とのASCII大文字小文字区別なし一致、または先頭がU+0030(0)でない2つの非負整数をU+0078(x)またはU+0058(X)で区切ったものです。キーワードは生ピクセル単位のアイコンサイズを表します。複数の画像オブジェクトがある場合、ユーザーエージェントは表示状況に最適なアイコンを選択するためにこの値を用いることがあり、不適切なものは無視されます。sizes属性のパース手順はHTML link要素のsizes属性のパース手順に従わなければなりません。

type 辞書メンバーは、MediaImage オブジェクトのMIMEタイプを指定します。これは画像のメディアタイプのヒントであり、ユーザーエージェントがサポートしていないメディアタイプの画像を無視できるようにするための属性です。

9. MediaPositionState 辞書

dictionary MediaPositionState {
  unrestricted double duration;
  double playbackRate;
  double position;
};

MediaPositionState 辞書は、MediaSession に紐付いた現在の再生位置を表し、ユーザーエージェントが再生位置や再生時間を表示するユーザーインターフェースを提供するために利用できます。

duration 辞書メンバーは、再生時間(秒単位)を指定します。常に正値でなければならず、終端のないメディア(ライブ再生など)には正の無限大を使うことができます。

playbackRate 辞書メンバー再生速度を指定します。正値で順再生、負値で逆再生を表すことができます。ゼロにはすべきではありません。

position 辞書メンバーは、最後に報告された再生位置(秒単位)を指定します。常に正値でなければなりません。

10. MediaSessionActionDetails 辞書

dictionary MediaSessionActionDetails {
  required MediaSessionAction action;
  double seekOffset;
  double seekTime;
  boolean fastSeek;
  boolean isActivating;
  MediaSessionEnterPictureInPictureReason enterPictureInPictureReason;
};

MediaSessionActionHandler は、辞書型MediaSessionActionDetailsdetailsパラメータ付きで実行されなければなりません。

action 辞書メンバーは、メディアセッションアクションを指定し、MediaSessionActionHandlerと関連付けられます。

seekOffset 辞書メンバーは、メディアセッションアクションseekbackward またはseekforwardのときに指定できる秒数です。存在すれば必ず正値でなければならず、指定されていない場合はサイト側で適切な時間(例:数秒)を選択します。

メディアセッションアクションseektoの場合:

isActivating 辞書メンバーは、ユーザーエージェントがキャプチャ関連の アクションに対して すべての入力ソースを一時停止 しようとしている場合falseとなり、それ以外の場合はtrueとなります。 この辞書メンバーは、ユーザーエージェントが すべての入力ソースの一時停止 ポリシーを実装しており、かつメディアセッションアクションtogglecameratogglemicrophonetogglescreenshare の場合は必ず存在しなければなりません。

メディアセッションアクションenterpictureinpictureの場合、 enterPictureInPictureReason 辞書メンバーは必須で、UAがこのアクションを発火した理由を表します。

enterPictureInPictureReason は以下の値を持つことができます:

11. Permissions Policy統合

本仕様は、"mediasession"という文字列で識別されるポリシー制御機能を定義します。そのデフォルト許可リスト*です。

ドキュメントのPermissions Policyによって、そのドキュメント内のコンテンツがMediaSession APIを使用できるかどうかが決定されます。ドキュメントで無効化されている場合、ユーザーエージェントはそのドキュメントのメディアセッションをアクティブなメディアセッションとして選択してはなりません。

12.

このセクションは規範的ではありません。

メタデータの設定 metadata:
navigator.mediaSession.metadata = new MediaMetadata({
  title: "Episode Title",
  artist: "Podcast Host",
  album: "Podcast Title",
  artwork: [{src: "podcast.jpg"}],
  chapterInfo: [
    {title: "Chapter 1", startTime: 0, artwork: [{src: "chapter1.jpg"}]},
    {title: "Chapter 2", startTime: 120, artwork: [{src: "chapter2.jpg"}]}
  ]
});

また、メタデータに複数のアートワーク画像を指定することで、ユーザーエージェントが用途や画面に合わせて最適な画像を選択できるようになります(chapterInfoのartworkも同様です):

navigator.mediaSession.metadata = new MediaMetadata({
  title: "Episode Title",
  artist: "Podcast Host",
  album: "Podcast Title",
  artwork: [
    {src: "podcast.jpg", sizes: "128x128", type: "image/jpeg"},
    {src: "podcast_hd.jpg", sizes: "256x256"},
    {src: "podcast_xhd.jpg", sizes: "1024x1024", type: "image/jpeg"},
    {src: "podcast.png", sizes: "128x128", type: "image/png"},
    {src: "podcast_hd.png", sizes: "256x256", type: "image/png"},
    {src: "podcast.ico", sizes: "128x128 256x256", type: "image/x-icon"}
  ],
  chapterInfo: [
    {title: "Chapter 1", startTime: 0, artwork: [
       {src: "chapter1_a.jpg", sizes: "128x128", type: "image/jpeg"},
       {src: "chapter1_b.png", sizes: "256x256", type: "image/png"}
     ]},
    {title: "Chapter 2", startTime: 120, artwork: [
       {src: "chapter2_a.jpg", sizes: "128x128", type: "image/jpeg"},
       {src: "chapter2_b.png", sizes: "256x256", type: "image/png"}
     ]}
  ]
});

例えば、ユーザーエージェントがアイコン画像を使いたい場合、低解像度画面では"podcast.jpg""podcast.png"、高解像度画面では"podcast_hd.jpg""podcast_hd.png"を選択します。ロック画面の背景画像には"podcast_xhd.jpg"が推奨されます。

メタデータの変更 metadata:

プレイリストやオーディオブックの章では、複数のメディア要素が1つのメディアセッションを共有できます。

var audio1 = document.createElement("audio");
audio1.src = "chapter1.mp3";

var audio2 = document.createElement("audio");
audio2.src = "chapter2.mp3";

audio1.play();
audio1.addEventListener("ended", function() {
  audio2.play();
});

セッションは共有されているため、現在再生中の内容に合わせてメタデータを更新する必要があります。

function updateMetadata(event) {
  navigator.mediaSession.metadata = new MediaMetadata({
    title: event.target == audio1 ? "Chapter 1" : "Chapter 2",
    artist: "An Author",
    album: "A Book",
    artwork: [{src: "cover.jpg"}]
  });
}

audio1.addEventListener("play", updateMetadata);
audio2.addEventListener("play", updateMetadata);
メディアセッションアクションの処理 media session actions:
var tracks = ["chapter1.mp3", "chapter2.mp3", "chapter3.mp3"];
var trackId = 0;

var audio = document.createElement("audio");
audio.src = tracks[trackId];

function updatePlayingMedia() {
  audio.src = tracks[trackId];
  // メタデータの更新(省略)
}

navigator.mediaSession.setActionHandler("previoustrack", function() {
  trackId = (trackId + tracks.length - 1) % tracks.length;
  updatePlayingMedia();
});

navigator.mediaSession.setActionHandler("nexttrack", function() {
  trackId = (trackId + 1) % tracks.length;
  updatePlayingMedia();
});

navigator.mediaSession.setActionHandler("seekto", function(details) {
  audio.currentTime = details.seekTime;
});
playbackStateの設定 playbackState:

ページがメディアを一時停止し、iframeでサードパーティ広告を再生する場合、UAはセッションを「再生中でない」とみなす可能性がありますが、ページは広告再生を一時停止して、広告終了後に保留中の再生をキャンセルできるようにしたい場合があります。

var adFrame;
var audio = document.createElement("audio");
audio.src = "foo.mp3";

function resetActionHandlers() {
  navigator.mediaSession.setActionHandler("play", _ => audio.play());
  navigator.mediaSession.setActionHandler("pause", _ => audio.pause());
}

resetActionHandlers();

// このメソッドはページが広告再生を行いたい場合に呼ばれます。
function pauseAudioAndPlayAd() {
  audio.pause();
  navigator.mediaSession.playbackState = "playing";
  setUpAdFrame();
  adFrame.contentWindow.postMessage("play_ad");
  navigator.mediaSession.setActionHandler("pause", pauseAd);
}

function pauseAd() {
  adFrame.contentWindow.postMessage("pause_ad");
  navigator.mediaSession.playbackState = "paused";
  navigator.mediaSession.setActionHandler("play", resumeAd);
}

function resumeAd() {
  adFrame.contentWindow.postMessage("resume_ad");
  navigator.mediaSession.playbackState = "playing";
  navigator.mediaSession.setActionHandler("pause", pauseAd);
}

window.onmessage = function(e) {
  if (e.data === "ad finished") {
    removeAdFrame();
    navigator.mediaSession.playbackState = "none";
    resetActionHandlers();
  }
}

function setUpAdFrame() {
  adFrame = document.createElement("iframe");
  adFrame.src = "https://example.com/ad-iframe.html";
  document.body.appendChild(adFrame);
}

function removeAdFrame() {
  adFrame.remove();
}
position stateの設定 position state:
// メディアがロードされたら、durationをセット
navigator.mediaSession.setPositionState({
  duration: 60
});

// 冒頭からメディア再生開始
navigator.mediaSession.playbackState = "playing";

// 10秒地点から2倍速で再生開始
navigator.mediaSession.setPositionState({
  duration: 60,
  playbackRate: 2,
  position: 10
});

// メディアが一時停止
navigator.mediaSession.playbackState = "paused";

// メディアがリセット
navigator.mediaSession.setPositionState(null);
ビデオ会議アクションの利用
var isMicrophoneActive = false;
var isCameraActive = false;

navigator.mediaSession.setMicrophoneActive(isMicrophoneActive);
navigator.mediaSession.setCameraActive(isCameraActive);

navigator.mediaSession.setActionHandler("togglemicrophone", function() {
  if (isMicrophoneActive) {
    // マイクをミュートする(実装省略)
  } else {
    // マイクをミュート解除する(実装省略)
  }
  isMicrophoneActive = !isMicrophoneActive;
  navigator.mediaSession.setMicrophoneActive(isMicrophoneActive);
});

navigator.mediaSession.setActionHandler("togglecamera", function() {
  if (isCameraActive) {
    // カメラを無効化(実装省略)
  } else {
    // カメラを有効化(実装省略)
  }
  isCameraActive = !isCameraActive;
  navigator.mediaSession.setCameraActive(isCameraActive);
});

navigator.mediaSession.setActionHandler("hangup", function() {
  // 通話終了(実装省略)
});
スライドプレゼンアクションの処理
var currentSlideIndex = 0;

navigator.mediaSession.setActionHandler("previousslide", function() {
  currentSlideIndex--;
  // 現在のスライドをセット(実装省略)
});

navigator.mediaSession.setActionHandler("nextslide", function() {
  currentSlideIndex++;
  // 現在のスライドをセット(実装省略)
});
ピクチャインピクチャの処理
navigator.mediaSession.setActionHandler("enterpictureinpicture", function() {
  remoteVideo.requestPictureInPicture();
});
音声アクティビティの処理
// 音声有効でMediaStream作成
const stream = await navigator.mediaDevices.getUserMedia({audio:true});
const track = stream.getAudioTracks()[0];
navigator.mediaSession.setActionHandler("voiceactivity", function() {
  if (track.muted) {
    // ミュート解除通知を表示。ユーザーが解除許可したらsetMicrophoneActive(true)でミュート解除。
  }
});

謝辞

編集者は、Paul Adenot、Jake Archibald、Tab Atkins、Jonathan Bailey、François Beaufort、Marcos Caceres、Domenic Denicola、Ralph Giles、Anne van Kesteren、Tobie Langel、Michael Mahemoff、Jer Noble、Elliott Sprehn、Chris Wilson、Jörn Zaefferer の技術的議論への参加に感謝します。これらの議論が本仕様の成立を可能にしました。

特に、Philip Jägenstedt と David Vest にはメディアセッションのあらゆる設計面での協力と、初期設計課題の解決における無限とも思える忍耐に感謝します。また、Jer Noble にはiOSのオーディオフォーカスモデルにも適合するモデル構築への協力に、Mounir Lamouri と Anton Vayvod には初期段階での関与、フィードバック、仕様成立への支援に特別な謝意を表します。

適合性

文書の約束事

適合性要件は、記述的な主張とRFC 2119の用語の組み合わせで表現されます。 規範的な部分における “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, “OPTIONAL” というキーワードは、RFC 2119で説明されている通りに解釈されます。 ただし、可読性のため、この仕様書ではこれらの語はすべて大文字では記述されていません。

この仕様書の文章は、明示的に非規範的と記されたセクション、例、注記を除き、すべて規範的です。 [RFC2119]

この仕様書における例は、「例えば」という語で導入されるか、 class="example"のように規範的な文書とは区別して表示されます。例:

これは情報的な例です。

情報的な注記は「注」として始まり、 class="note"のように規範的な文書とは区別して表示されます。例:

注:これは情報的な注記です。

適合するアルゴリズム

アルゴリズムの一部として命令形で記述された要件(例:「先頭の空白文字を取り除く」や「falseを返してこれらの手順を中断する」など)は、 そのアルゴリズムの導入部で使われているキーワード("must"、"should"、"may" など)の意味に従って解釈されます。

アルゴリズムや特定の手順として記述された適合性要件は、最終的な結果が同等であれば、どのような方法で実装しても構いません。 特に、この仕様書で定義されているアルゴリズムは理解しやすさを重視しており、性能を意図したものではありません。 実装者は最適化を推奨します。

索引

本仕様で定義される用語

参照で定義される用語

参考文献

規範的参考文献

[FETCH]
Anne van Kesteren. Fetch Standard. Living Standard. URL: https://fetch.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[MEDIACAPTURE-STREAMS]
Cullen Jennings; et al. Media Capture and Streams. 2025年9月11日. CRD. URL: https://www.w3.org/TR/mediacapture-streams/
[MIMESNIFF]
Gordon P. Hemsley. MIME Sniffing Standard. Living Standard. URL: https://mimesniff.spec.whatwg.org/
[PERMISSIONS-POLICY-1]
Ian Clelland. Permissions Policy. 2025年8月6日. WD. URL: https://www.w3.org/TR/permissions-policy-1/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. 1997年3月. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[URL]
Anne van Kesteren. URL Standard. Living Standard. URL: https://url.spec.whatwg.org/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. Living Standard. URL: https://webidl.spec.whatwg.org/

参考情報文献

[IMAGE-RESOURCE]
Aaron Gustafson; Rayan Kanso; Marcos Caceres. Image Resource. 2021年6月4日. WD. URL: https://www.w3.org/TR/image-resource/
[WEBAUDIO-1.1]
Paul Adenot; Hongchan Choi. Web Audio API 1.1. 2024年11月5日. FPWD. URL: https://www.w3.org/TR/webaudio-1.1/

IDL索引

[Exposed=Window]
partial interface Navigator {
  [SameObject] readonly attribute MediaSession mediaSession;
};

enum MediaSessionPlaybackState {
  "none",
  "paused",
  "playing"
};

enum MediaSessionAction {
  "play",
  "pause",
  "seekbackward",
  "seekforward",
  "previoustrack",
  "nexttrack",
  "skipad",
  "stop",
  "seekto",
  "togglemicrophone",
  "togglecamera",
  "togglescreenshare",
  "hangup",
  "previousslide",
  "nextslide",
  "enterpictureinpicture",
  "voiceactivity"
};

enum MediaSessionEnterPictureInPictureReason {
  "other",
  "useraction",
  "contentoccluded"
};

callback MediaSessionActionHandler = undefined(MediaSessionActionDetails details);

[Exposed=Window]
interface MediaSession {
  attribute MediaMetadata? metadata;

  attribute MediaSessionPlaybackState playbackState;

  undefined setActionHandler(MediaSessionAction action, MediaSessionActionHandler? handler);

  undefined setPositionState(optional MediaPositionState state = {});

  Promise<undefined> setMicrophoneActive(boolean active);

  Promise<undefined> setCameraActive(boolean active);

  Promise<undefined> setScreenshareActive(boolean active);
};

[Exposed=Window]
interface MediaMetadata {
  constructor(optional MediaMetadataInit init = {});
  attribute DOMString title;
  attribute DOMString artist;
  attribute DOMString album;
  attribute FrozenArray<object> artwork;
  [SameObject] readonly attribute FrozenArray<ChapterInformation> chapterInfo;
};

dictionary MediaMetadataInit {
  DOMString title = "";
  DOMString artist = "";
  DOMString album = "";
  sequence<MediaImage> artwork = [];
  sequence<ChapterInformationInit> chapterInfo = [];
};

[Exposed=Window]
interface ChapterInformation {
  readonly attribute DOMString title;
  readonly attribute double startTime;
  [SameObject] readonly attribute FrozenArray<MediaImage> artwork;
};

dictionary ChapterInformationInit {
  DOMString title = "";
  double startTime = 0;
  sequence<MediaImage> artwork = [];
};


dictionary MediaImage {
  required USVString src;
  DOMString sizes = "";
  DOMString type = "";
};

dictionary MediaPositionState {
  unrestricted double duration;
  double playbackRate;
  double position;
};

dictionary MediaSessionActionDetails {
  required MediaSessionAction action;
  double seekOffset;
  double seekTime;
  boolean fastSeek;
  boolean isActivating;
  MediaSessionEnterPictureInPictureReason enterPictureInPictureReason;
};