Já é possível compartilhar guias, janelas e telas na plataforma da Web com a API Screen Capture. Quando um app da Web chama getDisplayMedia()
, o Chrome pede que o usuário compartilhe uma guia, uma janela ou uma tela com o app da Web como um vídeo MediaStreamTrack
.
Muitos apps da Web que usam getDisplayMedia()
mostram ao usuário uma prévia em vídeo da superfície capturada. Por exemplo, apps de videoconferência geralmente transmitem esse vídeo para usuários remotos e também renderizam em um HTMLVideoElement
local para que o usuário local veja constantemente uma prévia do que está compartilhando.
Esta documentação apresenta a nova API Captured Surface Control no Chrome, que permite que seu app da Web role uma guia capturada, além de ler e gravar o nível de zoom de uma guia capturada.
Por que usar o Captured Surface Control?
Todos os apps de videoconferência têm a mesma desvantagem. Se o usuário quiser interagir com uma guia ou janela capturada, ele precisará mudar para essa superfície, saindo do app de videoconferência. Isso apresenta alguns desafios:
- O usuário não pode ver o app capturado e os feeds de vídeo dos usuários remotos ao mesmo tempo, a menos que use o recurso Picture-in-Picture ou janelas separadas lado a lado para a guia de videoconferência e a guia compartilhada. Em uma tela menor, isso pode ser difícil.
- O usuário precisa alternar entre o app de videoconferência e a superfície capturada.
- O usuário perde o acesso aos controles expostos pelo app de videoconferência enquanto está longe dele. Por exemplo, um app de chat incorporado, reações com emojis, notificações sobre usuários que pedem para participar da chamada, controles de multimídia e layout e outros recursos úteis de videoconferência.
- O apresentador não pode delegar o controle a participantes remotos. Isso leva ao cenário muito conhecido em que os usuários remotos pedem ao apresentador para mudar o slide, rolar um pouco para cima e para baixo ou ajustar o nível de zoom.
A API Captured Surface Control resolve esses problemas.
Como usar o controle de superfície capturada?
Para usar o controle de superfície capturada, é necessário seguir algumas etapas, como capturar explicitamente uma guia do navegador e receber permissão do usuário antes de rolar e aplicar zoom na guia capturada.
Capturar uma guia do navegador
Comece pedindo ao usuário para escolher uma superfície para compartilhar usando getDisplayMedia()
e, no processo, associe um objeto CaptureController
à sessão de captura. Vamos usar esse objeto para controlar a superfície capturada em breve.
const controller = new CaptureController();
const stream = await navigator.mediaDevices.getDisplayMedia({ controller });
Em seguida, produza uma prévia local da superfície capturada na forma de um elemento <video>
:
const previewTile = document.querySelector('video');
previewTile.srcObject = stream;
Se o usuário escolher compartilhar uma janela ou uma tela, isso não está no escopo por enquanto. Mas se ele escolher compartilhar uma guia, podemos continuar.
const [track] = stream.getVideoTracks();
if (track.getSettings().displaySurface !== 'browser') {
// Bail out early if the user didn't pick a tab.
return;
}
Solicitação de permissão
A primeira invocação de forwardWheel()
, increaseZoomLevel()
, decreaseZoomLevel()
ou resetZoomLevel()
em um determinado objeto CaptureController
gera uma solicitação de permissão. Se o usuário conceder permissão, outras invocações desses métodos serão permitidas.
É necessário um gesto do usuário para mostrar uma solicitação de permissão. Portanto, o app só deve chamar os métodos mencionados se já tiver a permissão ou em resposta a um gesto do usuário, como um click
em um botão relevante no app da Web.
Rolagem
Usando forwardWheel()
, um app de captura pode encaminhar eventos de roda de um elemento de origem no próprio app de captura para a janela de visualização da guia capturada. Esses eventos são indistinguíveis para o app capturado da interação direta do usuário.
Supondo que o app de captura use um elemento <video>
chamado "previewTile"
, o código a seguir mostra como retransmitir eventos de envio de roda para a guia 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.
// ...
}
O método forwardWheel()
usa uma única entrada que pode ser uma das seguintes opções:
- Um elemento HTML de que os eventos de roda serão encaminhados para a guia capturada.
null
, indicando que o encaminhamento precisa ser interrompido.
Uma chamada bem-sucedida para forwardWheel()
substitui as chamadas anteriores.
A promessa retornada por forwardWheel()
pode ser rejeitada nos seguintes casos:
- Se a sessão de captura ainda não começou ou já foi interrompida.
- Se o usuário não concedeu a permissão relevante.
Zoom
A interação com o nível de zoom da guia capturada é feita pelas seguintes superfícies da API CaptureController
:
getSupportedZoomLevels()
Esse método retorna uma lista de níveis de zoom compatíveis com o navegador para o tipo de superfície capturada. Os valores nessa lista são representados como uma porcentagem relativa ao "nível de zoom padrão", que é definido como 100%. A lista aumenta monotonicamente e contém o valor 100.
Esse método só pode ser chamado para tipos de superfície de exibição compatíveis, o que no momento significa apenas para guias.
controller.getSupportedZoomLevels()
pode ser chamado se as seguintes condições forem atendidas:
controller
está associado a uma captura ativa.- A captura é de uma guia.
Caso contrário, um erro será gerado.
A permissão "captured-surface-control"
não é necessária para chamar esse método.
zoomLevel
Esse atributo somente leitura contém o nível de zoom atual da guia capturada. É um atributo anulável e contém null
se o tipo de superfície capturada não tiver uma definição significativa de nível de zoom. No momento, o nível de zoom só é definido para guias, não para janelas ou telas.
Depois que a captura termina, o atributo mantém o último valor de nível de zoom.
A permissão "captured-surface-control"
não é necessária para ler esse atributo.
onzoomlevelchange
Esse manipulador de eventos facilita a detecção de mudanças no nível de zoom da guia capturada. Isso acontece:
- Quando o usuário interage com o navegador para mudar manualmente o nível de zoom da guia capturada.
- Em resposta às chamadas do app de captura para os métodos de definição de zoom (descritos abaixo).
A permissão "captured-surface-control"
não é necessária para ler esse atributo.
increaseZoomLevel()
, decreaseZoomLevel()
e resetZoomLevel()
Esses métodos permitem manipular o nível de zoom da guia capturada.
increaseZoomLevel()
e decreaseZoomLevel()
mudam o nível de zoom para o próximo ou anterior, respectivamente, de acordo com a ordenação retornada por getSupportedZoomLevels()
. resetZoomLevel()
define o valor como 100.
A permissão "captured-surface-control"
é necessária para chamar esses métodos. Se o app de captura não tiver essa permissão, o usuário vai precisar conceder ou negar o acesso.
Todos esses métodos retornam uma promessa que é resolvida se a chamada for bem-sucedida e rejeitada caso contrário. Possíveis causas para a rejeição:
- Permissão ausente.
- Chamado antes do início da captura.
- Chamado depois que a captura termina.
- Chamado em um
controller
associado a uma captura de um tipo de superfície de exibição incompatível. Ou seja, qualquer coisa, exceto a captura de guias. - Tentativas de aumentar ou diminuir além do valor máximo ou mínimo, respectivamente.
É recomendável evitar chamar decreaseZoomLevel()
se controller.zoomLevel == controller.getSupportedZoomLevels().at(0)
e proteger as chamadas para increaseZoomLevel()
de maneira semelhante com .at(-1)
.
O exemplo a seguir mostra como permitir que o usuário aumente o nível de zoom de uma guia capturada diretamente no 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.
// ...
}
});
O exemplo a seguir mostra como reagir a mudanças no nível de zoom de uma guia capturada:
controller.addEventListener('zoomlevelchange', (event) => {
const zoomLevelLabel = document.querySelector('#zoomLevelLabel');
zoomLevelLabel.textContent = `${controller.zoomLevel}%`;
});
Detecção de recursos
Para verificar se as APIs Captured Surface Control são compatíveis, use:
if (!!window.CaptureController?.prototype.forwardWheel) {
// CaptureController forwardWheel() is supported.
}
Também é possível usar qualquer uma das outras plataformas da API Captured Surface Control, como increaseZoomLevel
ou decreaseZoomLevel
, ou até mesmo verificar todas elas.
Suporte ao navegador
O controle de superfície capturada está disponível apenas para computadores a partir do Chrome 136.
Segurança e privacidade
A política de permissões do "captured-surface-control"
permite gerenciar como o app de captura e os iframes incorporados de terceiros acessam o controle de superfície capturada. Para entender as compensações de segurança, confira a seção Considerações sobre privacidade e segurança da explicação sobre o controle de superfície capturada.
Demonstração
Para testar o controle de superfície capturada, execute a demonstração.
Feedback
A equipe do Chrome e a comunidade de padrões da Web querem saber sobre suas experiências com o controle de superfície capturada.
Fale sobre o design
Há algo sobre a captura de superfície capturada que não funciona como esperado? Ou há métodos ou propriedades ausentes que você precisa implementar sua ideia? Tem uma dúvida ou um comentário sobre o modelo de segurança? Registre um problema de especificação no repositório do GitHub ou adicione suas ideias a um problema existente.
Problemas com a implementação?
Você encontrou um bug na implementação do Chrome? Ou a implementação é diferente da especificação? Registre um bug em https://new.crbug.com. Inclua o máximo de detalhes possível, além de instruções para reproduzir o problema.