Topik ini menjelaskan prosedur dan contoh kode untuk co-streaming, membantu Anda mengintegrasikan fitur ini dengan cepat.
Ikhtisar solusi
Gunakan komunikasi waktu nyata dan streaming bypass CDN untuk mencapai latensi ultra-rendah serta interaksi waktu nyata dengan lebih banyak peserta.
Streamer dan co-streamer mendorong aliran ke ruang RTC melalui ARTC SDK.
Server aplikasi memantau perubahan aliran dan memanggil StartLiveMPUTask - Buat tugas pencampuran aliran (baru) API untuk meneruskan aliran dari ruang RTC ke CDN.
Penonton biasa menggunakan SDK Pemutar Video Apsara untuk menarik dan menonton aliran dari CDN.
Proses dasar untuk streaming dan co-streaming adalah sebagai berikut:
Sebelum co-streaming | Sisi streamer: Menggunakan ARTC SDK untuk bergabung dengan ruang RTC dan mendorong aliran audio dan video waktu nyata. Server aplikasi: Memantau perubahan aliran di ruang RTC. Setelah streamer mendorong aliran, panggil StartLiveMPUTask - Buat tugas pencampuran aliran (baru) untuk memulai tugas streaming bypass (Task1), melewati URL ingest CDN, dan meneruskan aliran dari ruang RTC ke CDN. Penonton: Gunakan SDK Pemutar Video Apsara dengan URL pemutaran CDN untuk menarik dan memainkan aliran. |
Selama co-streaming | Co-streamer:
Streamer: Menarik aliran audio dan video waktu nyata dari co-streamer di ruang RTC, mengatur tampilan rendering, dan merender secara real-time. Server aplikasi: Memantau perubahan aliran di ruang RTC. Setelah co-streamer mendorong aliran, memperbarui tugas streaming bypass (Task1), mengubah mode dari bypass ke pencampuran aliran, dan melewati tata letak untuk streamer dan co-streamer. Penonton: Tidak diperlukan operasi tambahan. Siaran langsung secara otomatis beralih dari hanya menampilkan streamer menjadi menampilkan streamer dan co-streamer. |
Akhiri co-streaming | Co-streamer:
Streamer: Menghentikan penarikan aliran audio dan video dari co-streamer. Server aplikasi: Memantau perubahan aliran di ruang RTC. Setelah co-streamer berhenti mendorong aliran, memperbarui tugas pencampuran aliran (Task1) dan mengubah mode dari pencampuran aliran menjadi bypass. Penonton: Tidak diperlukan operasi tambahan. Siaran langsung secara otomatis beralih dari menampilkan streamer dan co-streamer menjadi hanya menampilkan streamer. |
Untuk API terkait pemantauan callback perubahan aliran di ruang RTC, lihat CreateEventSub - Buat langganan untuk callback pesan ruangan.
Untuk API terkait memulai tugas streaming bypass, lihat StartLiveMPUTask - Buat tugas pencampuran aliran (baru).
Langkah-langkah implementasi
Langkah 1: Streamer mulai siaran
Proses dasar untuk streamer memulai siaran adalah sebagai berikut:
1. Streamer mendorong aliran ke ruang RTC
Streamer menggunakan ARTC SDK untuk mendorong aliran ke ruang RTC.
Android
Untuk langkah-langkah terperinci tentang menggunakan ARTC SDK untuk bergabung dengan ruang RTC dan mendorong aliran, lihat: Langkah-langkah implementasi.
// Impor kelas ARTC terkait
import com.alivc.rtc.AliRtcEngine;
import com.alivc.rtc.AliRtcEngineEventListener;
import com.alivc.rtc.AliRtcEngineNotify;
private AliRtcEngine mAliRtcEngine = null;
if(mAliRtcEngine == null) {
mAliRtcEngine = AliRtcEngine.getInstance(this);
}
// Atur mode saluran
mAliRtcEngine.setChannelProfile(AliRtcEngine.AliRTCSdkChannelProfile.AliRTCSdkInteractiveLive);
mAliRtcEngine.setClientRole(AliRtcEngine.AliRTCSdkClientRole.AliRTCSdkInteractive);
mAliRtcEngine.setAudioProfile(AliRtcEngine.AliRtcAudioProfile.AliRtcEngineHighQualityMode, AliRtcEngine.AliRtcAudioScenario.AliRtcSceneMusicMode);
//Atur parameter pengkodean video
AliRtcEngine.AliRtcVideoEncoderConfiguration aliRtcVideoEncoderConfiguration = new AliRtcEngine.AliRtcVideoEncoderConfiguration();
aliRtcVideoEncoderConfiguration.dimensions = new AliRtcEngine.AliRtcVideoDimensions(
720, 1280);
aliRtcVideoEncoderConfiguration.frameRate = 20;
aliRtcVideoEncoderConfiguration.bitrate = 1200;
aliRtcVideoEncoderConfiguration.keyFrameInterval = 2000;
aliRtcVideoEncoderConfiguration.orientationMode = AliRtcVideoEncoderOrientationModeAdaptive;
mAliRtcEngine.setVideoEncoderConfiguration(aliRtcVideoEncoderConfiguration);
mAliRtcEngine.publishLocalAudioStream(true);
mAliRtcEngine.publishLocalVideoStream(true);
mAliRtcEngine.setDefaultSubscribeAllRemoteAudioStreams(true);
mAliRtcEngine.subscribeAllRemoteAudioStreams(true);
mAliRtcEngine.setDefaultSubscribeAllRemoteVideoStreams(true);
mAliRtcEngine.subscribeAllRemoteVideoStreams(true);
//Atur callback terkait
private AliRtcEngineEventListener mRtcEngineEventListener = new AliRtcEngineEventListener() {
@Override
public void onJoinChannelResult(int result, String channel, String userId, int elapsed) {
super.onJoinChannelResult(result, channel, userId, elapsed);
handleJoinResult(result, channel, userId);
}
@Override
public void onLeaveChannelResult(int result, AliRtcEngine.AliRtcStats stats){
super.onLeaveChannelResult(result, stats);
}
@Override
public void onConnectionStatusChange(AliRtcEngine.AliRtcConnectionStatus status, AliRtcEngine.AliRtcConnectionStatusChangeReason reason){
super.onConnectionStatusChange(status, reason);
handler.post(new Runnable() {
@Override
public void run() {
if(status == AliRtcEngine.AliRtcConnectionStatus.AliRtcConnectionStatusFailed) {
/* TODO: Pastikan menangani pengecualian. SDK telah mencoba berbagai kebijakan pemulihan tetapi masih tidak dapat pulih. */
ToastHelper.showToast(VideoChatActivity.this, R.string.video_chat_connection_failed, Toast.LENGTH_SHORT);
} else {
/* TODO: Tangani pengecualian sesuai kebutuhan. Kode bisnis ditambahkan, biasanya untuk statistik data dan perubahan UI. */
}
}
});
}
@Override
public void OnLocalDeviceException(AliRtcEngine.AliRtcEngineLocalDeviceType deviceType, AliRtcEngine.AliRtcEngineLocalDeviceExceptionType exceptionType, String msg){
super.OnLocalDeviceException(deviceType, exceptionType, msg);
/* TODO: Pastikan menangani pengecualian. Disarankan memberi tahu pengguna tentang kesalahan perangkat ketika SDK telah mencoba semua kebijakan pemulihan tetapi masih tidak dapat menggunakan perangkat. */
handler.post(new Runnable() {
@Override
public void run() {
String str = "OnLocalDeviceException deviceType: " + deviceType + " exceptionType: " + exceptionType + " msg: " + msg;
ToastHelper.showToast(VideoChatActivity.this, str, Toast.LENGTH_SHORT);
}
});
}
};
private AliRtcEngineNotify mRtcEngineNotify = new AliRtcEngineNotify() {
@Override
public void onAuthInfoWillExpire() {
super.onAuthInfoWillExpire();
/* TODO: Pastikan menangani ini. Token akan segera kedaluwarsa. Bisnis perlu memicu mendapatkan informasi autentikasi baru untuk saluran dan pengguna saat ini, lalu set refreshAuthInfo. */
}
@Override
public void onRemoteUserOnLineNotify(String uid, int elapsed){
super.onRemoteUserOnLineNotify(uid, elapsed);
}
//Hapus pengaturan kontrol rendering aliran video jarak jauh dalam callback onRemoteUserOffLineNotify
@Override
public void onRemoteUserOffLineNotify(String uid, AliRtcEngine.AliRtcUserOfflineReason reason){
super.onRemoteUserOffLineNotify(uid, reason);
}
//Atur kontrol rendering aliran video jarak jauh dalam callback onRemoteTrackAvailableNotify
@Override
public void onRemoteTrackAvailableNotify(String uid, AliRtcEngine.AliRtcAudioTrack audioTrack, AliRtcEngine.AliRtcVideoTrack videoTrack){
handler.post(new Runnable() {
@Override
public void run() {
if(videoTrack == AliRtcVideoTrackCamera) {
SurfaceView surfaceView = mAliRtcEngine.createRenderSurfaceView(VideoChatActivity.this);
surfaceView.setZOrderMediaOverlay(true);
FrameLayout view = getAvailableView();
if (view == null) {
return;
}
remoteViews.put(uid, view);
view.addView(surfaceView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
AliRtcEngine.AliRtcVideoCanvas remoteVideoCanvas = new AliRtcEngine.AliRtcVideoCanvas();
remoteVideoCanvas.view = surfaceView;
mAliRtcEngine.setRemoteViewConfig(remoteVideoCanvas, uid, AliRtcVideoTrackCamera);
} else if(videoTrack == AliRtcVideoTrackNo) {
if(remoteViews.containsKey(uid)) {
ViewGroup view = remoteViews.get(uid);
if(view != null) {
view.removeAllViews();
remoteViews.remove(uid);
mAliRtcEngine.setRemoteViewConfig(null, uid, AliRtcVideoTrackCamera);
}
}
}
}
});
}
/* Bisnis mungkin memicu situasi di mana perangkat yang berbeda bersaing untuk UserID yang sama, jadi ini juga perlu ditangani */
@Override
public void onBye(int code){
handler.post(new Runnable() {
@Override
public void run() {
String msg = "onBye code:" + code;
}
});
}
};
mAliRtcEngine.setRtcEngineEventListener(mRtcEngineEventListener);
mAliRtcEngine.setRtcEngineNotify(mRtcEngineNotify);
//Pratinjau lokal
mLocalVideoCanvas = new AliRtcEngine.AliRtcVideoCanvas();
SurfaceView localSurfaceView = mAliRtcEngine.createRenderSurfaceView(VideoChatActivity.this);
localSurfaceView.setZOrderOnTop(true);
localSurfaceView.setZOrderMediaOverlay(true);
FrameLayout fl_local = findViewById(R.id.fl_local);
fl_local.addView(localSurfaceView, layoutParams);
mLocalVideoCanvas.view = localSurfaceView;
mAliRtcEngine.setLocalViewConfig(mLocalVideoCanvas, AliRtcVideoTrackCamera);
mAliRtcEngine.startPreview();
//Gabung ruang RTC
mAliRtcEngine.joinChannel(token, null, null, null);
iOS
Untuk langkah-langkah terperinci tentang menggunakan ARTC SDK untuk bergabung dengan ruang RTC dan mendorong aliran, lihat: Langkah-langkah implementasi.
// Impor kelas ARTC terkait
import AliVCSDK_ARTC
private var rtcEngine: AliRtcEngine? = nil
// Buat mesin dan atur callback
let engine = AliRtcEngine.sharedInstance(self, extras:nil)
...
self.rtcEngine = engine
// Atur mode saluran
engine.setChannelProfile(AliRtcChannelProfile.interactivelive)
engine.setClientRole(AliRtcClientRole.roleInteractive)
engine.setAudioProfile(AliRtcAudioProfile.engineHighQualityMode, audio_scene: AliRtcAudioScenario.sceneMusicMode)
//Atur parameter pengkodean video
let config = AliRtcVideoEncoderConfiguration()
config.dimensions = CGSize(width: 720, height: 1280)
config.frameRate = 20
config.bitrate = 1200
config.keyFrameInterval = 2000
config.orientationMode = AliRtcVideoEncoderOrientationMode.adaptive
engine.setVideoEncoderConfiguration(config)
engine.setCapturePipelineScaleMode(.post)
engine.publishLocalVideoStream(true)
engine.publishLocalAudioStream(true)
engine.setDefaultSubscribeAllRemoteAudioStreams(true)
engine.subscribeAllRemoteAudioStreams(true)
engine.setDefaultSubscribeAllRemoteVideoStreams(true)
engine.subscribeAllRemoteVideoStreams(true)
//Atur callback terkait
extension VideoCallMainVC: AliRtcEngineDelegate {
func onJoinChannelResult(_ result: Int32, channel: String, elapsed: Int32) {
"onJoinChannelResult1 result: \(result)".printLog()
}
func onJoinChannelResult(_ result: Int32, channel: String, userId: String, elapsed: Int32) {
"onJoinChannelResult2 result: \(result)".printLog()
}
func onRemoteUser(onLineNotify uid: String, elapsed: Int32) {
// Pengguna jarak jauh online
"onRemoteUserOlineNotify uid: \(uid)".printLog()
}
func onRemoteUserOffLineNotify(_ uid: String, offlineReason reason: AliRtcUserOfflineReason) {
// Pengguna jarak jauh offline
"onRemoteUserOffLineNotify uid: \(uid) reason: \(reason)".printLog()
}
func onRemoteTrackAvailableNotify(_ uid: String, audioTrack: AliRtcAudioTrack, videoTrack: AliRtcVideoTrack) {
"onRemoteTrackAvailableNotify uid: \(uid) audioTrack: \(audioTrack) videoTrack: \(videoTrack)".printLog()
}
func onAuthInfoWillExpire() {
"onAuthInfoWillExpire".printLog()
/* TODO: Pastikan menangani ini. Token akan segera kedaluwarsa. Bisnis perlu memicu mendapatkan informasi autentikasi baru untuk saluran dan pengguna saat ini, lalu set refreshAuthInfo. */
}
func onAuthInfoExpired() {
"onAuthInfoExpired".printLog()
/* TODO: Pastikan menangani ini. Beri tahu bahwa token tidak valid, dan lakukan keluar dari pertemuan serta lepaskan mesin. */
}
func onBye(_ code: Int32) {
"onBye code: \(code)".printLog()
/* TODO: Pastikan menangani ini. Bisnis mungkin memicu situasi di mana perangkat yang berbeda bersaing untuk UserID yang sama. */
}
func onLocalDeviceException(_ deviceType: AliRtcLocalDeviceType, exceptionType: AliRtcLocalDeviceExceptionType, message msg: String?) {
"onLocalDeviceException deviceType: \(deviceType) exceptionType: \(exceptionType)".printLog()
/* TODO: Pastikan menangani ini. Disarankan memberi tahu pengguna tentang kesalahan perangkat ketika SDK telah mencoba semua kebijakan pemulihan tetapi masih tidak dapat menggunakan perangkat. */
}
func onConnectionStatusChange(_ status: AliRtcConnectionStatus, reason: AliRtcConnectionStatusChangeReason) {
"onConnectionStatusChange status: \(status) reason: \(reason)".printLog()
if status == .failed {
/* TODO: Pastikan menangani ini. Disarankan memberi tahu pengguna ketika SDK telah mencoba semua kebijakan pemulihan tetapi masih tidak dapat pulih. */
}
else {
/* TODO: Tangani ini sesuai kebutuhan. Tambahkan kode bisnis, biasanya untuk statistik data dan perubahan UI. */
}
}
}
//Pratinjau lokal
let videoView = self.createVideoView(uid: self.userId)
let canvas = AliVideoCanvas()
canvas.view = videoView.canvasView
canvas.renderMode = .auto
canvas.mirrorMode = .onlyFrontCameraPreviewEnabled
canvas.rotationMode = ._0
self.rtcEngine?.setLocalViewConfig(canvas, for: AliRtcVideoTrack.camera)
self.rtcEngine?.startPreview()
//Gabung ruang RTC
let ret = self.rtcEngine?.joinChannel(joinToken, channelId: nil, userId: nil, name: nil) { [weak self] errCode, channelId, userId, elapsed in
if errCode == 0 {
// sukses
}
else {
// gagal
}
let resultMsg = "\(msg) \n CallbackErrorCode: \(errCode)"
resultMsg.printLog()
UIAlertController.showAlertWithMainThread(msg: resultMsg, vc: self!)
}
let resultMsg = "\(msg) \n ReturnErrorCode: \(ret ?? 0)"
resultMsg.printLog()
if ret != 0 {
UIAlertController.showAlertWithMainThread(msg: resultMsg, vc: self)
}
2. Server aplikasi memulai tugas penerusan untuk meneruskan aliran ruang RTC ke CDN
Server aplikasi membuat langganan untuk callback pesan ruang RTC guna memantau peristiwa dorongan aliran streamer di ruang tersebut. Untuk informasi API terperinci tentang berlangganan pesan ruang RTC, lihat CreateEventSub - Buat langganan untuk callback pesan ruangan.
Setelah menerima notifikasi bahwa streamer telah mendorong aliran ke ruang RTC, panggil OpenAPI StartLiveMPUTask untuk meneruskan aliran dari ruang RTC ke CDN. Untuk detail tentang API streaming bypass, lihat StartLiveMPUTask - Buat tugas pencampuran aliran (baru).
CatatanKetika streamer memulai siaran, Anda dapat mengatur
MixModeke 0, yang menunjukkan penerusan aliran tunggal tanpa transkoding. API memerlukan URL ingest streaming langsung, yang hanya mendukung protokol RTMP. Untuk informasi tentang cara menghasilkan URL ini, lihat Hasilkan URL ingest dan pemutaran.Server aplikasi memantau callback pendorongan aliran CDN. Setelah aliran diteruskan ke CDN, ia mendistribusikan URL pemutaran siaran langsung untuk memberi tahu penonton agar memulai pemutaran. Untuk detail tentang callback pendorongan aliran CDN, lihat Pengaturan callback.
3. Penonton menggunakan SDK Pemutar Video Apsara untuk menarik dan memainkan aliran
Ketika penonton menerima notifikasi penarikan aliran dari server aplikasi, mereka membuat instans Pemutar Video Apsara dan menggunakan URL pemutaran siaran langsung untuk pemutaran. Untuk informasi API pemain terperinci dan penggunaannya, lihat SDK Pemutar Video Apsara.
Disarankan untuk mengubah URL pemutaran CDN untuk penonton biasa dari format RTMP menjadi format HTTP-FLV. Keduanya berisi konten yang sama tetapi menggunakan protokol transmisi yang berbeda. HTTP, sebagai protokol Internet utama, memiliki dasar optimalisasi jaringan yang lebih matang dan menggunakan port default 80/443, sehingga lebih mudah melewati firewall. Protokol RTMP lebih tua, dan port umumnya 1935 mungkin dibatasi, mempengaruhi stabilitas pemutaran. Secara keseluruhan, HTTP-FLV lebih unggul dari RTMP dalam hal kompatibilitas dan pengalaman pemutaran (seperti tersendat dan latensi), jadi disarankan untuk menggunakan HTTP-FLV sebagai pilihan pertama.
Android
AliPlayer aliPlayer = AliPlayerFactory.createAliPlayer(context);
aliPlayer.setAutoPlay(true);
UrlSource urlSource = new UrlSource();
urlSource.setUri("http://test.alivecdn.com/live/streamId.flv?auth_key=XXX"); // URL streaming CDN untuk penonton.
aliPlayer.setDataSource(urlSource);
aliPlayer.prepare();iOS
self.cdnPlayer = [[AliPlayer alloc] init];
self.cdnPlayer.delegate = self;
self.cdnPlayer.autoPlay = YES;
AVPUrlSource *source = [[AVPUrlSource alloc] urlWithString:@""http://test.alivecdn.com/live/streamId.flv?auth_key=XXX"];
[self.cdnPlayer setUrlSource:source];
[self.cdnPlayer prepare];
Langkah 2: Co-streaming penonton
Proses dasar untuk co-streaming antara streamer dan penonton adalah sebagai berikut:
1. Co-streamer menghentikan pemutaran aliran CDN dan mendorong aliran ke ruang RTC
Co-streamer menghentikan pemutaran aliran CDN Pemutar Video Apsara dan menghapus mesin pemain.
Android
aliPlayer.stop(); aliPlayer = nul;iOS
[self.cdnPlayer stop]; [self.cdnPlayer clearScreen]; self.cdnPlayer.playerView = nil;Co-streamer mendorong aliran ke ruang RTC: Proses untuk co-streamer mendorong aliran ke ruang RTC sama dengan proses untuk streamer yang dijelaskan di atas. Untuk detailnya, lihat Dorong aliran ke ruang RTC.
Co-streamer mengatur tampilan rendering streamer.
Android
Saat menginisialisasi mesin, atur callback yang sesuai
mAliRtcEngine.setRtcEngineNotify. Anda perlu mengatur tampilan jarak jauh untuk pengguna jarak jauh di callbackonRemoteTrackAvailableNotify. Contoh kode adalah sebagai berikut:@Override public void onRemoteTrackAvailableNotify(String uid, AliRtcEngine.AliRtcAudioTrack audioTrack, AliRtcEngine.AliRtcVideoTrack videoTrack){ handler.post(new Runnable() { @Override public void run() { if(videoTrack == AliRtcVideoTrackCamera) { SurfaceView surfaceView = mAliRtcEngine.createRenderSurfaceView(VideoChatActivity.this); surfaceView.setZOrderMediaOverlay(true); FrameLayout fl_remote = findViewById(R.id.fl_remote); if (fl_remote == null) { return; } fl_remote.addView(surfaceView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); AliRtcEngine.AliRtcVideoCanvas remoteVideoCanvas = new AliRtcEngine.AliRtcVideoCanvas(); remoteVideoCanvas.view = surfaceView; mAliRtcEngine.setRemoteViewConfig(remoteVideoCanvas, uid, AliRtcVideoTrackCamera); } else if(videoTrack == AliRtcVideoTrackNo) { FrameLayout fl_remote = findViewById(R.id.fl_remote); fl_remote.removeAllViews(); mAliRtcEngine.setRemoteViewConfig(null, uid, AliRtcVideoTrackCamera); } } }); }iOS
Ketika pengguna jarak jauh mendorong atau berhenti mendorong aliran, callback
onRemoteTrackAvailableNotifydipicu. Dalam callback ini, Anda mengatur atau menghapus tampilan jarak jauh. Contoh kode adalah sebagai berikut:func onRemoteTrackAvailableNotify(_ uid: String, audioTrack: AliRtcAudioTrack, videoTrack: AliRtcVideoTrack) { "onRemoteTrackAvailableNotify uid: \(uid) audioTrack: \(audioTrack) videoTrack: \(videoTrack)".printLog() // Status aliran pengguna jarak jauh if audioTrack != .no { let videoView = self.videoViewList.first { $0.uidLabel.text == uid } if videoView == nil { _ = self.createVideoView(uid: uid) } } if videoTrack != .no { var videoView = self.videoViewList.first { $0.uidLabel.text == uid } if videoView == nil { videoView = self.createVideoView(uid: uid) } let canvas = AliVideoCanvas() canvas.view = videoView!.canvasView canvas.renderMode = .auto canvas.mirrorMode = .onlyFrontCameraPreviewEnabled canvas.rotationMode = ._0 self.rtcEngine?.setRemoteViewConfig(canvas, uid: uid, for: AliRtcVideoTrack.camera) } else { self.rtcEngine?.setRemoteViewConfig(nil, uid: uid, for: AliRtcVideoTrack.camera) } if audioTrack == .no && videoTrack == .no { self.removeVideoView(uid: uid) self.rtcEngine?.setRemoteViewConfig(nil, uid: uid, for: AliRtcVideoTrack.camera) } }
2. Streamer mengatur tampilan rendering co-streamer
Proses untuk streamer merender tampilan co-streamer sama dengan proses untuk co-streamer merender tampilan streamer. Anda dapat merujuk pada langkah-langkah di atas.
3. Server aplikasi memperbarui dari streaming bypass ke pencampuran aliran
Setelah server aplikasi menerima notifikasi bahwa co-streamer telah mendorong aliran ke ruang RTC, ia memanggil UpdateLiveMPUTask - Perbarui tugas pencampuran aliran (baru) untuk memperbarui ID tugas streaming bypass asli, mengubahnya dari bypass ke pencampuran aliran dengan mengatur MixMode menjadi 1, dan mengonfigurasi tata letak pencampuran aliran untuk streamer dan co-streamer.
Langkah 3: Penonton mengakhiri co-streaming
Proses dasar untuk mengakhiri co-streaming antara streamer dan penonton adalah sebagai berikut:
1. Co-streamer berhenti mendorong aliran ke ruang RTC dan beralih ke menarik aliran CDN dengan pemain
Co-streamer keluar dari ruang RTC dan menghapus mesin RTC.
Android
mAliRtcEngine.stopPreview(); mAliRtcEngine.setLocalViewConfig(null, AliRtcVideoTrackCamera); mAliRtcEngine.leaveChannel(); mAliRtcEngine.destroy(); mAliRtcEngine = null;iOS
self.rtcEngine?.stopPreview() self.rtcEngine?.leaveChannel() AliRtcEngine.destroy() self.rtcEngine = nilBuat mesin pemain dan mainkan aliran CDN. Langkah-langkahnya sama dengan langkah-langkah untuk penonton biasa menggunakan SDK Pemutar Video Apsara untuk menarik dan memainkan aliran yang dijelaskan di atas.
2. Streamer berhenti menarik aliran audio dan video co-streamer
Streamer menghentikan pemutaran aliran audio dan video co-streamer dan menghapus tampilan jarak jauh di onRemoteTrackAvailableNotify.
3. Server aplikasi memperbarui dari pencampuran aliran ke streaming bypass
Setelah server aplikasi menerima notifikasi callback bahwa co-streamer telah meninggalkan ruang RTC, ia memanggil UpdateLiveMPUTask - Perbarui tugas pencampuran aliran (baru) untuk memperbarui ID tugas pencampuran aliran asli, mengubahnya dari pencampuran aliran menjadi bypass dengan mengatur MixMode menjadi 0. Tampilan siaran langsung CDN berubah dari menampilkan streamer dan co-streamer menjadi hanya menampilkan streamer.