La API de Captura de pantalla permite que el usuario seleccione una pestaña, una ventana o una pantalla para capturarla como transmisión de contenido multimedia. Luego, se puede grabar o compartir 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 estará enfocada 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.
Segundo plano
Cuando una app web comienza a capturar una pestaña o una ventana, el navegador debe tomar una decisión: ¿debe colocarse en primer plano la superficie capturada o debe permanecer enfocada la página de captura? La respuesta depende del motivo por el que se llama a getDisplayMedia()
y de la plataforma que el usuario termina seleccionando.
Considera una app web de videoconferencia hipotética. Cuando lee track.getSettings().displaySurface
y, posiblemente, examina el Control de captura, la app web de videoconferencia puede comprender lo que el usuario eligió compartir. Luego:
- Si la pestaña o ventana capturada se puede controlar de forma remota, mantén la videoconferencia en foco.
- De lo contrario, enfoca la pestaña o ventana capturada.
En el ejemplo anterior, la app web de videoconferencia retendría el enfoque si se comparte una presentación de diapositivas, lo que le permite al usuario pasar las diapositivas de forma remota. Sin embargo, si el usuario elige compartir un editor de texto, la app web de videoconferencia cambiará inmediatamente el enfoque a la pestaña o 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 se enfocará o no la pestaña o ventana capturada. 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 enfocar o no, puedes tener en cuenta el control 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 enfocarse 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 forma 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 anulació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 completa esa microtarea, se muestra un error.
- Llamar a setFocusBehavior()
más de un segundo después de que comienza la captura no realiza ninguna acción.
Es decir, fallarán los siguientes fragmentos:
// 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");
Las llamadas a setFocusBehavior()
también arrojan errores en los siguientes casos:
- la pista de video de la transmisión que muestra
getDisplayMedia()
no es "en vivo". - después de que se resuelva la promesa que devuelve
getDisplayMedia()
, si el usuario compartió una pantalla (no una pestaña ni una ventana).
Muestra
Para experimentar con el enfoque condicional, ejecuta la demo en Glitch. 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 web quieren conocer tus experiencias con el enfoque condicional.
Cuéntanos sobre el diseño
¿Hay algo en 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 un problema de especificación en el repositorio de GitHub o agrega tus comentarios 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 tantos detalles como sea posible y de proporcionar instrucciones sencillas para reproducirlo. Glitch funciona bien para compartir código.
Expresar apoyo
¿Planeas usar el enfoque condicional? Tu apoyo público ayuda al equipo de Chrome a priorizar las funciones y les muestra a otros proveedores de navegadores lo importante que es admitirlas.
Envía un tuit a @ChromiumDev y cuéntanos dónde y cómo lo usas.
Vínculos útiles
Agradecimientos
Imagen hero de Elena Taranenko.
Gracias a Rachel Andrew por revisar este artículo.