Configure and control video
Configure video capture, encoding, camera control, preview, mirroring, and rendering through the ARTC SDK.
Features
During a video call or interactive streaming, configure capture resolution, encoding resolution, frame rate, bitrate, mirror mode, and render mode.
-
Resolution:
-
Capture resolution: The resolution of the video from a capture device, such as a camera.
-
Encoding resolution: The resolution of the encoded video.
-
-
Bitrate: The number of bits transmitted per second (bps).
-
Frame rate: The number of frames displayed per second (fps).
Proper resolution, frame rate, and bitrate settings improve video quality. Mirror and render modes control how video is displayed.
Sample code
Basic video usage for Android: Android/ARTCExample/BasicUsage/src/main/java/com/aliyun/artc/api/basicusage/VideoBasicUsage/VideoBasicUsageActivity.java.
Basic video usage for iOS: iOS/ARTCExample/BasicUsage/VideoBasicUsage/VideoBasicUsageVC.swift.
Basic video usage for Harmony: Harmony/ARTCExample/entry/src/main/ets/pages/basicusage/VideoBasicUsage.ets.
Prerequisites
Before you configure video settings:
-
An Alibaba Cloud account with an ARTC application (Create an application). You need the App ID and App Key from the ApsaraVideo Live console.
-
The ARTC SDK is integrated and basic audio and video calls are implemented. SDK Download/Integration and Implement an audio and video call.
Implementation
1. Set camera capture configuration
Use setCameraCapturerConfiguration to set camera direction and capture frame rate.
-
Call this method before starting the camera, for example, before calling startPreview or joinChannel (which automatically starts the camera).
-
Calling
enableLocalVideo(false)to disable camera capture releases the camera resources. You can then reset the configuration.
The method is defined as follows:
/**
* @brief Sets the capture preference.
* @param cameraCapturerConfiguration The camera capture settings.
* - preference:
* - {@link AliRtcCaptureOutputPreference#ALIRTC_CAPTURER_OUTPUT_PREFERENCE_PREVIEW} Preview priority. Prioritizes video preview quality.
* - {@link AliRtcCaptureOutputPreference#ALIRTC_CAPTURER_OUTPUT_PREFERENCE_PERFORMANCE} Performance priority. Prioritizes device performance by selecting a resolution close to that of the published stream.
* - {@link AliRtcCaptureOutputPreference#ALIRTC_CAPTURER_OUTPUT_PREFERENCE_AUTO} Auto. The SDK automatically adjusts the capture resolution.
* - cameraDirection: The camera direction. You can set it to the front or rear camera.
* @return
* - 0: Success.
* - A non-zero value: Failure.
* @note You must call this method before you start the camera, for example, before you call {@link #startPreview} or {@link #joinChannel}.
*/
public abstract int setCameraCapturerConfiguration(AliEngineCameraCapturerConfiguration cameraCapturerConfiguration);
Parameters:
|
Parameter |
Type |
Description |
|
|
The capture preference.
|
|
|
|
The camera direction (front or rear). |
|
|
|
int |
The capture frame rate. Default value: -1, which means the SDK uses the fps from the encoding configuration (the SDK's internal default is 15). |
|
|
The video capture resolution.
|
|
|
|
int |
(Android only) Specifies whether to enable texture encoding. |
|
|
int |
(Android only) Specifies whether to enable texture capture for the camera. |
Sample code:
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);
macOS
AliRtcCameraCapturerConfiguration *configuration = [[AliRtcCameraCapturerConfiguration alloc] init];
configuration.preference = (AliRtcCaptureOutputPreference)outputBox.indexOfSelectedItem;
configuration.cameraCaptureProfile = AliRtcCameraCaptureProfileDefault;
configuration.fps = 15;
[self.engine setCameraCapturerConfiguration:configuration];
Windows
AliEngineCameraCapturerConfiguration config ;
config.preference = AliEngineCaptureOutputPreferencePerformance;
config.cameraCaptureProfile = AliEngineCameraCaptureProfileDefault;
config.fps = 30;
mAliRtcEngine->setCameraCapturerConfiguration(config);
2. Set video encoder configuration
Use setVideoEncoderConfiguration to set video resolution, frame rate, bitrate, and keyframe interval.
Call setVideoEncoderConfiguration before or after joining a channel. If called only once per call, call it before joining.
Parameters:
|
Parameter |
Type |
Description |
|
|
The video resolution. Default: 640x480. Maximum: 1920x1080. |
|
|
|
int |
The video encoding frame rate. Default: 15. Maximum: 30. |
|
|
int |
The video bitrate in kbps. Default: 512. Set to 0 for auto-calculation based on resolution and frame rate. If the bitrate falls outside the recommended range, the SDK adjusts it automatically. Recommended ranges are in the sample code comments. |
|
|
int |
The keyframe interval in milliseconds. Default: 0 (SDK-controlled). Note
This parameter is required for interactive streaming and for interoperability with a mini program. |
|
|
boolean |
Whether to force strict keyframe generation at the set interval. Default:
|
|
|
The mirror mode for the encoded video. Note
You can also use the |
|
|
|
The orientation mode of the encoded video.
|
|
|
|
The rotation angle of the encoded video. Valid values are 0, 90, 180, and 270. |
|
|
|
The codec type.
|
|
|
|
The video encoding format. Supported formats: system default, H.264, and H.265. |
|
|
|
int |
Whether to force an I-frame before sending an SEI message. Valid values: |
Sample code:
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;
// Call the RTC engine to set the configuration.
this.rtcEngine?.setVideoEncoderConfiguration(encoderConfig);
macOS
AliRtcVideoEncoderConfiguration *config = [[AliRtcVideoEncoderConfiguration alloc] init];
config.dimensions = CGSizeMake(720, 1280);
config.frameRate = 20;
config.bitrate = 1200
config.keyFrameInterval = 2000
config.orientationMode = AliRtcVideoEncoderOrientationModeAdaptive;
[self.engine setVideoEncoderConfiguration:config];
Windows
AliEngineVideoEncoderConfiguration aliRtcVideoEncoderConfiguration ;
aliRtcVideoEncoderConfiguration.dimensions = AliRtcVideoDimensions(720, 1280);
aliRtcVideoEncoderConfiguration.frameRate = AliEngineFrameRateFps20;
aliRtcVideoEncoderConfiguration.bitrate = 1200;
aliRtcVideoEncoderConfiguration.keyFrameInterval = 2000;
aliRtcVideoEncoderConfiguration.orientationMode = AliEngineVideoEncoderOrientationModeAdaptive;
mAliRtcEngine->SetVideoEncoderConfiguration(aliRtcVideoEncoderConfiguration);
3. Switch cameras
The SDK uses the front camera by default. Call setCameraCaptureConfiguration before starting capture to specify a different camera, or switchCamera to switch at runtime.
/**
* @brief Switches between the front and rear cameras.
* @return
* - `0`: Success
* - Non-zero: Failure
* @note This API is available on iOS and Android only.
*/
public abstract int switchCamera();
Sample code:
Android
mSwitchCameraBtn.setOnClickListener(v -> {
if(mAliRtcEngine != null) {
mAliRtcEngine.switchCamera();
}
});
iOS
@IBAction func onCameraDirectionChanged(_ sender: UISegmentedControl) {
rtcEngine?.switchCamera()
}
Harmony
this.rtcEngine.switchCamera();
4. Control the camera
Two APIs control the camera: muteLocalCamera and enableLocalVideo.
|
API |
|
|
|
How it works |
Sends black frames instead of video. |
Stops camera capture and releases device resources. |
|
Behavior |
The local preview remains active, but remote users see a black screen. |
Local preview and remote video freeze on the last frame. |
|
Characteristics |
|
|
4.1. Mute or unmute local video
muteLocalCamera keeps the video capture, encoding, and transmission pipeline active but sends black frames to remote users. The local preview is unaffected.
/**
* @brief Mutes or unmutes the local video stream.
* @param mute true: Sends black frames. false: Resumes sending normal video frames.
* @param track The video track to mute. Only {@link AliRtcVideoTrack#AliRtcVideoTrackCamera} is supported.
* @return
* - 0: Success.
* - A non-zero value: Failure.
* @note This method sends black frames while the local preview remains unaffected. The video capture pipeline continues to run.
*/
public abstract int muteLocalCamera(boolean mute, AliRtcVideoTrack track);
/**
* @brief Occurs when a remote user mutes or unmutes their video stream.
* @param uid The ID of the user who called muteLocalCamera.
* @param isMute
* - true: The user is sending black frames.
* - false: The user is sending normal video frames.
*/
public void onUserVideoMuted(String uid ,boolean isMute){}
Android
Mute or unmute the video stream:
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;
}
Listen for the remote callback:
@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
Mute or unmute the video stream:
@IBAction func onVideoMuteSwitched(_ sender: UISwitch) {
if sender.isOn {
// Send black frames.
rtcEngine?.muteLocalCamera(true, for: AliRtcVideoTrack.camera)
} else {
// Resume sending normal video frames.
rtcEngine?.muteLocalCamera(false, for: AliRtcVideoTrack.camera)
}
}
Listen for the remote callback:
extension VideoBasicUsageVC: AliRtcEngineDelegate {
func onUserVideoMuted(_ uid: String, videoMuted isMute: Bool) {
"onUserVideoMuted: user id \(uid) video muted: \(isMute)".printLog()
}
}
Harmony
Mute or unmute the video stream:
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;
}
}
}
Listen for the remote callback:
listener.onUserVideoMuted((uid : string, isMute : boolean) => {
console.info(`User ${uid}'s video has been ${isMute ? 'muted' : 'unmuted'}`);
});
macOS
Mute or unmute the video stream:
[self.engine muteLocalCamera:self.muteLocalCamera forTrack:AliRtcVideoTrackCamera];
Listen for the remote callback:
- (void)onUserVideoMuted:(NSString *_Nullable)uid videoMuted:(BOOL)isMute {
NSLog(@"uid=%@ mute:%d", uid, isMute );
}
Windows
Mute or unmute the video stream:
if ( mMuteLocalCamera == TRUE) {
mAliRtcEngine->MuteLocalCamera(TRUE, AliRtcVideoTrackCamera);
} else {
mAliRtcEngine->MuteLocalCamera(FALSE, AliRtcVideoTrackCamera);
}
Listen for the remote callback:
void CTutorialDlg::OnUserVideoMuted(const char* uid, bool isMute)
{
// Find the corresponding user view to update its status.
PartUserDlg *partUserView = mRemotePartDlgs[uid];
if (nullptr != partUserView)
{
partUserView->muteStream = isMute;
updateRemoteParticipants();
}
}
4.2. Enable or disable video capture
enableLocalVideo controls the camera. Disabling it stops capture and transmission, releasing the device.
/**
* @brief Enables or disables local video capture.
* @param enabled
* - true: Enables local video capture.
* - false: Disables local video capture.
* @return
* - 0: Success.
* - < 0: Failure.
* @note This feature is enabled by default. Listen for the {@link AliRtcEngineNotify#onUserVideoEnabled} callback to be notified of changes to a remote user's video capture status.
*/
public abstract int enableLocalVideo(boolean enabled);
/**
* @brief Occurs when a remote user enables or disables their local video capture.
* @param uid The ID of the user who called enableLocalVideo.
* @param isEnable
* - true: The user enabled local video capture.
* - false: The user disabled local video capture.
*/
public void onUserVideoEnabled(String uid, boolean isEnable){}
Android
Enable or disable video capture:
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);
}
}
});
Listen for the remote callback:
@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
Enable or disable video capture:
@IBAction func onCameraSwitch(_ sender: UISwitch) {
if sender.isOn {
rtcEngine?.enableLocalVideo(true)
} else {
rtcEngine?.enableLocalVideo(false)
}
updateCaptureUIVisibility()
}
Listen for the remote callback:
extension VideoBasicUsageVC: AliRtcEngineDelegate {
func onUserVideoEnabled(_ uid: String?, videoEnabled isEnable: Bool) {
"onUserVideoEnabled: user id \(uid ?? "invalid uid") video enable: \(isEnable)".printLog()
}
}
Harmony
Enable or disable video capture:
private toggleCamera(): void {
if (this.rtcEngine) {
if (this.isEnableCamera) {
this.rtcEngine.enableLocalVideo(false);
this.isEnableCamera = false;
} else {
this.rtcEngine.enableLocalVideo(true);
this.isEnableCamera = true;
}
}
}
Listen for the remote callback:
listener.onUserVideoEnabled((uid : string, isEnable : boolean) => {
console.info(`User ${uid}'s video has been ${isEnable ? 'enabled' : 'disabled'}`);
});
macOS
Enable or disable video capture:
[self.engine enableLocalVideo:isOpen];
Listen for the remote callback:
- (void)onUserVideoEnabled:(NSString *_Nullable)uid videoEnabled:(BOOL)isEnable) {
NSLog(@"uid=%@ enabled:%d", uid, isEnable );
}
Windows
Enable or disable video capture:
mbLocalVideo = !mbLocalVideo;
mAliRtcEngine->EnableLocalVideo(mbLocalVideo);
Listen for the remote callback:
void CTutorialDlg::OnUserVideoEnabled(const char* uid, bool isEnable) {
// Find the corresponding user view to update its status.
PartUserDlg *partUserView = mRemotePartDlgs[uid];
if (nullptr != partUserView)
{
partUserView->enableVideo = isEnable;
updateRemoteParticipants();
}
}
5. Start or stop preview
Use startPreview and stopPreview to control the local preview.
Note:
-
You must call
setLocalViewConfigto set a render view before you start the preview. -
By default, the SDK starts the preview when you join a channel. If you need to start the preview before joining the channel, call
startPreview. -
After stopping the preview, the local view freezes on the last frame.
API call sequence
Sample code:
Android
Start the preview:
private void startPreview() {
if (mAliRtcEngine != null) {
ViewGroup.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
// Set the local view.
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
}
}
}
// Start the preview.
mAliRtcEngine.startPreview();
}
}
Stop the preview:
mAliRtcEngine.stopPreview();
mAliRtcEngine.setLocalViewConfig(null, AliRtcVideoTrackCamera);
mAliRtcEngine.leaveChannel();
mAliRtcEngine.destroy();
mAliRtcEngine = null;
iOS
Start the preview:
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()
}
Stop the preview:
self.rtcEngine?.stopPreview()
self.rtcEngine?.setLocalViewConfig(nil, for: AliRtcVideoTrack.camera)
self.rtcEngine?.leaveChannel()
AliRtcEngine.destroy()
self.rtcEngine = nil
Harmony
Start the preview:
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();
Stop the preview:
this.rtcEngine.stopPreview();
Mac
Start the preview:
NSView * newView = [self createSeatView:uid];
AliVideoCanvas *canvas = [[AliVideoCanvas alloc] init];
canvas.renderMode = AliRtcRenderModeAuto;
canvas.view = newView;
canvas.mirrorMode = AliRtcRenderMirrorModeAllDisabled;
canvas.rotation = AliRtcRotationMode_0;
[self.engine setLocalViewConfig:canvas forTrack:AliRtcVideoTrackCamera];
[self.engine startPreview];
Stop the preview:
[self.engine stopPreview];
[self.engine setLocalViewConfig:nil, AliRtcVideoTrackCamera];
[self.engine leaveChannel];
[self.engine destroy];
_engine = nil ;
Windows
Start the preview:
AliEngineVideoCanvas canvas;
canvas.renderMode = AliEngineRenderModeAuto;
canvas.rotation = AliEngineRotationMode_0;
canvas.displayView = hLocalWnd;
mAliRtcEngine->SetLocalViewConfig(canvas, AliEngineVideoTrackCamera);
mAliRtcEngine->StartPreview();
Stop the preview:
mAliRtcEngine->StopPreview();
mAliRtcEngine->SetLocalViewConfig(nullptr, AliEngineVideoTrackCamera);
mAliRtcEngine->LeaveChannel();
mAliRtcEngine->Destroy();
mAliRtcEngine = nullptr;
6. Set the mirror mode
setVideoMirrorMode controls mirroring for the local preview and published stream. Call it at runtime during video calls or live streaming.
/**
* @brief Sets the mirror mode for the local video preview and the published stream.
* @param mirrorMode The mirror mode to set.
* @return
* - 0: Success.
* - <0: Failure.
* - AliRtcErrInner: An internal SDK state error occurred. Verify that the SDK instance was created successfully.
*
* @note
* - You can call this method to change the mirror mode at runtime, either before or after you join a channel. The SDK records the state and applies the setting when the preview and encoding are active.
* - This method overrides the mirror settings configured in `setLocalViewConfig` and `setVideoEncoderConfiguration`.
* - This method's settings duplicate those in `setLocalViewConfig` and `setVideoEncoderConfiguration`. Use only one method to configure mirroring.
*/
public abstract int setVideoMirrorMode(AliRtcVideoPipelineMirrorMode mirrorMode);
Mirror modes:
|
Enum value |
Description |
|
|
Mirroring is disabled for both preview and encoding. |
|
|
Enables mirroring for both the preview and encoding (default). |
|
|
Enables mirroring for the preview only. |
|
|
Enables mirroring for the published stream only. |
Sample code:
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);
macOS
[self.engine setVideoMirrorMode:AliRtcVideoPipelineMirrorModeOnlyPreviewMirror];
Windows
mAliRtcEngine->setVideoMirrorMode(AliEngineVideoPipelineMirrorModeOnlyPreviewMirror);
7. Set the render view
Call setLocalViewConfig or setRemoteViewConfig to set a render view before displaying video.
// Sets the render view for the local preview.
public abstract int setLocalViewConfig(AliRtcVideoCanvas viewConfig, AliRtcVideoTrack track);
// Sets the render view for a specified remote user.
public abstract int setRemoteViewConfig(AliRtcVideoCanvas canvas, String uid, AliRtcVideoTrack track);
AliRtcVideoCanvas parameters:
|
Parameter |
Type |
Description |
|
|
|
The display view (required). |
|
|
|
The render mode.
|
|
|
|
The mirror mode.
|
|
|
|
The rotation mode. Valid values: 0, 90, 180, and 270 degrees. |
|
|
|
The background color in hexadecimal RGB format, for example, 0x000000. |
|
|
|
(Android only) The texture ID, used for displaying a third-party OpenGL ES texture. |
|
|
|
(Android only) The width of the texture. |
|
|
|
(Android only) The height of the texture. |
|
|
|
(Android only) The shared OpenGL ES context for the texture. |
Sample code:
7.1. Set the local render view
Android
mLocalVideoCanvas = new AliRtcEngine.AliRtcVideoCanvas();
// Get and set the 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;
// Set the local preview view.
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()
macOS
NSView * newView = [self createSeatView:uid];
AliVideoCanvas *canvas = [[AliVideoCanvas alloc] init];
canvas.renderMode = AliRtcRenderModeAuto;
canvas.view = newView;
canvas.mirrorMode = AliRtcRenderMirrorModeAllDisabled;
canvas.rotation = AliRtcRotationMode_0;
[self.engine setLocalViewConfig:canvas forTrack:AliRtcVideoTrackCamera];
[self.engine startPreview];
Windows
AliEngineVideoCanvas canvas;
/* Window handle */
canvas.view = mHWnd;
canvas.mirrorMode = AliEngineRenderMirrorModeAllNoMirror;
mAliRtcEngine->setLocalViewConfig(canvas, AliEngineVideoTrackCamera);
Harmony
// Create or reuse the 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. Set the remote render view
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()
// Handles the availability of a remote user's stream.
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)
}
}
macOS
- (void)onRemoteTrackAvailableNotify:(NSString *)uid audioTrack:(AliRtcAudioTrack)audioTrack videoTrack:(AliRtcVideoTrack)videoTrack {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"Remote user stream information callback");
__weak typeof(self)weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
__strong typeof(weakSelf)strongSelf = self;
if (videoTrack == AliRtcVideoTrackNo) {
// [self removeRemoteViewWithUid:uid];
} else if(videoTrack == AliRtcVideoTrackCamera) {
[strongSelf addRemoteViewWithUid:uid videoTrack:AliRtcVideoTrackCamera];
} else if(videoTrack == AliRtcVideoTrackScreen) {
[strongSelf addRemoteViewWithUid:uid videoTrack:AliRtcVideoTrackScreen];
} else if(videoTrack == AliRtcVideoTrackBoth) {
[strongSelf addRemoteViewWithUid:uid videoTrack:AliRtcVideoTrackBoth];
}
});
});
}
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
// Remote audio/video stream availability notification
listener.onRemoteTrackAvailableNotify((userId: string, audioTrack: AliRtcAudioTrack,
videoTrack: AliRtcVideoTrack) => {
console.info(`Remote audio/video stream available: userId=${userId}, videoTrack=${videoTrack}`);
// Configure the remote view based on the video stream type.
if (videoTrack === AliRtcVideoTrack.AliRtcVideoTrackCamera) {
// Camera stream is available.
this.viewRemoteVideo(userId, AliRtcVideoTrack.AliRtcVideoTrackCamera);
this.removeRemoteVideo(userId, AliRtcVideoTrack.AliRtcVideoTrackScreen);
} else if (videoTrack === AliRtcVideoTrack.AliRtcVideoTrackScreen) {
// Screen sharing stream is available.
this.viewRemoteVideo(userId, AliRtcVideoTrack.AliRtcVideoTrackScreen);
this.removeRemoteVideo(userId, AliRtcVideoTrack.AliRtcVideoTrackCamera);
} else if (videoTrack === AliRtcVideoTrack.AliRtcVideoTrackBoth) {
// Dual streams are available (camera + screen sharing).
this.viewRemoteVideo(userId, AliRtcVideoTrack.AliRtcVideoTrackCamera);
this.viewRemoteVideo(userId, AliRtcVideoTrack.AliRtcVideoTrackScreen);
} else if (videoTrack === AliRtcVideoTrack.AliRtcVideoTrackNo) {
// No video stream.
this.removeAllRemoteVideo(userId);
}
});