View a markdown version of this page

Penerbitan & Berlangganan dengan IVS Android Broadcast SDK | Streaming Real-Time - Amazon IVS

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

Penerbitan & Berlangganan dengan IVS Android Broadcast SDK | Streaming Real-Time

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

Konsep

Tiga konsep inti mendasari fungsionalitas waktu nyata: panggung, strategi, dan perender. Tujuan desain adalah meminimalkan jumlah logika sisi klien yang diperlukan untuk membangun produk yang berfungsi.

Stage

StageKelas adalah titik utama interaksi antara aplikasi host dan SDK. Ini mewakili panggung itu sendiri dan digunakan untuk bergabung dan meninggalkan panggung. Membuat dan bergabung dengan tahap memerlukan string token yang valid dan belum kedaluwarsa dari bidang kontrol (direpresentasikan sebagaitoken). Bergabung dan meninggalkan panggung itu sederhana.

Stage stage = new Stage(context, token, strategy); try { stage.join(); } catch (BroadcastException exception) { // handle join exception } stage.leave();

Kel Stage as ini juga di mana StageRenderer dapat dilampirkan:

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

Strategi

Antar Stage.Strategy muka menyediakan cara bagi aplikasi host untuk mengkomunikasikan keadaan panggung yang diinginkan ke SDK. Tiga fungsi perlu diimplementasikan:shouldSubscribeToParticipant,shouldPublishFromParticipant, danstageStreamsToPublishForParticipant. Semua dibahas di bawah ini.

Berlangganan ke Peserta

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 adalahNONE,AUDIO_ONLY, danAUDIO_VIDEO. Saat mengembalikan nilai untuk fungsi ini, aplikasi host tidak perlu khawatir tentang status publikasi, status langganan saat ini, atau status koneksi tahap. Jika AUDIO_VIDEO dikembalikan, SDK menunggu hingga peserta jarak jauh menerbitkan sebelum berlangganan, dan memperbarui aplikasi host 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 saling bertemu; misalnya, aplikasi obrolan video.

Implementasi yang lebih maju juga dimungkinkan. Gunakan userInfo properti aktif 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

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

Jika peserta jarak jauh sedang berlangganan (lihat Berlangganan Peserta), SDK menanyakan aplikasi host tentang konfigurasi langganan khusus untuk peserta tersebut. Konfigurasi ini opsional dan memungkinkan aplikasi host untuk mengontrol aspek-aspek tertentu dari perilaku pelanggan. Untuk informasi tentang apa yang dapat dikonfigurasi, lihat 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 yang berlangganan ke preset. MEDIUM

Seperti halnyashouldSubscribeToParticipant, implementasi yang lebih maju dimungkinkan. Yang diberikan ParticipantInfo dapat digunakan untuk memperbarui konfigurasi berlangganan secara selektif untuk peserta tertentu.

Sebaiknya gunakan perilaku default. Tentukan konfigurasi khusus hanya jika ada perilaku tertentu yang ingin Anda ubah.

Publikasi

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

Setelah terhubung ke panggung, SDK menanyakan aplikasi host untuk melihat apakah peserta tertentu harus mempublikasikan. Ini hanya dipanggil pada peserta lokal yang memiliki izin untuk mempublikasikan berdasarkan token yang disediakan.

Berikut adalah contoh implementasi:

@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 mematikan audio dan video mereka, untuk langsung disembunyikan atau seen/heard. (Mereka juga bisa menggunakan publish/unpublish, tetapi itu jauh lebih lambat. Mute/unmute lebih disukai untuk kasus penggunaan di mana perubahan visibilitas sering diinginkan.)

Memilih Streaming untuk Dipublikasikan

@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 Publikasikan Aliran Media.

Memperbarui Strategi

Strategi ini dimaksudkan untuk menjadi dinamis: nilai yang dikembalikan dari salah satu fungsi di atas dapat diubah kapan saja. Misalnya, jika aplikasi host tidak ingin mempublikasikan sampai pengguna akhir mengetuk tombol, Anda dapat mengembalikan variabel dari shouldPublishFromParticipant (sesuatu sepertihasUserTappedPublishButton). 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 nil shouldPublishFromParticipant ainya telah berubah, itu akan memulai proses publikasi. Jika kueri SDK dan semua fungsi mengembalikan nilai yang sama seperti sebelumnya, refreshStrategy panggilan tidak akan melakukan modifikasi apa pun ke panggung.

Jika nilai pengembalian shouldSubscribeToParticipant berubah dari AUDIO_VIDEO keAUDIO_ONLY, aliran video akan dihapus untuk semua peserta dengan nilai yang dikembalikan yang diubah, jika aliran video ada sebelumnya.

Umumnya, tahap menggunakan strategi untuk paling efisien menerapkan perbedaan antara strategi sebelumnya dan saat ini, tanpa aplikasi host perlu khawatir tentang semua keadaan yang diperlukan untuk mengelolanya dengan benar. Karena itu, anggap menelepon stage.refreshStrategy() sebagai operasi murah, karena tidak ada gunanya kecuali strateginya berubah.

Perender

Antar StageRenderer muka mengkomunikasikan keadaan panggung ke aplikasi host. Pembaruan pada UI aplikasi host biasanya dapat didukung sepenuhnya oleh peristiwa yang disediakan oleh perender. Perender 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 tidak shouldSubscribeToParticipant diharapkan berubah saat onParticipantPublishStateChanged dipanggil. Jika aplikasi host ingin berlangganan peserta tertentu, aplikasi tersebut 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 panggung.

Dapat StageRenderer dilampirkan ke kelas panggung:

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

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

Publikasikan Aliran Media

Perangkat lokal seperti mikrofon internal dan kamera ditemukan melaluiDeviceDiscovery. Berikut adalah contoh memilih kamera menghadap ke depan dan mikrofon default, lalu mengembalikannya seperti LocalStageStreams yang akan diterbitkan 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

Setelah berlangganan selesai, Anda akan menerima array StageStream objek melalui fungsi per onStreamsAdded ender. Anda dapat mengambil pratinjau dariImageStageStream:

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 dihapus. Aplikasi host harus menggunakan ini sebagai sinyal untuk menghapus aliran video peserta dari hierarki tampilan.

onStreamsRemoveddipanggil untuk semua skenario di mana aliran dapat dihapus, termasuk:

  • Peserta jarak jauh berhenti menerbitkan.

  • Perangkat lokal berhenti berlangganan atau mengubah langganan dari AUDIO_VIDEO ke. AUDIO_ONLY

  • Peserta jarak jauh meninggalkan panggung.

  • Peserta lokal meninggalkan panggung.

Karena onStreamsRemoved dipanggil untuk semua skenario, tidak ada logika bisnis khusus yang diperlukan untuk menghapus peserta dari UI selama operasi cuti jarak jauh atau lokal.

Bisukan dan Aktifkan Aliran Media

LocalStageStreamobjek memiliki setMuted fungsi yang mengontrol apakah aliran dibisukan. Fungsi ini dapat dipanggil pada aliran sebelum atau setelah dikembalikan dari fungsi streamsToPublishForParticipant strategi.

Penting: Jika instance LocalStageStream objek baru dikembalikan streamsToPublishForParticipant setelah panggilan kerefreshStrategy, status bisu objek aliran baru diterapkan ke panggung. Berhati-hatilah saat membuat LocalStageStream instance baru untuk memastikan status bisu yang diharapkan dipertahankan.

Memantau Status Bisu Media Peserta Jarak Jauh

Ketika peserta mengubah status bisu aliran video atau audio mereka, onStreamMutedChanged fungsi perender 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

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

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

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

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

Pesan yang disematkan tidak dijamin akan sampai ke pelanggan karena mereka tertanam langsung dalam bingkai video dan dikirim melalui UDP, yang tidak menjamin pengiriman paket. Kehilangan paket selama transmisi dapat mengakibatkan hilangnya pesan, 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

Klien penerbitan dapat menyematkan muatan pesan ke aliran video mereka menggunakan embedMessage metode aktif. ImageDevice Ukuran payload 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}") }

