Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.
Menerbitkan & Berlangganan dengan Siaran IVS Web SDK | Streaming Waktu Nyata
Dokumen ini membawa Anda melalui langkah-langkah yang terlibat dalam penerbitan dan berlangganan ke panggung menggunakan siaran SDK Web streaming IVS waktu nyata.
Konsep
Tiga konsep inti mendasari fungsionalitas real-time: panggung, strategi, dan acara. Tujuan desain adalah meminimalkan jumlah logika sisi klien yang diperlukan untuk membangun produk yang berfungsi.
Stage
Stage
Kelas adalah titik utama interaksi antara aplikasi host danSDK. Ini mewakili panggung itu sendiri dan digunakan untuk bergabung dan meninggalkan panggung. Membuat dan menggabungkan tahap membutuhkan string token yang valid dan belum kedaluwarsa dari bidang kontrol (direpresentasikan sebagaitoken
). Bergabung dan meninggalkan panggung itu sederhana:
const stage = new Stage(token, strategy) try { await stage.join(); } catch (error) { // handle join exception } stage.leave();
Strategi
StageStrategy
Antarmuka menyediakan cara bagi aplikasi host untuk mengkomunikasikan keadaan panggung yang diinginkan keSDK. Tiga fungsi perlu diimplementasikan:shouldSubscribeToParticipant
,shouldPublishParticipant
, danstageStreamsToPublish
. Semua dibahas di bawah ini.
Untuk menggunakan strategi yang ditentukan, berikan ke Stage
konstruktor. Berikut ini adalah contoh lengkap aplikasi yang menggunakan strategi untuk mempublikasikan webcam peserta ke panggung dan berlangganan semua peserta. Setiap tujuan fungsi strategi yang diperlukan dijelaskan secara rinci di bagian selanjutnya.
const devices = await navigator.mediaDevices.getUserMedia({ audio: true, video: { width: { max: 1280 }, height: { max: 720 }, } }); const myAudioTrack = new LocalStageStream(devices.getAudioTracks()[0]); const myVideoTrack = new LocalStageStream(devices.getVideoTracks()[0]); // Define the stage strategy, implementing required functions const strategy = { audioTrack: myAudioTrack, videoTrack: myVideoTrack, // optional updateTracks(newAudioTrack, newVideoTrack) { this.audioTrack = newAudioTrack; this.videoTrack = newVideoTrack; }, // required stageStreamsToPublish() { return [this.audioTrack, this.videoTrack]; }, // required shouldPublishParticipant(participant) { return true; }, // required shouldSubscribeToParticipant(participant) { return SubscribeType.AUDIO_VIDEO; } }; // Initialize the stage and start publishing const stage = new Stage(token, strategy); await stage.join(); // To update later (e.g. in an onClick event handler) strategy.updateTracks(myNewAudioTrack, myNewVideoTrack); stage.refreshStrategy();
Berlangganan Peserta
shouldSubscribeToParticipant(participant: StageParticipantInfo): SubscribeType
Ketika peserta jarak jauh bergabung dengan panggung, SDK pertanyaan aplikasi host tentang status langganan yang diinginkan untuk peserta tersebut. Pilihannya adalahNONE
,AUDIO_ONLY
, danAUDIO_VIDEO
. Saat mengembalikan nilai untuk fungsi ini, aplikasi host tidak perlu khawatir tentang status publikasi, status langganan saat ini, atau status koneksi tahap. Jika AUDIO_VIDEO
dikembalikan, SDK menunggu hingga peserta jarak jauh menerbitkan sebelum berlangganan, dan memperbarui aplikasi host dengan memancarkan acara selama proses berlangsung.
Berikut adalah contoh implementasi:
const strategy = { shouldSubscribeToParticipant: (participant) => { return SubscribeType.AUDIO_VIDEO; } // ... other strategy functions }
Ini adalah implementasi lengkap dari fungsi ini untuk aplikasi host yang selalu ingin semua peserta saling bertemu; misalnya, aplikasi obrolan video.
Implementasi yang lebih maju juga dimungkinkan. Misalnya, asumsikan aplikasi menyediakan role
atribut saat membuat token dengan CreateParticipantToken. Aplikasi dapat menggunakan attributes
properti StageParticipantInfo
untuk berlangganan peserta secara selektif berdasarkan atribut yang disediakan server:
const strategy = { shouldSubscribeToParticipant(participant) { switch (participant.attributes.role) { case 'moderator': return SubscribeType.NONE; case 'guest': return SubscribeType.AUDIO_VIDEO; default: return SubscribeType.NONE; } } // . . . other strategies properties }
Ini dapat digunakan untuk membuat panggung di mana moderator dapat memantau semua tamu tanpa terlihat atau didengar sendiri. Aplikasi host dapat menggunakan logika bisnis tambahan untuk membiarkan moderator melihat satu sama lain tetapi tetap tidak terlihat oleh tamu.
Konfigurasi untuk Berlangganan Peserta
subscribeConfiguration(participant: StageParticipantInfo): SubscribeConfiguration
Jika peserta jarak jauh sedang berlangganan (lihat Berlangganan Peserta), akan SDK menanyakan aplikasi host tentang konfigurasi langganan khusus untuk peserta tersebut. Konfigurasi ini bersifat opsional dan memungkinkan aplikasi host untuk mengontrol aspek-aspek tertentu dari perilaku pelanggan. Untuk informasi tentang apa yang dapat dikonfigurasi, lihat SubscribeConfiguration
Berikut adalah contoh implementasi:
const strategy = { subscribeConfiguration: (participant) => { return { jitterBuffer: { minDelay: JitterBufferMinDelay.MEDIUM } } // ... other strategy functions }
Implementasi ini memperbarui penundaan minimum jitter-buffer untuk semua peserta berlangganan ke preset. MEDIUM
Seperti halnyashouldSubscribeToParticipant
, implementasi yang lebih maju dimungkinkan. Yang diberikan ParticipantInfo
dapat digunakan untuk memperbarui konfigurasi berlangganan secara selektif untuk peserta tertentu.
Sebaiknya gunakan perilaku default. Tentukan konfigurasi khusus hanya jika ada perilaku tertentu yang ingin Anda ubah.
Publikasi
shouldPublishParticipant(participant: StageParticipantInfo): boolean
Setelah terhubung ke panggung, SDK kueri aplikasi host untuk melihat apakah peserta tertentu harus mempublikasikan. Ini hanya dipanggil pada peserta lokal yang memiliki izin untuk mempublikasikan berdasarkan token yang disediakan.
Berikut adalah contoh implementasi:
const strategy = { shouldPublishParticipant: (participant) => { return true; } // . . . other strategies properties }
Ini untuk aplikasi obrolan video standar di mana pengguna selalu ingin mempublikasikan. Mereka dapat membisukan dan menonaktifkan audio dan video mereka, untuk langsung disembunyikan atau seen/heard. (They also can use publish/unpublish, but that is much slower. Mute/unmute lebih disukai untuk kasus penggunaan di mana mengubah visibilitas sering diinginkan.)
Memilih Streaming untuk Publikasikan
stageStreamsToPublish(): LocalStageStream[];
Saat menerbitkan, ini digunakan untuk menentukan aliran audio dan video apa yang harus dipublikasikan. Ini dibahas secara lebih rinci nanti di Publish a Media Stream.
Memperbarui Strategi
Strategi ini dimaksudkan untuk menjadi dinamis: nilai yang dikembalikan dari salah satu fungsi di atas dapat diubah kapan saja. Misalnya, jika aplikasi host tidak ingin mempublikasikan sampai pengguna akhir mengetuk tombol, Anda dapat mengembalikan variabel dari shouldPublishParticipant
(sesuatu sepertihasUserTappedPublishButton
). Ketika variabel itu berubah berdasarkan interaksi oleh pengguna akhir, panggil stage.refreshStrategy()
untuk memberi sinyal kepada SDK bahwa ia harus menanyakan strategi untuk nilai terbaru, hanya menerapkan hal-hal yang telah berubah. Jika SDK mengamati bahwa shouldPublishParticipant
nilainya telah berubah, itu memulai proses publikasi. Jika SDK kueri dan semua fungsi mengembalikan nilai yang sama seperti sebelumnya, refreshStrategy
panggilan tidak mengubah tahap.
Jika nilai pengembalian shouldSubscribeToParticipant
perubahan dari AUDIO_VIDEO
keAUDIO_ONLY
, aliran video akan dihapus untuk semua peserta dengan nilai yang dikembalikan diubah, jika aliran video sudah ada sebelumnya.
Umumnya, tahap menggunakan strategi untuk menerapkan perbedaan antara strategi sebelumnya dan saat ini secara efisien, tanpa aplikasi host perlu khawatir tentang semua keadaan yang diperlukan untuk mengelolanya dengan benar. Karena itu, anggap menelepon stage.refreshStrategy()
sebagai operasi yang murah, karena tidak melakukan apa-apa kecuali strateginya berubah.
Peristiwa
Stage
Instance adalah emitor peristiwa. Menggunakanstage.on()
, keadaan panggung dikomunikasikan ke aplikasi host. Pembaruan untuk UI aplikasi host biasanya dapat didukung sepenuhnya oleh peristiwa. Peristiwa tersebut adalah sebagai berikut:
stage.on(StageEvents.STAGE_CONNECTION_STATE_CHANGED, (state) => {}) stage.on(StageEvents.STAGE_PARTICIPANT_JOINED, (participant) => {}) stage.on(StageEvents.STAGE_PARTICIPANT_LEFT, (participant) => {}) stage.on(StageEvents.STAGE_PARTICIPANT_PUBLISH_STATE_CHANGED, (participant, state) => {}) stage.on(StageEvents.STAGE_PARTICIPANT_SUBSCRIBE_STATE_CHANGED, (participant, state) => {}) stage.on(StageEvents.STAGE_PARTICIPANT_STREAMS_ADDED, (participant, streams) => {}) stage.on(StageEvents.STAGE_PARTICIPANT_STREAMS_REMOVED, (participant, streams) => {}) stage.on(StageEvents.STAGE_STREAM_MUTE_CHANGED, (participant, stream) => {})
Untuk sebagian besar acara ini, yang sesuai ParticipantInfo
disediakan.
Tidak diharapkan bahwa informasi yang diberikan oleh peristiwa berdampak pada nilai pengembalian strategi. Misalnya, nilai pengembalian shouldSubscribeToParticipant
tidak diharapkan berubah ketika STAGE_PARTICIPANT_PUBLISH_STATE_CHANGED
dipanggil. Jika aplikasi host ingin berlangganan ke peserta tertentu, itu harus mengembalikan jenis langganan yang diinginkan terlepas dari status publikasi peserta tersebut. Bertanggung SDK jawab untuk memastikan bahwa keadaan strategi yang diinginkan ditindaklanjuti pada waktu yang tepat berdasarkan keadaan panggung.
Publikasikan Aliran Media
Perangkat lokal seperti mikrofon dan kamera diambil menggunakan langkah yang sama seperti yang diuraikan di atas dalam Ambil MediaStream dari Perangkat. Dalam contoh yang kita gunakan MediaStream
untuk membuat daftar LocalStageStream
objek yang digunakan untuk penerbitan olehSDK:
try { // Get stream using steps outlined in document above const stream = await getMediaStreamFromDevice(); let streamsToPublish = stream.getTracks().map(track => { new LocalStageStream(track) }); // Create stage with strategy, or update existing strategy const strategy = { stageStreamsToPublish: () => streamsToPublish } }
Publikasikan Screenshare
Aplikasi sering perlu mempublikasikan screenshare selain kamera web pengguna. Menerbitkan screenshare mengharuskan membuat token tambahan untuk panggung, khususnya untuk menerbitkan media screenshare. Gunakan getDisplayMedia
dan batasi resolusi hingga maksimum 720p. Setelah itu, langkah-langkahnya mirip dengan menerbitkan kamera ke panggung.
// Invoke the following lines to get the screenshare's tracks const media = await navigator.mediaDevices.getDisplayMedia({ video: { width: { max: 1280, }, height: { max: 720, } } }); const screenshare = { videoStream: new LocalStageStream(media.getVideoTracks()[0]) }; const screenshareStrategy = { stageStreamsToPublish: () => { return [screenshare.videoStream]; }, shouldPublishParticipant: (participant) => { return true; }, shouldSubscribeToParticipant: (participant) => { return SubscribeType.AUDIO_VIDEO; } } const screenshareStage = new Stage(screenshareToken, screenshareStrategy); await screenshareStage.join();
Tampilkan dan Hapus Peserta
Setelah berlangganan selesai, Anda menerima berbagai StageStream
objek melalui STAGE_PARTICIPANT_STREAMS_ADDED
acara. Acara ini juga memberi Anda info peserta untuk membantu saat menampilkan aliran media:
stage.on(StageEvents.STAGE_PARTICIPANT_STREAMS_ADDED, (participant, streams) => { const streamsToDisplay = streams; if (participant.isLocal) { // Ensure to exclude local audio streams, otherwise echo will occur streamsToDisplay = streams.filter(stream => stream.streamType === StreamType.VIDEO) } // Create or find video element already available in your application const videoEl = getParticipantVideoElement(participant.id); // Attach the participants streams videoEl.srcObject = new MediaStream(); streamsToDisplay.forEach(stream => videoEl.srcObject.addTrack(stream.mediaStreamTrack)); })
Ketika peserta berhenti menerbitkan atau berhenti berlangganan dari aliran, STAGE_PARTICIPANT_STREAMS_REMOVED
fungsi dipanggil dengan aliran yang telah dihapus. Aplikasi host harus menggunakan ini sebagai sinyal untuk menghapus aliran video peserta dariDOM.
STAGE_PARTICIPANT_STREAMS_REMOVED
dipanggil untuk semua skenario di mana aliran mungkin dihapus, termasuk:
-
Peserta jarak jauh berhenti menerbitkan.
-
Perangkat lokal berhenti berlangganan atau mengubah langganan dari ke
AUDIO_VIDEO
.AUDIO_ONLY
-
Peserta jarak jauh meninggalkan panggung.
-
Peserta lokal meninggalkan panggung.
Karena STAGE_PARTICIPANT_STREAMS_REMOVED
dipanggil untuk semua skenario, tidak diperlukan logika bisnis khusus untuk menghapus peserta dari UI selama operasi cuti jarak jauh atau lokal.
Bisukan dan Bunyikan Streaming Media
LocalStageStream
objek memiliki setMuted
fungsi yang mengontrol apakah aliran diredam. Fungsi ini dapat dipanggil pada aliran sebelum atau sesudah dikembalikan dari fungsi stageStreamsToPublish
strategi.
Penting: Jika instance LocalStageStream
objek baru dikembalikan stageStreamsToPublish
setelah panggilan kerefreshStrategy
, status bisu objek aliran baru diterapkan ke panggung. Hati-hati saat membuat LocalStageStream
instance baru untuk memastikan status bisu yang diharapkan dipertahankan.
Pantau Status Bisu Media Peserta Jarak Jauh
Saat peserta mengubah status bisu video atau audio mereka, STAGE_STREAM_MUTE_CHANGED
acara dipicu dengan daftar aliran yang telah berubah. Gunakan isMuted
properti StageStream
untuk memperbarui UI Anda sesuai dengan itu:
stage.on(StageEvents.STAGE_STREAM_MUTE_CHANGED, (participant, stream) => { if (stream.streamType === 'video' && stream.isMuted) { // handle UI changes for video track getting muted } })
Selain itu, Anda dapat melihat StageParticipantInfo
stage.on(StageEvents.STAGE_STREAM_MUTE_CHANGED, (participant, stream) => { if (participant.videoStopped || participant.audioMuted) { // handle UI changes for either video or audio } })
Dapatkan RTC Statistik Web
Untuk mendapatkan RTC statistik Web terbaru untuk aliran penerbitan atau aliran berlangganan, gunakan getStats
terusStageStream
. Ini adalah metode asinkron yang dengannya Anda dapat mengambil statistik baik melalui await atau dengan merantai janji. Hasilnya adalah kamus RTCStatsReport
yang berisi semua statistik standar.
try { const stats = await stream.getStats(); } catch (error) { // Unable to retrieve stats }
Mengoptimalkan Media
Disarankan untuk membatasi getUserMedia
dan getDisplayMedia
memanggil ke batasan berikut untuk kinerja terbaik:
const CONSTRAINTS = { video: { width: { ideal: 1280 }, // Note: flip width and height values if portrait is desired height: { ideal: 720 }, framerate: { ideal: 30 }, }, };
Anda selanjutnya dapat membatasi media melalui opsi tambahan yang diteruskan ke LocalStageStream
konstruktor:
const localStreamOptions = { minBitrate?: number; maxBitrate?: number; maxFramerate?: number; simulcast: { enabled: boolean } } const localStream = new LocalStageStream(track, localStreamOptions)
Dalam kode di atas:
-
minBitrate
menetapkan bitrate minimum yang diharapkan digunakan browser. Namun, aliran video dengan kompleksitas rendah dapat mendorong encoder lebih rendah dari bitrate ini. -
maxBitrate
menetapkan bitrate maksimum yang diharapkan tidak melebihi browser untuk aliran ini. -
maxFramerate
menetapkan frame rate maksimum yang diharapkan tidak melebihi browser untuk aliran ini. -
simulcast
Opsi ini hanya dapat digunakan di browser berbasis Chromium. Ini memungkinkan pengiriman tiga lapisan rendisi aliran.-
Ini memungkinkan server untuk memilih rendisi mana yang akan dikirim ke peserta lain, berdasarkan keterbatasan jaringan mereka.
-
Ketika
simulcast
ditentukan bersama denganmaxFramerate
nilaimaxBitrate
dan/atau, diharapkan bahwa lapisan rendisi tertinggi akan dikonfigurasi dengan nilai-nilai ini dalam pikiran, asalkanmaxBitrate
tidak berada di bawahmaxBitrate
nilai default lapisan tertinggi kedua internal SDK 900 kbps. -
Jika
maxBitrate
ditentukan sebagai terlalu rendah dibandingkan dengan nilai default lapisan tertinggi kedua,simulcast
akan dinonaktifkan. -
simulcast
tidak dapat dinyalakan dan dimatikan tanpa menerbitkan ulang media melalui kombinasishouldPublishParticipant
pengembalianfalse
, panggilan, pengembalian,true
dan panggilanrefreshStrategy
shouldPublishParticipant
lagi.refreshStrategy
-
Dapatkan Atribut Peserta
Jika Anda menentukan atribut dalam permintaan CreateParticipantToken
titik akhir, Anda dapat melihat atribut di StageParticipantInfo
properti:
stage.on(StageEvents.STAGE_PARTICIPANT_JOINED, (participant) => { console.log(`Participant ${participant.id} info:`, participant.attributes); })
Menangani Masalah Jaringan
Ketika koneksi jaringan perangkat lokal terputus, SDK internal mencoba untuk menyambung kembali tanpa tindakan pengguna. Dalam beberapa kasus, SDK tidak berhasil dan tindakan pengguna diperlukan.
Secara umum keadaan panggung dapat ditangani melalui acara: STAGE_CONNECTION_STATE_CHANGED
stage.on(StageEvents.STAGE_CONNECTION_STATE_CHANGED, (state) => { switch (state) { case StageConnectionState.DISCONNECTED: // handle disconnected UI break; case StageConnectionState.CONNECTING: // handle establishing connection UI break; case StageConnectionState.CONNECTED: // SDK is connected to the Stage break; case StageConnectionState.ERRORED: // SDK encountered an error and lost its connection to the stage. Wait for CONNECTED. break; })
Secara umum, Anda dapat mengabaikan keadaan kesalahan yang ditemui setelah berhasil bergabung dengan tahap, karena SDK akan mencoba memulihkan secara internal. Jika SDK laporan ERRORED
status dan tahapan tetap dalam CONNECTING
keadaan untuk jangka waktu yang lama (misalnya, 30 detik atau lebih), Anda mungkin terputus dari jaringan.
Siarkan Panggung ke IVS Saluran
Untuk menyiarkan panggung, buat IVSBroadcastClient
sesi terpisah dan kemudian ikuti instruksi biasa untuk penyiaran denganSDK, dijelaskan di atas. Daftar StageStream
ekspos via STAGE_PARTICIPANT_STREAMS_ADDED
dapat digunakan untuk mengambil aliran media peserta yang dapat diterapkan pada komposisi aliran siaran, sebagai berikut:
// Setup client with preferred settings const broadcastClient = getIvsBroadcastClient(); stage.on(StageEvents.STAGE_PARTICIPANT_STREAMS_ADDED, (participant, streams) => { streams.forEach(stream => { const inputStream = new MediaStream([stream.mediaStreamTrack]); switch (stream.streamType) { case StreamType.VIDEO: broadcastClient.addVideoInputDevice(inputStream, `video-${participant.id}`, { index: DESIRED_LAYER, width: MAX_WIDTH, height: MAX_HEIGHT }); break; case StreamType.AUDIO: broadcastClient.addAudioInputDevice(inputStream, `audio-${participant.id}`); break; } }) })
Secara opsional, Anda dapat menggabungkan panggung dan menyiarkannya ke saluran IVS latensi rendah, untuk menjangkau audiens yang lebih besar. Lihat Mengaktifkan Beberapa Host di Amazon IVS Stream di Panduan Pengguna Streaming IVS Latensi Rendah.