

Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.

# SDK Siaran IVS: Panduan Web \$1 Streaming Waktu Nyata
<a name="broadcast-web"></a>

IVS real-time streaming Web broadcast SDK memberi pengembang alat untuk membangun pengalaman interaktif dan real-time di web. SDK ini untuk pengembang yang sedang membangun aplikasi web dengan Amazon IVS.

Web broadcast SDK memungkinkan peserta untuk mengirim dan menerima video. SDK mendukung operasi berikut:
+ Bergabunglah dengan panggung
+ Publikasikan media ke peserta lain di panggung
+ Berlangganan media dari peserta lain di panggung
+ Kelola dan pantau video dan audio yang dipublikasikan ke panggung
+ Dapatkan statistik WebRTC untuk setiap koneksi rekan
+ Semua operasi dari SDK siaran Web streaming latensi rendah IVS

**Versi terbaru dari Web broadcast SDK:** [1.34.0 (Catatan Rilis)](https://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/release-notes.html#apr09-26-broadcast-web-rt) 

**Dokumentasi referensi:** [Untuk informasi tentang metode terpenting yang tersedia di Amazon IVS Web Broadcast SDK, lihat https://aws.github. io/amazon-ivs-web-broadcast/docs/sdk-referensi](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference). Pastikan versi SDK terbaru dipilih.

**Contoh kode**: Sampel di bawah ini adalah tempat yang baik untuk memulai dengan cepat dengan SDK:
+ [Pemutaran Sederhana](https://codepen.io/amazon-ivs/pen/RNwVBRK)
+ [Penerbitan dan Berlangganan Sederhana](https://codepen.io/amazon-ivs/pen/ZEqgrpo)
+ [Demo Kolaborasi Real-Time React Komprehensif](https://github.com/aws-samples/amazon-ivs-real-time-collaboration-web-demo/tree/main)

**Persyaratan platform**: Lihat [Amazon IVS Broadcast SDK](https://docs.aws.amazon.com//ivs/latest/RealTimeUserGuide/broadcast.html) untuk daftar platform yang didukung

**Catatan:** Menerbitkan dari browser nyaman bagi pengguna akhir karena tidak memerlukan menginstal perangkat lunak tambahan. Namun, penerbitan berbasis browser tunduk pada kendala dan variabilitas lingkungan browser. Jika Anda perlu memprioritaskan stabilitas (misalnya, untuk streaming acara), kami umumnya merekomendasikan penerbitan dari sumber non-browser (misalnya, OBS Studio atau encoder khusus lainnya), yang sering memiliki akses langsung ke sumber daya sistem dan menghindari keterbatasan browser. Untuk informasi lebih lanjut tentang opsi penerbitan non-browser, lihat dokumentasi [Stream Ingest](rt-stream-ingest.md).

# Memulai dengan SDK Siaran Web IVS \$1 Streaming Waktu Nyata
<a name="broadcast-web-getting-started"></a>

Dokumen ini membawa Anda melalui langkah-langkah yang terlibat dalam memulai dengan SDK siaran Web streaming real-time IVS.

## Impor
<a name="broadcast-web-getting-started-imports"></a>

Blok bangunan untuk waktu nyata terletak di namespace yang berbeda dari modul penyiaran root.

### Menggunakan Tag Skrip
<a name="broadcast-web-getting-started-imports-script"></a>

SDK siaran Web didistribusikan sebagai JavaScript perpustakaan dan dapat diambil di [https://web-broadcast.live-video.net/1.34.0/ amazon-ivs-web-broadcast](https://web-broadcast.live-video.net/1.34.0/amazon-ivs-web-broadcast.js) .js.

Kelas dan enum yang didefinisikan dalam contoh di bawah ini dapat ditemukan pada objek `IVSBroadcastClient` global:

```
const { Stage, SubscribeType } = IVSBroadcastClient;
```

### Menggunakan npm
<a name="broadcast-web-getting-started-imports-npm"></a>

Untuk menginstal `npm` paket: 

```
npm install amazon-ivs-web-broadcast
```

Kelas, enum, dan tipe juga dapat diimpor dari modul paket:

```
import { Stage, SubscribeType, LocalStageStream } from 'amazon-ivs-web-broadcast'
```

### Dukungan Rendering Sisi Server
<a name="broadcast-web-getting-started-imports-server-side-rendering"></a>

Pustaka Tahapan SDK Siaran Web tidak dapat dimuat dalam konteks sisi server, karena mereferensikan primitif browser yang diperlukan untuk fungsi pustaka saat dimuat. Untuk mengatasinya, muat pustaka secara dinamis, seperti yang ditunjukkan dalam [Demo Siaran Web menggunakan Next dan React](https://github.com/aws-samples/amazon-ivs-broadcast-web-demo/blob/main/hooks/useBroadcastSDK.js#L26-L31).

## Permintaan Izin
<a name="broadcast-web-request-permissions"></a>

Aplikasi Anda harus meminta izin untuk mengakses kamera dan mikrofon pengguna, dan harus disajikan menggunakan HTTPS. (Ini tidak khusus untuk Amazon IVS; diperlukan untuk situs web apa pun yang membutuhkan akses ke kamera dan mikrofon.)

Berikut adalah contoh fungsi yang menunjukkan bagaimana Anda dapat meminta dan menangkap izin untuk perangkat audio dan video:

```
async function handlePermissions() {
   let permissions = {
       audio: false,
       video: false,
   };
   try {
       const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
       for (const track of stream.getTracks()) {
           track.stop();
       }
       permissions = { video: true, audio: true };
   } catch (err) {
       permissions = { video: false, audio: false };
       console.error(err.message);
   }
   // If we still don't have permissions after requesting them display the error message
   if (!permissions.video) {
       console.error('Failed to get video permissions.');
   } else if (!permissions.audio) {
       console.error('Failed to get audio permissions.');
   }
}
```

[Untuk informasi tambahan, lihat [API Izin](https://developer.mozilla.org/en-US/docs/Web/API/Permissions_API) danMediaDevices. getUserMedia()](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia).

## Daftar Perangkat yang Tersedia
<a name="broadcast-web-request-list-devices"></a>

Untuk melihat perangkat apa yang tersedia untuk ditangkap, kueri metode [MediaDevices.enumerateDevices](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/enumerateDevices) () browser:

```
const devices = await navigator.mediaDevices.enumerateDevices();
window.videoDevices = devices.filter((d) => d.kind === 'videoinput');
window.audioDevices = devices.filter((d) => d.kind === 'audioinput');
```

## Mengambil MediaStream dari Perangkat
<a name="broadcast-web-retrieve-mediastream"></a>

Setelah memperoleh daftar perangkat yang tersedia, Anda dapat mengambil aliran dari sejumlah perangkat. Misalnya, Anda dapat menggunakan `getUserMedia()` metode ini untuk mengambil aliran dari kamera.

Jika Anda ingin menentukan perangkat mana yang akan menangkap aliran, Anda dapat secara eksplisit menyetel `video` bagian `audio` atau batasan media. `deviceId` Sebagai alternatif, Anda dapat menghilangkan `deviceId` dan meminta pengguna memilih perangkat mereka dari prompt browser.

Anda juga dapat menentukan resolusi kamera yang ideal menggunakan `width` dan `height` kendala. [(Baca lebih lanjut tentang kendala ini di sini.)](https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints#properties_of_video_tracks) SDK secara otomatis menerapkan batasan lebar dan tinggi yang sesuai dengan resolusi siaran maksimum Anda; namun, sebaiknya Anda juga menerapkannya sendiri untuk memastikan bahwa rasio aspek sumber tidak berubah setelah Anda menambahkan sumber ke SDK.

Untuk streaming real-time, pastikan media dibatasi hingga resolusi 720p. Secara khusus, nilai Anda `getUserMedia` dan `getDisplayMedia` batasan untuk lebar dan tinggi tidak boleh melebihi 921600 (1280\$1 720) saat dikalikan bersama. 

```
const videoConfiguration = {
  maxWidth: 1280,
  maxHeight: 720,
  maxFramerate: 30,
}

window.cameraStream = await navigator.mediaDevices.getUserMedia({
   video: {
       deviceId: window.videoDevices[0].deviceId,
       width: {
           ideal: videoConfiguration.maxWidth,
       },
       height: {
           ideal:videoConfiguration.maxHeight,
       },
   },
});
window.microphoneStream = await navigator.mediaDevices.getUserMedia({
   audio: { deviceId: window.audioDevices[0].deviceId },
});
```

# Menerbitkan & Berlangganan dengan SDK Siaran Web IVS \$1 Streaming Waktu Nyata
<a name="web-publish-subscribe"></a>

Dokumen ini membawa Anda melalui langkah-langkah yang terlibat dalam penerbitan dan berlangganan ke panggung menggunakan SDK siaran Web streaming real-time IVS.

## Konsep
<a name="web-publish-subscribe-concepts"></a>

Tiga konsep inti mendasari fungsionalitas waktu nyata: [panggung](#web-publish-subscribe-concepts-stage), [strategi](#web-publish-subscribe-concepts-strategy), dan [acara](#web-publish-subscribe-concepts-events). Tujuan desain adalah meminimalkan jumlah logika sisi klien yang diperlukan untuk membangun produk yang berfungsi.

### Stage
<a name="web-publish-subscribe-concepts-stage"></a>

`Stage`Kelas adalah titik utama interaksi antara aplikasi host dan SDK. 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 sebagai`token`). Bergabung dan meninggalkan panggung itu sederhana:

```
const stage = new Stage(token, strategy)

try {
   await stage.join();
} catch (error) {
   // handle join exception
}

stage.leave();
```

### Strategi
<a name="web-publish-subscribe-concepts-strategy"></a>

`StageStrategy`Antarmuka menyediakan cara bagi aplikasi host untuk mengkomunikasikan status tahap yang diinginkan ke SDK. Tiga fungsi perlu diimplementasikan:`shouldSubscribeToParticipant`,`shouldPublishParticipant`, dan`stageStreamsToPublish`. 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
<a name="web-publish-subscribe-concepts-strategy-participants"></a>

```
shouldSubscribeToParticipant(participant: StageParticipantInfo): SubscribeType
```

Ketika peserta jarak jauh bergabung dengan panggung, SDK menanyakan aplikasi host tentang status langganan yang diinginkan untuk peserta tersebut. Pilihannya adalah`NONE`,`AUDIO_ONLY`, dan`AUDIO_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 mempublikasikan sebelum berlangganan, dan memperbarui aplikasi host dengan memancarkan peristiwa 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 untuk melihat satu sama lain; 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
<a name="web-publish-subscribe-concepts-strategy-participants-config"></a>

```
subscribeConfiguration(participant: StageParticipantInfo): SubscribeConfiguration
```

Jika peserta jarak jauh sedang berlangganan (lihat [Berlangganan Peserta](#web-publish-subscribe-concepts-strategy-participants)), SDK akan 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](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference/interfaces/SubscribeConfiguration)di dokumentasi referensi SDK.

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 halnya`shouldSubscribeToParticipant`, 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
<a name="web-publish-subscribe-concepts-strategy-publishing"></a>

```
shouldPublishParticipant(participant: StageParticipantInfo): boolean
```

Setelah terhubung ke panggung, SDK menanyakan aplikasi host untuk melihat apakah peserta tertentu harus mempublikasikannya. 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
<a name="web-publish-subscribe-concepts-strategy-streams"></a>

```
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](#web-publish-subscribe-publish-stream).

#### Memperbarui Strategi
<a name="web-publish-subscribe-concepts-strategy-updates"></a>

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 seperti`hasUserTappedPublishButton`). Ketika variabel itu berubah berdasarkan interaksi oleh pengguna akhir, panggil `stage.refreshStrategy()` untuk memberi sinyal ke SDK bahwa ia harus menanyakan strategi untuk nilai terbaru, hanya menerapkan hal-hal yang telah berubah. Jika SDK mengamati bahwa `shouldPublishParticipant` nilainya telah berubah, SDK memulai proses publikasi. Jika kueri SDK dan semua fungsi mengembalikan nilai yang sama seperti sebelumnya, `refreshStrategy` panggilan tidak mengubah tahapan.

Jika nilai pengembalian `shouldSubscribeToParticipant` perubahan dari `AUDIO_VIDEO` ke`AUDIO_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
<a name="web-publish-subscribe-concepts-events"></a>

`Stage`Instance adalah emitor peristiwa. Menggunakan`stage.on()`, keadaan panggung dikomunikasikan ke aplikasi host. Pembaruan untuk UI aplikasi host biasanya dapat didukung sepenuhnya oleh peristiwa. 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_ADAPTION_CHANGED, (participant, stream, isAdapting) => ())
stage.on(StageEvents.STAGE_STREAM_LAYERS_CHANGED, (participant, stream, layers) => ())
stage.on(StageEvents.STAGE_STREAM_LAYER_SELECTED, (participant, stream, layer, reason) => ())
stage.on(StageEvents.STAGE_STREAM_MUTE_CHANGED, (participant, stream) => {})
stage.on(StageEvents.STAGE_STREAM_SEI_MESSAGE_RECEIVED, (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. SDK bertanggung jawab untuk memastikan bahwa keadaan strategi yang diinginkan ditindaklanjuti pada waktu yang tepat berdasarkan keadaan tahap.

## Publikasikan Aliran Media
<a name="web-publish-subscribe-publish-stream"></a>

Perangkat lokal seperti mikrofon dan kamera diambil menggunakan langkah yang sama seperti yang diuraikan di atas dalam [Ambil MediaStream ](broadcast-web-getting-started.md#broadcast-web-retrieve-mediastream) dari Perangkat. Dalam contoh yang kita gunakan `MediaStream` untuk membuat daftar `LocalStageStream` objek yang digunakan untuk penerbitan oleh SDK:

```
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
<a name="web-publish-subscribe-publish-screenshare"></a>

Aplikasi sering perlu mempublikasikan screenshare selain kamera web pengguna. Menerbitkan screenshare mengharuskan pembuatan 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
<a name="web-publish-subscribe-participants"></a>

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) => {
    let 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 dari DOM.

`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
<a name="web-publish-subscribe-mute-streams"></a>

`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 ke`refreshStrategy`, 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
<a name="web-publish-subscribe-mute-state"></a>

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](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference#stageparticipantinfo)informasi negara tentang apakah audio atau video diredam:

```
stage.on(StageEvents.STAGE_STREAM_MUTE_CHANGED, (participant, stream) => {
   if (participant.videoStopped || participant.audioMuted) {
       // handle UI changes for either video or audio
   }
})
```

## Dapatkan Statistik WebRTC
<a name="web-publish-subscribe-webrtc-stats"></a>

`requestQualityStats()`Metode ini menyediakan akses ke statistik WebRTC terperinci untuk aliran lokal dan jarak jauh. Ini tersedia pada keduanya LocalStageStream dan RemoteStageStream objek. Ini mengembalikan metrik kualitas yang komprehensif termasuk kualitas jaringan, statistik paket, informasi bitrate, dan metrik terkait bingkai.

Ini adalah metode asinkron yang dengannya Anda dapat mengambil statistik baik melalui await atau dengan merantai janji. Ini kembali `undefined` ketika statistik tidak tersedia; misalnya, aliran tidak aktif atau statistik internal tidak tersedia. Jika statistik tersedia, dan tergantung pada aliran (jarak jauh atau lokal, video atau audio), metode mengembalikan [LocalVideoStats](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference/interfaces/LocalVideoStats), [LocalAudioStats](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference/interfaces/LocalAudioStats), [RemoteVideoStats](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference/interfaces/RemoteVideoStats), atau [RemoteAudioStats](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference/interfaces/RemoteAudioStats)objek.

Perhatikan bahwa untuk streaming video dengan simulcast, array berisi beberapa objek stat (satu per lapisan).

**Praktik Terbaik**
+ Frekuensi polling - Panggilan `requestQualityStats()` pada interval yang wajar (1-5 detik) untuk menghindari dampak kinerja
+ Penanganan kesalahan - Selalu periksa apakah nilai yang dikembalikan `undefined` sebelum diproses
+ Manajemen memori — Hapus intervals/timeouts saat aliran tidak lagi diperlukan
+ Kualitas jaringan — Gunakan `networkQuality` untuk umpan balik pengguna mengenai kemungkinan degradasi yang disebabkan oleh jaringan. Lihat perinciannya di [NetworkQuality](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference/enumerations/NetworkQuality).

**Contoh Penggunaan**

```
// For local streams
const localStats = await localVideoStream.requestQualityStats();
const audioStats = await localAudioStream.requestQualityStats();

// For remote streams
const remoteVideoStats = await remoteVideoStream.requestQualityStats();
const remoteAudioStats = await remoteAudioStream.requestQualityStats();

// Example: Monitor stats every 10 seconds
const statsInterval = setInterval(async () => {
   const stats = await localVideoStream.requestQualityStats();
   if (stats) {
      // Note: If simulcast is enabled, you may receive multiple 
      // stats records for each layer
      stats.forEach(layer => {
         const rid = layer.rid || 'default';
         console.log(`Layer ${rid}:`, {
            active: layer.active,
            networkQuality: layer.networkQuality,
            packetsSent: layer.packetsSent,
            bytesSent: layer.bytesSent,
            resolution: `${layer.frameWidth}x${layer.frameHeight}`,
            fps: layer.framesPerSecond
         });
      });
   }
}, 10000);
```

## Mengoptimalkan Media
<a name="web-publish-subscribe-optimizing-media"></a>

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.
  + Hal ini memungkinkan server untuk memilih rendisi mana yang akan dikirim ke peserta lain, berdasarkan keterbatasan jaringan mereka.
  + Ketika `simulcast` ditentukan bersama dengan `maxBitrate` and/or `maxFramerate` nilai, diharapkan bahwa lapisan rendisi tertinggi akan dikonfigurasi dengan nilai-nilai ini dalam pikiran, asalkan `maxBitrate` tidak berada di bawah `maxBitrate` nilai default lapisan tertinggi kedua SDK internal yaitu 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 kombinasi `shouldPublishParticipant` pengembalian`false`, panggilan, pengembalian, `true` dan panggilan `refreshStrategy` `shouldPublishParticipant` lagi. `refreshStrategy`

## Dapatkan Atribut Peserta
<a name="web-publish-subscribe-participant-attributes"></a>

Jika Anda menentukan atribut dalam permintaan `CreateParticipantToken` operasi, Anda dapat melihat atribut di `StageParticipantInfo` properti:

```
stage.on(StageEvents.STAGE_PARTICIPANT_JOINED, (participant) => {
   console.log(`Participant ${participant.id} info:`, participant.attributes);
})
```

## Informasi Peningkatan Tambahan (SEI)
<a name="web-publish-subscribe-sei-attributes"></a>

Unit Supplemental Enhancement Information (SEI) NAL digunakan untuk menyimpan metadata yang selaras dengan bingkai di samping video. Ini dapat digunakan saat menerbitkan dan berlangganan aliran video H.264. Payload SEI tidak dijamin sampai ke pelanggan, terutama dalam kondisi jaringan yang buruk. Karena muatan SEI menyimpan data secara langsung dalam struktur bingkai H.264, kemampuan ini tidak dapat dimanfaatkan untuk aliran audio saja.

### Memasukkan Muatan SEI
<a name="sei-attributes-inserting-sei-payloads"></a>

Klien penerbitan dapat memasukkan muatan SEI ke aliran panggung yang sedang dipublikasikan dengan mengonfigurasi video mereka LocalStageStream untuk mengaktifkan `inBandMessaging` dan kemudian menjalankan metode. `insertSeiMessage` Perhatikan bahwa mengaktifkan `inBandMessaging` meningkatkan penggunaan memori SDK.

Muatan harus dari [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer)jenisnya. Ukuran muatan harus lebih besar dari 0KB dan kurang dari 1KB. Jumlah pesan SEI yang dimasukkan per detik tidak boleh melebihi 10KB per detik.

```
const config = {
    inBandMessaging: { enabled: true }
};
const vidStream = new LocalStageStream(videoTrack, config);
const payload = new TextEncoder().encode('hello world').buffer;
vidStream.insertSeiMessage(payload);
```

#### Mengulangi Muatan SEI
<a name="sei-attributes-repeating-sei-payloads"></a>

Opsional menyediakan `repeatCount` untuk mengulangi penyisipan muatan SEI untuk N frame berikutnya yang dikirim. Ini dapat membantu untuk mengurangi kerugian bawaan yang mungkin terjadi karena protokol transportasi UDP yang mendasari yang digunakan untuk mengirim video. Perhatikan nilai ini harus antara 0 dan 30. Klien yang menerima harus memiliki logika untuk menghapus duplikat pesan.

```
vidStream.insertSeiMessage(payload, { repeatCount: 5 }); // Optional config, repeatCount must be between 0 and 30
```

### Membaca Muatan SEI
<a name="sei-attributes-reading-sei-payloads"></a>

Klien berlangganan dapat membaca muatan SEI dari penerbit yang menerbitkan video H.264 jika ada dengan mengonfigurasi pelanggan `SubscribeConfiguration` untuk mengaktifkan `inBandMessaging` dan mendengarkan acara, seperti yang ditunjukkan pada `StageEvents.STAGE_STREAM_SEI_MESSAGE_RECEIVED` contoh berikut:

```
const strategy = {
    subscribeConfiguration: (participant) => {
        return {
            inBandMessaging: {
                enabled: true
            }
        }
    }
    // ... other strategy functions
}

stage.on(StageEvents.STAGE_STREAM_SEI_MESSAGE_RECEIVED, (participant, seiMessage) => {
    console.log(seiMessage.payload, seiMessage.uuid);
});
```

## Pengkodean Berlapis dengan Simulcast
<a name="web-publish-subscribe-layered-encoding-simulcast"></a>

Layered encoding dengan simulcast adalah fitur streaming real-time IVS yang memungkinkan penerbit mengirim beberapa lapisan video berkualitas berbeda, dan pelanggan untuk mengubah lapisan tersebut secara dinamis atau manual. Fitur ini dijelaskan lebih lanjut dalam dokumen [Pengoptimalan Streaming](https://docs.aws.amazon.com//ivs/latest/RealTimeUserGuide/real-time-streaming-optimization.html).

### Mengkonfigurasi Layered Encoding (Publisher)
<a name="web-layered-encoding-simulcast-configure-publisher"></a>

Sebagai penerbit, untuk mengaktifkan pengkodean berlapis dengan simulcast, tambahkan konfigurasi berikut ke instantiasi saat Anda: `LocalStageStream`

```
// Enable Simulcast
let cameraStream = new LocalStageStream(cameraDevice, {
   simulcast: { enabled: true }
})
```

*Bergantung pada resolusi input perangkat kamera Anda, sejumlah lapisan akan dikodekan dan dikirim seperti yang didefinisikan di bagian [Default Layers, Quality, dan Framerates](real-time-streaming-optimization.md#real-time-streaming-optimization-default-layers) dari Pengoptimalan Streaming.*

Selain itu, Anda dapat secara opsional mengonfigurasi lapisan individual dari dalam konfigurasi simulcast:

```
import { SimulcastLayerPresets } from ‘amazon-ivs-web-broadcast’

// Enable Simulcast
let cameraStream = new LocalStageStream(cameraDevice, {
   simulcast: {
      enabled: true,
      layers: [
         SimulcastLayerPresets.DEFAULT_720,
          SimulcastLayerPresets.DEFAULT_360,
          SimulcastLayerPresets.DEFAULT_180, 
   }
})
```

Sebagai alternatif, Anda dapat membuat konfigurasi lapisan kustom Anda sendiri hingga tiga lapisan. Jika Anda memberikan array kosong atau tidak ada nilai, default yang dijelaskan di atas digunakan. Lapisan dijelaskan dengan properti yang diperlukan berikut:
+ `height: number;`
+ `width: number;`
+ `maxBitrateKbps: number;`
+ `maxFramerate: number;`

Mulai dari preset, Anda dapat mengganti properti individual atau membuat konfigurasi yang sama sekali baru:

```
import { SimulcastLayerPresets } from ‘amazon-ivs-web-broadcast’

const custom720pLayer = {
   ...SimulcastLayerPresets.DEFAULT_720,
   maxFramerate: 15,
}

const custom360pLayer = {
       maxBitrateKbps: 600,
       maxFramerate: 15,
       width: 640,
       height: 360,
}

// Enable Simulcast
let cameraStream = new LocalStageStream(cameraDevice, {
   simulcast: {
      enabled: true,
      layers: [
         custom720pLayer,
         custom360pLayer, 
   }
})
```

Untuk nilai maksimum, batas, dan kesalahan yang dapat dipicu saat mengonfigurasi lapisan individual, lihat dokumentasi referensi SDK.

### Mengkonfigurasi Layered Encoding (Subscriber)
<a name="web-layered-encoding-simulcast-configure-subscriber"></a>

Sebagai pelanggan, tidak ada yang diperlukan untuk mengaktifkan pengkodean berlapis. Jika penerbit mengirim lapisan simulcast, maka secara default server secara dinamis beradaptasi di antara lapisan untuk memilih kualitas optimal berdasarkan perangkat pelanggan dan kondisi jaringan.

Atau, untuk memilih lapisan eksplisit yang dikirimkan penerbit, ada beberapa opsi, yang dijelaskan di bawah ini.

### Opsi 1: Preferensi Kualitas Lapisan Awal
<a name="web-layered-encoding-simulcast-layer-quality-preference"></a>

Dengan menggunakan `subscribeConfiguration` strategi, dimungkinkan untuk memilih lapisan awal apa yang ingin Anda terima sebagai pelanggan:

```
const strategy = {
    subscribeConfiguration: (participant) => {
        return {
            simulcast: {
                initialLayerPreference: InitialLayerPreference.LOWEST_QUALITY
            }
        }
    }
    // ... other strategy functions
}
```

Secara default, pelanggan selalu dikirim lapisan kualitas terendah terlebih dahulu; ini perlahan naik ke lapisan kualitas tertinggi. Ini mengoptimalkan konsumsi bandwidth pengguna akhir dan memberikan waktu terbaik untuk video, mengurangi pembekuan video awal bagi pengguna di jaringan yang lebih lemah.

Opsi ini tersedia untuk`InitialLayerPreference`:
+ `LOWEST_QUALITY`— Server memberikan lapisan video dengan kualitas terendah terlebih dahulu. Ini mengoptimalkan konsumsi bandwidth, serta waktu ke media. Kualitas didefinisikan sebagai kombinasi ukuran, bitrate, dan framerate video. Misalnya, video 720p memiliki kualitas lebih rendah dari video 1080p.
+ `HIGHEST_QUALITY`— Server memberikan lapisan video kualitas tertinggi terlebih dahulu. Ini mengoptimalkan kualitas tetapi dapat meningkatkan waktu ke media. Kualitas didefinisikan sebagai kombinasi ukuran, bitrate, dan framerate video. Misalnya, video 1080p memiliki kualitas lebih tinggi dari video 720p.

**Catatan:** Agar preferensi lapisan awal (`initialLayerPreference`panggilan) diterapkan, berlangganan ulang diperlukan karena pembaruan ini tidak berlaku untuk langganan aktif.



### Opsi 2: Lapisan Pilihan untuk Stream
<a name="web-layered-encoding-simulcast-preferred-layer"></a>

Setelah streaming dimulai, Anda dapat menggunakan metode `preferredLayerForStream ` strategi. Metode strategi ini mengekspos peserta dan informasi aliran.

Metode strategi dapat dikembalikan dengan yang berikut:
+ Objek layer secara langsung, berdasarkan apa yang `RemoteStageStream.getLayers` kembali 
+ String label objek lapisan, berdasarkan `StageStreamLayer.label`
+ Tidak terdefinisi atau null, yang menunjukkan bahwa tidak ada lapisan yang harus dipilih, dan adaptasi dinamis lebih disukai

Misalnya, strategi berikut akan selalu membuat pengguna memilih lapisan video dengan kualitas terendah yang tersedia:

```
const strategy = {
    preferredLayerForStream: (participant, stream) => {
        return stream.getLowestQualityLayer();
    }
    // ... other strategy functions
}
```

Untuk mengatur ulang pemilihan lapisan dan kembali ke adaptasi dinamis, kembalikan null atau undefined dalam strategi. Dalam contoh ini `appState` adalah variabel dummy yang mewakili status aplikasi yang mungkin.

```
const strategy = {
    preferredLayerForStream: (participant, stream) => {
        if (appState.isAutoMode) {
            return null;
        } else {
            return appState.layerChoice
        }
    }
    // ... other strategy functions
}
```

### Opsi 3: Pembantu RemoteStageStream Lapisan
<a name="web-layered-encoding-simulcast-remotestagestream-helpers"></a>

`RemoteStageStream`memiliki beberapa pembantu yang dapat digunakan untuk membuat keputusan tentang pemilihan lapisan dan menampilkan pilihan yang sesuai untuk pengguna akhir:
+ **Layer Events** — Di samping itu`StageEvents`, `RemoteStageStream` objek itu sendiri memiliki peristiwa yang mengkomunikasikan perubahan adaptasi layer dan simulcast:
  + `stream.on(RemoteStageStreamEvents.ADAPTION_CHANGED, (isAdapting) => {})`
  + `stream.on(RemoteStageStreamEvents.LAYERS_CHANGED, (layers) => {})`
  + `stream.on(RemoteStageStreamEvents.LAYER_SELECTED, (layer, reason) => {})`
+ **Metode Layer** — `RemoteStageStream` memiliki beberapa metode pembantu yang dapat digunakan untuk mendapatkan informasi tentang aliran dan lapisan yang disajikan. Metode ini tersedia di aliran jarak jauh yang disediakan dalam `preferredLayerForStream ` strategi, serta aliran jarak jauh yang diekspos melalui`StageEvents.STAGE_PARTICIPANT_STREAMS_ADDED`.
  + `stream.getLayers`
  + `stream.getSelectedLayer`
  + `stream.getLowestQualityLayer`
  + `stream.getHighestQualityLayer`

Untuk detailnya, lihat `RemoteStageStream` kelas dalam [dokumentasi referensi SDK](https://aws.github.io/amazon-ivs-web-broadcast/docs/sdk-reference). Untuk `LAYER_SELECTED` alasannya, jika `UNAVAILABLE` dikembalikan, ini menunjukkan bahwa lapisan yang diminta tidak dapat dipilih. Pilihan upaya terbaik dilakukan sebagai gantinya, yang biasanya merupakan lapisan kualitas yang lebih rendah untuk menjaga stabilitas aliran.

## Menangani Masalah Jaringan
<a name="web-publish-subscribe-network-issues"></a>

Ketika koneksi jaringan perangkat lokal terputus, SDK secara internal mencoba menyambung kembali tanpa tindakan pengguna apa pun. 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
         return;
      case StageConnectionState.CONNECTING:
         // handle establishing connection UI
         return;
      case StageConnectionState.CONNECTED:
         // SDK is connected to the Stage
         return;
      case StageConnectionState.ERRORED:
         // SDK encountered an error and lost its connection to the stage. Wait for CONNECTED.
         return;
    }
})
```

Secara umum, Anda dapat mengabaikan status kesalahan yang ditemui setelah berhasil bergabung dengan tahap, karena SDK akan mencoba memulihkan secara internal. Jika SDK melaporkan `ERRORED` status dan tahapan tetap dalam `CONNECTING` status untuk jangka waktu yang lama (misalnya, 30 detik atau lebih), Anda mungkin terputus dari jaringan.

## Siarkan Panggung ke Saluran IVS
<a name="web-publish-subscribe-broadcast-stage"></a>

Untuk menyiarkan panggung, buat `IVSBroadcastClient` sesi terpisah dan kemudian ikuti instruksi biasa untuk penyiaran dengan SDK, yang 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 latensi rendah IVS, untuk menjangkau audiens yang lebih besar. Lihat [Mengaktifkan Beberapa Host di Amazon IVS Stream di Panduan Pengguna Streaming](https://docs.aws.amazon.com//ivs/latest/LowLatencyUserGuide/multiple-hosts.html) Latensi Rendah IVS.

# Masalah & Solusi yang Diketahui di SDK Siaran Web IVS \$1 Streaming Waktu Nyata
<a name="broadcast-web-known-issues"></a>

Dokumen ini mencantumkan masalah yang diketahui yang mungkin Anda temui saat menggunakan SDK siaran Web streaming real-time Amazon IVS dan menyarankan solusi potensial.
+ Saat menutup tab browser atau keluar dari browser tanpa menelepon`stage.leave()`, pengguna masih dapat muncul dalam sesi dengan bingkai beku atau layar hitam hingga 10 detik.

  **Solusi**: Tidak ada.
+ Sesi Safari sebentar-sebentar muncul dengan layar hitam untuk pengguna yang bergabung setelah sesi dimulai.

  **Solusi:** Segarkan browser dan sambungkan kembali sesi.
+ Safari tidak pulih dengan anggun dari switching jaringan.

  **Solusi:** Segarkan browser dan sambungkan kembali sesi.
+ Konsol pengembang mengulangi `Error: UnintentionalError at StageSocket.onClose` kesalahan.

  **Solusi:** Hanya satu tahap yang dapat dibuat per token peserta. Kesalahan ini terjadi ketika lebih dari satu `Stage` instance dibuat dengan token peserta yang sama, terlepas dari apakah instance tersebut ada di satu perangkat atau beberapa perangkat.
+ Anda mungkin mengalami kesulitan mempertahankan `StageParticipantPublishState.PUBLISHED` status dan mungkin menerima `StageParticipantPublishState.ATTEMPTING_PUBLISH` status berulang saat mendengarkan `StageEvents.STAGE_PARTICIPANT_PUBLISH_STATE_CHANGED` acara tersebut.

  **Solusi:** Batasi resolusi video ke 720p saat memanggil atau. `getUserMedia` `getDisplayMedia` Secara khusus, nilai Anda `getUserMedia` dan `getDisplayMedia` batasan untuk lebar dan tinggi tidak boleh melebihi 921600 (1280\$1 720) saat dikalikan bersama.
+ Ketika `stage.leave()` dipanggil atau peserta jarak jauh pergi, kesalahan 404 DELETE muncul di konsol debug browser.

  **Solusi**: Tidak ada. Ini adalah kesalahan yang tidak berbahaya.

## Keterbatasan Safari
<a name="broadcast-web-safari-limitations"></a>
+ Menolak prompt izin memerlukan pengaturan ulang izin di pengaturan situs web Safari di tingkat OS.
+ Safari tidak secara native mendeteksi semua perangkat seefektif Firefox atau Chrome. Misalnya, OBS Virtual Camera tidak terdeteksi.

## Keterbatasan Firefox
<a name="broadcast-web-firefox-limitations"></a>
+ Izin sistem harus diaktifkan agar Firefox dapat berbagi layar. Setelah mengaktifkannya, pengguna harus me-restart Firefox agar berfungsi dengan benar; jika tidak, jika izin dianggap diblokir, browser akan memberikan [NotFoundError](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia#exceptions)pengecualian.
+ `getCapabilities`Metodenya hilang. Ini berarti pengguna tidak bisa mendapatkan resolusi atau rasio aspek trek media. Lihat utas [bugzilla](https://bugzilla.mozilla.org/show_bug.cgi?id=1179084) ini.
+ Beberapa `AudioContext` properti hilang; misalnya, latensi dan jumlah saluran. Ini bisa menimbulkan masalah bagi pengguna tingkat lanjut yang ingin memanipulasi trek audio.
+ Umpan kamera dari `getUserMedia` dibatasi hingga rasio aspek 4:3 di macOS. Lihat utas [bugzilla 1 dan utas](https://bugzilla.mozilla.org/show_bug.cgi?id=1193640) [bugzilla](https://bugzilla.mozilla.org/show_bug.cgi?id=1306034) 2.
+ Pengambilan audio tidak didukung dengan`getDisplayMedia`. Lihat utas [bugzilla](https://bugzilla.mozilla.org/show_bug.cgi?id=1541425) ini.
+ Framerate dalam tangkapan layar kurang optimal (sekitar 15fps?). Lihat utas [bugzilla](https://bugzilla.mozilla.org/show_bug.cgi?id=1703522) ini.

## Batasan Web Seluler
<a name="broadcast-web-mobile-web-limitations"></a>
+ [getDisplayMedia](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia#browser_compatibility)berbagi layar tidak didukung di perangkat seluler.

  **Solusi**: Tidak ada.
+ Peserta membutuhkan waktu 15-30 detik untuk pergi saat menutup browser tanpa menelepon`leave()`.

  **Solusi**: Tambahkan UI yang mendorong pengguna untuk memutuskan sambungan dengan benar.
+ Aplikasi latar belakang menyebabkan penerbitan video berhenti.

  **Solusi**: Menampilkan papan tulis UI saat penerbit dijeda.
+ Video framerate turun selama kurang lebih 5 detik setelah mematikan kamera di perangkat Android.

  **Solusi**: Tidak ada.
+ Umpan video diregangkan pada rotasi untuk iOS 16.0.

  **Solusi**: Tampilkan UI yang menguraikan masalah OS yang diketahui ini.
+ Mengalihkan perangkat input audio secara otomatis mengalihkan perangkat output audio.

  **Solusi**: Tidak ada.
+ Latar belakang browser menyebabkan aliran penerbitan menjadi hitam dan hanya menghasilkan audio.

  **Solusi**: Tidak ada. Ini untuk alasan keamanan.

# Penanganan Kesalahan di SDK Siaran Web IVS \$1 Streaming Waktu Nyata
<a name="broadcast-web-error-handling"></a>

Bagian ini adalah ikhtisar kondisi kesalahan, bagaimana SDK siaran Web melaporkannya ke aplikasi, dan apa yang harus dilakukan aplikasi ketika kesalahan tersebut ditemui. Kesalahan dilaporkan oleh SDK kepada pendengar acara: `StageEvents.ERROR`

```
stage.on(StageEvents.ERROR, (error: StageError) => {
    // log or handle errors here
    console.log(`${error.code}, ${error.category}, ${error.message}`);
});
```

## Kesalahan Panggung
<a name="web-error-handling-stage-errors"></a>

A StageError dilaporkan ketika SDK mengalami masalah yang tidak dapat dipulihkan dan umumnya memerlukan koneksi ulang and/or jaringan intervensi aplikasi untuk pulih.

Setiap dilaporkan `StageError` memiliki kode (atau`StageErrorCode`), pesan (string), dan kategori (`StageErrorCategory`). Masing-masing terkait dengan kategori operasi yang mendasarinya.

Kategori operasi kesalahan ditentukan berdasarkan apakah itu terkait dengan koneksi ke tahap (`JOIN_ERROR`), mengirim media ke tahap (`PUBLISH_ERROR`), atau menerima aliran media yang masuk dari tahap (`SUBSCRIBE_ERROR`).

Properti kode `StageError` melaporkan masalah spesifik:


| Nama | Kode | Tindakan yang Direkomendasikan | 
| --- | --- | --- | 
| TOKEN\$1MALFORMED | 1 | Buat token yang valid dan coba lagi membuat instance stage. | 
| TOKEN\$1KEDALUWARSA | 2 | Buat token yang belum kedaluwarsa dan coba lagi membuat instance panggung. | 
| BATAS WAKTU | 3 | Waktu operasi habis. Jika tahap ada dan token valid, kegagalan ini kemungkinan merupakan masalah jaringan. Dalam hal ini, tunggu konektivitas perangkat pulih. | 
| FAILED | 4 | Kondisi fatal ditemui ketika mencoba operasi. Periksa detail kesalahan. Jika tahap ada dan token valid, kegagalan ini kemungkinan merupakan masalah jaringan. Dalam hal ini, tunggu konektivitas perangkat pulih. Untuk sebagian besar kegagalan yang terkait dengan stabilitas jaringan, SDK akan mencoba lagi secara internal untuk jangka waktu hingga 30 detik sebelum memancarkan kesalahan GAGAL.  | 
| MEMBATALKAN | 5 | Periksa kode aplikasi dan pastikan tidak ada pemanggilan berulang `join``refreshStrategy`, atau `replaceStrategy` pemanggilan, yang dapat menyebabkan operasi berulang dimulai dan dibatalkan sebelum selesai. | 
| STAGE\$1AT\$1CAPACITY | 6 | Kesalahan ini menunjukkan bahwa panggung atau akun Anda dalam kapasitas. Jika tahap telah mencapai batas pesertanya, coba operasi lagi ketika tahap tidak lagi dalam kapasitas, dengan menyegarkan strategi. [Jika akun Anda telah mencapai langganan bersamaan atau kuota penayang bersamaan, kurangi penggunaan atau minta peningkatan kuota melalui konsol AWS Service Quotas.](https://console.aws.amazon.com/servicequotas/)  | 
| CODEC\$1MISMATCH | 7 | Codec tidak didukung oleh panggung. Periksa browser dan platform untuk dukungan codec. Untuk streaming real-time IVS, browser harus mendukung codec H.264 untuk video dan codec Opus untuk audio. | 
| TOKEN\$1NOT\$1ALLOWED | 8 | Token tidak memiliki izin untuk operasi. Buat ulang token dengan izin yang benar dan coba lagi. | 
| STAGE\$1DELETED | 9 | Tidak ada; mencoba bergabung dengan tahap yang dihapus memicu kesalahan ini. | 
| PARTISIPANT\$1TERPUTUS | 10 | Tidak ada; mencoba bergabung dengan token peserta yang terputus memicu kesalahan ini. | 

### StageError Contoh Penanganan
<a name="web-error-handling-stage-errors-example"></a>

Gunakan StageError kode untuk menentukan apakah kesalahan disebabkan oleh token yang kedaluwarsa:

```
stage.on(StageEvents.ERROR, (error: StageError) => {
    if (error.code === StageError.TOKEN_EXPIRED) {
        // recreate the token and stage instance and re-join
    }
});
```

### Kesalahan Jaringan saat Sudah Bergabung
<a name="web-error-handling-stage-errors-network"></a>

Jika koneksi jaringan perangkat mati, SDK mungkin kehilangan koneksinya ke server panggung. Anda mungkin melihat kesalahan di konsol karena SDK tidak dapat lagi menjangkau layanan backend. POSTs ke https://broadcast.stats.live-video.net akan gagal.

Jika Anda menerbitkan and/or langganan, Anda akan melihat kesalahan di konsol terkait dengan upaya untuk menerbitkan/berlangganan.

Secara internal SDK akan mencoba terhubung kembali dengan strategi backoff eksponensial.

**Tindakan**: Tunggu konektivitas perangkat pulih.

## Negara Tersalah
<a name="web-error-handling-errored-states"></a>

Kami menyarankan Anda menggunakan status ini untuk pencatatan aplikasi dan untuk menampilkan pesan kepada pengguna yang memberi tahu mereka tentang masalah konektivitas ke panggung untuk peserta tertentu.

### Publikasikan
<a name="errored-states-publish"></a>

SDK melaporkan `ERRORED` saat publikasi gagal.

```
stage.on(StageEvents.STAGE_PARTICIPANT_PUBLISH_STATE_CHANGED, (participantInfo, state) => {
  if (state === StageParticipantPublishState.ERRORED) {
      // Log and/or display message to user
  }
});
```

### Langganan
<a name="errored-states-subscribe"></a>

SDK melaporkan `ERRORED` saat berlangganan gagal. Ini dapat terjadi karena kondisi jaringan atau jika suatu tahap berada pada kapasitas untuk pelanggan.

```
stage.on(StageEvents.STAGE_PARTICIPANT_SUBSCRIBE_STATE_CHANGED, (participantInfo, state) => {
  if (state === StageParticipantSubscribeState.ERRORED) {
    // Log and/or display message to user
  }
});
```