本文将为您介绍Harmony端如何实现屏幕共享。
功能介绍
屏幕共享功能允许用户在视频通话、直播过程中将自己的屏幕内容实时分享给频道内的其他用户,实现信息的即时共享与可视化交流。
示例项目
ARTC 提供了开源示例代码供您参考:Harmony实现屏幕共享。
前提条件
在实现屏幕共享前,请确保达成以下条件:
实现步骤
实现屏幕共享的调用时序如下:
如果您的场景中如果仅需要推送屏幕流,由于SDK会默认推送相机流,因此需要您主动调用publishLocalVideoStream关闭相机流推送,流程如下:
加入频道前调用
publishLocalVideoStream(false)来关闭相机流推送。加入频道后调用
startScreenShare开启屏幕录制并推送屏幕共享流。
mAliRtcEngine.publishLocalVideoStream(false);2.2. 需要同时推送屏幕共享流和相机流
如果您的场景中需要同时推送相机流和屏幕共享流,需要:
调用
publishLocalVideoStream(true)开启相机流推送。(默认行为,可省略)。加入频道后调用
startScreenShare开启屏幕录制并推送屏幕共享流。
mAliRtcEngine.publishLocalVideoStream(true);3. 设置屏幕流编码配置
如果需要自定义屏幕共享视频流的编码属性,可以调用setScreenShareEncoderConfiguration接口进行配置,包含分辨率、帧率、码率、GOP、视频旋转方向。
该接口在加入频道前后均可配置,如果每次入会只需要设置一次屏幕流视频编码属性,建议在入会前调用。
如果需要更新配置,可以多次调用该接口。
相关配置如下:
参数名 | 参数说明 | 默认值 |
| 视频分辨率。 | 0x0,表示推流分辨率跟随屏幕采集的分辨率。最大取值为3840x2160。 |
| 视频帧率。 | 默认帧率为 5,最大取值为 30。 |
| 视频编码码率(Kbps)。注意:码率设置根据分辨率和帧率有对应的合理范围,该值设置在合理范围内有效,否则SDK会自动调节码率到有效值。 | 512 |
| 关键帧间隔,GOP。单位为毫秒(ms)。 | 默认值0,表示SDK内部控制关键帧间隔。 |
| 是否强制编码器严格按照设置的关键帧间隔产生关键帧。 | 默认值为 false。
|
| 推流旋转。 | 默认值为AliRtcRotationMode_0。可选择 0、90、180、270 四个角度。 |
示例代码如下:
private aliRtcScreenShareConfig: AliRtcVideoEncoderConfiguration | undefined;
this.aliRtcScreenShareConfig = new AliRtcVideoEncoderConfiguration();
this.aliRtcScreenShareConfig.dimensions.width = 720
this.aliRtcScreenShareConfig.dimensions.height = 1080
this.aliRtcScreenShareConfig.frameRate = this.screenShareEncoderConfig.fps;
this.aliRtcScreenShareConfig.bitrate = this.screenShareEncoderConfig.bitrate;
this.aliRtcScreenShareConfig.keyFrameInterval = this.screenShareEncoderConfig.gop;
this.aliRtcScreenShareConfig.forceStrictKeyFrameInterval = this.screenShareEncoderConfig.forceGOP ? 1 : 0;
// 配置屏幕共享编码配置
this.rtcEngine.setScreenShareEncoderConfiguration(this.aliRtcScreenShareConfig);4. (远端)观看屏幕共享
当用户开启屏幕共享后,频道内的其他用户会收到 onRemoteTrackAvailableNotify 回调通知。通过该回调,客户端能够实时感知远端用户音视频流的变化,包括摄像头视频流和屏幕共享视频流的发布或停止。应用可以根据回调参数动态创建或移除对应的渲染视图,实现对远端屏幕共享内容的展示与管理。
onRemoteTrackAvailableNotify 回调中,远端视频流的变化通过枚举 AliRtcVideoTrack 进行标识,具体包括:
AliRtcVideoTrackNo (0):无视频流,表示远端用户当前未推送任何视频流。AliRtcVideoTrackCamera (1):仅推送摄像头视频流。AliRtcVideoTrackScreen (2):仅推送屏幕共享视频流。AliRtcVideoTrackBoth (3):同时推送摄像头和屏幕共享视频流。
应用需要通过判断该枚举值,动态调整 UI 显示逻辑,如分别显示摄像头画面和屏幕共享画面,或移除对应的视图。
this.rtcEventListener.onRemoteTrackAvailableNotify((userId: string, audioTrack: AliRtcAudioTrack,
videoTrack: AliRtcVideoTrack) => {
console.info(`远端音视频流可用: userId=${userId}, audioTrack=${audioTrack}, videoTrack=${videoTrack}`);
// 视频track为Screen或者Both的时候通过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);
}
});
// 查看远端视频
private viewRemoteVideo(uid: string, videoTrack: AliRtcVideoTrack): void {
// 检查是否已存在相同的流
const existingIndex = this.remoteVideoStreams.findIndex(
s => s.uid === uid && s.videoTrack === videoTrack
);
if (existingIndex >= 0) {
return;
}
// 创建新的远端视频流对象
const newStream: RemoteVideoStream = {
uid,
videoTrack,
canvas: new AliRtcVideoCanvas(),
xcomponentController: new XComponentController(),
surfaceId: ''
};
// 添加到数组并触发UI更新
this.remoteVideoStreams = [...this.remoteVideoStreams, newStream];
// 立即尝试设置视频
setTimeout(() => {
this.setupRemoteVideo(newStream);
}, 100);
}
// 设置远端视频
private setupRemoteVideo(stream: RemoteVideoStream): void {
if (!this.rtcEngine) {
console.error('RTC引擎未初始化');
return;
}
try {
// 获取XComponent的surfaceId
stream.surfaceId = stream.xcomponentController.getXComponentSurfaceId();
if (!stream.surfaceId) {
console.warn(`获取surfaceId失败: ${stream.uid}_${stream.videoTrack}`);
return;
}
// 配置视频画布
if (!stream.canvas) {
stream.canvas = new AliRtcVideoCanvas();
}
stream.canvas.surfaceId = stream.surfaceId;
stream.canvas.renderMode = AliRtcRenderMode.AliRtcRenderModeAuto;
stream.canvas.mirrorMode = AliRtcRenderMirrorMode.AliRtcRenderMirrorModeAllNoMirror;
// 关键:设置远端视图配置
this.rtcEngine.setRemoteViewConfig(
stream.canvas,
this.componentController,
stream.uid,
stream.videoTrack
);
// 确保订阅该视频流
if (stream.videoTrack === AliRtcVideoTrack.AliRtcVideoTrackCamera) {
this.rtcEngine.subscribeRemoteVideoStream(stream.uid, stream.videoTrack, true);
} else if (stream.videoTrack === AliRtcVideoTrack.AliRtcVideoTrackScreen) {
// 特别处理屏幕共享流
this.rtcEngine.subscribeRemoteVideoStream(stream.uid, stream.videoTrack, true);
console.info(`已订阅屏幕共享流: ${stream.uid}`);
}
} catch (error) {
}
}5. 开始屏幕采集
调用 startScreenShare 接口启动屏幕采集流程,开始采集设备屏幕内容并推送至通话频道。根据你的应用场景进行参数设置:
mode:屏幕共享模式,只共享音频/视频/音视频。
注意:应用调用此接口启动屏幕采集时,系统会弹出一个系统级别的授权弹窗,提示用户是否允许当前应用捕获屏幕内容。该授权弹窗由系统统一管理,用户必须主动同意才能开始屏幕共享。
this.rtcEngine.startScreenShare(mode);6. 停止屏幕采集
调用 stopScreenShare 方法停止屏幕共享采集,结束屏幕内容的采集和推送,释放相关资源。
this.rtcEngine.stopScreenShare();