Ya es posible compartir pestañas, ventanas y pantallas en la plataforma web con la API de Screen Capture. Cuando una app web llama a getDisplayMedia()
, Chrome le solicita al usuario que comparta una pestaña, una ventana o una pantalla con la app web como un video MediaStreamTrack
.
Muchas apps web que usan getDisplayMedia()
le muestran al usuario una vista previa en video de la superficie capturada. Por ejemplo, las apps de videoconferencias suelen transmitir este video a usuarios remotos y, al mismo tiempo, renderizarlo en un HTMLVideoElement
local para que el usuario local vea constantemente una vista previa de lo que comparte.
En esta documentación, se presenta la nueva API de Captured Surface Control en Chrome, que permite que tu app web desplace una pestaña capturada, así como leer y escribir el nivel de zoom de una pestaña capturada.
¿Por qué usar el control de superficie capturada?
Todas las apps de videoconferencias tienen el mismo inconveniente. Si el usuario desea interactuar con una pestaña o ventana capturada, debe cambiar a esa superficie, lo que lo aleja de la app de videoconferencia. Esto presenta algunos desafíos:
- El usuario no puede ver la app capturada y los feeds de video de los usuarios remotos al mismo tiempo, a menos que use la función Pantalla en pantalla o ventanas separadas para la pestaña de videoconferencia y la pestaña compartida. En una pantalla más pequeña, esto podría ser difícil.
- El usuario se ve abrumado por la necesidad de alternar entre la app de videoconferencia y la superficie capturada.
- El usuario pierde el acceso a los controles que expone la app de videoconferencia mientras no la está usando, por ejemplo, una app de chat incorporada, reacciones con emojis, notificaciones sobre usuarios que solicitan unirse a la llamada, controles multimedia y de diseño, y otras funciones útiles de videoconferencia.
- El presentador no puede delegar el control a los participantes remotos. Esto genera la situación tan conocida en la que los usuarios remotos le piden al presentador que cambie la diapositiva, que se desplace un poco hacia arriba y abajo, o que ajuste el nivel de zoom.
La API de Captured Surface Control aborda estos problemas.
¿Cómo uso el control de superficie capturada?
Para usar el control de superficie capturada de forma correcta, debes seguir algunos pasos, como capturar explícitamente una pestaña del navegador y obtener el permiso del usuario antes de poder desplazarte y acercar la pestaña capturada.
Captura una pestaña del navegador
Para comenzar, pídele al usuario que elija una superficie para compartir con getDisplayMedia()
y, en el proceso, asocia un objeto CaptureController
con la sesión de captura. Pronto usaremos ese objeto para controlar la superficie capturada.
const controller = new CaptureController();
const stream = await navigator.mediaDevices.getDisplayMedia({ controller });
A continuación, crea una vista previa local de la superficie capturada en forma de un elemento <video>
:
const previewTile = document.querySelector('video');
previewTile.srcObject = stream;
Si el usuario elige compartir una ventana o una pantalla, eso está fuera de nuestro alcance por el momento. Sin embargo, si elige compartir una pestaña, podemos continuar.
const [track] = stream.getVideoTracks();
if (track.getSettings().displaySurface !== 'browser') {
// Bail out early if the user didn't pick a tab.
return;
}
Mensaje de permiso
La primera invocación de forwardWheel()
, increaseZoomLevel()
, decreaseZoomLevel()
o resetZoomLevel()
en un objeto CaptureController
determinado genera un mensaje de permiso. Si el usuario otorga permiso, se permiten más invocaciones de estos métodos.
Se requiere un gesto del usuario para mostrarle un mensaje de permiso, por lo que la app solo debe llamar a los métodos mencionados anteriormente si ya tiene el permiso o en respuesta a un gesto del usuario, como un click
en un botón relevante de la app web.
Desplazamiento
Con forwardWheel()
, una app de captura puede reenviar eventos de rueda desde un elemento de origen dentro de la app de captura al viewport de la pestaña capturada. Para la app capturada, estos eventos no se distinguen de la interacción directa del usuario.
Suponiendo que la app de captura emplea un elemento <video>
llamado "previewTile"
, el siguiente código muestra cómo retransmitir eventos de la rueda a la pestaña capturada:
const previewTile = document.querySelector('video');
try {
// Relay the user's action to the captured tab.
await controller.forwardWheel(previewTile);
} catch (error) {
// Inspect the error.
// ...
}
El método forwardWheel()
toma una sola entrada que puede ser una de las siguientes:
- Es un elemento HTML desde el que se reenviarán los eventos de la rueda a la pestaña capturada.
null
, lo que indica que se debe detener el reenvío.
Una llamada correcta a forwardWheel()
anula las llamadas anteriores.
La promesa que muestra forwardWheel()
se puede rechazar en los siguientes casos:
- Si la sesión de captura aún no comenzó o ya se detuvo.
- Si el usuario no otorgó el permiso correspondiente.
Zoom
La interacción con el nivel de zoom de la pestaña capturada se realiza a través de las siguientes plataformas de la API de CaptureController
:
getSupportedZoomLevels()
Este método muestra una lista de los niveles de zoom que admite el navegador para el tipo de superficie que se captura. Los valores de esta lista se representan como un porcentaje en relación con el "nivel de zoom predeterminado", que se define como 100%. La lista aumenta de forma monótona y contiene el valor 100.
Solo se puede llamar a este método para los tipos de superficie de visualización admitidos, lo que, por el momento, significa solo para las pestañas.
Se puede llamar a controller.getSupportedZoomLevels()
si se cumplen las siguientes condiciones:
controller
está asociado con una captura activa.- La captura es de una pestaña.
De lo contrario, se generará un error.
No se requiere el permiso "captured-surface-control"
para llamar a este método.
zoomLevel
Este atributo de solo lectura contiene el nivel de zoom actual de la pestaña capturada. Es un atributo que admite valores nulos y contiene null
si el tipo de superficie capturada no tiene una definición significativa del nivel de zoom. Por el momento, el nivel de zoom solo se define para las pestañas, no para las ventanas ni las pantallas.
Cuando finalice la captura, el atributo conservará el último valor a nivel del zoom.
No se requiere el permiso "captured-surface-control"
para leer este atributo.
onzoomlevelchange
Este controlador de eventos facilita la detección de cambios en el nivel de zoom de la pestaña capturada. Esto puede ocurrir de las siguientes maneras:
- Cuando el usuario interactúa con el navegador para cambiar manualmente el nivel de zoom de la pestaña capturada.
- En respuesta a las llamadas de la app de captura a los métodos de configuración de zoom (que se describen a continuación).
No se requiere el permiso "captured-surface-control"
para leer este atributo.
increaseZoomLevel()
, decreaseZoomLevel()
y resetZoomLevel()
Estos métodos permiten manipular el nivel de zoom de la pestaña capturada.
increaseZoomLevel()
y decreaseZoomLevel()
cambian el nivel de zoom al siguiente o al anterior, respectivamente, según el orden que muestra getSupportedZoomLevels()
. resetZoomLevel()
establece el valor en 100.
El permiso "captured-surface-control"
es obligatorio para llamar a estos métodos. Si la app de captura no tiene este permiso, se le pedirá al usuario que lo otorgue o deniegue.
Todos estos métodos muestran una promesa que se resuelve si la llamada se realiza correctamente y se rechaza en caso contrario. Estas son algunas de las posibles causas de rechazo:
- Faltan permisos.
- Se llama antes de que comience la captura.
- Se llama después de que finaliza la captura.
- Se llamó a un
controller
asociado con una captura de un tipo de superficie de visualización no admitido. (es decir, cualquier cosa que no sea la captura de pestañas). - Intenta aumentar o disminuir más allá del valor máximo o mínimo, respectivamente.
En particular, se recomienda evitar llamar a decreaseZoomLevel()
si controller.zoomLevel == controller.getSupportedZoomLevels().at(0)
y proteger las llamadas a increaseZoomLevel()
de manera similar con .at(-1)
.
En el siguiente ejemplo, se muestra cómo permitir que el usuario aumente el nivel de zoom de una pestaña capturada directamente desde la app de captura:
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.
// ...
}
});
En el siguiente ejemplo, se muestra cómo reaccionar a los cambios de nivel de zoom de una pestaña capturada:
controller.addEventListener('zoomlevelchange', (event) => {
const zoomLevelLabel = document.querySelector('#zoomLevelLabel');
zoomLevelLabel.textContent = `${controller.zoomLevel}%`;
});
Detección de atributos
Para verificar si las APIs de Captured Surface Control son compatibles, usa lo siguiente:
if (!!window.CaptureController?.prototype.forwardWheel) {
// CaptureController forwardWheel() is supported.
}
También es posible usar cualquiera de las otras plataformas de la API de Captured Surface Control, como increaseZoomLevel
o decreaseZoomLevel
, o incluso verificarlas todas.
Navegadores compatibles
El control de superficie capturado está disponible a partir de Chrome 136 solo en computadoras.
Seguridad y privacidad
La política de permisos de "captured-surface-control"
te permite administrar cómo tu app de captura y los iframes de terceros incorporados tienen acceso al Control de superficie capturada. Para comprender las compensaciones de seguridad, consulta la sección Consideraciones sobre la privacidad y la seguridad de la explicación del control de la superficie capturada.
Demostración
Para jugar con el control de superficie capturado, ejecuta la demo en Glitch. Asegúrate de consultar el código fuente.
Comentarios
El equipo de Chrome y la comunidad de estándares web quieren conocer tus experiencias con el control de superficie capturada.
Cuéntanos sobre el diseño
¿Hay algo relacionado con la Captura de superficie capturada 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, así como instrucciones para reproducirlo. Glitch es ideal para compartir errores reproducibles.