Faire défiler et zoomer sur un onglet capturé

François Beaufort
François Beaufort

Le partage d'onglets, de fenêtres et d'écrans est déjà possible sur la plate-forme Web avec l'API Screen Capture. Lorsqu'une application Web appelle getDisplayMedia(), Chrome invite l'utilisateur à partager un onglet, une fenêtre ou un écran avec l'application Web en tant que vidéo MediaStreamTrack.

De nombreuses applications Web qui utilisent getDisplayMedia() affichent un aperçu vidéo de la surface capturée. Par exemple, les applications de visioconférence diffusent souvent cette vidéo en streaming auprès des utilisateurs distants tout en l'affichant sur un HTMLVideoElement local, afin que l'utilisateur local voit constamment un aperçu de ce qu'il partage.

Cette documentation présente la nouvelle API Captured Surface Control (Contrôle de la surface capturée) dans Chrome, qui permet à votre application Web de faire défiler un onglet capturé, ainsi que de lire et d'écrire le niveau de zoom d'un onglet capturé.

Un utilisateur fait défiler et fait un zoom sur un onglet capturé (démo).

Pourquoi utiliser le contrôle de la surface capturée ?

Toutes les applications de visioconférence présentent le même inconvénient. Si l'utilisateur souhaite interagir avec un onglet ou une fenêtre capturés, il doit passer à cette surface, ce qui l'éloigne de l'application de visioconférence. Cela présente certains défis:

  • L'utilisateur ne peut pas voir l'application capturée et les flux vidéo des utilisateurs distants en même temps, sauf s'il utilise la fonctionnalité Picture-in-picture (Mode Picture-in-picture) ou des fenêtres côte à côte distinctes pour l'onglet de la visioconférence et l'onglet partagé. Sur un écran de petite taille, cela peut être difficile.
  • L'utilisateur doit passer de l'application de visioconférence à la surface capturée.
  • L'utilisateur perd l'accès aux commandes exposées par l'application de visioconférence lorsqu'il n'y accède pas (par exemple, une application de chat intégrée, des réactions emoji, des notifications concernant des utilisateurs demandant à rejoindre l'appel, des commandes multimédias et de mise en page, et d'autres fonctionnalités de visioconférence utiles).
  • Le présentateur ne peut pas déléguer le contrôle aux participants à distance. Cela conduit au scénario bien connu où les utilisateurs à distance demandent au présentateur de changer de diapositive, de faire défiler la page vers le haut ou vers le bas, ou d'ajuster le niveau de zoom.

L'API Captured Surface Control résout ces problèmes.

Comment utiliser le contrôle de la surface capturée ?

Pour utiliser le contrôle de la surface capturée, vous devez suivre quelques étapes, par exemple capturer explicitement un onglet de navigateur et obtenir l'autorisation de l'utilisateur avant de pouvoir faire défiler et zoomer sur l'onglet capturé.

Capturer un onglet de navigateur

Commencez par demander à l'utilisateur de choisir une surface à partager à l'aide de getDisplayMedia(), puis associez un objet CaptureController à la session de capture. Nous utiliserons bientôt cet objet pour contrôler la surface capturée.

const controller = new CaptureController();
const stream = await navigator.mediaDevices.getDisplayMedia({ controller });

Ensuite, créez un aperçu local de la surface capturée sous la forme d'un élément <video>:

const previewTile = document.querySelector('video');
previewTile.srcObject = stream;

Si l'utilisateur choisit de partager une fenêtre ou un écran, cela n'entre pas dans le champ d'application pour le moment. En revanche, s'il choisit de partager un onglet, nous pouvons continuer.

const [track] = stream.getVideoTracks();

if (track.getSettings().displaySurface !== 'browser') {
  // Bail out early if the user didn't pick a tab.
  return;
}

Invite d'autorisation

La première invocation de forwardWheel(), increaseZoomLevel(), decreaseZoomLevel() ou resetZoomLevel() sur un objet CaptureController donné génère une invite d'autorisation. Si l'utilisateur accorde l'autorisation, d'autres appels de ces méthodes sont autorisés.

Un geste utilisateur est nécessaire pour afficher une invite d'autorisation à l'utilisateur. Par conséquent, l'application ne doit appeler les méthodes mentionnées ci-dessus que si elle dispose déjà de l'autorisation ou en réponse à un geste utilisateur, tel qu'un click sur un bouton approprié dans l'application Web.

Faire défiler

À l'aide de forwardWheel(), une application de capture peut transférer les événements de la roue à partir d'un élément source dans l'application de capture elle-même vers la fenêtre d'affichage de l'onglet capturé. Pour l'application capturée, ces événements sont indiscernables de l'interaction directe de l'utilisateur.

En supposant que l'application de capture utilise un élément <video> appelé "previewTile", le code suivant montre comment transmettre des événements de défilement à l'onglet capturé:

const previewTile = document.querySelector('video');
try {
  // Relay the user's action to the captured tab.
  await controller.forwardWheel(previewTile);
} catch (error) {
  // Inspect the error.
  // ...
}

La méthode forwardWheel() accepte une seule entrée, qui peut être l'une des suivantes:

  • Élément HTML à partir duquel les événements de la roue seront transférés vers l'onglet capturé.
  • null, ce qui indique que la redirection doit s'arrêter.

Un appel réussi à forwardWheel() remplace les appels précédents.

La promesse renvoyée par forwardWheel() peut être rejetée dans les cas suivants:

  • Si la session de capture n'a pas encore commencé ou s'est déjà arrêtée.
  • Si l'utilisateur n'a pas accordé l'autorisation appropriée.

Zoom

