功能描述
本文主要介绍如何在 TRTC Web SDK 实现屏幕分享功能。
前提条件
-
本文介绍的教程基于 TRTC Web SDK v4.15.0+ 版本,若您的 SDK 低于该版本,可以参考旧版教程。
- 在 v4.15.0+ 版本,SDK 支持一个 Client 同时推主流 + 辅流,即可在一个 Client 同时推摄像头 + 屏幕分享流。
- 在 v4.15.0 之前的版本,若需要同时推摄像头 + 屏幕分享,需要单独创建额外的 Client 来推屏幕分享流。
-
TRTC Web SDK 屏幕分享支持度请查看 浏览器支持情况。同时 SDK 提供 TRTC.isScreenShareSupported 接口判断当前浏览器是否支持屏幕分享。
-
推辅流支持 Chrome 69+, Safari 11+, Firefox 59+, Edge 79+,只要是支持推屏幕分享的环境,都支持推辅流。
什么是主流和辅流?
在 TRTC Web SDK 中,一个 Client 实例可以同时推两路流,其中:
- 一路称为主流(主音视频流),一般用于推摄像头和麦克风,也可以推业务侧自定义采集的流。
- 一路称为辅流(辅助视频流),用于推屏幕分享流。
实现流程
-
【推流端】创建和发布屏幕分享流
const clientA = TRTC.createClient({ mode: 'rtc', sdkAppId: 140000000, // 填写您的 sdkAppId userId: 'userA', // 填写您的 userId userSig: 'userA_sig', // 填写 userId 对应的 userSig }) await clientA.join({ roomId: 6969 }); const shareStream = TRTC.createStream({ userId: 'userA', screen: true, // 采集屏幕分享 }) await shareStream.initialize(); await clientA.publish(shareStream, { isAuxiliary: true }); // 将 isAuxiliary 设为 true,将以辅流的形式进行推流。
-
【拉流端】拉流并播放
const clientB = TRTC.createClient({ mode: 'rtc', sdkAppId: 140000000, // 填写您的 sdkAppId userId: 'userB', // 填写您的 userId userSig: 'userB_sig', // 填写 userId 对应的 userSig }) clientB.on('stream-added', async event => { const remoteStream = event.stream; // 订阅远端流 await clientB.subscribe(remoteStream); // 主路视频流,一般是推麦克风、摄像头的那路流 if (remoteStream.getType() === 'main') { // 1. 在页面中放置一个 id 为 `${remoteStream.getUserId()}_main` 的 div 标签,用于在 div 标签内播放主路流。业务侧可自定义 div 标签的 id,此处只是举例说明。 // 2. 播放主路视频流 await remoteStream.play(`${remoteStream.getUserId()}_main`) } else if (remoteStream.getType() === 'auxiliary') { // 辅路视频流,一般是推屏幕分享的那路流。 // 1. 在页面中放置一个 id 为 `${remoteStream.getUserId()}_screen` 的 div 标签,用于在 div 标签内播放屏幕分享。业务侧可自定义 div 标签的 id,此处只是举例说明。 // 2. 播放屏幕分享 await remoteStream.play(`${remoteStream.getUserId()}_screen`) } }); await clientB.join({ roomId: 6969 });
-
同时推摄像头 + 屏幕分享
const localStream = TRTC.createStream({ userId: 'userA', audio: true, // 采集麦克风 video: true // 采集摄像头 }) const shareStream = TRTC.createStream({ userId: 'userA', screen: true, // 采集屏幕分享 }) await localStream.initialize(); await shareStream.initialize(); await clientA.publish(localStream); await clientA.publish(shareStream, { isAuxiliary: true })
注意:若辅流中含有音频(例如屏幕分享 + 系统音频),则 SDK 会将辅流的音频混音到主流音频中推流,拉流端需要订阅主流来订阅音频流。
-
停止屏幕分享
// 取消推流 await clientA.unpublish(shareStream); // 停止采集屏幕分享 shareStream.close();
另外用户还可能会通过浏览器自带的按钮停止屏幕分享,因此屏幕分享流需要监听屏幕分享停止事件,并进行相应的处理。
// 屏幕分享流监听屏幕分享停止事件 shareStream.on('screen-sharing-stopped', async event => { // 取消推流 await clientA.unpublish(shareStream); // 停止采集屏幕分享 shareStream.close(); });
-
屏幕分享采集系统音频
屏幕分享采集系统声音只支持 Chrome M74+
- 在 Windows 和 Chrome OS 上,可以捕获整个系统的音频。
- 在 Linux 和 Mac 上,只能捕获选项卡(某个 Tab 页面)的音频。
- 其它 Chrome 版本、其它系统、其它浏览器均不支持。
// 创建屏幕分享流 screenAudio 请设置为 true, 不支持同时采集系统和麦克风音量,请勿同时设置 audio 属性为 true const shareStream = TRTC.createStream({ userId: 'userA' screen: true, screenAudio: true // 采集系统音频 // audio: false 是否采集麦克风,不支持同时采集系统音频和麦克风,请勿同时设置 audio 和 screen 属性为 true }); await shareStream.initialize(); ...
在弹出的对话框中勾选
分享音频
,发布的 stream 将会带上系统声音。
注意事项
-
一个房间只能推一路辅流。
-
SDK 默认使用
1080p
参数配置来采集屏幕分享,具体参考接口:LocalStream.setScreenProfile。 -
在 v4.15.0 版本开始,屏幕分享流支持以辅流的形式推流,如下差异需要注意:
- 在 v4.15.0 之前的版本,屏幕分享流是以主流的形式推流的,其他 Web 用户拉流的 RemoteStream.getType() 返回值是 'main'。业务侧需要通过 RemoteStream.getUserId() 来标识是否为屏幕分享流。
- 在 v4.15.0+ 版本:
- 默认情况下,屏幕分享以主流的形式推流,向下兼容。
- 若在 Client.publish(stream, { isAuxiliary: true }) 时将
isAuxiliary
参数设为 true,则会以辅流的形式推流。其他 Web 用户拉流的 RemoteStream.getType() 返回值是 'auxiliary'。业务侧可直接通过 'auxiliary' 来标识屏幕分享流。
常见问题
-
Safari 屏幕分享出现报错
getDisplayMedia must be called from a user gesture handler
这是因为 Safari 限制了
getDisplayMedia
屏幕采集的接口,必须在用户点击事件的回调函数执行的 1 秒内才可以调用。参考:webkit issue。
// good async function onClick() { // 建议在 onClick 执行时,先执行采集逻辑 const screenStream = TRTC.createStream({ screen: true }); await screenStream.initialize(); await client.join({ roomId: 123123 }); } // bad async function onClick() { await client.join({ roomId: 123123 }); // 进房可能耗时超过 1s,可能会采集失败 const screenStream = TRTC.createStream({ screen: true }); await screenStream.initialize(); }
-
Mac Chrome 在已授权屏幕录制的情况下屏幕分享失败,出现 "NotAllowedError: Permission denied by system" 或者 "NotReadableError: Could not start video source" 错误信息,Chrome bug。解决方案:打开【设置】> 点击【安全性与隐私】> 点击【隐私】> 点击【屏幕录制】> 关闭 Chrome 屏幕录制授权 > 重新打开 Chrome 屏幕录制授权 > 关闭 Chrome 浏览器 > 重新打开 Chrome 浏览器。
-
判断用户选择的屏幕分享类型:整个屏幕、窗口、Chrome 标签页。
// 在屏幕分享采集成功后 const shareStream = TRTC.createStream({ screenAudio: true, screen: true, userId }); await shareStream.initialize(); // 根据 displaySurface 来判断采集的类型。 const { displaySurface } = shareStream.getVideoTrack().getSettings(); // 例如:monitor 为整个屏幕、window 为某个应用窗口、browser 为 Chrome 某个标签页