Udostępnianie kart, okien i ekranów jest już możliwe na platformie internetowej dzięki interfejsowi Screen Capture API. Gdy aplikacja internetowa wywołuje getDisplayMedia()
, Chrome prosi użytkownika o udostępnienie jej karty, okna lub ekranu w postaci MediaStreamTrack
filmu.
Wiele aplikacji internetowych, które korzystają z getDisplayMedia()
, wyświetla użytkownikowi podgląd wideo z przechwyczonej powierzchni. Na przykład aplikacje do wideokonferencji często przesyłają strumień wideo do użytkowników zdalnych, a także renderują go lokalnie HTMLVideoElement
, aby użytkownik lokalny stale widział podgląd tego, co udostępnia.
W tej dokumentacji opisujemy nowy interfejs Captured Surface Control API w Chrome, który umożliwia aplikacji internetowej przewijanie przechwyconej karty oraz odczytywanie i zapisywanie poziomu powiększenia przechwyconej karty.
Dlaczego warto korzystać z funkcji kontroli powierzchni rejestrowanej?
Wszystkie aplikacje do rozmów wideo mają ten sam mankament: jeśli użytkownik chce wejść w interakcję z przechwyconą kartą lub oknem, musi przełączyć się na tę powierzchnię, co spowoduje opuszczenie aplikacji do rozmów wideo. Stwarza to pewne problemy:
- Użytkownik nie może jednocześnie widzieć przechwyczonej aplikacji i filmów użytkowników zdalnych, chyba że korzysta z obrazu w obrazie lub oddzielnych okien obok siebie na kartę konferencji wideo i kartę udostępnioną. Na mniejszym ekranie może to być trudne.
- Użytkownik musi przełączać się między aplikacją do rozmów wideo a uchwytem.
- Użytkownik traci dostęp do elementów sterujących udostępnianych przez aplikację do konferencji wideo, gdy nie korzysta z tej aplikacji. Na przykład nie może korzystać z wbudowanej aplikacji do czatu, reakcji emotikonami, powiadomień o użytkownikach proszących o dołączenie do rozmowy, elementów sterujących multimediami i układem oraz innych przydatnych funkcji konferencji wideo.
- Prezenter nie może przekazać kontroli uczestnikom zdalnym. Prowadzi to do dobrze znanego scenariusza, w którym użytkownicy zdalni proszą prezentera o zmianę slajdu, przewinięcie w górę lub w dół lub dostosowanie poziomu powiększenia.
Interfejs Captured Surface Control API rozwiązuje te problemy.
Jak korzystać z Captured Surface Control?
Aby można było korzystać z zarządzania przechwyconym interfejsem, należy wykonać kilka czynności, takich jak wyraźne przechwycenie karty przeglądarki i uzyskanie zgody użytkownika, zanim będzie można przewijać i powiększać przechwyconą kartę.
Przechwytywanie karty przeglądarki
Najpierw poproś użytkownika o wybranie platformy do udostępnienia za pomocą getDisplayMedia()
, a następnie powiąż obiekt CaptureController
z sesją przechwytywania. Będziemy używać tego obiektu do sterowania przechwyconą powierzchnią.
const controller = new CaptureController();
const stream = await navigator.mediaDevices.getDisplayMedia({ controller });
Następnie wygeneruj lokalny podgląd sfilmowanej powierzchni w postaci elementu <video>
:
const previewTile = document.querySelector('video');
previewTile.srcObject = stream;
Jeśli użytkownik zdecyduje się udostępnić okno lub ekran, nie będziemy mogli tego obsłużyć. Jeśli jednak zdecyduje się udostępnić kartę, możemy to zrobić.
const [track] = stream.getVideoTracks();
if (track.getSettings().displaySurface !== 'browser') {
// Bail out early if the user didn't pick a tab.
return;
}
Prośba o zgodę
Pierwsze wywołanie metody sendWheel()
lub setZoomLevel()
dla danego obiektu CaptureController
powoduje wyświetlenie prośby o przyznanie uprawnień. Jeśli użytkownik udzieli zgody, dalsze wywołania tych metod na obiekcie CaptureController
będą dozwolone. Jeśli użytkownik odmówi, zwrócone obietnice zostaną odrzucone.
Pamiętaj, że obiekty CaptureController
są powiązane z konkretną sesją rejestrowania, nie można ich powiązać z inną sesją rejestrowania i nie są one dostępne po przejściu na inną stronę. Sesje przechwytywania zachowują jednak ważność po poruszaniu się po przechwyconej stronie.
Aby wyświetlić użytkownikowi prośbę o uprawnienia, wymagane jest jego działanie. Tylko połączenia sendWheel()
i setZoomLevel()
wymagają działania użytkownika, ale tylko wtedy, gdy należy wyświetlić prompt. Jeśli użytkownik kliknie przycisk powiększania lub pomniejszania w aplikacji internetowej, jest to dany gest użytkownika. Jeśli jednak aplikacja chce najpierw zaoferować kontrolę przewijania, deweloperzy powinni pamiętać, że przewijanie nie stanowi gestu użytkownika. Jedną z możliwości jest zaoferowanie użytkownikowi najpierw przycisku „Rozpocznij przewijanie”, jak w tym przykładzie:
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.
}
});
Przewiń
Dzięki funkcji sendWheel()
aplikacja do przechwytywania może wyświetlać zdarzenia koła o wybranej wielkości przez wybrane współrzędne w widocznym obszarze karty. Zdarzenie jest nie do odróżnienia od bezpośredniej interakcji użytkownika z aplikacją.
Zakładając, że aplikacja do przechwytywania ruchu wykorzystuje element <video>
o nazwie "previewTile"
, poniższy kod pokazuje, jak przekazywać zdarzenia wysyłane kołami do przechwyconych kart:
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.
// ...
}
});
Metoda sendWheel()
przyjmuje słownik z 2 zestawami wartości:
x
iy
: współrzędne miejsca, w którym ma być dostarczone zdarzenie koła.wheelDeltaX
iwheelDeltaY
: wielkość przewijania w pikselach, odpowiednio dla przewijania poziomego i pionowego. Pamiętaj, że te wartości są odwrócone w porównaniu z pierwotnym zdarzeniem koła.
Oto możliwa implementacja 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)];
}
Pamiętaj, że w powyższym kodzie występują 3 różne rozmiary:
- Rozmiar elementu
<video>
. - Rozmiar przechwycionych klatek (przedstawiony tutaj jako
trackSettings.width
itrackSettings.height
). - Rozmiar karty.
Rozmiar elementu <video>
jest całkowicie zależny od aplikacji do przechwytywania i nieznany przeglądarce. Rozmiar karty mieści się w całej domenie przeglądarki i nie jest znany aplikacji internetowej.
Aplikacja internetowa używa elementu translateCoordinates()
, aby przekształcić przesunięcia względem elementu <video>
w współrzędne w przestrzeni współrzędnych ścieżki wideo. Przeglądarka przekształca rozmiary uchwycionych klatek w rozmiary karty i przesyła zdarzenie przewijania z opóźnieniem odpowiadającym oczekiwaniom aplikacji internetowej.
Obietnica z poziomu sendWheel()
może zostać odrzucona w tych przypadkach:
- Sesja przechwytywania jeszcze się nie rozpoczęła lub już się zakończyła, w tym zatrzymanie asynchroniczne, gdy działanie
sendWheel()
jest obsługiwane przez przeglądarkę. - jeśli użytkownik nie przyznał aplikacji uprawnień do korzystania z funkcji
sendWheel()
. - Jeśli aplikacja do przechwytywania próbuje przewinąć do zdarzenia w współrzędnych spoza obszaru
[trackSettings.width, trackSettings.height]
. Pamiętaj, że te wartości mogą się zmieniać asynchronicznie, dlatego warto wykryć błąd i go zignorować. (Uwaga:0, 0
zwykle nie wykracza poza granice, więc można bezpiecznie użyć tego parametru, aby poprosić użytkownika o pozwolenie).
Zoom
Interakcje z poziomem powiększenia przechwyconej karty są realizowane za pomocą tych elementów CaptureController
:
getSupportedZoomLevels()
zwraca listę poziomów powiększenia obsługiwanych przez przeglądarkę, reprezentowanych jako odsetek „domyślnego poziomu powiększenia”, który jest zdefiniowany jako 100%. Ta lista rośnie monotonicznie i zawiera wartość 100.getZoomLevel()
zwraca bieżący poziom powiększenia karty.setZoomLevel()
ustawia poziom powiększenia karty na dowolną wartość całkowitą występującą w polugetSupportedZoomLevels()
i zwraca obietnicę, gdy operacja się uda. Pamiętaj, że poziom powiększenia nie jest resetowany na koniec sesji przechwytywania.oncapturedzoomlevelchange
pozwala słuchać zmian poziomu powiększenia na uchwyconej karcie, ponieważ użytkownicy mogą zmieniać poziom powiększenia za pomocą aplikacji do przechwytywania lub poprzez bezpośrednią interakcję z uchwyconą kartą.
Wywołania metody setZoomLevel()
są ograniczone przez uprawnienia. Wywołania innych metod zoom tylko do odczytu są „bezpłatne”, podobnie jak nasłuchiwanie zdarzeń.
Ten przykład pokazuje, jak zwiększyć poziom powiększenia przechwyconej karty w istniejącej sesji przechwytywania:
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.
// ...
}
});
Z poniższego przykładu dowiesz się, jak reagować na zmiany poziomu powiększenia uchwyconej karty:
controller.addEventListener('capturedzoomlevelchange', (event) => {
const zoomLevel = controller.getZoomLevel();
document.querySelector('#zoomLevelLabel').textContent = `${zoomLevel}%`;
});
Wykrywanie cech
Aby sprawdzić, czy wysyłanie zdarzeń kółka myszy jest obsługiwane, użyj polecenia:
if (!!window.CaptureController?.prototype.sendWheel) {
// CaptureController sendWheel() is supported.
}
Aby sprawdzić, czy kontrolowanie powiększenia jest obsługiwane, użyj:
if (!!window.CaptureController?.prototype.setZoomLevel) {
// CaptureController setZoomLevel() is supported.
}
Włączanie sterowania powierzchnią uchwytu
Interfejs Captured Surface Control API jest dostępny w Chrome na komputerach z flagą Captured Surface Control i można go włączyć na stronie chrome://flags/#captured-surface-control
.
Ta funkcja wchodzi też w fazę testów na komputerach stacjonarnych (od Chrome 122), co pozwala deweloperom włączyć ją dla odwiedzających ich witryny, aby zbierać dane od rzeczywistych użytkowników. Więcej informacji o testach pochodzenia i o tym, jak je przeprowadzać, znajdziesz w artykule Pierwsze kroki z testami pochodzenia.
Bezpieczeństwo i prywatność
Zasady dotyczące uprawnień "captured-surface-control"
umożliwiają zarządzanie dostępem aplikacji do rejestrowania i osadzonych ramek iframe innych firm do funkcji sterowania powierzchnią rejestrowania. Aby poznać kompromisy związane z bezpieczeństwem, przeczytaj sekcję Prywatność i bezpieczeństwo w artykule na temat kontrolowania urządzeń rejestrujących.
Prezentacja
Możesz korzystać z Captured Surface Control, uruchamiając demo w Glitch. Pamiętaj, aby sprawdzić kod źródłowy.
Zmiany w stosunku do poprzednich wersji Chrome
Oto najważniejsze różnice w zachowaniu związane z kontrolą obrazu:
- W Chrome 124 lub starszej wersji:
- Uprawnienia (jeśli zostaną przyznane) są ograniczone do sesji rejestrowania powiązanej z tym
CaptureController
, a nie do źródła rejestrowania.
- Uprawnienia (jeśli zostaną przyznane) są ograniczone do sesji rejestrowania powiązanej z tym
- W Chrome 122:
getZoomLevel()
zwraca obietnicę z bieżącym poziomem powiększenia karty.sendWheel()
zwraca obietnicę odrzuconą z wiadomością o błędzie"No permission."
, jeśli użytkownik nie przyznał aplikacji uprawnień do użycia. Typ błędu to"NotAllowedError"
w Chrome 123 i nowszych wersjach.- Źródło
oncapturedzoomlevelchange
jest niedostępne. Możesz użyć kodu polyfill za pomocąsetInterval()
.
Prześlij opinię
Zespół Chrome i społeczność zajmująca się standardami internetowymi chce poznać Twoje wrażenia związane z użyciem funkcji Captured Surface Control.
Opowiedz nam o projekcie
Czy jest coś, co w rejestrowanych obrazach powierzchni nie działa zgodnie z oczekiwaniami? A może brakuje Ci metod lub właściwości, które pozwolą Ci zrealizować Twój pomysł? Masz pytania lub uwagi dotyczące modelu zabezpieczeń? Zgłoś problem ze specyfikacją w repozytorium GitHub lub podziel się opinią na temat istniejącego problemu.
Problem z implementacją?
Czy znalazłeś/znalazłaś błąd w implementacji Chrome? A może implementacja różni się od specyfikacji? Zgłoś błąd na stronie https://new.crbug.com. Podaj jak najwięcej szczegółów, a także instrukcje odtwarzania błędu. Glitch świetnie sprawdza się do udostępniania błędów, które można odtworzyć.