本文將為您介紹如何通過調用API設定視頻編碼屬性。
功能介紹
在進行視訊通話或直播時,開發人員可以根據需要設定視頻相關配置,如視頻採集、編碼解析度、視訊框架率、碼率、鏡像模式、視圖模式等。
解析度:
採集解析度:指網路攝影機等採集裝置提供的畫面解析度。
編碼解析度:指經過編碼處理的畫面的解析度。
碼率:指每秒傳輸的位元(bit)數,單位為 bps(bit per second)。
幀率:單位時間內視頻顯示幀數的量度單位,測量單位為“每秒顯示幀數”(Frame Per Second,fps)。
設定合適的視頻解析度、幀率和碼率可以在音視頻情境中為使用者提供更好的使用體驗。選擇合適鏡像模式與視圖模式則可以讓開發人員提供個人化的視頻顯示模式。
範例程式碼
Android端視頻常用操作和配置:Android/ARTCExample/BasicUsage/src/main/java/com/aliyun/artc/api/basicusage/VideoBasicUsage/VideoBasicUsageActivity.java。
iOS端視頻常用操作和配置:iOS/ARTCExample/BasicUsage/VideoBasicUsage/VideoBasicUsageVC.swift。
Harmony端視頻常用操作和配置:Harmony/ARTCExample/entry/src/main/ets/pages/basicusage/VideoBasicUsage.ets。
前提條件
在設定視頻配置之前,請確保達成以下條件:
功能實現
1.設定相機採集配置
ARTC 提供setCameraCapturerConfiguration方法設定相機採集配置,包括相機方向、採集幀率。
需要在啟動相機前調用,例如在 startPreview 啟動預覽或者 joinChannel 加入頻道(自動啟動相機)前。
調用
enableLocalVideo(false)關閉網路攝影機採集會釋放網路攝影機資源,此時可以重新設定。
介面定義如下:
/**
* @brief 採集喜好設定
* @param cameraCapturerConfiguration 喜好設定
* - preference:
* - {@link AliRtcCaptureOutputPreference#ALIRTC_CAPTURER_OUTPUT_PREFERENCE_PREVIEW} 高清預覽,採集優先保證視頻預覽品質
* - {@link AliRtcCaptureOutputPreference#ALIRTC_CAPTURER_OUTPUT_PREFERENCE_PERFORMANCE} 採集選擇最接近推流的解析度,優先保證裝置效能
* - {@link AliRtcCaptureOutputPreference#ALIRTC_CAPTURER_OUTPUT_PREFERENCE_AUTO} 自動調整採集解析度
* - cameraDirection: 設定採集方向,前置或後置網路攝影機
* @return
* - 0: 成功
* - 非0: 表示失敗
* @note 必須在開啟網路攝影機之前設定,如{@link #startPreview},{@link #joinChannel}之前設定
*/
public abstract int setCameraCapturerConfiguration(AliEngineCameraCapturerConfiguration cameraCapturerConfiguration);相關配置如下:
參數 | 類型 | 描述 |
| 採集偏好。
| |
| 相機方向(前置/後置)。 | |
| int | 採集幀率。 預設值為-1,表示使用編碼配置的 fps,SDK 內部為 15。 |
| 指定視頻採集的特定解析度。
| |
| int | (僅 Android)是否使用紋理編碼。 |
| int | (僅 Android)網路攝影機是否開啟紋理採集。 |
介面調用樣本如下:
Android
AliRtcEngine.AliEngineCameraCapturerConfiguration config = new AliRtcEngine.AliEngineCameraCapturerConfiguration();
config.preference = AliRtcEngine.AliRtcCaptureOutputPreference.ALIRTC_CAPTURER_OUTPUT_PREFERENCE_AUTO;
config.cameraCaptureProfile = AliRtcEngine.AliRtcCameraCaptureProfile.ALIRTC_CAMERA_CAPTURER_PROFILE_DEFAULT;
config.cameraDirection = AliRtcEngine.AliRtcCameraDirection.CAMERA_FRONT;
config.fps = 30;
mAliRtcEngine.setCameraCapturerConfiguration(config);iOS
let cameraCaptureConfig: AliRtcCameraCapturerConfiguration = AliRtcCameraCapturerConfiguration()
cameraCaptureConfig.preference = .auto
cameraCaptureConfig.cameraCaptureProfile = .profileDefault
cameraCaptureConfig.cameraDirection = .front
cameraCaptureConfig.fps = 30
engine.setCameraCapturerConfiguration(cameraCaptureConfig)Harmony
const cameraConfig = new AliRtcCameraCaptureConfiguration();
cameraConfig.preference = AliRtcCaptureOutputPreference.AliRtcCaptureOutputPreferenceAuto;
cameraConfig.cameraDirection = AliRtcCameraDirection.AliRtcCameraDirectionFront;
cameraConfig.cameraCaptureProfile = AliRtcCameraCaptureProfile.AliRtcCameraCaptureProfileDefault;
cameraConfig.fps = 30;
this.rtcEngine?.setCameraCaptureConfiguration(cameraConfig);2.設定視頻編碼配置
ARTC 提供setVideoEncoderConfiguration介面用於配置視頻編碼屬性,包含視頻解析度、幀率、碼率、主要畫面格間隔等影響視頻品質的參數設定。開發人員可以通過設定視頻編碼屬性,控制視頻流在不同網路條件下的展示方式。
setVideoEncoderConfiguration在加入頻道前後均可設定,如果在一次通話過程中僅需要設定一次,推薦在加入頻道前設定。
相關配置如下:
參數名 | 類型 | 描述 |
| 視頻解析度,視頻解析度,預設值640x480,最大值1920x1080。 | |
| int | 視頻編碼幀率,預設值15, 最大值30。 |
| int | 視頻編碼碼率(kbps),預設值為 512。設定為0表示由SDK內部根據視頻解析度和碼率計算合適的編碼碼率。 碼率設定應根據解析度和幀率有對應的合理範圍,該值設定在合理範圍內有效,否則SDK會自動調節碼率到有效值。碼率與解析度、幀率對應關係請參考代碼注釋。 |
| int | 主要畫面格間隔,單位毫秒。預設值0,表示SDK內部控制主要畫面格間隔。 說明 互動直播情境、需要和小程式互連情境必須設定。 |
| boolean | 是否強制編碼器嚴格按照設定的主要畫面格間隔產生主要畫面格,預設值false。
|
| 編碼視頻鏡像模式,控制推流視頻是否鏡像。 說明 設定鏡像可以使用 | |
| 編碼視頻旋轉模式。
| |
| 視頻旋轉角度(0/90/180/270)。 | |
| 轉碼器類型。
| |
| 視頻編碼格式(系統預設/ H264/H265)。 | |
| int | SEI發送前強制I幀。 -1表示使用預設值,0表示不強制,1表示強制(預設值)。 |
介面調用樣本如下:
Android
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);iOS
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)Harmony
const encoderConfig = new AliRtcVideoEncoderConfiguration();
const dimensions = new AliRtcVideoDimensions();
dimensions.width = 720;
dimensions.height = 1280;
encoderConfig.dimensions = dimensions;
encoderConfig.bitrate = 1200;
encoderConfig.frameRate = 20;
encoderConfig.orientationMode = AliRtcVideoEncoderOrientationMode.AliRtcVideoEncoderOrientationModeAdaptive;
encoderConfig.rotationMode = AliRtcRotationMode.AliRtcRotationMode_0;
// 調用RTC引擎設定配置
this.rtcEngine?.setVideoEncoderConfiguration(encoderConfig);3.切換相機方向
Android 和 iOS 裝置通常具有前置和後置網路攝影機。SDK 預設使用自拍,如果需要修改,請調用setCameraCaptureConfiguration介面在開啟網路攝影機前進行設定。如果已經開啟網路攝影機,需要切換網路攝影機則可以調用switchCamera介面。
/**
* @brief 切換前後網路攝影機
* @return
* - 0: 成功
* - 非0: 失敗
* @note 只有iOS和android提供這個介面
*/
public abstract int switchCamera();介面調用樣本如下:
Android
mSwitchCameraBtn.setOnClickListener(v -> {
if(mAliRtcEngine != null) {
mAliRtcEngine.switchCamera();
}
});iOS
@IBAction func onCameraDirectionChanged(_ sender: UISegmentedControl) {
rtcEngine?.switchCamera()
}Harmony
this.rtcEngine.switchCamera();4.開關網路攝影機
在音視訊通話中實現網路攝影機開關功能,ARTC 提供兩個介面,muteLocalCamera和enableLocalVideo。
介面 |
|
|
實現原理 | 發送資料替換為黑幀。 | 直接停止網路攝影機硬體採集,釋放相關資源。 |
關閉網路攝影機現象 | 本地預覽正常顯示,遠端使用者黑屏。 | 本地預覽和遠端均停留在最後一幀。 |
特點 |
|
|
4.1. 停止或恢複視頻資料發送
ARTC 提供muteLocalCamera介面實現禁視頻功能,在保留視頻採集/編碼/傳輸通道啟動並執行前提下,向遠端發送全黑視訊框架(本地預覽保持正常畫面)。介面定義如下:
/**
* 是否將停止本地視頻資料發送
* @param mute true表示視頻資料發送黑幀;false表示恢複正常
* @param track 只支援{@link AliRtcVideoTrack#AliRtcVideoTrackCamera}
* @return
* - 0: 成功
* - 非0: 失敗
* @note 發送黑色的視訊框架。本地正常預覽。採集、編碼、發送模組仍然工作,只是視頻內容被替換為黑色幀
*/
public abstract int muteLocalCamera(boolean mute, AliRtcVideoTrack track);
/**
* @brief 對端使用者發送視頻黑幀資料發送通知
* @param uid 執行muteVideo的使用者ID
* @param isMute
* - true: 推流黑幀
* - false: 正常推流
* @note 該介面用於對端使用者發送視頻黑幀資料時的回調
*/
public void onUserVideoMuted(String uid ,boolean isMute){}程式碼範例如下:
Android
開關網路攝影機採集:
if(!isMutedCamera) {
mAliRtcEngine.muteLocalCamera(true, AliRtcEngine.AliRtcVideoTrack.AliRtcVideoTrackCamera);
mPublishVideoBtn.setText(R.string.resume_pub_video);
isMutedCamera = true;
} else {
mAliRtcEngine.muteLocalCamera(false, AliRtcEngine.AliRtcVideoTrack.AliRtcVideoTrackCamera);
mPublishVideoBtn.setText(R.string.stop_pub_video);
isMutedCamera = false;
}遠端監聽回調:
@Override
public void onUserVideoMuted(String uid ,boolean isMute){
handler.post(new Runnable() {
@Override
public void run() {
ToastHelper.showToast(VideoBasicUsageActivity.this, "remote user uid:" + uid + " camera mute:" + isMute, Toast.LENGTH_SHORT);
}
});
}iOS
開關網路攝影機採集:
@IBAction func onVideoMuteSwitched(_ sender: UISwitch) {
if sender.isOn {
// 黑幀
rtcEngine?.muteLocalCamera(false, for: AliRtcVideoTrack.camera)
} else {
rtcEngine?.muteLocalCamera(true, for: AliRtcVideoTrack.camera)
}
}遠端監聽回調
extension VideoBasicUsageVC: AliRtcEngineDelegate {
func onUserVideoMuted(_ uid: String, videoMuted isMute: Bool) {
"onUserVideoMuted: user id \(uid) video muted: \(isMute)".printLog()
}
}Harmony
開關相機:
private toggleVideoSending(): void {
if (this.rtcEngine) {
if (!this.isMutedCamera) {
this.rtcEngine.muteLocalCamera(true, AliRtcVideoTrack.AliRtcVideoTrackCamera);
this.isMutedCamera = true;
} else {
this.rtcEngine.muteLocalCamera(false, AliRtcVideoTrack.AliRtcVideoTrackCamera);
this.isMutedCamera = false;
}
}
}遠端監聽回調:
listener.onUserVideoMuted((uid : string, isMute : boolean) => {
console.info(`使用者${uid}的視頻已${isMute ? '靜音' : '取消靜音'}`);
});4.2. 開關相機採集
通過 enableLocalVideo 介面實現全域性控制本地視頻採集裝置(如網路攝影機)的啟停狀態,直接影響視頻資料流的產生與傳輸。
/**
* @brief 禁用或啟用本地視頻採集
* @param enabled
* - true : 啟用本地視頻採集
* - false : 禁用本地視頻採集
* @return
* - 0 : 成功
* - < 0 : 失敗
* @note 預設為開啟狀態, 通過監聽 {@link AliRtcEngineNotify#onUserVideoEnabled} 擷取使用者是否禁用或啟用本地視頻採集狀態。
*/
public abstract int enableLocalVideo(boolean enabled);
/**
* @brief 對端使用者關閉相機流採集發送通知
* @param uid 執行EnableLocalVideo的使用者ID
* @param isEnable
* - true: 開啟相機流採集
* - false: 關閉相機流採集
* @note 該介面用於對端使用者關閉相機流採集時的回調
*/
public void onUserVideoEnabled(String uid, boolean isEnable){}代碼調用樣本:
Android
開關相機
mCameraSwitchBtn = findViewById(R.id.camera_control_btn);
mCameraSwitchBtn.setOnClickListener(v -> {
if(mAliRtcEngine != null) {
if(isEnableCamera) {
mAliRtcEngine.enableLocalVideo(false);
isEnableCamera = false;
mCameraSwitchBtn.setText(R.string.camera_on);
} else {
mAliRtcEngine.enableLocalVideo(true);
isEnableCamera = true;
mCameraSwitchBtn.setText(R.string.camera_off);
}
}
});遠端監聽回調
@Override
public void onUserVideoEnabled(String uid, boolean isEnable) {
handler.post(new Runnable() {
@Override
public void run() {
ToastHelper.showToast(VideoBasicUsageActivity.this, "remote user uid:" + uid + " camera enable:" + isEnable, Toast.LENGTH_SHORT);
}
});
}iOS
開關相機採集
@IBAction func onCameraSwitch(_ sender: UISwitch) {
if sender.isOn {
rtcEngine?.enableLocalVideo(true)
} else {
rtcEngine?.enableLocalVideo(false)
}
updateCaptureUIVisibility()
}遠端監聽回調
extension VideoBasicUsageVC: AliRtcEngineDelegate {
func onUserVideoEnabled(_ uid: String?, videoEnabled isEnable: Bool) {
"onUserVideoEnabled: user id \(uid ?? "invalid uid") video enable: \(isEnable)".printLog()
}
}Harmony
開關相機採集:
private toggleCamera(): void {
if (this.rtcEngine) {
if (this.isEnableCamera) {
this.rtcEngine.enableLocalVideo(false);
this.isEnableCamera = false;
} else {
this.rtcEngine.enableLocalVideo(true);
this.isEnableCamera = true;
}
}
}遠端監聽回調:
listener.onUserVideoEnabled((uid : string, isMute : boolean) => {
console.info(`使用者${uid}的視頻已${isMute ? '禁用' : '啟用'}`);
});5. 開啟或關閉預覽
ARTC 提供startPreview和stopPreview介面來控制本地預覽的啟停。
注意:
預覽前需要調用
setLocalViewConfig為本地預覽畫面設定渲染視圖。SDK 加入頻道預設會開啟預覽,如果需要在入會前開啟預覽可以提前調用
startPreview。調用關閉預覽後,本端預覽畫面會停留在最後一幀。
開啟預覽。
程式碼範例如下:
Android
啟動預覽:
private void startPreview() {
if (mAliRtcEngine != null) {
ViewGroup.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
// 設定本地視圖
if (mLocalVideoCanvas == null) {
mLocalVideoCanvas = new AliRtcEngine.AliRtcVideoCanvas();
SurfaceView localSurfaceView = mAliRtcEngine.createRenderSurfaceView(VideoBasicUsageActivity.this);
if (localSurfaceView != null) {
localSurfaceView.setZOrderOnTop(true);
localSurfaceView.setZOrderMediaOverlay(true);
fl_local.addView(localSurfaceView, layoutParams);
mLocalVideoCanvas.view = localSurfaceView;
try {
mAliRtcEngine.setLocalViewConfig(mLocalVideoCanvas, AliRtcVideoTrackCamera);
} catch (Exception e) {
e.printStackTrace(); // Handle potential exceptions
}
}
}
// 開始預覽
mAliRtcEngine.startPreview();
}
}關閉預覽:
mAliRtcEngine.stopPreview();
mAliRtcEngine.setLocalViewConfig(null, AliRtcVideoTrackCamera);
mAliRtcEngine.leaveChannel();
mAliRtcEngine.destroy();
mAliRtcEngine = null;iOS
啟動預覽:
func startPreview() {
let seatView = self.createSeatView(uid: self.userId)
let canvas = AliVideoCanvas()
canvas.view = seatView.canvasView
canvas.renderMode = .auto
canvas.mirrorMode = .onlyFrontCameraPreviewEnabled
canvas.rotationMode = ._0
self.rtcEngine?.setLocalViewConfig(canvas, for: AliRtcVideoTrack.camera)
self.rtcEngine?.startPreview()
}關閉預覽:
self.rtcEngine?.stopPreview()
self.rtcEngine?.leaveChannel()
AliRtcEngine.destroy()
self.rtcEngine = nilHarmony
啟動預覽:
if (!this.aliRtcVideoCanvas) {
this.aliRtcVideoCanvas = new AliRtcVideoCanvas();
}
this.aliRtcVideoCanvas.surfaceId = this.localSurfaceId;
this.aliRtcVideoCanvas.renderMode = AliRtcRenderMode.AliRtcRenderModeAuto;
this.aliRtcVideoCanvas.mirrorMode = AliRtcRenderMirrorMode.AliRtcRenderMirrorModeAllMirror;
this.rtcEngine.setLocalViewConfig(
this.aliRtcVideoCanvas,
this.componentController,
AliRtcVideoTrack.AliRtcVideoTrackCamera
);
this.rtcEngine.startPreview();關閉預覽:
this.rtcEngine.stopPreview();6. 設定鏡像模式
ARTC 提供setVideoMirrorMode介面控制本地視頻的預覽畫面鏡像與推流畫面鏡像行為,支援運行時動態調整,適用於音視訊通話、直播等情境。
/**
* @brief 設定預覽和推流鏡像能力
* @param mirrorMode 設定鏡像的模式
* @return
* - 0: 設定成功
* - <0: 設定失敗
* - AliRtcErrInner: SDK內部狀態錯誤,需檢查是否建立SDK執行個體成功
*
* @note
* - 此介面在入會前和入會後均可以動態設定,SDK內部會選項組,並在可以操作預覽及編碼的時候對視頻進行操作;
* - 使用此介面的優先順序會高於setLocalViewConfig&setVideoEncoderConfiguration
* - 此介面與setLocalViewConfiguration&setVideoEncoderConfiguration裡面的mirror重合,建議只有一個方式
*/
public abstract int setVideoMirrorMode(AliRtcVideoPipelineMirrorMode mirrorMode);鏡像模式如下:
枚舉值 | 描述 |
| 預覽和編碼均關閉鏡像。 |
| 預覽和編碼均開啟鏡像(預設)。 |
| 僅預覽開啟鏡像。 |
| 僅推流開啟鏡像。 |
程式碼範例如下:
Android
mMirrorSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long id) {
if(mAliRtcEngine != null) {
AliRtcEngine.AliRtcVideoPipelineMirrorMode mirrorMode = AliRtcEngine.AliRtcVideoPipelineMirrorMode.values()[position];
mAliRtcEngine.setVideoMirrorMode(mirrorMode);
}
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});iOS
let mirrorMode: AliRtcVideoPipelineMirrorMode = {
switch row {
case 0: return .bothMirror
case 1: return .noMirror
case 2: return .onlyPreviewMirror
case 3: return .onlyPublishMirror
default: return .bothMirror
}
}()
self.rtcEngine?.setVideoMirrorMode(mirrorMode)Harmony
const mirrorMode = AliRtcVideoPipelineMirrorMode.AliRtcVideoPipelineMirrorModeBothMirror;
this.rtcEngine.setVideoMirrorMode(mirrorMode);7. 設定渲染視圖
在顯示本地預覽和遠端使用者畫面前,需要調用setLocalViewConfig或setRemoteViewConig 介面為待顯示畫面設定渲染視圖。
// 設定本地預覽顯示視圖
public abstract int setLocalViewConfig(AliRtcVideoCanvas viewConfig, AliRtcVideoTrack track);
// 設定遠端置頂使用者顯示視圖
public abstract int setRemoteViewConfig(AliRtcVideoCanvas canvas, String uid, AliRtcVideoTrack track);AliRtcVideoCanvas 常用配置如下:
參數 | 類型 | 說明 |
|
| 顯示視圖(必需)。 |
|
| 渲染模式。
|
|
| 鏡像模式。
|
|
| 旋轉模式(0/90/180/270)。 |
|
| 背景顏色,格式為RGB的Hex,例如0x000000。 |
|
| (僅 Android)支援第三方OpenGL ES紋理顯示,紋理ID。 |
|
| (僅 Android)支援第三方OpenGL ES紋理顯示,紋理寬。 |
|
| (僅 Android)支援第三方OpenGL ES紋理顯示,紋理高。 |
|
| (僅 Android)支援第三方OpenGL ES紋理顯示,紋理共用上下文。 |
程式碼範例如下:
7.1. 設定本地渲染視圖
Android
mLocalVideoCanvas = new AliRtcEngine.AliRtcVideoCanvas();
// 擷取並設定SurfaceView
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();iOS
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()Windows
AliEngineVideoCanvas canvas;
/* windows 視窗控制代碼 */
canvas.view = mHWnd;
mAliRtcEngine.setLocalViewConfig(canvas, AliEngineVideoTrackCamera);Harmony
// 建立或重用canvas
if (!this.aliRtcVideoCanvas) {
this.aliRtcVideoCanvas = new AliRtcVideoCanvas();
}
this.aliRtcVideoCanvas.surfaceId = this.localSurfaceId;
this.aliRtcVideoCanvas.renderMode = AliRtcRenderMode.AliRtcRenderModeAuto;
this.aliRtcVideoCanvas.mirrorMode = AliRtcRenderMirrorMode.AliRtcRenderMirrorModeAllMirror;
this.rtcEngine.setLocalViewConfig(
this.aliRtcVideoCanvas,
this.componentController,
AliRtcVideoTrack.AliRtcVideoTrackCamera
);
this.rtcEngine.startPreview();7.2. 設定遠端渲染視圖
Android
@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
func onRemoteTrackAvailableNotify(_ uid: String, audioTrack: AliRtcAudioTrack, videoTrack: AliRtcVideoTrack) {
"onRemoteTrackAvailableNotify uid: \(uid) audioTrack: \(audioTrack) videoTrack: \(videoTrack)".printLog()
// 遠端使用者的流狀態
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)
}
}Windows
virtual void OnRemoteTrackAvailableNotify(const char *uid, AliEngineAudioTrack audioTrack, AliEngineVideoTrack videoTrack) {
AliEngineVideoCanvas remote_canvas;
if (videoTrack == AliEngineVideoTrackCamera
|| videoTrack == AliEngineVideoTrackBoth) {
RECT rect;
::GetWindowRect(mHWnd, &rect);
remote_canvas.displayView = remoteView;
remote_canvas.renderMode = AliEngineRenderModeAuto;
mAliRtcEngine->SetRemoteViewConfig(remote_canvas,uid,AliEngineVideoTrackCamera);
} else {
mAliRtcEngine->SetRemoteViewConfig(remote_canvas, uid, AliEngineVideoTrackCamera);
}
}Harmony
// 遠端音視頻流可用通知
listener.onRemoteTrackAvailableNotify((userId: string, audioTrack: AliRtcAudioTrack,
videoTrack: AliRtcVideoTrack) => {
console.info(`遠端音視頻流可用: userId=${userId}, videoTrack=${videoTrack}`);
// 根據視頻流類型,調用setRemoteViewConfig配置遠端視圖
if (videoTrack === AliRtcVideoTrack.AliRtcVideoTrackCamera) {
// 網路攝影機流可用
this.viewRemoteVideo(userId, AliRtcVideoTrack.AliRtcVideoTrackCamera);
this.removeRemoteVideo(userId, AliRtcVideoTrack.AliRtcVideoTrackScreen);
} else if (videoTrack === AliRtcVideoTrack.AliRtcVideoTrackScreen) {
// 螢幕畫面分享流可用
this.viewRemoteVideo(userId, AliRtcVideoTrack.AliRtcVideoTrackScreen);
this.removeRemoteVideo(userId, AliRtcVideoTrack.AliRtcVideoTrackCamera);
} else if (videoTrack === AliRtcVideoTrack.AliRtcVideoTrackBoth) {
// 雙流可用(網路攝影機+螢幕畫面分享)
this.viewRemoteVideo(userId, AliRtcVideoTrack.AliRtcVideoTrackCamera);
this.viewRemoteVideo(userId, AliRtcVideoTrack.AliRtcVideoTrackScreen);
} else if (videoTrack === AliRtcVideoTrack.AliRtcVideoTrackNo) {
// 無視頻流
this.removeAllRemoteVideo(userId);
}
});