Berbagi tab, jendela, dan layar sudah dapat dilakukan di platform web dengan Screen Capture API. Saat aplikasi web memanggil getDisplayMedia()
, Chrome akan meminta pengguna untuk membagikan tab, jendela, atau layar ke aplikasi web sebagai video MediaStreamTrack
.
Banyak aplikasi web yang menggunakan getDisplayMedia()
menampilkan pratinjau video permukaan yang diambil kepada pengguna. Misalnya, aplikasi konferensi video akan sering melakukan streaming video ini ke pengguna jarak jauh sekaligus merendernya ke HTMLVideoElement
lokal, sehingga pengguna lokal akan terus melihat pratinjau dari apa yang mereka bagikan.
Dokumentasi ini memperkenalkan Captured Surface Control API baru di Chrome, yang memungkinkan aplikasi web Anda men-scroll tab yang diambil, serta membaca dan menulis tingkat zoom tab yang diambil.
Mengapa menggunakan Kontrol Permukaan yang Diambil?
Semua aplikasi konferensi video memiliki kekurangan yang sama: jika pengguna ingin berinteraksi dengan tab atau jendela yang direkam, pengguna harus beralih ke platform tersebut, sehingga mereka keluar dari aplikasi konferensi video. Hal ini menimbulkan beberapa tantangan:
- Pengguna tidak dapat melihat aplikasi yang direkam dan video pengguna jarak jauh secara bersamaan, kecuali jika mereka menggunakan Picture-in-Picture atau jendela terpisah berdampingan untuk tab konferensi video dan tab bersama. Pada layar yang lebih kecil, hal ini mungkin sulit dilakukan.
- Pengguna terbebani dengan kebutuhan untuk beralih antara aplikasi konferensi video dan platform yang direkam.
- Pengguna kehilangan akses ke kontrol yang ditampilkan oleh aplikasi konferensi video saat mereka tidak berada di aplikasi tersebut; misalnya, aplikasi chat tersemat, reaksi emoji, notifikasi tentang pengguna yang meminta untuk bergabung ke panggilan, kontrol multimedia dan tata letak, serta fitur konferensi video berguna lainnya.
- Presentator tidak dapat mendelegasikan kontrol kepada peserta jarak jauh. Hal ini menyebabkan skenario yang sudah terlalu sering terjadi, yaitu pengguna jarak jauh meminta presenter untuk mengubah slide, men-scroll sedikit ke atas dan ke bawah, atau menyesuaikan tingkat zoom.
Captured Surface Control API mengatasi masalah ini.
Bagaimana cara menggunakan Kontrol Permukaan yang Ditangkap?
Penggunaan Captured Surface Control berhasil memerlukan beberapa langkah, seperti secara eksplisit merekam tab browser dan mendapatkan izin dari pengguna sebelum dapat men-scroll dan memperbesar/memperkecil tab yang direkam.
Mengambil gambar tab browser
Mulai dengan meminta pengguna untuk memilih platform yang akan dibagikan menggunakan getDisplayMedia()
, dan dalam prosesnya, kaitkan objek CaptureController
dengan sesi pengambilan. Kita akan menggunakan objek tersebut untuk mengontrol permukaan yang diambil sebentar lagi.
const controller = new CaptureController();
const stream = await navigator.mediaDevices.getDisplayMedia({ controller });
Selanjutnya, buat pratinjau lokal platform yang diambil dalam bentuk elemen <video>
:
const previewTile = document.querySelector('video');
previewTile.srcObject = stream;
Jika pengguna memilih untuk membagikan jendela atau layar, hal itu di luar cakupan untuk saat ini—tetapi jika mereka memilih untuk membagikan tab, kita dapat melanjutkan.
const [track] = stream.getVideoTracks();
if (track.getSettings().displaySurface !== 'browser') {
// Bail out early if the user didn't pick a tab.
return;
}
Permintaan izin
Pemanggilan pertama sendWheel()
atau setZoomLevel()
pada objek CaptureController
tertentu akan menghasilkan perintah izin. Jika pengguna memberikan izin, pemanggilan metode ini lebih lanjut pada objek CaptureController
tersebut diizinkan. Jika pengguna menolak izin, promise yang ditampilkan akan ditolak.
Perhatikan bahwa objek CaptureController
secara unik dikaitkan dengan capture-session tertentu, tidak dapat dikaitkan dengan capture-session lain, dan tidak bertahan saat halaman tempat objek tersebut ditentukan dinavigasi. Namun, sesi pengambilan tetap ada setelah navigasi halaman yang diambil.
Gestur pengguna diperlukan untuk menampilkan perintah izin kepada pengguna. Hanya panggilan sendWheel()
dan setZoomLevel()
yang memerlukan gestur pengguna, dan hanya jika perintah perlu ditampilkan. Jika pengguna mengklik tombol zoom in atau zoom out di aplikasi web, gestur pengguna tersebut sudah pasti; tetapi jika aplikasi ingin menawarkan kontrol scroll terlebih dahulu, developer harus ingat bahwa scroll tidak merupakan gestur pengguna. Salah satu kemungkinannya adalah menawarkan tombol "mulai scroll" terlebih dahulu kepada pengguna, sesuai contoh berikut:
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.
}
});
Scroll
Dengan menggunakan sendWheel()
, aplikasi yang merekam dapat mengirimkan peristiwa roda dengan magnitudo yang dipilih di atas koordinat yang dipilih dalam area pandang tab. Peristiwa tidak dapat dibedakan oleh aplikasi yang direkam dari interaksi pengguna langsung.
Dengan asumsi aplikasi pengambilan menggunakan elemen <video>
yang disebut "previewTile"
, kode berikut menunjukkan cara meneruskan peristiwa roda pengiriman ke tab yang diambil:
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.
// ...
}
});
Metode sendWheel()
menggunakan kamus dengan dua kumpulan nilai:
x
dany
: koordinat tempat peristiwa roda akan dikirim.wheelDeltaX
danwheelDeltaY
: besarnya scroll, dalam piksel, untuk scroll horizontal dan vertikal. Perhatikan bahwa nilai ini dibalik dibandingkan dengan peristiwa roda asli.
Kemungkinan implementasi translateCoordinates()
adalah:
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)];
}
Perhatikan bahwa ada tiga ukuran yang berbeda dalam kode sebelumnya:
- Ukuran elemen
<video>
. - Ukuran frame yang diambil (diwakili di sini sebagai
trackSettings.width
dantrackSettings.height
). - Ukuran tab.
Ukuran elemen <video>
sepenuhnya berada dalam domain aplikasi pengambilan, dan tidak diketahui oleh browser. Ukuran tab sepenuhnya berada dalam domain browser, dan tidak diketahui oleh aplikasi web.
Aplikasi web menggunakan translateCoordinates()
untuk menerjemahkan offset relatif terhadap elemen <video>
menjadi koordinat dalam ruang koordinat trek video itu sendiri. Browser juga akan menerjemahkan antara ukuran frame yang diambil dan ukuran tab, serta mengirimkan peristiwa scroll pada offset yang sesuai dengan ekspektasi aplikasi web.
Promise yang ditampilkan oleh sendWheel()
dapat ditolak dalam kasus berikut:
- Jika sesi pengambilan belum dimulai atau telah berhenti, termasuk berhenti secara asinkron saat tindakan
sendWheel()
ditangani oleh browser. - Jika pengguna tidak memberikan izin aplikasi untuk menggunakan
sendWheel()
. - Jika aplikasi pengambilan mencoba mengirimkan peristiwa scroll dalam koordinat yang berada di luar
[trackSettings.width, trackSettings.height]
. Perhatikan bahwa nilai ini dapat berubah secara asinkron, jadi sebaiknya tangkap error dan abaikan. (Perhatikan bahwa0, 0
biasanya tidak akan berada di luar batas, jadi aman menggunakannya untuk meminta izin pengguna.)
Zoom
Interaksi dengan tingkat zoom tab yang diambil dilakukan melalui platform CaptureController
berikut:
getSupportedZoomLevels()
menampilkan daftar tingkat zoom yang didukung oleh browser, yang direpresentasikan sebagai persentase dari "tingkat zoom default", yang ditentukan sebagai 100%. Daftar ini meningkat secara monoton dan berisi nilai 100.getZoomLevel()
menampilkan tingkat zoom tab saat ini.setZoomLevel()
menetapkan tingkat zoom tab ke nilai bilangan bulat yang ada digetSupportedZoomLevels()
, dan menampilkan promise saat berhasil. Perhatikan bahwa tingkat zoom tidak direset di akhir sesi pengambilan.oncapturedzoomlevelchange
memungkinkan Anda memproses perubahan tingkat zoom tab yang direkam karena pengguna dapat mengubah tingkat zoom baik melalui aplikasi yang merekam maupun melalui interaksi langsung dengan tab yang direkam.
Panggilan ke setZoomLevel()
dibatasi oleh izin; panggilan ke metode zoom hanya baca lainnya "bebas", seperti memproses peristiwa.
Contoh berikut menunjukkan cara meningkatkan tingkat zoom tab yang diambil dalam sesi pengambilan yang ada:
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.
// ...
}
});
Contoh berikut menunjukkan cara Anda bereaksi terhadap perubahan tingkat zoom dari tab yang diambil:
controller.addEventListener('capturedzoomlevelchange', (event) => {
const zoomLevel = controller.getZoomLevel();
document.querySelector('#zoomLevelLabel').textContent = `${zoomLevel}%`;
});
Deteksi fitur
Untuk memeriksa apakah pengiriman peristiwa roda didukung, gunakan:
if (!!window.CaptureController?.prototype.sendWheel) {
// CaptureController sendWheel() is supported.
}
Untuk memeriksa apakah kontrol zoom didukung, gunakan:
if (!!window.CaptureController?.prototype.setZoomLevel) {
// CaptureController setZoomLevel() is supported.
}
Mengaktifkan Kontrol Permukaan yang Diambil
Captured Surface Control API tersedia di Chrome di desktop di balik tanda Captured Surface Control, dan dapat diaktifkan di chrome://flags/#captured-surface-control
.
Fitur ini juga memasuki uji coba origin mulai Chrome 122 di desktop, yang memungkinkan developer mengaktifkan fitur ini bagi pengunjung situs mereka untuk mengumpulkan data dari pengguna sebenarnya. Lihat Memulai uji coba origin untuk mengetahui informasi selengkapnya tentang uji coba origin dan cara kerjanya.
Keamanan dan privasi
Kebijakan izin "captured-surface-control"
memungkinkan Anda mengelola cara aplikasi yang merekam dan iframe pihak ketiga yang disematkan memiliki akses ke Captured Surface Control. Untuk memahami kompromi keamanan, lihat bagian Pertimbangan Privasi dan Keamanan dalam penjelasan Kontrol Permukaan yang Direkam.
Demo
Anda dapat bermain dengan Captured Surface Control dengan menjalankan demo di Glitch. Pastikan untuk memeriksa kode sumbernya.
Perubahan dari versi Chrome sebelumnya
Berikut beberapa perbedaan perilaku utama tentang Captured Surface Control yang harus Anda ketahui:
- Di Chrome 124 dan yang lebih lama:
- Izin—jika diberikan—dibatasi untuk sesi pengambilan yang terkait dengan
CaptureController
tersebut, bukan untuk asal pengambilan.
- Izin—jika diberikan—dibatasi untuk sesi pengambilan yang terkait dengan
- Di Chrome 122:
getZoomLevel()
menampilkan promise dengan tingkat zoom tab saat ini.sendWheel()
menampilkan promise yang ditolak dengan pesan error"No permission."
jika pengguna tidak memberikan izin penggunaan aplikasi. Jenis error-nya adalah"NotAllowedError"
di Chrome 123 dan yang lebih baru.oncapturedzoomlevelchange
tidak tersedia. Anda dapat melakukan polyfill pada fitur ini menggunakansetInterval()
.
Masukan
Tim Chrome dan komunitas standar web ingin mengetahui pengalaman Anda dengan Captured Surface Control.
Beri tahu kami tentang desain
Apakah ada sesuatu tentang Captured Surface Capture yang tidak berfungsi seperti yang Anda harapkan? Atau apakah ada metode atau properti yang hilang yang Anda perlukan untuk menerapkan ide Anda? Ada pertanyaan atau komentar tentang model keamanan? Ajukan masalah spesifikasi di repo GitHub, atau tambahkan pendapat Anda ke masalah yang ada.
Ada masalah dengan implementasinya?
Apakah Anda menemukan bug pada penerapan Chrome? Atau apakah implementasinya berbeda dengan spesifikasi? Laporkan bug di https://new.crbug.com. Pastikan untuk menyertakan detail sebanyak mungkin, serta petunjuk untuk mereproduksinya. Glitch sangat cocok untuk membagikan bug yang dapat direproduksi.