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
をアクティブなメディアセッションに設定した時、ユーザーエージェントはメタデータ更新アルゴリズムを実行しなければなりません。手順は以下の通りです:
- アクティブなメディアセッションがnullの場合、プラットフォームに提示しているメディアメタデータを解除し、これらの手順を終了する。
-
アクティブなメディアセッションの
metadata
が空のメタデータの場合、プラットフォームに提示しているメディアメタデータを解除し、手順を終了する。 -
プラットフォームに提示するメディアメタデータを、アクティブなメディアセッションの
metadata
と一致するように更新する。 - ユーザーエージェントがアートワーク画像を表示したい場合、画像取得アルゴリズムを実行しなければならない。
画像取得アルゴリズムは以下の通りです:
- 他に画像取得アルゴリズムが実行中の場合、既存のアルゴリズム実行インスタンスをキャンセルする。
-
アクティブなメディアセッションのmetadataの
artwork
が空の場合、手順を終了する。 -
プラットフォームがメディアアートワークの表示をサポートしている場合、metadataの
artwork
からアクティブなメディアセッションの優先アートワーク画像を選択する。 - 新しいrequestを作成する。このrequestのURLは優先アートワーク画像の
src
、 destination は "image"、mode は "no-cors"、credentials mode は "include"、 use-URL-credentials flag をセットする。 -
Fetch requestを実行し、fetchのprocessResponseアルゴリズムとして以下の手順を実行する。
- responseをfetchのprocessResponseアルゴリズムに渡されたresponseとする。
-
responseのtypeが
"error"
でない場合、 responseのbodyを画像としてデコードしようと試みる。 - 画像フォーマットがサポートされていれば、プラットフォーム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
に対してactionとhandlerパラメータでアクションハンドラー更新アルゴリズムが呼び出された場合、ユーザーエージェントは以下の手順を実行しなければなりません。
-
handlerが
null
なら、MediaSession
のサポートされるメディアセッションアクションからactionを削除し、これらの手順を中断する。 -
actionを
MediaSession
のサポートされるメディアセッションアクションに追加し、handlerを関連付ける。
サポートされるメディアセッションアクションが変更されたとき、ユーザーエージェントはメディアセッションアクション更新アルゴリズムを実行するべきです。 また、同じイベントループ内で複数のアクションが修正された際にUIのちらつきを避けるため、ユーザーエージェントはタスクをキューしてメディアセッションアクション更新アルゴリズムを実行してもよいです。
ユーザーエージェントがsourceというメディアセッションアクションソースから、actionというメディアセッションアクションが発火された通知を受け取った場合、ユーザーエージェントはタスクをキューし、ユーザーインタラクションタスクソースを使って、以下のメディアセッションアクション処理手順を実行しなければなりません。
- sessionをsourceのターゲットとする。
-
sessionが
null
なら、sessionをアクティブなメディアセッションに設定する。 -
sessionが
null
なら、これらの手順を中断する。 - actionsをsessionのサポートされるメディアセッションアクションとする。
- actionsにactionキーが含まれていなければ、これらの手順を中断する。
-
handlerをactionsのactionキーに関連付けられている
MediaSessionActionHandler
とする。 -
handlerをdetailsパラメータ(
MediaSessionActionDetails
)で実行する。 - sessionに関連する閲覧コンテキスト内でアクティベーション通知手順を実行する。
ユーザーエージェントがヘッドセットのボタン押下など、playとpauseの合同コマンドを受け取った場合、タスクをキューし、ユーザーインタラクションタスクソースで以下の手順を実行する。
-
アクティブなメディアセッションが
null
なら、この手順を中断する。 - actionをメディアセッションアクションとする。
- アクティブなメディアセッションの実際の再生状態がplayingなら、actionをpauseに設定する。
- それ以外の場合はactionをplayに設定する。
- actionでメディアセッションアクション処理手順を実行する。
playとpauseのメディアセッションアクションについて、アクティブなメディアセッションにハンドラが提供されていない場合、ユーザーエージェントがデフォルトハンドラを実装することが推奨されます。
togglemicrophone、 togglecamera、 togglescreenshare、 hangup のメディアセッションアクションについても、アクティブなメディアセッションにハンドラが提供されていない場合、ユーザーエージェントがデフォルトハンドラを実装してもよいです。
ユーザーエージェントは、MediaStreamTrack
の
muted
属性を通じて、マイク・カメラ・画面共有の状態をWebページに公開してもよいです。
その場合、ユーザーエージェントは
MediaSessionActionHandler
を実行した後、別タスクとして
トラックのミュート状態をセットする手順を実行しなければなりません。
voiceactivity
アクションソースは常にターゲットを持ち、そのドキュメントは常にlive
なマイクMediaStreamTrack
を持たなければなりません。
ユーザーエージェントは、MediaSessionActionHandler
をvoiceactivity
に対して、1つ以上のlive
MediaStreamTrack
を持つマイクから音声活動が検出されたときのみ呼び出さなければなりません。
ユーザーエージェントは、マイクがミュートされておらず、そのマイクに関連するすべてのMediaStreamTrack
がenabled
の場合、音声活動を無視してもよいです。
また、ユーザーエージェントはプライバシーや省電力の観点から、MediaSessionActionHandler
のvoiceactivity
の呼び出し間隔を最小限にすることが推奨されます。
voiceactivity
は音声活動の開始のみを示します。例えば、MediaStreamTrack
がミュートされている状態でユーザーが話している場合に通知を表示したり、AudioWorklet
で音声処理を開始することも可能です。音声活動の終了に対するアクションは定義されていません。
他のアクションがユーザーによって明示的にトリガーされるのに対し、voiceactivity
はユーザーエージェントやシステムの音声活動検出アルゴリズムにも依存します。
プライバシーや省電力の理由から、音声活動が終了してすぐに再開された場合、Webページに通知しないこともあります。これは直前のvoiceactivity
アクション直後のケースです。
ページは、ユーザーエージェントがサポートされるメディアセッションアクションとして一覧表示し、メディアセッションアクションソースを更新するため、実際にそのアクションを処理できる場合のみMediaSessionActionHandler
を登録するべきです。
メディアセッションアクション更新アルゴリズムが呼び出された場合、ユーザーエージェントは以下の手順を実行しなければなりません。
- available actionsをメディアセッションアクションの配列にする。
- アクティブなメディアセッションがnullの場合、available actionsを空配列にする。
- それ以外の場合、available actionsをアクティブなメディアセッションのサポートされるメディアセッションアクションのキー一覧に設定する。
-
すべてのメディアセッションアクションソースsourceについて、以下のサブステップを実行する:
-
オプションで、アクティブなメディアセッションがnullでなければ:
- アクティブなメディアセッションの実際の再生状態がplayingなら、playをavailable actionsから削除する。
- それ以外の場合、pauseをavailable actionsから削除する。
- sourceがユーザーエージェントが生成したUI要素の場合、利用可能なスペースに比べて多すぎる場合はavailable actionsの要素を一部削除してもよい。
- sourceに更新されたavailable actionsのリストを通知する。
-
オプションで、アクティブなメディアセッションがnullでなければ:
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
属性は、
MediaSession
の
metadata
を反映します。取得時は
MediaSession
の
metadata
を返さなければなりません。設定時は新しい値valueで以下の手順を実行する必要があります:
-
MediaSession
のmetadata
がnull
でない場合は、その media sessionをnull
に設定する。 -
MediaSession
のmetadata
を valueに設定する。 -
MediaSession
のmetadata
がnull
でない場合は、その media sessionを現在のMediaSession
に設定する。 - 並行して、メタデータ更新アルゴリズムを実行する。
playbackState
属性は、media
sessionの宣言された再生状態を表し、セッションがその
閲覧コンテキスト
でメディアを再生しているかどうかを宣言します。初期値はnoneです。設定時は、有効な
MediaSessionPlaybackState
値ならIDL属性に新しい値を設定しなければなりません。取得時は、最後に設定された有効な値を返す必要があります。
playbackState
属性は、閲覧コンテキストが再生中か一時停止中かを判断するためのヒントです。
playbackState
を設定すると、実際の再生状態が変化する可能性があり、
メディアセッションアクション更新アルゴリズムが実行されることがあります。
MediaSessionPlaybackState
列挙型は、
閲覧コンテキストがメディアを再生中かどうかを示すために使われます。値は以下の通りです:
-
none
は、 閲覧コンテキストが再生・一時停止状態を指定しない場合を意味し、playbackState
属性でのみ使えます。 -
playing
は、 閲覧コンテキストが現在メディアを再生中で、一時停止できることを意味します。 -
paused
は、 閲覧コンテキストがメディアを一時停止していて、再開可能なことを意味します。
setActionHandler(action, handler)
メソッドは、呼び出されるとMediaSession
で
actionとhandlerを使ってアクションハンドラー更新アルゴリズムを実行しなければなりません。
setPositionState(state)
メソッドは、
呼び出された時、以下の手順を実行しなければなりません:
- stateが空の辞書なら、ポジション状態をクリアし、これらの手順を中断する。
- stateのduration が存在しなければ、TypeErrorを投げる。
-
stateの
duration
が負またはNaN
なら、TypeErrorを投げる。 -
stateの
position
が存在しなければ、ゼロに設定する。 - stateのposition が負またはdurationより大きければ、 TypeErrorを投げる。
- stateのplaybackRateが存在しなければ、1.0に設定する。
-
stateの
playbackRate
がゼロなら、 TypeErrorを投げる。 - ポジション状態および最後に位置が更新された時刻を更新する。
setMicrophoneActive(active)
メソッドは、
ページが望むマイクキャプチャ状態(例:通話で音声送信していないので「非アクティブ」とみなすなど)をユーザーエージェントに通知します。呼び出すと以下の手順を実行しなければなりません:
- documentをthisの関連グローバルオブジェクトの 関連付けられたDocumentとする。
- captureKindに"microphone"を設定する。
- キャプチャ状態更新アルゴリズムをdocument、active、captureKindで実行した結果を返す。
同様に、setCameraActive(active)
メソッドは、ページが望むカメラキャプチャ状態をユーザーエージェントに通知します。呼び出されると以下の手順を実行しなければなりません:
- documentをthisの関連グローバルオブジェクトの 関連付けられたDocumentとする。
- captureKindに"camera"を設定する。
- キャプチャ状態更新アルゴリズムをdocument、active、captureKindで実行した結果を返す。
同様に、setScreenshareActive(active)
メソッドは、ページが望む画面共有キャプチャ状態をユーザーエージェントに通知します。呼び出されると以下の手順を実行しなければなりません:
- documentをthisの関連グローバルオブジェクトの 関連付けられたDocumentとする。
- captureKindに"screenshare"を設定する。
- キャプチャ状態更新アルゴリズムをdocument、active、captureKindで実行した結果を返す。
キャプチャ状態更新アルゴリズムは、 document、active、captureKindで呼び出された時、以下の手順を実行しなければなりません:
- documentが完全にアクティブでなければ、promiseをInvalidStateErrorで拒否して返す。
-
activeが
true
かつdocumentの visibility stateが"visible"でなければ、ユーザーエージェントは promiseを InvalidStateErrorで拒否して返してもよい。 - pを新しいpromiseとする。
-
並行して、次の手順を実行する:
-
すべての入力ソース一時停止ポリシーをユーザーエージェントが
captureKind型の入力ソースに対してUIで実装している場合はapplyPausePolicyを
true
、そうでなければfalse
とする。 -
applyPausePolicyが
true
なら次のサブステップを実行する:-
currentlyActive を、ユーザーエージェントが現在 captureKind 型の すべての入力ソースを一時停止している場合は
false
、それ以外の場合はtrue
とする。 -
active が currentlyActive と等しい場合、タスクをキューし、ユーザー操作タスクソースを使って p を
undefined
で解決し、これらの手順を終了する。 -
active が
true
の場合、ユーザーエージェントは進行を待つことができる(例えばユーザーへのプロンプト表示など)。 - ユーザーエージェントがキャプチャ状態の更新要求を拒否した場合、タスクをキューし、ユーザー操作タスクソースを使って p を NotAllowedError で拒否し、これらの手順を終了する。
-
currentlyActive を、ユーザーエージェントが現在 captureKind 型の すべての入力ソースを一時停止している場合は
- ユーザーエージェントのキャプチャ状態UIをcaptureKindとactiveに基づき更新する。
-
タスクをキューし、ユーザーインタラクションタスクソースでpを
undefined
で解決する。 -
applyPausePolicyが
true
なら次のサブステップを実行する:-
newMutedStateをactiveが
false
ならtrue
、そうでなければfalse
とする。 -
captureKind型の入力ソースを持つすべての
MediaStreamTrack
について、タスクをキューし、ユーザーインタラクションタスクソースで トラックのミュート状態を設定する(newMutedState)。
-
newMutedStateをactiveが
-
すべての入力ソース一時停止ポリシーをユーザーエージェントが
captureKind型の入力ソースに対してUIで実装している場合はapplyPausePolicyを
- 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
には、
チャプター情報のリストが関連付けられます。
MediaMetadata
がnull
と等しいか、以下のすべての条件を満たす場合、空のメタデータであると言います:
MediaMetadata(init)
コンストラクタが呼び出されたとき、以下の手順を実行しなければなりません:
-
metadataを新しい
MediaMetadata
オブジェクトとする。 -
metadataの
title
をinitのtitle
に設定する。 -
metadataの
artist
をinitのartist
に設定する。 -
metadataの
album
をinitのalbum
に設定する。 -
アートワーク変換アルゴリズムをinitの
artwork
をinputとして実行し、 成功した場合はその結果をmetadataのアートワーク画像に設定する。 -
chaptersを
ChapterInformation
型の空のリストとする。 -
initの
chapterInfo
の各entryについて、 ChapterInformationを作成しchaptersに追加する。 - metadataのチャプター情報をchaptersから凍結配列を作成した結果に設定する。
- metadataを返す。
アートワーク変換アルゴリズムがinputパラメータで呼び出された場合(inputはMediaImage
型のシーケンス)、ユーザーエージェントは以下の手順を実行しなければなりません:
-
outputを
MediaImage
型の空のリストとする。 -
input(
MediaImage
リスト)の各entryについて、以下の手順を実行する:-
imageを新しい
MediaImage
とする。 - baseURLをentry settings objectで指定されたAPIのベースURLとする。
-
Parse entryの
src
をbaseURLで行い、失敗でなければその値をimageのsrc
に設定する。失敗なら TypeErrorを投げてこれらの手順を中断する。 -
imageの
sizes
をentryのsizes
に設定する。 -
imageの
type
をentryのtype
に設定する。 - outputにimageを追加する。
-
imageを新しい
- outputを結果として返す。
title
属性は
MediaMetadata
の
タイトルを反映します。取得時は
MediaMetadata
の
タイトルを返し、設定時は
MediaMetadata
の
タイトルに与えられた値を設定する。
artist
属性は
MediaMetadata
の
アーティストを反映します。取得時は
MediaMetadata
の
アーティストを返し、設定時は
MediaMetadata
の
アーティストに与えられた値を設定する。
album
属性は
MediaMetadata
の
アルバムを反映します。取得時は
MediaMetadata
の
アルバムを返し、設定時は
MediaMetadata
の
アルバムに与えられた値を設定する。
artwork
属性はMediaMetadata
の
アートワーク画像を反映します。取得時は以下の手順を実行します:
-
MediaMetadata
の 変換済みアートワーク画像がundefined
の場合、以下の手順を実行する:- frozenArtworkをJavaScriptの配列値とする。
-
MediaMetadata
の アートワーク画像の各entryについて、以下の手順を実行する:- imageをIDLからJavaScriptオブジェクトへの変換結果とする。
-
SetIntegrityLevel(image,
"
frozen
")を実行し、スクリプトによる偶発的な変更を防ぐ。 - frozenArtworkにimageを追加する。
-
SetIntegrityLevel(frozenArtwork, "
frozen
")を実行する。 -
MediaMetadata
の 変換済みアートワーク画像にfrozenArtworkを設定する。
-
MediaMetadata
の 変換済みアートワーク画像を返す。
設定時は、valueが新しい値として以下の手順を実行する:
-
convertedArtworkをECMAScriptからIDL値への変換でvalueを
MediaImage
型のシーケンスに変換する。 -
アートワーク変換アルゴリズムをconvertedArtworkで実行し、成功したらその結果を
MediaMetadata
の アートワーク画像に設定する。 -
MediaMetadata
の 変換済みアートワーク画像をundefined
に設定する。
MediaMetadata
の
タイトル、
アーティスト、
アルバムまたは
アートワーク画像が変更された場合、ユーザーエージェントは以下の手順を実行しなければなりません:
- インスタンスに関連付けられたメディアセッションがなければ、これらの手順を中断する。
-
それ以外の場合は、タスクをキューして以下のサブステップを実行する:
- インスタンスに関連付けられたメディアセッションがなくなった場合は、これらの手順を中断する。
- それ以外の場合は、並行して、メタデータ更新アルゴリズムを実行する。
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 = 0;
startTime sequence <MediaImage >= []; };
artwork
ChapterInformation
オブジェクトは、章ごとのメタデータ(セクションのタイトル、タイムスタンプ、このセクションのスクリーンショット画像データなど)を表し、ユーザーエージェントがカスタマイズされたユーザーインターフェースを提供するために利用できます。
ChapterInformation
には、タイトル(DOMString型)が関連付けられます。
ChapterInformation
には、
startTime(double型)が関連付けられます。
ChapterInformation
には、
アートワーク画像のリストが関連付けられます。
ChapterInformation
をinitで作成するには、以下の手順を実行します:
-
chapterInfoを新しい
ChapterInformation
オブジェクトとする。 -
chapterInfoの
title
をinitのtitle
に設定する。 -
chapterInfoの
startTime
をinitのstartTime
に設定する。 startTimeが負またはdurationより大きい場合、TypeErrorを投げる。 -
artwork
をinitのartwork
を使い アートワーク変換アルゴリズムを実行した結果とする。 -
chapterInfoのアートワーク画像を、
artwork
から凍結配列を作成した結果に設定する。 - chapterInfoを返す。
title
属性は
ChapterInformation
の
タイトルを反映します。取得時は
ChapterInformation
の
タイトルを返します。
startTime
属性は
ChapterInformation
の
startTime(秒単位)を反映します。取得時は
ChapterInformation
の
startTimeを返します。
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
は、辞書型MediaSessionActionDetails
のdetailsパラメータ付きで実行されなければなりません。
action
辞書メンバーは、メディアセッションアクションを指定し、MediaSessionActionHandler
と関連付けられます。
seekOffset
辞書メンバーは、メディアセッションアクション
がseekbackward
またはseekforward
のときに指定できる秒数です。存在すれば必ず正値でなければならず、指定されていない場合はサイト側で適切な時間(例:数秒)を選択します。
メディアセッションアクションがseekto
の場合:
-
seekTime
辞書メンバーは必須で、再生時間を移動する秒数を指定します。 -
fastSeek
辞書メンバーは指定可能で、actionがシーケンスの一部として複数回呼び出されており、今回がその最後でない場合にtrueとなります。
isActivating
辞書メンバーは、ユーザーエージェントがキャプチャ関連の
アクションに対して
すべての入力ソースを一時停止
しようとしている場合false
となり、それ以外の場合はtrue
となります。
この辞書メンバーは、ユーザーエージェントが
すべての入力ソースの一時停止
ポリシーを実装しており、かつメディアセッションアクションが
togglecamera
、
togglemicrophone
、
togglescreenshare
の場合は必ず存在しなければなりません。
メディアセッションアクションがenterpictureinpicture
の場合、
enterPictureInPictureReason
辞書メンバーは必須で、UAがこのアクションを発火した理由を表します。
enterPictureInPictureReason
は以下の値を持つことができます:
-
other
:ピクチャインピクチャに入る理由が既存の列挙値に当てはまらない場合 -
useraction
:ユーザーがUAのUIでピクチャインピクチャボタンをクリックするなど、明示的な操作を行った場合 -
contentoccluded
:タブ切替やタブの最小化などでページが不可視になったためUAがピクチャインピクチャを要求した場合
11. Permissions Policy統合
本仕様は、"mediasession"という文字列で識別されるポリシー制御機能を定義します。そのデフォルト許可リストは*です。
ドキュメントのPermissions Policyによって、そのドキュメント内のコンテンツがMediaSession APIを使用できるかどうかが決定されます。ドキュメントで無効化されている場合、ユーザーエージェントはそのドキュメントのメディアセッションをアクティブなメディアセッションとして選択してはなりません。
12. 例
このセクションは規範的ではありません。
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"
が推奨されます。
プレイリストやオーディオブックの章では、複数のメディア要素が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);
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
:
ページがメディアを一時停止し、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(); }
// メディアがロードされたら、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 には初期段階での関与、フィードバック、仕様成立への支援に特別な謝意を表します。