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.
Ta dokumentacja przedstawia nowy interfejs Captured Surface Control API w Chrome, który umożliwia aplikacji internetowej przewijanie przechwyczonej karty oraz odczyt i zapisywanie poziomu powiększenia tej karty.
Dlaczego warto korzystać z Captured Surface Control?
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ę i 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 powierzchni do udostępnienia za pomocą getDisplayMedia()
, a potem powiązaj obiekt CaptureController
z sesją rejestrowania. Wkrótce zaczniemy używać tego obiektu do kontrolowania przechwyconej 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 uprawnienia
Pierwsze wywołanie metody sendWheel()
lub setZoomLevel()
w danym obiekcie CaptureController
powoduje wyświetlenie prośby o uprawnienia. Jeśli użytkownik udzieli zgody, dalsze wywołania tych metod na obiekcie CaptureController
będą dozwolone. Jeśli użytkownik odmówi, zwrócona obietnica zostanie odrzucona.
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 przetrwają jednak w przypadku nawigacji po stronie przechwyconej.
Aby wyświetlić użytkownikowi prośbę o przyznanie uprawnień, musi on wykonać określone 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 wyświetlenie użytkownikowi 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ń
Za pomocą sendWheel()
aplikacja do przechwytywania może wysyłać zdarzenia związane z kołem o wybranym rozmiarze w wybranych współrzędnych w widoku karty. Zdarzenie jest nie do odróżnienia od bezpośredniej interakcji użytkownika z aplikacją.
Zakładając, że aplikacja do przechwytywania używa elementu <video>
o nazwie "previewTile"
, poniższy kod pokazuje, jak przekazywać zdarzenia kółka do wysyłania do karty przechwytywania:
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, w których ma być wysyłane zdarzenie związane z kołem.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.
Możliwe wdrożenie 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 jest w pełni w domenie przeglądarki i nieznany 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:
- Jeśli sesja przechwytywania nie została jeszcze rozpoczęta lub została już zatrzymana, w tym asynkroniczne zatrzymanie podczas wykonywania przez przeglądarkę działania
sendWheel()
. - jeśli użytkownik nie przyznał aplikacji uprawnień do korzystania z funkcji
sendWheel()
. - Jeśli aplikacja do przechwytywania próbuje przewinąć zdarzenie w współrzędnych, które znajdują się poza obszarem
[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 jest monotonicznie rosnąca i zawiera wartość 100.getZoomLevel()
zwraca bieżący poziom powiększenia karty.setZoomLevel()
ustawia poziom powiększenia karty na dowolną wartość całkowitą obecną wgetSupportedZoomLevels()
i zwraca obietnicę, gdy się powiedzie. Pamiętaj, że poziom powiększenia nie jest resetowany po zakończeniu sesji rejestrowania.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 jest obsługiwane, użyj:
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 stronie pochodzenia od wersji Chrome 122 na komputery, 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 ich działaniu znajdziesz w artykule Zaczynamy korzystać z testów pochodzenia.
Bezpieczeństwo i prywatność
Zasady 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 kontrolowaniem obrazu:
- W Chrome 124 i starszych wersjach:
- 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. W Chrome 123 i nowszych wersjach typ błędu to"NotAllowedError"
.- Źródło
oncapturedzoomlevelchange
jest niedostępne. Możesz wypełnić tę funkcję 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 projektowaniu
Czy coś w przypadku Captured Surface Capture nie działa zgodnie z oczekiwaniami? A może brakuje metod lub właściwości, których potrzebujesz do wdrożenia swojego pomysłu? 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 problemu. Glitch świetnie sprawdza się do udostępniania błędów, które można odtworzyć.