The ARTC SDK provides APIs for managing video capture devices across platforms, including camera zoom, exposure, focus, and flashlight control.
Feature overview
The ARTC SDK provides comprehensive control over video capture devices. On platforms such as iOS and Android, you can fine-tune camera parameters including zoom, exposure, and manual or auto focus to improve video capture quality.
Sample code
Android video capture device management: Android/ARTCExample/BasicUsage/src/main/java/com/aliyun/artc/api/basicusage/CameraCommonControl/CameraActivity.java.
iOS video capture device management: iOS/ARTCExample/BasicUsage/CameraCommonSetting/CameraCommonControlVC.swift.
Harmony video capture device management: Harmony/ARTCExample/entry/src/main/ets/pages/basicusage/CameraPage.ets.
Prerequisites
-
You have an Alibaba Cloud account and have created a Real-Time Communication (RTC) application. For more information, see Create an application. You have obtained an AppID and an AppKey from the ApsaraVideo Live console.
-
SDK integration and basic feature implementation:
-
You have integrated the ARTC SDK into your project and implemented basic Real-Time Communication (RTC) features. For more information, see Integrate the SDK and Implement an audio and video call.
-
The camera has been started, for example, by starting a preview with
startPreviewor joining a channel withjoinChannel.
-
Implementation
Set camera zoom
The ARTC SDK allows you to control camera zoom.
API reference
/**
* @brief Sets the camera zoom.
* @param zoom The zoom factor. The value ranges from 1 to the maximum zoom value supported by the camera.
* @return
* - 0: Success.
* - A non-zero value: Failure.
* @note This API is available only on iOS and Android.
*/
public abstract int setCameraZoom(float zoom);
/**
* @brief Gets the maximum zoom factor of the camera.
* @return The maximum zoom factor of the camera.
*/
public abstract float GetCameraMaxZoomFactor();
/**
* @brief Gets the current zoom factor of the camera.
* @return The current zoom factor of the camera.
*/
public abstract float GetCurrentZoom();
Examples
Android
// Get zoom information.
private void initZoomSeekBar() {
if (mAliRtcEngine != null) {
zoomSeekBar.setEnabled(true);
// Get the maximum zoom value.
float maxZoom = mAliRtcEngine.GetCameraMaxZoomFactor();
float currZoom = mAliRtcEngine.GetCurrentZoom();
// Set the SeekBar range (from 1.0 to maxZoom, with a step of 0.1).
if(maxZoom >= 1.0) {
int maxProgress = (int)((maxZoom - 1) * 10);
zoomSeekBar.setMax(maxProgress);
int currProgress = (int)((currZoom - 1) * 10);
zoomSeekBar.setProgress(currProgress);
} else{
zoomSeekBar.setEnabled(false);
}
}
}
// Set the zoom.
zoomSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
if(mAliRtcEngine != null) {
float newZoom = (float)((i+10) / 10.0);
mAliRtcEngine.setCameraZoom(newZoom);
zoomTextView.setText(String.format("%.1f", newZoom));
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
iOS
// Get zoom information.
self.cameraZoomSlider.isEnabled = true
let maxZoom = rtcEngine.getCameraMaxZoomFactor()
let currZoom = rtcEngine.getCurrentZoom()
"Get maxZoom=\(maxZoom), currZoom=\(currZoom)".printLog()
self.cameraZoomSlider.minimumValue = 1.0
if maxZoom > 1.0 {
self.cameraZoomSlider.maximumValue = maxZoom
} else {
self.cameraZoomSlider.isEnabled = false
}
if currZoom >= 1.0 && currZoom <= maxZoom {
self.cameraZoomSlider.value = currZoom
self.cameraZoomValueLabel.text = String(format: "%.1f", self.cameraZoomSlider.value)
}
else {
self.cameraZoomSlider.value = self.cameraZoomSlider.minimumValue
self.cameraZoomValueLabel.text = "\(self.cameraZoomSlider.minimumValue)"
}
// Set the zoom.
@IBOutlet weak var cameraZoomSlider: UISlider!
@IBOutlet weak var cameraZoomValueLabel: UILabel!
@IBAction func onCameraZoomChanged(_ sender: UISlider) {
let currValue = sender.value
self.cameraZoomValueLabel.text = String(format: "%.1f", currValue)
self.rtcEngine?.setCameraZoom(currValue)
}
Harmony
private handleZoomChange(value: number): void {
if (!this.rtcEngine) {
return;
}
// Calculate the zoom value based on the progress: zoom = 1.0 + (value / 10.0).
const newZoom = 1.0 + (value / 10.0);
// Clamp the zoom value between 1.0 and 10.0.
const clampedZoom = Math.max(1.0, Math.min(10.0, newZoom));
this.rtcEngine.setCameraZoom(clampedZoom);
this.zoomValue = clampedZoom.toFixed(1);
console.info(`Set zoom: ${clampedZoom}`);
}
Set camera exposure
The ARTC SDK allows you to adjust camera exposure to control image brightness.
API reference
/**
* @brief Sets the camera exposure.
* @param exposure The exposure value.
* @return
* - 0: Success.
* - A non-zero value: Failure.
*/
public abstract int SetExposure(float exposure);
/**
* @brief Gets the current camera exposure.
* @return The current camera exposure.
*/
public abstract float GetCurrentExposure();
/**
* @brief Gets the minimum camera exposure.
* @return The minimum camera exposure.
*/
public abstract float GetMinExposure();
/**
* @brief Gets the maximum camera exposure.
* @return The maximum camera exposure.
*/
public abstract float GetMaxExposure();
Examples
Android
// Get exposure information.
private void initExposureSeekBar() {
if (mAliRtcEngine != null) {
exposureSeekBar.setEnabled(true);
// Get the maximum exposure value.
float maxExposure = mAliRtcEngine.GetMaxExposure();
// Get the minimum exposure value.
float minExposure = mAliRtcEngine.GetMinExposure();
float currExposure = mAliRtcEngine.GetCurrentExposure();
if(maxExposure > minExposure) {
// Reset the SeekBar range.
int maxProgress = (int)((maxExposure - minExposure) * 10);
exposureSeekBar.setMax(maxProgress);
int currProgress = (int)((currExposure - minExposure) * 10);
exposureSeekBar.setProgress(currProgress);
} else {
exposureSeekBar.setEnabled(false);
}
}
}
// Set the exposure.
exposureSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
if(mAliRtcEngine != null) {
float minExposure = mAliRtcEngine.GetMinExposure();
float newExposure = minExposure + (float)(i / 10.0);
mAliRtcEngine.SetExposure(newExposure);
exposureTextView.setText(String.format("% .1f", newExposure));
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
iOS
// Get device exposure information.
self.cameraExposureSlider.isEnabled = true
let minExposure = rtcEngine.getMinExposure()
let maxExposure = rtcEngine.getMaxExposure()
let currExposure = rtcEngine.getCurrentExposure()
"Get minExposure=\(minExposure), maxExposure=\(maxExposure), currExposure=\(currExposure)".printLog()
if maxExposure > minExposure {
self.cameraExposureSlider.minimumValue = minExposure
self.cameraExposureSlider.maximumValue = maxExposure
} else {
self.cameraExposureSlider.isEnabled = false
}
if currExposure >= minExposure && currExposure <= maxExposure {
self.cameraExposureSlider.value = currExposure
self.cameraExposureValueLabel.text = String(format: "%.1f", self.cameraExposureSlider.value)
}
else {
self.cameraExposureSlider.value = self.cameraExposureSlider.minimumValue
self.cameraExposureValueLabel.text = "\(self.cameraExposureSlider.minimumValue)"
}
// Set the exposure.
@IBOutlet weak var cameraExposureValueLabel: UILabel!
@IBOutlet weak var cameraExposureSlider: UISlider!
@IBAction func onCameraExposureChanged(_ sender: UISlider) {
let currValue = sender.value
self.cameraExposureValueLabel.text = String(format: "%.1f", currValue)
self.rtcEngine?.setExposure(currValue)
}
Harmony
// Handle exposure change.
private handleExposureChange(value: number): void {
if (!this.rtcEngine) {
return;
}
// Conversion formula: exposure value = progress value / 10.
const actualValue = value / 10.0;
// Clamp the exposure value between -12.0 and 12.0.
const clampedExposure = Math.max(-12.0, Math.min(12.0, actualValue));
// Update the state.
this.exposureSliderValue = value;
this.exposureValue = this.formatExposureValue(clampedExposure);
// Call the RTC engine to set the exposure compensation.
try {
this.rtcEngine.setExposure(clampedExposure);
console.info(`Set exposure compensation: ${clampedExposure}`);
} catch (error) {
console.error('Failed to set exposure compensation:', error);
}
}
Manually set the exposure point
The ARTC SDK allows you to set an exposure point manually. When a user taps a location on the screen, the camera adjusts exposure based on the lighting conditions in that area.
-
Before setting an exposure point, call
isCameraExposurePointSupportedto verify that the device supports this feature. -
The coordinates must be normalized values.
API reference
/**
* @brief Checks whether the camera supports setting a manual exposure point.
* @return
* - true: Supported.
* - false: Not supported.
* @note This API is available only on iOS and Android and is used to check if an exposure point can be set for the current camera.
*/
public abstract boolean isCameraExposurePointSupported();
/**
* @brief Sets the camera exposure point.
* @param x The normalized x-coordinate. The value ranges from 0 to 1.
* @param y The normalized y-coordinate. The value ranges from 0 to 1.
* @return
* - 0: Success.
* - A non-zero value: Failure.
* @note This API is available only on iOS and Android. After you call this method, the camera performs a one-time exposure adjustment at the specified point and maintains that exposure value.
*/
public abstract int setCameraExposurePoint(float x, float y);
Examples
Android
// Manually set the exposure point.
mLocalViewGestureDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onDoubleTap(@NonNull MotionEvent e) {
// Handle double-tap.
// ...
return true;
}
@Override
public boolean onSingleTapConfirmed(@NonNull MotionEvent e) {
// Handle single-tap.
if(mAliRtcEngine != null && mAliRtcEngine.isCameraExposurePointSupported()) {
float[] normalizedCoords = getNormalizedCoordinates(e.getX(), e.getY());
if (normalizedCoords[0] != -1 && normalizedCoords[1] != -1) {
mAliRtcEngine.setCameraExposurePoint(normalizedCoords[0], normalizedCoords[1]);
mCameraExposurePointX.setText(String.format("%.2f", normalizedCoords[0]));
mCameraExposurePointY.setText(String.format("%.2f", normalizedCoords[1]));
}
}
return true;
}
});
iOS
@objc func handleSeatViewTap(_ gesture: UITapGestureRecognizer) {
guard let localSeatView = self.localPreviewSeatView else {
return
}
guard let rtcEngine = self.rtcEngine, rtcEngine.isCameraExposurePointSupported() else { return }
let tapPoint = gesture.location(in: localSeatView)
// Convert the tap coordinates to normalized coordinates (0-1 range) of the video frame.
let normalizedX = tapPoint.x / localSeatView.bounds.width
let normalizedY = tapPoint.y / localSeatView.bounds.height
rtcEngine.setCameraExposurePoint(CGPoint(x: normalizedX, y: normalizedY))
self.cameraExposurePointXTextField.text = String(format: "%.2f", normalizedX)
self.cameraExposurePointYTextField.text = String(format: "%.2f", normalizedY)
}
Harmony
private handleSingleTap(touchX: number, touchY: number): void {
if (!this.rtcEngine) {
return;
}
// Get normalized coordinates.
const normalizedCoords = this.getNormalizedCoordinates(touchX, touchY);
if (normalizedCoords[0] !== -1 && normalizedCoords[1] !== -1) {
this.rtcEngine.setCameraExposurePoint(normalizedCoords[0], normalizedCoords[1]);
this.exposurePointX = normalizedCoords[0].toFixed(2);
this.exposurePointY = normalizedCoords[1].toFixed(2);
console.info('Set exposure point:', this.exposurePointX, this.exposurePointY);
}
}
Manually set the focus point
The ARTC SDK allows you to set a manual camera focus point. This works similarly to the exposure point feature but adjusts the camera focus position instead. Before using this feature, call isCameraFocusPointSupported to verify device support.
After you manually set a focus point, the focus becomes static. It does not continuously track the area or dynamically adjust as the object moves. For dynamic tracking, consider using the auto-focus on faces feature.
API reference
/**
* @brief Checks whether the camera supports manual focus.
* @return
* - true: Supported.
* - false: Not supported.
* @note This API is available only on iOS and Android and is used to check if a focus point can be set for the current camera.
*/
public abstract boolean isCameraFocusPointSupported();
/**
* @brief Sets the manual focus point for the camera.
* @param x The x-coordinate value (normalized).
* @param y The y-coordinate value (normalized).
* @return
* - 0: Success.
* - A non-zero value: Failure.
* @note This API is available only on iOS and Android. After you call this method, the camera performs a one-time focus adjustment at the specified point and maintains that focus value.
*/
public abstract int setCameraFocusPoint(float x, float y);
Examples
The following examples show how to set the exposure point on a single tap and the focus point on a double tap.
Android
mLocalViewGestureDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onDoubleTap(@NonNull MotionEvent e) {
// Handle double-tap.
if(mAliRtcEngine != null && mAliRtcEngine.isCameraFocusPointSupported()) {
float[] normalizedCoords = getNormalizedCoordinates(e.getX(), e.getY());
if (normalizedCoords[0] != -1 && normalizedCoords[1] != -1) {
mAliRtcEngine.setCameraFocusPoint(normalizedCoords[0], normalizedCoords[1]);
mCameraFocusPointX.setText(String.format("%.2f", normalizedCoords[0]));
mCameraFocusPointY.setText(String.format("%.2f", normalizedCoords[1]));
}
}
return true;
}
@Override
public boolean onSingleTapConfirmed(@NonNull MotionEvent e) {
// Handle single-tap.
// ...
return true;
}
});
iOS
@objc func handleSeatViewDoubleTap(_ gesture: UITapGestureRecognizer) {
guard let localSeatView = self.localPreviewSeatView else {
return
}
guard let rtcEngine = self.rtcEngine, rtcEngine.isCameraFocusPointSupported() else { return }
let tapPoint = gesture.location(in: localSeatView)
// Convert the tap coordinates to normalized coordinates (0-1 range) of the video frame.
let normalizedX = tapPoint.x / localSeatView.bounds.width
let normalizedY = tapPoint.y / localSeatView.bounds.height
rtcEngine.setCameraFocus(CGPoint(x: normalizedX, y: normalizedY))
self.cameraFocusPointXTextField.text = String(format: "%.2f", normalizedX)
self.cameraFocusPointYTextField.text = String(format: "%.2f", normalizedY)
}
Harmony
private handleDoubleTap(touchX: number, touchY: number): void {
if (!this.rtcEngine) {
return;
}
// Get normalized coordinates.
const normalizedCoords = this.getNormalizedCoordinates(touchX, touchY);
if (normalizedCoords[0] !== -1 && normalizedCoords[1] !== -1) {
this.rtcEngine.setCameraFocusPoint(normalizedCoords[0], normalizedCoords[1]);
this.focusPointX = normalizedCoords[0].toFixed(2);
this.focusPointY = normalizedCoords[1].toFixed(2);
console.info('Set focus point:', this.focusPointX, this.focusPointY);
}
}
Auto-focus on faces
The ARTC SDK provides an API to enable auto-focus on faces. On supported devices, the camera automatically detects faces in the video frame and adjusts focus to keep them sharp.
Use cases: Face recognition, portrait optimization, and enhanced visual quality in video calls.
Before starting, call isCameraAutoFocusFaceModeSupported to check if the current device supports this feature.
API reference
/**
* @brief Checks whether the camera supports the auto-focus on faces feature.
* @return
* - true: Supported.
* - false: Not supported.
* @note This API is available only on iOS and Android. It returns false if the camera is off.
* If the camera is on and supports both face detection and auto-focus, it returns true.
*/
public abstract boolean isCameraAutoFocusFaceModeSupported();
/**
* @brief Enables or disables the auto-focus on faces feature.
* @param enable
* - true: Enable.
* - false: Disable.
* @return
* - true: Success.
* - false: Failure.
* @note This API is available only on iOS and Android. If {@link AliRtcEngine#isCameraAutoFocusFaceModeSupported} returns true
* and you set enable to true, the camera continuously focuses on the detected faces.
*/
public abstract boolean setCameraAutoFocusFaceModeEnabled(boolean enable);
Examples
Android
if (mAliRtcEngine.isCameraAutoFocusFaceModeSupported()) {
mAliRtcEngine.setCameraAutoFocusFaceModeEnabled(isChecked);
}
iOS
@IBAction func onCameraAudoFocusSwitch(_ sender: UISwitch) {
if ((self.rtcEngine?.isCameraAutoFocusFaceModeSupported()) != nil) {
self.rtcEngine?.setCameraAutoFocusFaceModeEnabled(sender.isOn)
}
}
Toggle the flashlight
The ARTC SDK allows you to turn the camera flashlight on or off, which is useful in low-light conditions or for other special lighting needs.
-
This feature is available only on iOS and Android and requires a hardware flashlight.
-
The flashlight is typically available only for the rear camera. Front-facing cameras usually do not have a physical flashlight. Although some devices simulate a flash effect using the screen, this API does not control that function.
API reference
/**
* @brief Turns the camera flashlight on or off.
* @param flash Specifies whether to turn on the flashlight.
* @return
* - 0: Success.
* - A non-zero value: Failure.
* @note This API is available only on iOS and Android. Typically, only the rear camera has a flashlight.
*/
public abstract int setCameraFlash(boolean flash);
Examples
Android
mCameraFlashSwitch = findViewById(R.id.camera_flash_switch);
mCameraFlashSwitch.setEnabled(false);
mCameraFlashSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
if (mAliRtcEngine != null) {
mAliRtcEngine.setCameraFlash(isChecked);
}
});
iOS
@IBOutlet weak var cameraFlashSwitch: UISwitch!
@IBAction func onCameraFlashSwitch(_ sender: UISwitch) {
if self.rtcEngine?.getCurrentCameraDirection() == .back {
self.rtcEngine?.setCameraFlash(sender.isOn)
}
}
Harmony
private handleFlashChange(value: boolean): void {
if (!this.rtcEngine) {
return;
}
this.rtcEngine.setCameraFlash(value);
}