Mejor uso compartido de pantalla con el enfoque condicional

Francisco Beaufort
François Beaufort
Elad Alon
Elad Alon

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 multimedia. Puedes grabar o compartir esta transmisión 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 capturadas se enfocará cuando se inicie la captura, o si esta 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: ¿debería pasar a primer plano la superficie capturada o la página de captura debería permanecer enfocada? La respuesta depende del motivo de la llamada a getDisplayMedia(), y, en la superficie, el usuario terminará la selección.

Considera el caso de una app web de videoconferencias hipotética. Si lees track.getSettings().displaySurface y posiblemente examinas el identificador de captura, la app web de videoconferencia puede comprender lo que el usuario eligió compartir. Luego:

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

En el ejemplo anterior, la aplicación web de videoconferencias conservaría el foco si compartiera una presentación, lo que le permitiría al usuario pasar las diapositivas de forma remota; pero si el usuario optara por compartir un editor de texto, la aplicación web de videoconferencia cambiaría inmediatamente el foco a la pestaña o ventana capturadas.

Usa la API de enfoque condicional

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 la pestaña o ventana capturada se enfocará o no. 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");
}

A la hora de decidir si debes enfocarte, puedes 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 debes enfocarte 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 promesa. 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 del inicio de la captura es no-op.

Es decir, los siguientes fragmentos 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 en 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 ventana).

Ejemplo

Puedes ejecutar la demostración en Glitch para jugar con el enfoque condicional. Asegúrate de consultar el código fuente.

Detección de atributos

Para verificar 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 de la Web quieren conocer tu experiencia con el enfoque condicional.

Cuéntanos sobre el diseño

¿Hay algo sobre el enfoque condicional 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 sobre un problema específico 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? ¿La implementación es diferente de la especificación?

  • Informa el error en https://new.crbug.com. Asegúrate de incluir todos los detalles que puedas, además de instrucciones simples para reproducir el contenido. Glitch funciona bien para compartir código.

Demuestra tu apoyo

¿Planeas usar el enfoque condicional? Tu asistencia pública ayuda al equipo de Chrome a priorizar funciones y les muestra a otros proveedores de navegadores lo importante que es brindarles asistencia.

Envía un tweet a @ChromiumDev y cuéntanos dónde y cómo lo estás usando.

Agradecimientos

Hero image de Elena Taranenko.

Agradecemos a Rachel Andrew por revisar este artículo.