Mejor uso compartido de pantalla con el enfoque condicional

François Beaufort
François Beaufort

Browser Support

  • Chrome: 109.
  • Edge: 109.
  • Firefox: not supported.
  • Safari: not supported.

Source

La API de Screen Capture permite que el usuario seleccione una pestaña, una ventana o una pantalla para capturar como una transmisión de medios. Luego, esta transmisión se puede grabar o compartir con otras personas a través de la red. En esta documentación, se presenta Conditional Focus, un mecanismo para que las apps web controlen si la pestaña o la ventana capturada se enfocará cuando comience la captura o si la página de captura permanecerá enfocada.

Navegadores compatibles

Conditional Focus está disponible a partir de Chrome 109.

Fondo

Cuando una app web comienza a capturar una pestaña o una ventana, el navegador debe tomar una decisión: ¿se debe llevar la superficie capturada al primer plano o se debe mantener enfocada la página de captura? La respuesta depende del motivo por el que se llama a getDisplayMedia() y de la superficie que el usuario termina seleccionando.

Considera una app web de videoconferencias hipotética. Si lee track.getSettings().displaySurface y, posiblemente, examina el controlador de captura, la app web de videoconferencias puede comprender lo que el usuario eligió compartir. Luego, haz lo siguiente:

  • Si la pestaña o la ventana capturada se pueden controlar de forma remota, mantén la videoconferencia en primer plano.
  • De lo contrario, enfoca la pestaña o la ventana capturada.

En el ejemplo anterior, la app web de videoconferencias conservaría el enfoque si se compartiera una presentación de diapositivas, lo que permitiría al usuario pasar las diapositivas de forma remota. Sin embargo, si el usuario eligiera compartir un editor de texto, la app web de videoconferencias cambiaría de inmediato el enfoque a la pestaña o la ventana capturada.

Cómo usar la API de Conditional Focus

Crea una instancia de CaptureController y pásala a getDisplayMedia(). Si llamas a setFocusBehavior() inmediatamente después de que se resuelva la promesa que muestra getDiplayMedia(), puedes controlar si la pestaña o la ventana capturada se enfocará o no. Esto solo se puede hacer si el usuario compartió una pestaña o una ventana.

const controller = new CaptureController();

// Prompt the user to share a tab, a window or a screen.
const stream =
    await navigator.mediaDevices.getDisplayMedia({ controller });

const [track] = stream.getVideoTracks();
const displaySurface = track.getSettings().displaySurface;
if (displaySurface == "browser") {
  // Focus the captured tab.
  controller.setFocusBehavior("focus-captured-surface");
} else if (displaySurface == "window") {
  // Do not move focus to the captured window.
  // Keep the capturing page focused.
  controller.setFocusBehavior("focus-capturing-application");
}

Cuando decidas si quieres enfocar, es posible que tengas en cuenta el controlador de captura.

// Retain focus if capturing a tab dialed to example.com.
// Focus anything else.
const origin = track.getCaptureHandle().origin;
if (displaySurface == "browser" && origin == "https://example.com") {
  controller.setFocusBehavior("focus-capturing-application");
} else if (displaySurface != "monitor") {
  controller.setFocusBehavior("focus-captured-surface");
}

Incluso es posible decidir si quieres enfocar antes de llamar a getDisplayMedia().

// Focus the captured tab or window when capture starts.
const controller = new CaptureController();
controller.setFocusBehavior("focus-captured-surface");

// Prompt the user to share their screen.
const stream =
    await navigator.mediaDevices.getDisplayMedia({ controller });

Puedes llamar a setFocusBehavior() tantas veces como quieras antes de que se resuelva la promesa o, como máximo, una vez inmediatamente después de que se resuelva la promesa. La última invocación anula todas las invocaciones anteriores.

Más precisamente:

  • La promesa que muestra getDisplayMedia() se resuelve en una microtarea. Si llamas a setFocusBehavior() después de que se complete esa microtarea, se arroja un error.
  • Si llamas a setFocusBehavior() más de un segundo después de que comience la captura, no se realiza ninguna operación.

Es decir, fallarán ambos fragmentos siguientes:

// Prompt the user to share their screen.
const stream =
    await navigator.mediaDevices.getDisplayMedia({ controller });

// Too late, because it follows the completion of the task
// on which the getDisplayMedia() promise resolved.
// This will throw.
setTimeout(() => {
  controller.setFocusBehavior("focus-captured-surface");
});
// Prompt the user to share their screen.
const stream =
    await navigator.mediaDevices.getDisplayMedia({ controller });

const start = new Date();
while (new Date() - start <= 1000) {
  // Idle for ≈1s.
}

// Because too much time has elapsed, the browser will have
// already decided whether to focus.
// This fails silently.
controller.setFocusBehavior("focus-captured-surface");

Si llamas a setFocusBehavior(), también se arroja un error en los siguientes casos:

  • La pista de video de la transmisión que muestra getDisplayMedia() no está "en vivo".
  • Después de que se resuelva la promesa que muestra getDisplayMedia(), si el usuario compartió una pantalla (no una pestaña ni una ventana).

Muestra

Puedes jugar con Conditional Focus ejecutando la demostración.

Detección de funciones

Para verificar si se admite CaptureController.setFocusBehavior(), usa lo siguiente:

if (
  "CaptureController" in window &&
  "setFocusBehavior" in CaptureController.prototype
) {
  // CaptureController.setFocusBehavior() is supported.
}

Comentarios

El equipo de Chrome y la comunidad de estándares web quieren conocer tus experiencias con Conditional Focus.

Cuéntanos sobre el diseño

¿Hay algo sobre Conditional Focus que no funciona como esperabas? ¿O faltan métodos o propiedades que necesitas para implementar tu idea? ¿Tienes alguna pregunta o comentario sobre el modelo de seguridad?

  • Informa un problema de especificación en el repositorio de GitHub o agrega tus ideas a un problema existente.

¿Tienes problemas con la implementación?

¿Encontraste un error en la implementación de Chrome? ¿O la implementación es diferente de la especificación?

  • Informa un error en https://new.crbug.com. Asegúrate de incluir la mayor cantidad de detalles posible y las instrucciones para reproducirlo.

Expresar apoyo

¿Planeas usar Conditional Focus? Tu apoyo público ayuda al equipo de Chrome a priorizar funciones y muestra a otros proveedores de navegadores lo fundamental que es admitirlas.

Envía un tweet a @ChromiumDev y cuéntanos dónde y cómo lo usas.

Agradecimientos

Gracias a Rachel Andrew por revisar este documento.