La condivisione di schede, finestre e schermate è già possibile sulla piattaforma web con l'API Screen Capture. Quando un'app web chiama getDisplayMedia()
, Chrome chiede all'utente di condividere una scheda, una finestra o uno schermo con l'app web come video MediaStreamTrack
.
Molte app web che utilizzano getDisplayMedia()
mostrano all'utente un'anteprima video della superficie acquisita. Ad esempio, le app di videoconferenza spesso trasmettono questo video in streaming agli utenti remoti e lo visualizzano anche su un HTMLVideoElement
locale, in modo che l'utente locale possa vedere costantemente un'anteprima di ciò che sta condividendo.
Questa documentazione presenta la nuova API Captured Surface Control in Chrome, che consente all'app web di scorrere una scheda acquisita e di leggere e scrivere il livello di zoom di una scheda acquisita.
Perché usare il Controllo della superficie acquisita?
Tutte le app di videoconferenza presentano lo stesso svantaggio: se l'utente desidera interagire con una scheda o una finestra acquisita, deve passare a quella piattaforma, rimuovendola dall'app di videoconferenza. Ciò presenta alcune sfide:
- L'utente non può vedere contemporaneamente l'app acquisita e i video degli utenti remoti, a meno che non utilizzi la funzionalità Picture in picture o finestre separate una accanto all'altra per la scheda della videoconferenza e la scheda condivisa. Su uno schermo più piccolo, questa operazione potrebbe essere difficile.
- L'utente è gravato dalla necessità di passare dall'app di videoconferenza alla superficie acquisita.
- L'utente perde l'accesso ai controlli esposti dall'app di videoconferenza quando non è in uso, ad esempio un'app di chat incorporata, reazioni con emoji, notifiche relative agli utenti che chiedono di partecipare alla chiamata, controlli multimediali e di layout e altre funzionalità utili per le videoconferenze.
- Il presentatore non può delegare il controllo ai partecipanti da remoto. Questo conduce a uno scenario fin troppo familiare in cui gli utenti da remoto chiedono al presentatore di cambiare la slide, scorrere un po' su e giù o regolare il livello di zoom.
L'API Captured Surface Control risolve questi problemi.
Come faccio a utilizzare il controllo della superficie acquisita?
Per utilizzare correttamente il controllo della superficie acquisita sono necessari alcuni passaggi, ad esempio acquisire esplicitamente una scheda del browser e ottenere l'autorizzazione dell'utente prima di poter scorrere e aumentare lo zoom della scheda acquisita.
Acquisire una scheda del browser
Per iniziare, chiedi all'utente di scegliere una superficie da condividere utilizzando getDisplayMedia()
e, nel processo, associa un oggetto CaptureController
alla sessione di acquisizione. A breve utilizzeremo questo oggetto per controllare la superficie acquisita.
const controller = new CaptureController();
const stream = await navigator.mediaDevices.getDisplayMedia({ controller });
Quindi, crea un'anteprima locale della piattaforma acquisita sotto forma di elemento <video>
:
const previewTile = document.querySelector('video');
previewTile.srcObject = stream;
Se l'utente sceglie di condividere una finestra o una schermata, per il momento non rientra nell'ambito, ma se sceglie di condividere una scheda, possiamo procedere.
const [track] = stream.getVideoTracks();
if (track.getSettings().displaySurface !== 'browser') {
// Bail out early if the user didn't pick a tab.
return;
}
Richiesta di autorizzazione
La prima chiamata di sendWheel()
o setZoomLevel()
su un determinato oggetto CaptureController
genera una richiesta di autorizzazione. Se l'utente concede l'autorizzazione, sono consentite ulteriori invocazioni di questi metodi sull'oggetto CaptureController
. Se l'utente nega l'autorizzazione, la promessa restituita viene rifiutata.
Tieni presente che gli oggetti CaptureController
sono associati in modo univoco a una specifica sessione di acquisizione, non possono essere associati a un'altra sessione di acquisizione e non sopravvivono alla navigazione della pagina in cui sono definiti. Tuttavia, le sessioni di acquisizione sopravvivono alla navigazione nella pagina acquisita.
È necessario un gesto dell'utente per mostrare una richiesta di autorizzazione. Solo le chiamate sendWheel()
e setZoomLevel()
richiedono un gesto dell'utente e solo se è necessario mostrare la richiesta. Se l'utente fa clic su un pulsante per aumentare o diminuire lo zoom nell'app web, questo gesto è scontato; ma se l'app vuole offrire prima il controllo dello scorrimento, gli sviluppatori devono tenere presente che lo scorrimento non costituisce un gesto dell'utente. Una possibilità è offrire prima all'utente un pulsante "Inizia a scorrere", come nell'esempio seguente:
const startScrollingButton = document.querySelector('button');
startScrollingButton.addEventListener('click', async () => {
try {
const noOpWheelAction = {};
await controller.sendWheel(noOpWheelAction);
// The user approved the permission prompt.
// You can now scroll and zoom the captured tab as shown later in the article.
} catch (error) {
return; // Permission denied. Bail.
}
});
Scorri
Utilizzando sendWheel()
, un'app di acquisizione può inviare eventi relativi alla rotella di entità scelte in base alle coordinate scelte all'interno dell'area visibile di una scheda. L'evento non è distinguibile per l'app acquisita dall'interazione diretta dell'utente.
Presumendo che l'app di acquisizione utilizzi un elemento <video>
denominato "previewTile"
, il seguente codice mostra come inoltrare gli eventi wheel invia gli eventi alla scheda acquisita:
const previewTile = document.querySelector('video');
previewTile.addEventListener('wheel', async (event) => {
// Translate the offsets into coordinates which sendWheel() can understand.
// The implementation of this translation is explained further below.
const [x, y] = translateCoordinates(event.offsetX, event.offsetY);
const [wheelDeltaX, wheelDeltaY] = [-event.deltaX, -event.deltaY];
try {
// Relay the user's action to the captured tab.
await controller.sendWheel({ x, y, wheelDeltaX, wheelDeltaY });
} catch (error) {
// Inspect the error.
// ...
}
});
Il metodo sendWheel()
utilizza un dizionario con due insiemi di valori:
x
ey
: le coordinate in cui deve essere pubblicato l'evento ruota.wheelDeltaX
ewheelDeltaY
: la grandezza degli scorrimenti, in pixel, per gli scorrimenti orizzontali e verticali, rispettivamente. Tieni presente che questi valori vengono invertiti rispetto all'evento wheel originale.
Una possibile implementazione di translateCoordinates()
è:
function translateCoordinates(offsetX, offsetY) {
const previewDimensions = previewTile.getBoundingClientRect();
const trackSettings = previewTile.srcObject.getVideoTracks()[0].getSettings();
const x = trackSettings.width * offsetX / previewDimensions.width;
const y = trackSettings.height * offsetY / previewDimensions.height;
return [Math.floor(x), Math.floor(y)];
}
Tieni presente che nel codice precedente sono presenti tre dimensioni diverse:
- Le dimensioni dell'elemento
<video>
. - Le dimensioni dei frame acquisiti (rappresentate qui come
trackSettings.width
etrackSettings.height
). - Le dimensioni della scheda.
Le dimensioni dell'elemento <video>
rientrano completamente nel dominio dell'app di acquisizione e sono sconosciute al browser. Le dimensioni della scheda rientrano completamente nel dominio del browser e sono sconosciute all'app web.
L'app web utilizza translateCoordinates()
per tradurre gli offset relativi all'elemento <video>
in coordinate all'interno dello spazio delle coordinate della traccia video. Analogamente, il browser eseguirà la conversione tra le dimensioni dei frame acquisiti e le dimensioni della scheda e invierà l'evento di scorrimento con un offset corrispondente alle aspettative dell'app web.
La promessa restituita da sendWheel()
può essere rifiutata nei seguenti casi:
- Se la sessione di acquisizione non è ancora iniziata o è già stata interrotta, inclusa l'interruzione in modo asincrono mentre l'azione
sendWheel()
viene gestita dal browser. - Se l'utente non ha concesso all'app l'autorizzazione a utilizzare
sendWheel()
. - Se l'app di acquisizione tenta di inviare un evento di scorrimento in coordinate esterne a
[trackSettings.width, trackSettings.height]
. Tieni presente che questi valori potrebbero cambiare in modo asincrono, quindi è consigliabile rilevare l'errore e ignorarlo. Tieni presente che0, 0
in genere non è fuori limite, quindi è sicuro utilizzarlo per chiedere all'utente l'autorizzazione.
Zoom
L'interazione con il livello di zoom della scheda acquisita avviene tramite le seguenti CaptureController
superfici:
getSupportedZoomLevels()
restituisce un elenco dei livelli di zoom supportati dal browser, rappresentati come percentuali del "livello di zoom predefinito", definito come 100%. Questo elenco è in ordine crescente e contiene il valore 100.getZoomLevel()
restituisce il livello di zoom corrente della scheda.setZoomLevel()
imposta il livello di zoom della scheda su qualsiasi valore intero presente ingetSupportedZoomLevels()
e restituisce una promessa in caso di esito positivo. Tieni presente che il livello di zoom non viene reimpostato alla fine della sessione di acquisizione.oncapturedzoomlevelchange
ti consente di ascoltare i cambiamenti del livello di zoom di una scheda acquisita, poiché gli utenti possono cambiarlo tramite l'app di acquisizione o tramite l'interazione diretta con la scheda acquisita.
Le chiamate a setZoomLevel()
sono controllate dall'autorizzazione; le chiamate all'altro metodo di zoom di sola lettura sono "senza costi", così come l'ascolto di eventi.
L'esempio seguente mostra come aumentare il livello di zoom di una scheda acquisita in una sessione di acquisizione esistente:
const zoomIncreaseButton = document.getElementById('zoomInButton');
zoomIncreaseButton.addEventListener('click', async (event) => {
const levels = CaptureController.getSupportedZoomLevels();
const index = levels.indexOf(controller.getZoomLevel());
const newZoomLevel = levels[Math.min(index + 1, levels.length - 1)];
try {
await controller.setZoomLevel(newZoomLevel);
} catch (error) {
// Inspect the error.
// ...
}
});
Il seguente esempio mostra come reagire alle modifiche del livello di zoom di una scheda acquisita:
controller.addEventListener('capturedzoomlevelchange', (event) => {
const zoomLevel = controller.getZoomLevel();
document.querySelector('#zoomLevelLabel').textContent = `${zoomLevel}%`;
});
Rilevamento delle caratteristiche
Per verificare se l'invio di eventi relativi al mouse è supportato, utilizza:
if (!!window.CaptureController?.prototype.sendWheel) {
// CaptureController sendWheel() is supported.
}
Per verificare se il controllo dello zoom è supportato, usa:
if (!!window.CaptureController?.prototype.setZoomLevel) {
// CaptureController setZoomLevel() is supported.
}
Attiva il controllo della superficie acquisita
L'API Captured Surface Control è disponibile in Chrome su computer desktop dietro il flag Captured Surface Control e può essere attivata all'indirizzo chrome://flags/#captured-surface-control
.
Inoltre, questa funzionalità è in fase di prova per le origini a partire da Chrome 122 su computer, il che consente agli sviluppatori di attivarla per i visitatori dei loro siti al fine di raccogliere dati da utenti reali. Consulta la Guida introduttiva alle prove dell'origine per saperne di più sulle prove dell'origine e su come funzionano.
Sicurezza e privacy
I criteri di autorizzazione "captured-surface-control"
ti consentono di gestire il modo in cui l'app di acquisizione e gli iframe di terze parti incorporati hanno accesso al controllo delle aree acquisite. Per comprendere i compromessi in termini di sicurezza, consulta la sezione Considerazioni su privacy e sicurezza della spiegazione del controllo della superficie acquisita.
Demo
Puoi provare il controllo della superficie acquisita eseguendo la demo su Glitch. Assicurati di controllare il codice sorgente.
Modifiche rispetto alle versioni precedenti di Chrome
Di seguito sono riportate alcune differenze di comportamento principali del controllo delle aree acquisite da tenere presenti:
- In Chrome 124 e versioni precedenti:
- L'autorizzazione, se concessa, è limitata alla sessione di acquisizione associata a quel
CaptureController
, non all'origine di acquisizione.
- L'autorizzazione, se concessa, è limitata alla sessione di acquisizione associata a quel
- In Chrome 122:
getZoomLevel()
restituisce una promessa con il livello di zoom corrente della scheda.sendWheel()
restituisce una promessa rifiutata con il messaggio di errore"No permission."
se l'utente non ha concesso all'app l'autorizzazione di utilizzo. Il tipo di errore è"NotAllowedError"
in Chrome 123 e versioni successive.oncapturedzoomlevelchange
non è disponibile. Puoi eseguire il polyfill di questa funzionalità utilizzandosetInterval()
.
Feedback
Il team di Chrome e la community degli standard web vogliono conoscere le tue esperienze con il controllo delle aree acquisite.
Parlaci del design
C'è qualcosa in merito a Captured Surface Capture che non funziona come previsto? Oppure mancano metodi o proprietà necessari per implementare la tua idea? Hai una domanda o un commento sul modello di sicurezza? Invia una segnalazione relativa alle specifiche nel repository GitHub o aggiungi il tuo parere a una segnalazione esistente.
Problemi con l'implementazione?
Hai trovato un bug nell'implementazione di Chrome? Oppure l'implementazione è diversa dalla specifica? Segnala un bug all'indirizzo https://new.crbug.com. Assicurati di includere il maggior numero di dettagli possibile, nonché le istruzioni per la riproduzione. Glitch è ideale per condividere bug riproducibili.