Muatan Pesan Berulang

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

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

Dapatkan Informasi Peningkatan Tambahan (SEI)

Unit NAL Informasi Peningkatan Tambahan (SEI) digunakan untuk menyimpan metadata yang selaras dengan bingkai di samping video. Klien yang berlangganan dapat membaca payload SEI dari penerbit yang H.264 menerbitkan video dengan memeriksa embeddedMessages properti pada ImageDeviceFrame objek yang keluar dari penerbit. ImageDevice Untuk melakukan ini, dapatkan penerbitImageDevice, lalu amati setiap frame melalui panggilan balik yang disediakansetOnFrameCallback, 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

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

// 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

Pengkodean berlapis dengan simulcast adalah fitur streaming real-time IVS yang memungkinkan penerbit mengirim beberapa lapisan kualitas video yang berbeda, dan pelanggan untuk mengonfigurasi lapisan tersebut secara dinamis atau manual. Fitur ini dijelaskan lebih lanjut dalam dokumen Pengoptim alan Streaming.

Mengkonfigurasi Pengkodean Berlapis (Penerbit)

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

// 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 yang ditetapkan akan dikodekan dan dikirim seperti yang didefinisikan di bagian Def ault Layers, Qualitties, dan Framerates 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 penyetel properti yang diperlukan 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 Pengkodean Berlapis (Pelanggan)

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 dikirim penerbit, ada beberapa opsi, dijelaskan di bawah ini.

