Harmony端实现屏幕共享

更新时间:
复制为 MD 格式

本文将为您介绍Harmony端如何实现屏幕共享。

功能介绍

屏幕共享功能允许用户在视频通话、直播过程中将自己的屏幕内容实时分享给频道内的其他用户,实现信息的即时共享与可视化交流。

示例项目

ARTC 提供了开源示例代码供您参考:Harmony实现屏幕共享

前提条件

在实现屏幕共享前,请确保达成以下条件:

实现步骤

实现屏幕共享的调用时序如下:

image

如果您的场景中如果仅需要推送屏幕流,由于SDK会默认推送相机流,因此需要您主动调用publishLocalVideoStream关闭相机流推送,流程如下:

  • 加入频道前调用publishLocalVideoStream(false)来关闭相机流推送。

  • 加入频道后调用startScreenShare开启屏幕录制并推送屏幕共享流。

mAliRtcEngine.publishLocalVideoStream(false);

2.2. 需要同时推送屏幕共享流和相机流

如果您的场景中需要同时推送相机流和屏幕共享流,需要:

  • 调用publishLocalVideoStream(true)开启相机流推送。(默认行为,可省略)。

  • 加入频道后调用startScreenShare开启屏幕录制并推送屏幕共享流。

mAliRtcEngine.publishLocalVideoStream(true);

3. 设置屏幕流编码配置

如果需要自定义屏幕共享视频流的编码属性,可以调用setScreenShareEncoderConfiguration接口进行配置,包含分辨率、帧率、码率、GOP、视频旋转方向。

说明
  • 该接口在加入频道前后均可配置,如果每次入会只需要设置一次屏幕流视频编码属性,建议在入会前调用。

  • 如果需要更新配置,可以多次调用该接口。

相关配置如下:

参数名

参数说明

默认值

dimensions

视频分辨率。

0x0,表示推流分辨率跟随屏幕采集的分辨率。最大取值为3840x2160。

frameRate

视频帧率。

默认帧率为 5,最大取值为 30。

bitrate

视频编码码率(Kbps)。注意:码率设置根据分辨率和帧率有对应的合理范围,该值设置在合理范围内有效,否则SDK会自动调节码率到有效值。

512

keyFrameInterval

关键帧间隔,GOP。单位为毫秒(ms)。

默认值0,表示SDK内部控制关键帧间隔。

forceStrictKeyFrameInterval

是否强制编码器严格按照设置的关键帧间隔产生关键帧。

默认值为 false。

  • false表示编码器会响应他人入会等关键帧请求,关键帧间隔和设置的值不严格匹配。

  • true表示编码器不响应其他关键帧请求,严格按照设置的值产生关键帧。可能会造成订阅者首帧变慢。

rotationMode

推流旋转。

默认值为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 接口启动屏幕采集流程,开始采集设备屏幕内容并推送至通话频道。根据你的应用场景进行参数设置:

  1. mode:屏幕共享模式,只共享音频/视频/音视频。

注意:应用调用此接口启动屏幕采集时,系统会弹出一个系统级别的授权弹窗,提示用户是否允许当前应用捕获屏幕内容。该授权弹窗由系统统一管理,用户必须主动同意才能开始屏幕共享。

this.rtcEngine.startScreenShare(mode);

6. 停止屏幕采集

调用 stopScreenShare 方法停止屏幕共享采集,结束屏幕内容的采集和推送,释放相关资源。

this.rtcEngine.stopScreenShare();