ウェブ プラットフォームでは、Screen Capture API を使用して、タブ、ウィンドウ、画面を共有できます。ウェブアプリが getDisplayMedia()
を呼び出すと、Chrome はユーザーにタブ、ウィンドウ、画面を MediaStreamTrack
動画としてウェブアプリと共有するよう求めます。
getDisplayMedia()
を使用する多くのウェブアプリでは、キャプチャされたサーフェスの動画プレビューがユーザーに表示されます。たとえば、ビデオ会議アプリでは、この動画をリモート ユーザーにストリーミングしながら、ローカルの HTMLVideoElement
にもレンダリングすることがよくあります。これにより、ローカル ユーザーは共有している内容のプレビューを常に確認できます。HTMLVideoElement
このドキュメントでは、Chrome の新しい Captured Surface Control API について説明します。この API を使用すると、ウェブアプリでキャプチャしたタブをスクロールしたり、キャプチャしたタブのズームレベルを読み書きしたりできます。
Captured Surface Control を使用する理由
すべてのビデオ会議アプリに同じ欠点があります。キャプチャしたタブやウィンドウを操作するには、ユーザーはビデオ会議アプリから離れて、そのサーフェスに切り替える必要があります。これには次のような課題があります。
- ピクチャー イン ピクチャーを使用するか、ビデオ会議タブと共有タブを並べて表示するウィンドウを別々に開かない限り、ユーザーはキャプチャされたアプリとリモート ユーザーのビデオフィードを同時に表示することはできません。小さな画面では、この操作が難しい場合があります。
- ユーザーは、ビデオ会議アプリとキャプチャしたサーフェスを切り替える必要に迫られます。
- ユーザーがビデオ会議アプリから離れている間は、ビデオ会議アプリによって公開されているコントロール(埋め込みチャットアプリ、絵文字リアクション、通話への参加をリクエストしているユーザーに関する通知、マルチメディアとレイアウトのコントロール、その他の便利なビデオ会議機能など)にアクセスできなくなります。
- 発表者は、リモートの参加者に操作権限を委任できません。そのため、リモート ユーザーがプレゼンターにスライドの変更、上下へのスクロール、ズームレベルの調整を依頼するという、よくあるシナリオが発生します。
Captured Surface Control API は、これらの問題に対処します。
キャプチャされたサーフェス コントロールの使用方法
キャプチャしたサーフェス コントロールを正常に使用するには、ブラウザタブを明示的にキャプチャする、キャプチャしたタブをスクロールおよびズームする前にユーザーから権限を取得するなど、いくつかの手順が必要です。
ブラウザタブをキャプチャする
まず、getDisplayMedia()
を使用して共有するサーフェスを選択するようユーザーに促し、その過程で CaptureController
オブジェクトをキャプチャ セッションに関連付けます。このオブジェクトを使用して、キャプチャされたサーフェスを制御する予定です。
const controller = new CaptureController(); const stream = await navigator.mediaDevices.getDisplayMedia({ controller });
次に、キャプチャしたサーフェスのローカル プレビューを <video>
要素の形式で生成します。
const previewTile = document.querySelector('video'); previewTile.srcObject = stream;
ユーザーがウィンドウまたは画面の共有を選択した場合は、現時点では対象外ですが、タブの共有を選択した場合は、続行できる可能性があります。
const [track] = stream.getVideoTracks(); if (track.getSettings().displaySurface !== 'browser') { // Bail out early if the user didn't pick a tab. return; }
権限のプロンプト
特定の CaptureController
オブジェクトで forwardWheel()
、increaseZoomLevel()
、decreaseZoomLevel()
、resetZoomLevel()
のいずれかを初めて呼び出すと、権限プロンプトが表示されます。ユーザーが権限を付与すると、これらのメソッドの呼び出しが許可されます。
ユーザーに権限プロンプトを表示するにはユーザー ジェスチャーが必要なため、アプリは、権限をすでに持っている場合、またはウェブアプリの関連するボタンの click
などのユーザー ジェスチャーに応答する場合にのみ、前述のメソッドを呼び出す必要があります。
スクロール
forwardWheel()
を使用すると、キャプチャ アプリは、キャプチャ アプリ内のソース要素からキャプチャされたタブのビューポートにホイール イベントを転送できます。これらのイベントは、キャプチャされたアプリから見ると、ユーザーの直接的な操作と区別できません。
キャプチャ アプリが "previewTile"
という <video>
要素を使用していると仮定すると、次のコードは、キャプチャされたタブにホイール イベントをリレー送信する方法を示しています。
const previewTile = document.querySelector('video'); try { // Relay the user's action to the captured tab. await controller.forwardWheel(previewTile); } catch (error) { // Inspect the error. // ... }
メソッド forwardWheel()
は、次のいずれかの単一の入力を取ります。
- ホイール イベントがキャプチャされたタブに転送される HTML 要素。
null
。転送を停止する必要があることを示します。
forwardWheel()
の呼び出しが成功すると、以前の呼び出しがオーバーライドされます。
forwardWheel()
によって返される Promise は、次の場合に拒否される可能性があります。
- キャプチャ セッションがまだ開始されていないか、すでに停止している場合。
- ユーザーが関連する権限を付与していない場合。
ズーム
キャプチャされたタブのズームレベルの操作は、次の CaptureController
API サーフェスを通じて行われます。
getSupportedZoomLevels()
このメソッドは、キャプチャされるサーフェス タイプに対してブラウザがサポートするズームレベルのリストを返します。このリストの値は、「デフォルトのズームレベル」を 100% として、それに対する割合で表されます。リストは単調に増加し、値 100 が含まれています。
このメソッドは、サポートされている表示サーフェス タイプに対してのみ呼び出すことができます。現時点では、タブに対してのみ呼び出すことができます。
次の条件が満たされる場合、controller.getSupportedZoomLevels()
が呼び出されることがあります。
controller
はアクティブなキャプチャに関連付けられています。- キャプチャはタブのものです。
それ以外の場合は、エラーが発生します。
このメソッドの呼び出しに "captured-surface-control"
権限は不要です。
zoomLevel
この読み取り専用属性には、キャプチャされたタブの現在のズームレベルが保持されます。これは null 許容属性であり、キャプチャされたサーフェス タイプにズームレベルの有意義な定義がない場合は null
を保持します。現時点では、ズームレベルはタブに対してのみ定義されており、ウィンドウや画面に対しては定義されていません。
キャプチャが終了すると、属性には最後のズームレベルの値が保持されます。
この属性の読み取りに "captured-surface-control"
権限は不要です。
onzoomlevelchange
このイベント ハンドラは、キャプチャされたタブのズームレベルの変更をリッスンするのに役立ちます。これらのイベントは次のいずれかのタイミングで発生します。
- ユーザーがブラウザを操作して、キャプチャしたタブのズームレベルを手動で変更した場合。
- キャプチャ アプリによるズーム設定メソッドの呼び出しに応答して(後述)。
この属性の読み取りに "captured-surface-control"
権限は不要です。
increaseZoomLevel()
、decreaseZoomLevel()
、resetZoomLevel()
これらのメソッドを使用すると、キャプチャされたタブのズームレベルを操作できます。
increaseZoomLevel()
と decreaseZoomLevel()
は、それぞれ getSupportedZoomLevels()
によって返された順序に従って、ズームレベルを次のズームレベルまたは前のズームレベルに変更します。resetZoomLevel()
は値を 100 に設定します。
これらのメソッドを呼び出すには、"captured-surface-control"
権限が必要です。キャプチャ アプリにこの権限がない場合、ユーザーに権限の付与または拒否を求めるメッセージが表示されます。
これらのメソッドはすべて、呼び出しが成功した場合は解決され、それ以外の場合は拒否される Promise を返します。拒否の理由として、次のようなものが考えられます。
- 権限がありません。
- キャプチャが開始される前に呼び出されます。
- キャプチャの終了後に呼び出されます。
- サポートされていないディスプレイ サーフェス タイプのキャプチャに関連付けられた
controller
で呼び出されます。(つまり、タブキャプチャ以外のすべて)。 - 最大値または最小値を超えて増減しようとします。
特に、controller.zoomLevel == controller.getSupportedZoomLevels().at(0)
の場合は decreaseZoomLevel()
の呼び出しを避けること、また .at(-1)
を使用して同様の方法で increaseZoomLevel()
の呼び出しを保護することをおすすめします。
次の例は、キャプチャ アプリから直接、キャプチャしたタブのズームレベルをユーザーが上げられるようにする方法を示しています。
const zoomIncreaseButton = document.getElementById('zoomInButton'); zoomIncreaseButton.addEventListener('click', async (event) => { if (controller.zoomLevel >= controller.getSupportedZoomLevels().at(-1)) { return; } try { await controller.increaseZoomLevel(); } catch (error) { // Inspect the error. // ... } });
次の例は、キャプチャされたタブのズームレベルの変更に対応する方法を示しています。
controller.addEventListener('zoomlevelchange', (event) => { const zoomLevelLabel = document.querySelector('#zoomLevelLabel'); zoomLevelLabel.textContent = `${controller.zoomLevel}%`; });
特徴検出
Captured Surface Control API がサポートされているかどうかを確認するには、次のコードを使用します。
if (!!window.CaptureController?.prototype.forwardWheel) { // CaptureController forwardWheel() is supported. }
increaseZoomLevel
や decreaseZoomLevel
などの他のキャプチャされたサーフェス コントロール API サーフェスを使用することも、それらすべてをチェックすることもできます。
ブラウザ サポート
キャプチャされた Surface Control は、パソコン版 Chrome 136 以降でのみご利用いただけます。
セキュリティとプライバシー
"captured-surface-control"
権限ポリシーを使用すると、キャプチャ アプリと埋め込まれたサードパーティの iframe がキャプチャされたサーフェス コントロールにアクセスする方法を管理できます。セキュリティのトレードオフについては、Captured Surface Control の説明のプライバシーとセキュリティの考慮事項のセクションをご覧ください。
デモ
デモを実行して、Captured Surface Control を試すことができます。
フィードバック
Chrome チームとウェブ標準コミュニティは、キャプチャされたサーフェス制御に関する皆様のご意見をお待ちしています。
デザインについて教えてください
キャプチャしたサーフェス キャプチャについて、想定どおりに動作しない点はありますか?アイデアを実装するために必要なメソッドやプロパティが不足している場合はどうすればよいですか?セキュリティ モデルについてご質問やご意見がある場合は、GitHub リポジトリで仕様に関する問題を提出するか、既存の問題に意見を追加します。
実装に関する問題ですか?
Chrome の実装にバグが見つかりましたか?それとも、実装が仕様と異なるのでしょうか?https://new.crbug.com でバグを報告します。できるだけ詳細な情報と、再現手順を記載してください。