L'interaction avec le niveau de zoom de l'onglet capturé s'effectue via les surfaces d'API CaptureController suivantes:

getSupportedZoomLevels()

Cette méthode renvoie une liste des niveaux de zoom compatibles avec le navigateur pour le type de surface capturé. Les valeurs de cette liste sont exprimées en pourcentage par rapport au "niveau de zoom par défaut", qui est défini sur 100%. La liste est monotone croissante et contient la valeur 100.

Cette méthode ne peut être appelée que pour les types de surfaces d'affichage compatibles, ce qui signifie actuellement uniquement pour les onglets.

controller.getSupportedZoomLevels() peut être appelé si les conditions suivantes sont remplies:

  • controller est associé à une capture active.
  • La capture concerne un onglet.

Sinon, une erreur est générée.

L'autorisation "captured-surface-control" n'est pas requise pour appeler cette méthode.

zoomLevel

Cet attribut en lecture seule contient le niveau de zoom actuel de l'onglet capturé. Il s'agit d'un attribut nullable qui contient null si le type de surface capturé n'a pas de définition pertinente du niveau de zoom. Pour le moment, le niveau de zoom n'est défini que pour les onglets, et non pour les fenêtres ni les écrans.

Une fois la capture terminée, l'attribut contient la dernière valeur de niveau de zoom.

L'autorisation "captured-surface-control" n'est pas requise pour lire cet attribut.

onzoomlevelchange

Ce gestionnaire d'événements facilite l'écoute des modifications apportées au niveau de zoom de l'onglet capturé. Cela se produit dans les cas suivants:

  • Lorsque l'utilisateur interagit avec le navigateur pour modifier manuellement le niveau de zoom de l'onglet capturé.
  • En réponse aux appels de l'application de capture aux méthodes de réglage du zoom (décrites ci-dessous).

L'autorisation "captured-surface-control" n'est pas requise pour lire cet attribut.

increaseZoomLevel(), decreaseZoomLevel() et resetZoomLevel()

Ces méthodes permettent de manipuler le niveau de zoom de l'onglet capturé.

increaseZoomLevel() et decreaseZoomLevel() définissent le niveau de zoom sur le niveau suivant ou précédent, respectivement, conformément à l'ordre renvoyé par getSupportedZoomLevels(). resetZoomLevel() définit la valeur sur 100.

L'autorisation "captured-surface-control" est requise pour appeler ces méthodes. Si l'application de capture ne dispose pas de cette autorisation, l'utilisateur est invité à l'accorder ou à la refuser.

Ces méthodes renvoient toutes une promesse qui est résolue si l'appel aboutit et refusée dans le cas contraire. Voici quelques raisons possibles:

  • Autorisation manquante.
  • Appelé avant le début de la capture.
  • Appelé après la fin de la capture.
  • Appelé sur un controller associé à une capture d'un type de surface d'affichage non compatible. (c'est-à-dire tout sauf la capture d'onglets).
  • Tentatives d'augmentation ou de diminution au-delà de la valeur maximale ou minimale, respectivement.

Il est notamment recommandé d'éviter d'appeler decreaseZoomLevel() si controller.zoomLevel == controller.getSupportedZoomLevels().at(0) et de protéger les appels à increaseZoomLevel() de la même manière avec .at(-1).

L'exemple suivant montre comment permettre à l'utilisateur d'augmenter le niveau de zoom d'un onglet capturé directement depuis l'application de capture:

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

L'exemple suivant montre comment réagir aux changements de niveau de zoom d'un onglet capturé:

controller.addEventListener('zoomlevelchange', (event) => {
  const zoomLevelLabel = document.querySelector('#zoomLevelLabel');
  zoomLevelLabel.textContent = `${controller.zoomLevel}%`;
});

Détection de fonctionnalités

Pour vérifier si les API de contrôle de la surface capturée sont compatibles, utilisez:

if (!!window.CaptureController?.prototype.forwardWheel) {
  // CaptureController forwardWheel() is supported.
}

Vous pouvez également utiliser l'une des autres surfaces de l'API Captured Surface Control, telles que increaseZoomLevel ou decreaseZoomLevel, ou même toutes.

Prise en charge des navigateurs

Le contrôle de la surface capturée est disponible à partir de Chrome 136 sur ordinateur uniquement.

Sécurité et confidentialité

La règle d'autorisation "captured-surface-control" vous permet de gérer l'accès de votre application de capture et des iFrames tierces intégrés au contrôle de la surface capturée. Pour comprendre les compromis de sécurité, consultez la section Considérations sur la confidentialité et la sécurité de la vidéo expliquant le contrôle des surfaces capturées.

Démo

Vous pouvez tester la commande de surface capturée en exécutant la démo sur Glitch. N'oubliez pas de consulter le code source.

Commentaires

L'équipe Chrome et la communauté des normes Web souhaitent connaître votre expérience avec le contrôle de la surface capturée.

Parlez-nous de la conception

La capture de surface capturée ne fonctionne-t-elle pas comme prévu ? Ou manque-t-il des méthodes ou des propriétés dont vous avez besoin pour implémenter votre idée ? Vous avez une question ou un commentaire sur le modèle de sécurité ? Signalez un problème de spécification dans le dépôt GitHub ou ajoutez vos commentaires à un problème existant.

Problème d'implémentation ?

Avez-vous trouvé un bug dans l'implémentation de Chrome ? Ou l'implémentation est-elle différente de la spécification ? Signalez un bug sur https://new.crbug.com. Veillez à inclure autant de détails que possible, ainsi que des instructions pour reproduire le problème. Glitch est idéal pour partager des bugs reproductibles.