Opsi 1: Preferensi Kualitas Lapisan Awal

Dengan menggunakan subscribeConfigurationForParticipant strategi ini, 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 untuk pengguna di jaringan yang lebih lemah.

Opsi ini tersedia untukInitialLayerPreference:

  • LOWEST_QUALITY— Server memberikan lapisan video berkualitas terendah terlebih dahulu. Ini mengoptimalkan konsumsi bandwidth, serta waktu ke media. Kualitas didefinisikan sebagai kombinasi ukuran, bitrate, dan framerate video. Misalnya, kualitas video 720p lebih rendah daripada video 1080p.

  • HIGHEST_QUALITY— Server memberikan lapisan video kualitas tertinggi terlebih dahulu. Ini mengoptimalkan kualitas tetapi dapat meningkatkan waktu untuk media. Kualitas didefinisikan sebagai kombinasi ukuran, bitrate, dan framerate video. Misalnya, video 1080p memiliki kualitas lebih tinggi daripada video 720p.

Catatan: Agar preferensi lapisan awal (setInitialLayerPreferencepanggilan) berlaku, berlangganan ulang diperlukan karena pembaruan ini tidak berlaku untuk langganan aktif.

Opsi 2: Lapisan Pilihan untuk Stream

Metode preferredLayerForStream strategi memungkinkan Anda memilih layer setelah streaming dimulai. Metode strategi ini menerima peserta dan informasi aliran, sehingga Anda dapat memilih lapisan berdasarkan partisipan per peserta. 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 ini:

  • Objek layer, seperti yang dikembalikan olehRemoteStageStream.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: Pemb RemoteStageStream antu Lapisan

RemoteStageStreammemiliki beberapa pembantu yang dapat digunakan untuk membuat keputusan tentang pemilihan lapisan dan menampilkan pilihan yang sesuai untuk pengguna akhir:

  • Peristiwa Lap isan - Ber StageRenderer sama-sama, RemoteStageStream.Listener memiliki peristiwa yang mengkomunikasikan perubahan adaptasi lapisan dan simulcast:

    • void onAdaptionChanged(boolean adaption)

    • void onLayersChanged(@NonNull List<Layer> layers)

    • void onLayerSelected(@Nullable Layer layer, @NonNull LayerSelectedReason reason)

  • Layer Me RemoteStageStream thods — memiliki beberapa metode pembantu yang dapat digunakan untuk mendapatkan informasi tentang aliran dan lapisan yang disajikan. Metode-metode ini tersedia pada aliran jarak jauh yang disediakan dalam preferredLayerForStream strategi, serta aliran jarak jauh yang diekspos melaluiStageRenderer.onStreamsAdded.

    • stream.getLayers

    • stream.getSelectedLayer

    • stream.getLowestQualityLayer

    • stream.getHighestQualityLayer

    • stream.getLayersWithConstraints

Untuk detailnya, lihat RemoteStageStream kelas dalam dokumentasi referensi SDK. Untuk LayerSelected alasannya, jika UNAVAILABLE dikembalikan, ini menunjukkan bahwa lapisan yang diminta tidak dapat dipilih. Pilihan upaya terbaik dibuat sebagai gantinya, yang biasanya merupakan lapisan kualitas lebih rendah untuk menjaga stabilitas aliran.

Video-Configuration Keterbatasan

SDK tidak mendukung pemaksaan mode potret atau mode lanskap menggunakanStageVideoConfiguration.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

Ketika koneksi jaringan perangkat lokal hilang, 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 terkait kehilangan koneksi jaringan:

  • Kode kesalahan 1400, pesan: "PeerConnection hilang karena kesalahan jaringan yang tidak diketahui”

  • Kode kesalahan 1300, pesan: “Upaya coba lagi habis”

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

Jika kesalahan kedua diterima, upaya menyambung kembali SDK 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 telah dibangun kembali.

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

Menggunakan Mikrofon Bluetooth

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);