

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

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

IVS real-time streaming Android broadcast SDK memungkinkan peserta untuk mengirim dan menerima video di Android.

Paket `com.amazonaws.ivs.broadcast` mengimplementasikan antarmuka yang dijelaskan dalam dokumen ini. 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 Android streaming latensi rendah IVS

**Versi terbaru SDK siaran Android:** [1.40.0 (Catatan Rilis)](https://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/release-notes.html#mar12-26-broadcast-android-rt) 

**Dokumentasi referensi:** [Untuk informasi tentang metode terpenting yang tersedia di SDK siaran Android Amazon IVS, lihat dokumentasi referensi di https://aws.github. io/amazon-ivs-broadcast-docs/1.40.0/android](https://aws.github.io/amazon-ivs-broadcast-docs/1.40.0/android/)/.

**Contoh kode:** [Lihat repositori contoh Android di GitHub: https://github.com/aws-samples/ amazon-ivs-real-time -. streaming-android-samples](https://github.com/aws-samples/amazon-ivs-real-time-streaming-android-samples)

**Persyaratan platform:** Android 9.0\$1

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

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

## Instal Perpustakaan
<a name="broadcast-android-install"></a>

Ada beberapa cara untuk menambahkan library siaran Android Amazon IVS ke lingkungan pengembangan Android Anda: gunakan Gradle secara langsung, gunakan katalog versi Gradle, atau instal SDK secara manual.

**Gunakan Gradle secara langsung**: Tambahkan pustaka ke `build.gradle` file modul Anda, seperti yang ditunjukkan di sini (untuk versi terbaru SDK siaran IVS):

```
repositories {
    mavenCentral()
}
 
dependencies {
     implementation 'com.amazonaws:ivs-broadcast:1.40.0:stages@aar'
}
```

**Gunakan katalog versi Gradle**: Pertama sertakan ini dalam file modul Anda: `build.gradle`

```
implementation(libs.ivs){
   artifact {
      classifier = "stages"
      type = "aar"
   }
}
```

Kemudian sertakan yang berikut ini dalam `libs.version.toml` file (untuk versi terbaru SDK siaran IVS):

```
[versions]
ivs="1.40.0"

[libraries]
ivs = {module = "com.amazonaws:ivs-broadcast", version.ref = "ivs"}
```

**Instal SDK secara manual**: Unduh versi terbaru dari lokasi ini:

[https://search.maven.org/artifact/com.amazonaws/ivs-broadcast](https://search.maven.org/artifact/com.amazonaws/ivs-broadcast)

Pastikan untuk mengunduh `aar` dengan `-stages` menambahkan.

**Juga izinkan kontrol SDK atas speakerphone**: Terlepas dari metode penginstalan yang Anda pilih, tambahkan juga izin berikut ke manifes Anda, untuk memungkinkan SDK mengaktifkan dan menonaktifkan speakerphone:

```
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
```

## Menggunakan SDK dengan Simbol Debug
<a name="broadcast-android-using-debug-symbols-rt"></a>

Kami juga menerbitkan versi SDK siaran Android yang menyertakan simbol debug. Anda dapat menggunakan versi ini untuk meningkatkan kualitas laporan debug (jejak tumpukan) di Firebase Crashlytics, jika Anda mengalami crash di SDK broadcast IVS; yaitu,. `libbroadcastcore.so` Saat Anda melaporkan crash ini ke tim IVS SDK, jejak tumpukan berkualitas lebih tinggi memudahkan untuk memperbaiki masalah.

Untuk menggunakan versi SDK ini, letakkan yang berikut ini di file build Gradle Anda:

```
implementation "com.amazonaws:ivs-broadcast:$version:stages-unstripped@aar"
```

Gunakan baris di atas alih-alih ini:

```
implementation "com.amazonaws:ivs-broadcast:$version:stages@aar"
```

### Mengunggah Simbol ke Firebase Crashlytics
<a name="android-debug-symbols-rt-firebase-crashlytics"></a>

Pastikan file build Gradle Anda disiapkan untuk Firebase Crashlytics. Ikuti instruksi Google di sini:

[https://firebase.google.com/docs/crashlytics/ndk-laporan](https://firebase.google.com/docs/crashlytics/ndk-reports)

Pastikan untuk memasukkan `com.google.firebase:firebase-crashlytics-ndk` sebagai ketergantungan.

Saat membuat aplikasi Anda untuk rilis, plugin Firebase Crashlytics akan mengunggah simbol secara otomatis. Untuk mengunggah simbol secara manual, jalankan salah satu dari berikut ini:

```
gradle uploadCrashlyticsSymbolFileRelease
```

```
./gradlew uploadCrashlyticsSymbolFileRelease
```

(Tidak ada salahnya jika simbol diunggah dua kali, baik secara otomatis maupun manual.)

### Mencegah Rilis Anda .apk dari Menjadi Lebih Besar
<a name="android-debug-symbols-rt-sizing-apk"></a>

Sebelum mengemas `.apk` file rilis, Plugin Android Gradle secara otomatis mencoba menghapus informasi debug dari pustaka bersama (termasuk library SDK siaran IVS). `libbroadcastcore.so` Namun, terkadang hal ini tidak terjadi. Akibatnya, `.apk` file Anda bisa menjadi lebih besar dan Anda bisa mendapatkan pesan peringatan dari Plugin Android Gradle bahwa file tersebut tidak dapat menghapus simbol debug dan mengemas `.so` file apa adanya. Jika ini terjadi, lakukan hal berikut:
+ Instal Android NDK. Versi terbaru apa pun akan berfungsi.
+ Tambahkan `ndkVersion <your_installed_ndk_version_number>` ke `build.gradle` file aplikasi Anda. Lakukan ini bahkan jika aplikasi Anda sendiri tidak mengandung kode asli.

Untuk informasi selengkapnya, lihat [laporan masalah](https://issuetracker.google.com/issues/353554169) ini.

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

Aplikasi Anda harus meminta izin untuk mengakses kamera dan mikrofon pengguna. (Ini tidak spesifik untuk Amazon IVS; diperlukan untuk aplikasi apa pun yang membutuhkan akses ke kamera dan mikrofon.)

Di sini, kami memeriksa apakah pengguna telah memberikan izin dan, jika tidak, memintanya:

```
final String[] requiredPermissions =
         { Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO };

for (String permission : requiredPermissions) {
    if (ContextCompat.checkSelfPermission(this, permission) 
                != PackageManager.PERMISSION_GRANTED) {
        // If any permissions are missing we want to just request them all.
        ActivityCompat.requestPermissions(this, requiredPermissions, 0x100);
        break;
    }
}
```

Di sini, kami mendapatkan respons pengguna:

```
@Override
public void onRequestPermissionsResult(int requestCode, 
                                      @NonNull String[] permissions,
                                      @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode,
               permissions, grantResults);
    if (requestCode == 0x100) {
        for (int result : grantResults) {
            if (result == PackageManager.PERMISSION_DENIED) {
                return;
            }
        }
        setupBroadcastSession();
    }
}
```

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

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

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

Tiga konsep inti mendasari fungsionalitas real-time: [panggung](#android-publish-subscribe-concepts-stage), [strategi](#android-publish-subscribe-concepts-strategy), dan [penyaji](#android-publish-subscribe-concepts-renderer). Tujuan desain adalah meminimalkan jumlah logika sisi klien yang diperlukan untuk membangun produk yang berfungsi.

### Stage
<a name="android-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. 

```
Stage stage = new Stage(context, token, strategy);

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

stage.leave();
```

`Stage`Kelas juga di mana `StageRenderer` dapat dilampirkan:

```
stage.addRenderer(renderer); // multiple renderers can be added
```

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

`Stage.Strategy`Antarmuka menyediakan cara bagi aplikasi host untuk mengkomunikasikan status tahap yang diinginkan ke SDK. Tiga fungsi perlu diimplementasikan:`shouldSubscribeToParticipant`,`shouldPublishFromParticipant`, dan`stageStreamsToPublishForParticipant`. Semua dibahas di bawah ini.

#### Berlangganan Peserta
<a name="android-publish-subscribe-concepts-strategy-participants"></a>

```
Stage.SubscribeType shouldSubscribeToParticipant(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo);
```

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 memublikasikan sebelum berlangganan, dan memperbarui aplikasi host melalui perender selama proses berlangsung.

Berikut adalah contoh implementasi:

```
@Override
Stage.SubscribeType shouldSubscribeToParticipant(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo) {
	return Stage.SubscribeType.AUDIO_VIDEO;
}
```

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. Gunakan `userInfo` properti `ParticipantInfo` untuk berlangganan peserta secara selektif berdasarkan atribut yang disediakan server:

```
@Override
Stage.SubscribeType shouldSubscribeToParticipant(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo) {
	switch(participantInfo.userInfo.get(“role”)) {
		case “moderator”:
			return Stage.SubscribeType.NONE;
		case “guest”:
			return Stage.SubscribeType.AUDIO_VIDEO;
		default:
			return Stage.SubscribeType.NONE;
	}
}
```

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 moderat melihat satu sama lain tetapi tetap tidak terlihat oleh tamu.

#### Konfigurasi untuk Berlangganan Peserta
<a name="android-publish-subscribe-concepts-strategy-participants-config"></a>

```
SubscribeConfiguration subscribeConfigurationForParticipant(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo);
```

Jika peserta jarak jauh sedang berlangganan (lihat [Berlangganan Peserta](#android-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:

```
@Override
public SubscribeConfiguration subscribeConfigrationForParticipant(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo) {
    SubscribeConfiguration config = new SubscribeConfiguration();

    config.jitterBuffer.setMinDelay(JitterBufferConfiguration.JitterBufferDelay.MEDIUM());

    return config;
}
```

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="android-publish-subscribe-concepts-strategy-publishing"></a>

```
boolean shouldPublishFromParticipant(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo);
```

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:

```
@Override
boolean shouldPublishFromParticipant(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo) {
	return true;
}
```

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="android-publish-subscribe-concepts-strategy-streams"></a>

```
@Override
List<LocalStageStream> stageStreamsToPublishForParticipant(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo);
}
```

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

#### Memperbarui Strategi
<a name="android-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 `shouldPublishFromParticipant` (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 `shouldPublishFromParticipant` nilainya telah berubah, SDK akan memulai proses publikasi. Jika kueri SDK dan semua fungsi mengembalikan nilai yang sama seperti sebelumnya, `refreshStrategy` panggilan tidak akan melakukan modifikasi apa pun pada 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 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.

### Penyaji
<a name="android-publish-subscribe-concepts-renderer"></a>

`StageRenderer`Antarmuka mengkomunikasikan keadaan panggung ke aplikasi host. Pembaruan pada UI aplikasi host biasanya dapat didukung sepenuhnya oleh peristiwa yang disediakan oleh perender. Penyaji menyediakan fungsi-fungsi berikut:

```
void onParticipantJoined(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo);

void onParticipantLeft(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo);

void onParticipantPublishStateChanged(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo, @NonNull Stage.PublishState publishState);

void onParticipantSubscribeStateChanged(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo, @NonNull Stage.SubscribeState subscribeState);

void onStreamsAdded(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo, @NonNull List<StageStream> streams);

void onStreamsRemoved(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo, @NonNull List<StageStream> streams);

void onStreamsMutedChanged(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo, @NonNull List<StageStream> streams);

void onError(@NonNull BroadcastException exception);

void onConnectionStateChanged(@NonNull Stage stage, @NonNull Stage.ConnectionState state, @Nullable BroadcastException exception);
                
void onStreamAdaptionChanged(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo, @NonNull RemoteStageStream stream, boolean adaption);

void onStreamLayersChanged(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo, @NonNull RemoteStageStream stream, @NonNull List<RemoteStageStream.Layer> layers);

void onStreamLayerSelected(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo, @NonNull RemoteStageStream stream, @Nullable RemoteStageStream.Layer layer, @NonNull RemoteStageStream.LayerSelectedReason reason);
```

Untuk sebagian besar metode ini, yang sesuai `Stage` dan `ParticipantInfo` disediakan.

Tidak diharapkan bahwa informasi yang diberikan oleh penyaji berdampak pada nilai pengembalian strategi. Misalnya, nilai pengembalian `shouldSubscribeToParticipant` tidak diharapkan berubah ketika `onParticipantPublishStateChanged` 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.

`StageRenderer`Dapat dilampirkan ke kelas panggung:

```
stage.addRenderer(renderer); // multiple renderers can be added
```

Perhatikan bahwa hanya peserta penerbitan yang dipicu`onParticipantJoined`, dan setiap kali peserta berhenti menerbitkan atau meninggalkan sesi panggung, `onParticipantLeft` dipicu.

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

Perangkat lokal seperti mikrofon dan kamera internal ditemukan melalui`DeviceDiscovery`. Berikut adalah contoh memilih kamera yang menghadap ke depan dan mikrofon default, lalu mengembalikannya seperti `LocalStageStreams` yang akan dipublikasikan oleh SDK:

```
DeviceDiscovery deviceDiscovery = new DeviceDiscovery(context);

List<Device> devices = deviceDiscovery.listLocalDevices();
List<LocalStageStream> publishStreams = new ArrayList<LocalStageStream>();

Device frontCamera = null;
Device microphone = null;

// Create streams using the front camera, first microphone
for (Device device : devices) {
	Device.Descriptor descriptor = device.getDescriptor();
	if (!frontCamera && descriptor.type == Device.Descriptor.DeviceType.Camera && descriptor.position = Device.Descriptor.Position.FRONT) {
		front Camera = device;
	}
	if (!microphone && descriptor.type == Device.Descriptor.DeviceType.Microphone) {
		microphone = device;
	}
}

ImageLocalStageStream cameraStream = new ImageLocalStageStream(frontCamera);
AudioLocalStageStream microphoneStream = new AudioLocalStageStream(microphoneDevice);

publishStreams.add(cameraStream);
publishStreams.add(microphoneStream);

// Provide the streams in Stage.Strategy
@Override
@NonNull List<LocalStageStream> stageStreamsToPublishForParticipant(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo) {
	return publishStreams;
}
```

## Tampilkan dan Hapus Peserta
<a name="android-publish-subscribe-participants"></a>

Setelah berlangganan selesai, Anda akan menerima array `StageStream` objek melalui fungsi renderer. `onStreamsAdded` Anda dapat mengambil pratinjau dari: `ImageStageStream`

```
ImagePreviewView preview = ((ImageStageStream)stream).getPreview();

// Add the view to your view hierarchy
LinearLayout previewHolder = findViewById(R.id.previewHolder);
preview.setLayoutParams(new LinearLayout.LayoutParams(
		LinearLayout.LayoutParams.MATCH_PARENT,
		LinearLayout.LayoutParams.MATCH_PARENT));
previewHolder.addView(preview);
```

Anda dapat mengambil statistik tingkat audio dari: `AudioStageStream`

```
((AudioStageStream)stream).setStatsCallback((peak, rms) -> {
	// handle statistics
});
```

Ketika peserta berhenti menerbitkan atau berhenti berlangganan, `onStreamsRemoved` fungsi dipanggil dengan aliran yang telah dihapus. Aplikasi host harus menggunakan ini sebagai sinyal untuk menghapus aliran video peserta dari hierarki tampilan.

`onStreamsRemoved`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 `onStreamsRemoved` 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="android-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 `streamsToPublishForParticipant` strategi.

**Penting**: Jika instance `LocalStageStream` objek baru dikembalikan `streamsToPublishForParticipant` 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="android-publish-subscribe-mute-state"></a>

Saat peserta mengubah status bisu aliran video atau audio mereka, `onStreamMutedChanged` fungsi penyaji dipanggil dengan daftar aliran yang telah berubah. Gunakan `getMuted` metode ini `StageStream` untuk memperbarui UI Anda sesuai dengan itu. 

```
@Override
void onStreamsMutedChanged(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo, @NonNull List<StageStream> streams) {
	for (StageStream stream : streams) {
		boolean muted = stream.getMuted();
		// handle UI changes
	}
}
```

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

Untuk mendapatkan statistik WebRTC terbaru untuk aliran penerbitan atau aliran berlangganan, gunakan terus. `requestRTCStats` `StageStream` Ketika koleksi selesai, Anda akan menerima statistik melalui `StageStream.Listener` yang dapat diatur`StageStream`.

```
stream.requestRTCStats();

@Override
void onRTCStats(Map<String, Map<String, String>> statsMap) {
	for (Map.Entry<String, Map<String, string>> stat : statsMap.entrySet()) {
		for(Map.Entry<String, String> member : stat.getValue().entrySet()) {
			Log.i(TAG, stat.getKey() + “ has member “ + member.getKey() + “ with value “ + member.getValue());
		}
	}
}
```

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

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

```
@Override
void onParticipantJoined(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo) {
	for (Map.Entry<String, String> entry : participantInfo.userInfo.entrySet()) {
		Log.i(TAG, “attribute: “ + entry.getKey() + “ = “ + entry.getValue());
	}
}
```

## Sematkan Pesan
<a name="android-publish-subscribe-embed-messages"></a>

`embedMessage`Metode ini ImageDevice memungkinkan Anda untuk memasukkan muatan metadata langsung ke bingkai video selama penerbitan. Ini memungkinkan pesan yang disinkronkan bingkai untuk aplikasi waktu nyata. Penyematan pesan hanya tersedia saat menggunakan SDK untuk penerbitan real-time (bukan penerbitan latensi rendah).

Pesan yang disematkan tidak dijamin sampai ke pelanggan karena mereka disematkan langsung dalam bingkai video dan ditransmisikan melalui UDP, yang tidak menjamin pengiriman paket. Kehilangan paket selama transmisi dapat mengakibatkan pesan hilang, terutama dalam kondisi jaringan yang buruk. Untuk mengurangi ini, `embedMessage` metode ini menyertakan `repeatCount` parameter yang menduplikasi pesan di beberapa frame berturut-turut, meningkatkan keandalan pengiriman. Kemampuan ini hanya tersedia untuk streaming video.

### Menggunakan EmbedMessage
<a name="android-embed-messages-using-embedmessage"></a>

Klien penerbitan dapat menyematkan muatan pesan ke dalam aliran video mereka menggunakan `embedMessage` metode aktif. ImageDevice Ukuran muatan harus lebih besar dari 0KB dan kurang dari 1KB. Jumlah pesan tertanam yang dimasukkan per detik tidak boleh melebihi 10KB per detik. 

```
val surfaceSource: SurfaceSource = imageStream.device as SurfaceSource
val message = "hello world"
val messageBytes = message.toByteArray(StandardCharsets.UTF_8)

try {
    surfaceSource.embedMessage(messageBytes, 0)
} catch (e: BroadcastException) {
    Log.e("EmbedMessage", "Failed to embed message: ${e.message}")
}
```

### Mengulangi Muatan Pesan
<a name="android-embed-messages-repeat-payloads"></a>

Gunakan `repeatCount` untuk menduplikasi pesan di beberapa frame untuk meningkatkan keandalan. Nilai ini harus antara 0 dan 30. Klien penerima harus memiliki logika untuk menghapus duplikat pesan.

```
try {
    surfaceSource.embedMessage(messageBytes, 5)
    // repeatCount: 0-30, receiving clients should handle duplicates
} catch (e: BroadcastException) {
    Log.e("EmbedMessage", "Failed to embed message: ${e.message}")
}
```

### Membaca Pesan Tertanam
<a name="android-embed-messages-read-messages"></a>

Lihat “Dapatkan Informasi Peningkatan Tambahan (SEI)” di bawah ini untuk mengetahui cara membaca pesan yang disematkan dari aliran masuk.

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

Unit Supplemental Enhancement Information (SEI) NAL digunakan untuk menyimpan metadata yang selaras dengan bingkai di samping video. Klien berlangganan dapat membaca muatan SEI dari penerbit yang menerbitkan video H.264 dengan memeriksa `embeddedMessages` properti pada objek yang keluar dari penerbit. `ImageDeviceFrame` `ImageDevice` Untuk melakukan ini, dapatkan publisher`ImageDevice`, lalu amati setiap frame melalui callback yang disediakan`setOnFrameCallback`, seperti yang ditunjukkan pada contoh berikut:

```
// in a StageRenderer’s onStreamsAdded function, after acquiring the new ImageStream

val imageDevice = imageStream.device as ImageDevice
imageDevice.setOnFrameCallback(object : ImageDevice.FrameCallback {
	override fun onFrame(frame: ImageDeviceFrame) {
    		for (message in frame.embeddedMessages) {
        		if (message is UserDataUnregisteredSeiMessage) {
            		val seiMessageBytes = message.data
            		val seiMessageUUID = message.uuid
           	 
            		// interpret the message's data based on the UUID
        		}
    		}
	}
})
```

## Lanjutkan Sesi di Latar Belakang
<a name="android-publish-subscribe-background-session"></a>

Saat aplikasi memasuki latar belakang, Anda mungkin ingin berhenti menerbitkan atau berlangganan hanya audio peserta jarak jauh lainnya. Untuk mencapai hal ini, perbarui `Strategy` implementasi Anda untuk menghentikan penerbitan, dan berlangganan `AUDIO_ONLY` (atau`NONE`, jika ada).

```
// Local variables before going into the background
boolean shouldPublish = true;
Stage.SubscribeType subscribeType = Stage.SubscribeType.AUDIO_VIDEO;

// Stage.Strategy implementation
@Override
boolean shouldPublishFromParticipant(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo) {
	return shouldPublish;
}

@Override
Stage.SubscribeType shouldSubscribeToParticipant(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo) {
	return subscribeType;
}

// In our Activity, modify desired publish/subscribe when we go to background, then call refreshStrategy to update the stage
@Override
void onStop() {
	super.onStop();
	shouldPublish = false;
	subscribeTpye = Stage.SubscribeType.AUDIO_ONLY;
	stage.refreshStrategy();
}
```

## Pengkodean Berlapis dengan Simulcast
<a name="android-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 mengonfigurasi lapisan tersebut secara dinamis atau manual. Fitur ini dijelaskan lebih lanjut dalam dokumen [Pengoptimalan Streaming](real-time-streaming-optimization.md).

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

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

```
// Enable Simulcast
StageVideoConfiguration config = new StageVideoConfiguration();
config.simulcast.setEnabled(true);

ImageLocalStageStream cameraStream = new ImageLocalStageStream(frontCamera, config);

// Other Stage implementation code
```

*Bergantung pada resolusi yang Anda tetapkan pada konfigurasi video, 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: 

```
// Enable Simulcast
StageVideoConfiguration config = new StageVideoConfiguration();
config.simulcast.setEnabled(true);

List<StageVideoConfiguration.Simulcast.Layer> simulcastLayers = new ArrayList<>();
simulcastLayers.add(StagePresets.SimulcastLocalLayer.DEFAULT_720);
simulcastLayers.add(StagePresets.SimulcastLocalLayer.DEFAULT_180);

config.simulcast.setLayers(simulcastLayers);

ImageLocalStageStream cameraStream = new ImageLocalStageStream(frontCamera, config);

// Other Stage implementation code
```

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 setter properti wajib berikut:
+ `setSize: Vec2;`
+ `setMaxBitrate: integer;`
+ `setMinBitrate: integer;`
+ `setTargetFramerate: integer;`

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

```
// Enable Simulcast
StageVideoConfiguration config = new StageVideoConfiguration();
config.simulcast.setEnabled(true);

List<StageVideoConfiguration.Simulcast.Layer> simulcastLayers = new ArrayList<>();

// Configure high quality layer with custom framerate
StageVideoConfiguration.Simulcast.Layer customHiLayer = StagePresets.SimulcastLocalLayer.DEFAULT_720;
customHiLayer.setTargetFramerate(15);

// Add layers to the list
simulcastLayers.add(customHiLayer);
simulcastLayers.add(StagePresets.SimulcastLocalLayer.DEFAULT_180);

config.simulcast.setLayers(simulcastLayers);

ImageLocalStageStream cameraStream = new ImageLocalStageStream(frontCamera, config);

// Other Stage implementation code
```

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

### Mengkonfigurasi Layered Encoding (Subscriber)
<a name="android-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="android-layered-encoding-simulcast-layer-quality-preference"></a>

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

```
@Override
public SubscribeConfiguration subscribeConfigrationForParticipant(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo) {
    SubscribeConfiguration config = new SubscribeConfiguration();

    config.simulcast.setInitialLayerPreference(SubscribeSimulcastConfiguration.InitialLayerPreference.LOWEST_QUALITY);

    return config;
}
```

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 berkualitas lebih tinggi dari video 720p.

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

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

Metode `preferredLayerForStream` strategi memungkinkan Anda memilih lapisan setelah aliran dimulai. Metode strategi ini menerima peserta dan informasi aliran, sehingga Anda dapat memilih lapisan participant-by-participant berdasarkan. SDK memanggil metode ini sebagai respons terhadap peristiwa tertentu, seperti ketika lapisan aliran berubah, status peserta berubah, atau aplikasi host menyegarkan strategi.

Metode strategi mengembalikan `RemoteStageStream.Layer` objek, yang dapat menjadi salah satu dari berikut:
+ Objek layer, seperti yang dikembalikan oleh`RemoteStageStream.getLayers`.
+ 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:

```
@Nullable
@Override
public RemoteStageStream.Layer preferredLayerForStream(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo, @NonNull RemoteStageStream stream) {
    return stream.getLowestQualityLayer();
}
```

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

```
@Nullable
@Override
public RemoteStageStream.Layer preferredLayerForStream(@NonNull Stage stage, @NonNull ParticipantInfo participantInfo, @NonNull RemoteStageStream stream) {
    if (appState.isAutoMode) {
        return null;
    } else {
        return appState.layerChoice;
    }
}
```

### Opsi 3: Pembantu RemoteStageStream Lapisan
<a name="android-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`StageRenderer`, `RemoteStageStream.Listener` memiliki peristiwa yang mengkomunikasikan perubahan adaptasi layer dan simulcast:
  + `void onAdaptionChanged(boolean adaption)`
  + `void onLayersChanged(@NonNull List<Layer> layers)`
  + `void onLayerSelected(@Nullable Layer layer, @NonNull LayerSelectedReason 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`StageRenderer.onStreamsAdded`.
  + `stream.getLayers`
  + `stream.getSelectedLayer`
  + `stream.getLowestQualityLayer`
  + `stream.getHighestQualityLayer`
  + `stream.getLayersWithConstraints`

Untuk detailnya, lihat `RemoteStageStream` kelas dalam [dokumentasi referensi SDK](https://aws.github.io/amazon-ivs-broadcast-docs/latest/android/). Untuk `LayerSelected` 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.

## Batasan Konfigurasi Video
<a name="android-publish-subscribe-video-limits"></a>

SDK tidak mendukung pemaksaan mode potret atau mode lanskap menggunakan`StageVideoConfiguration.setSize(BroadcastConfiguration.Vec2 size)`. Dalam orientasi potret, dimensi yang lebih kecil digunakan sebagai lebar; dalam orientasi lanskap, tinggi. Ini berarti bahwa dua panggilan berikut `setSize` memiliki efek yang sama pada konfigurasi video:

```
StageVideo Configuration config = new StageVideo Configuration();

config.setSize(BroadcastConfiguration.Vec2(720f, 1280f);
config.setSize(BroadcastConfiguration.Vec2(1280f, 720f);
```

## Menangani Masalah Jaringan
<a name="android-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. Ada dua kesalahan utama yang terkait dengan kehilangan koneksi jaringan:
+ Kode kesalahan 1400, pesan: "PeerConnection hilang karena kesalahan jaringan yang tidak diketahui”
+ Kode kesalahan 1300, pesan: “Coba lagi upaya habis”

Jika kesalahan pertama diterima tetapi yang kedua tidak, SDK masih terhubung ke panggung dan akan mencoba membangun kembali koneksinya secara otomatis. Sebagai pengaman, Anda dapat memanggil `refreshStrategy` tanpa perubahan apa pun pada nilai pengembalian metode strategi, untuk memicu upaya penyambungan kembali manual.

Jika kesalahan kedua diterima, upaya penyambungan kembali SDK telah gagal dan perangkat lokal tidak lagi terhubung ke panggung. Dalam hal ini, cobalah untuk bergabung kembali dengan panggung dengan menelepon `join` setelah koneksi jaringan Anda dibangun kembali.

Secara umum, menemukan kesalahan setelah bergabung dengan tahap berhasil menunjukkan bahwa SDK tidak berhasil membangun kembali koneksi. Buat `Stage` objek baru dan cobalah untuk bergabung ketika kondisi jaringan membaik.

## Menggunakan Mikrofon Bluetooth
<a name="android-publish-subscribe-bluetooth-microphones"></a>

Untuk mempublikasikan menggunakan perangkat mikrofon Bluetooth, Anda harus memulai koneksi Bluetooth SCO:

```
Bluetooth.startBluetoothSco(context);
// Now bluetooth microphones can be used
…
// Must also stop bluetooth SCO
Bluetooth.stopBluetoothSco(context);
```

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

Dokumen ini mencantumkan masalah yang diketahui yang mungkin Anda temui saat menggunakan SDK siaran Android streaming real-time Amazon IVS dan menyarankan solusi potensial.
+ Saat perangkat Android tertidur dan bangun, pratinjau mungkin dalam keadaan beku.

  **Solusi:** Buat dan gunakan yang baru. `Stage`
+ Ketika peserta bergabung dengan token yang digunakan oleh peserta lain, koneksi pertama terputus tanpa kesalahan tertentu.

  **Solusi**: Tidak ada. 
+ Ada masalah langka di mana penerbit menerbitkan tetapi status publikasi yang diterima pelanggan adalah`inactive`.

  **Solusi:** Coba pergi dan kemudian bergabung dengan sesi. Jika masalah tetap ada, buat token baru untuk penerbit.
+ Masalah distorsi audio yang jarang terjadi dapat terjadi sebentar-sebentar selama sesi panggung, biasanya pada panggilan dengan durasi yang lebih lama.

  **Solusi:** Peserta dengan audio yang terdistorsi dapat meninggalkan dan bergabung kembali dengan sesi, atau membatalkan publikasi dan menerbitkan ulang audio mereka untuk memperbaiki masalah.
+ Mikrofon eksternal tidak didukung saat menerbitkan ke panggung.

  **Solusi:** Jangan gunakan mikrofon eksternal yang terhubung melalui USB untuk menerbitkan ke panggung.
+ Penerbitan ke panggung dengan berbagi layar menggunakan `createSystemCaptureSources` tidak didukung.

  **Solusi:** Kelola pengambilan sistem secara manual, menggunakan sumber input gambar khusus dan sumber input audio khusus.
+ Ketika `ImagePreviewView` dihapus dari induk (misalnya, `removeView()` dipanggil di induk), segera `ImagePreviewView` dilepaskan. `ImagePreviewView`Tidak menampilkan bingkai apa pun saat ditambahkan ke tampilan induk lain.

  **Solusi:** Minta pratinjau lain menggunakan. `getPreview`
+ Saat bergabung dengan panggung dengan Samsung Galaxy S22/\$1 dengan Android 12, Anda mungkin mengalami kesalahan 1401 dan perangkat lokal gagal bergabung dengan panggung atau bergabung tetapi tidak memiliki audio.

  **Solusi: Tingkatkan** ke Android 13.
+ Saat bergabung dengan panggung dengan Nokia X20 di Android 13, kamera mungkin gagal dibuka dan pengecualian dilemparkan.

  **Solusi**: Tidak ada.
+ Perangkat dengan chipset MediaTek Helio mungkin tidak merender video peserta jarak jauh dengan benar.

  **Solusi**: Tidak ada.
+ Pada beberapa perangkat, OS perangkat dapat memilih mikrofon yang berbeda dari yang dipilih melalui SDK. Ini karena Amazon IVS Broadcast SDK tidak dapat mengontrol bagaimana rute `VOICE_COMMUNICATION` audio didefinisikan, karena bervariasi sesuai dengan produsen perangkat yang berbeda.

  **Solusi**: Tidak ada.
+ Beberapa encoder video Android tidak dapat dikonfigurasi dengan ukuran video kurang dari 176x176. Mengkonfigurasi ukuran yang lebih kecil menyebabkan kesalahan dan mencegah streaming.

  **Solusi:** Jangan mengonfigurasi ukuran video menjadi kurang dari 176x176.

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

Bagian ini adalah ikhtisar kondisi kesalahan, bagaimana SDK siaran Android streaming real-time IVS melaporkannya ke aplikasi, dan apa yang harus dilakukan aplikasi ketika kesalahan tersebut ditemui.

## Kesalahan Fatal vs Non-Fatal
<a name="broadcast-android-fatal-vs-nonfatal-errors"></a>

Objek kesalahan memiliki bidang boolean “fatal” dari. `BroadcastException`

Secara umum, kesalahan fatal terkait dengan koneksi ke server Tahapan (baik koneksi tidak dapat dibuat atau hilang dan tidak dapat dipulihkan). Aplikasi harus membuat ulang panggung dan bergabung kembali, mungkin dengan token baru atau ketika konektivitas perangkat pulih.

Kesalahan non-fatal umumnya terkait dengan publish/subscribe status dan ditangani oleh SDK, yang mencoba ulang operasi. publish/subscribe 

Anda dapat memeriksa properti ini:

```
try {
  stage.join(...)
} catch (e: BroadcastException) {
  If (e.isFatal) { 
    // the error is fatal
```

## Bergabung Error
<a name="broadcast-android-stage-join-errors"></a>

### Token Cacat
<a name="broadcast-android-stage-join-errors-malformed-token"></a>

Ini terjadi ketika token panggung salah bentuk.

SDK melempar pengecualian Java dari panggilan ke`stage.join`, dengan kode kesalahan = 1000 dan fatal = true.

**Tindakan**: Buat token yang valid dan coba lagi bergabung.

### Token Kadaluwarsa
<a name="broadcast-android-stage-join-errors-expired-token"></a>

Ini terjadi ketika token panggung kedaluwarsa.

SDK melempar pengecualian Java dari panggilan ke`stage.join`, dengan kode kesalahan = 1001 dan fatal = true.

**Tindakan**: Buat token baru dan coba lagi bergabung.

### Token Tidak Valid atau Dicabut
<a name="broadcast-android-stage-join-errors-invalid-token"></a>

Ini terjadi ketika token panggung tidak cacat tetapi ditolak oleh server Stages. Ini dilaporkan secara asinkron melalui perender tahap yang disediakan aplikasi.

SDK memanggil `onConnectionStateChanged` dengan pengecualian, dengan kode kesalahan = 1026 dan fatal = true.

**Tindakan**: Buat token yang valid dan coba lagi bergabung.

### Kesalahan Jaringan untuk Gabung Awal
<a name="broadcast-android-stage-join-errors-network-initial-join"></a>

Ini terjadi ketika SDK tidak dapat menghubungi server Stages untuk membuat koneksi. Ini dilaporkan secara asinkron melalui perender tahap yang disediakan aplikasi.

SDK memanggil `onConnectionStateChanged` dengan pengecualian, dengan kode kesalahan = 1300 dan fatal = true.

**Tindakan**: Tunggu konektivitas perangkat pulih dan coba lagi bergabung.

### Kesalahan Jaringan saat Sudah Bergabung
<a name="broadcast-android-stage-join-errors-network-already-joined"></a>

Jika koneksi jaringan perangkat mati, SDK mungkin kehilangan koneksinya ke server Stage. Ini dilaporkan secara asinkron melalui perender tahap yang disediakan aplikasi.

SDK memanggil `onConnectionStateChanged` dengan pengecualian, dengan kode kesalahan = 1300 dan fatal = true.

**Tindakan**: Tunggu konektivitas perangkat pulih dan coba lagi bergabung.

## Kesalahan Publikasi/Berlangganan
<a name="broadcast-android-publish-subscribe-errors"></a>

### Awal
<a name="broadcast-android-publish-subscribe-errors-initial"></a>

Ada beberapa kesalahan:
+ MultihostSessionOfferCreationFailPublish (1020)
+ MultihostSessionOfferCreationFailSubscribe (1021)
+ MultihostSessionNoIceCandidates (1022)
+ MultihostSessionStageAtCapacity (1024)
+ SignallingSessionCannotRead (1201)
+ SignallingSessionCannotSend (1202)
+ SignallingSessionBadResponse (1203)

Ini dilaporkan secara asinkron melalui perender tahap yang disediakan aplikasi.

SDK mencoba ulang operasi untuk beberapa kali. Selama percobaan ulang, publish/subscribe negara adalah`ATTEMPTING_PUBLISH`/`ATTEMPTING_SUBSCRIBE`. Jika upaya coba lagi berhasil, status berubah menjadi`PUBLISHED`/`SUBSCRIBED`.

Panggilan SDK `onError` dengan kode kesalahan yang relevan dan fatal = false.

**Tindakan**: Tidak diperlukan tindakan, karena SDK mencoba ulang secara otomatis. Secara opsional, aplikasi dapat menyegarkan strategi untuk memaksa lebih banyak percobaan ulang.

### Sudah Didirikan, Lalu Gagal
<a name="broadcast-android-publish-subscribe-errors-established"></a>

Publikasi atau berlangganan dapat gagal setelah dibuat, kemungkinan besar karena kesalahan jaringan. Kode kesalahan untuk “koneksi rekan hilang karena kesalahan jaringan” adalah 1400.

Ini dilaporkan secara asinkron melalui perender tahap yang disediakan aplikasi.

SDK mencoba ulang operasi. publish/subscribe Selama percobaan ulang, publish/subscribe negara adalah`ATTEMPTING_PUBLISH`/`ATTEMPTING_SUBSCRIBE`. Jika upaya coba lagi berhasil, status berubah menjadi`PUBLISHED`/`SUBSCRIBED`.

SDK memanggil `onError` dengan kode kesalahan = 1400 dan fatal = false.

**Tindakan**: Tidak diperlukan tindakan, karena SDK mencoba ulang secara otomatis. Secara opsional, aplikasi dapat menyegarkan strategi untuk memaksa lebih banyak percobaan ulang. Jika terjadi kehilangan konektivitas total, kemungkinan koneksi ke Stages juga akan gagal.