Mejor uso compartido de pantalla con el enfoque condicional

François Beaufort
François Beaufort

Navegadores compatibles

  • 109
  • 109
  • x
  • x

Origen

La API de Screen Capture le permite al usuario seleccionar una pestaña, ventana o pantalla para capturar como una transmisión de contenido multimedia. Esta transmisión puede grabarse o compartirse con otras personas a través de la red. En esta documentación, se presenta el enfoque condicional, un mecanismo para que las apps web controlen si la pestaña o ventana capturada se enfocará cuando comience la captura, o si la página de captura permanecerá enfocada.

Navegadores compatibles

El enfoque condicional está disponible a partir de Chrome 109.

Información general

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

Considera usar una app web de videoconferencias hipotética. Si lees track.getSettings().displaySurface y, potencialmente, examinas 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 ventana capturada se puede controlar de forma remota, mantén la videoconferencia en primer plano.
  • De lo contrario, enfoca la pestaña o ventana capturada.

En el ejemplo anterior, la aplicación web de videoconferencia retendría el enfoque si compartiera una presentación de diapositivas, lo que permitiría al usuario pasar las diapositivas de forma remota; pero si el usuario eligió compartir un editor de texto, la aplicación web de videoconferencia cambiará de inmediato el enfoque a la pestaña o ventana capturada.

Cómo usar la API de Condition Focus

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

Para decidir si te enfocarás, es posible tener en cuenta el identificador 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 enfocar o no 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() de manera arbitraria muchas veces antes de que se resuelva la promesa o, como máximo, una vez inmediatamente después de que se resuelva. La última invocación anula todas las anteriores.

Más precisamente: - La promesa getDisplayMedia() que se muestra se resuelve en una microtarea. Llamar a setFocusBehavior() después de que se completa la microtarea arroja un error. - Llamar a setFocusBehavior() más de un segundo después de que comienza la captura es no-op.

Es decir, los dos fragmentos siguientes fallarán:

// 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");

Llamar a setFocusBehavior() también arroja los siguientes casos:

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

Ejemplo

Para jugar con el enfoque condicional, ejecuta la demostración en Glitch. Asegúrate de consultar el código fuente.

Detección de funciones

Para comprobar si CaptureController.setFocusBehavior() es compatible, 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 el enfoque condicional.

Cuéntanos sobre el diseño

¿El enfoque condicional tiene algo que no funciona como esperabas? ¿O faltan métodos o propiedades que necesites para implementar tu idea? ¿Tienes alguna pregunta o comentario sobre el modelo de seguridad?

  • Informa un problema de especificaciones en el repositorio de GitHub o agrega tus ideas sobre un problema existente.

¿Tiene 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 tantos detalles como puedas, así como instrucciones sencillas para reproducirlo. Glitch funciona bien para compartir código.

Demostrar apoyo

¿Planeas usar enfoque condicional? Tu asistencia pública ayuda al equipo de Chrome a priorizar funciones y les muestra a otros proveedores de navegadores la importancia de brindar compatibilidad con ellas.

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

Agradecimientos

Imagen hero de Elena Taranenko.

Gracias a Rachel Andrew por revisar este artículo.