基于 Web 端的屏幕共享实践

屏幕共享的英文叫作 DesktopSharing,通俗点讲就是将本身电脑的画面分享给其余人, 被分享的能够是整个电脑屏幕、应用程序或者某一个打开的网页等等。html

而随着音视频领域的深刻发展,完备的功能在用户需求激增的背景下催生,不论是是在学习、生活或是娱乐场景下,屏幕共享做为实现互动的一种方式被愈来愈多的用户应用在平常生活中:前端

一、远程协做(TeamViewer):控制远程计算机,完成协做等;git

二、在线会议:参会者只需在本身的电脑屏幕上查看共享的文件材料,并观看文件演示等;github

三、在线课堂:屏幕共享能够将老师的课件、笔记、讲课内容等画面展现给学生观看等;web

......express

因而可知,屏幕共享这个衍生功能已经在愈来愈多的场景上成功使用,那么该如何实现屏幕共享呢?本篇文章咱们将详细介绍在 Web 端的屏幕共享实践。 canvas

Web 端如何实现屏幕捕捉

Web 端浏览器能够实现屏幕共享么? 在电脑端是能够作到的。屏幕共享分为两个步骤:屏幕捕捉 + 流媒体传输segmentfault

屏幕捕捉: 获取数据, 为流媒体传输提供数据源;promise

流媒体传输: 将音视频数据从一个客户端传输到另外一个客户端。当前比较成熟的方案是使用WebRTC协议提供的低延迟和抗弱网能力以此来保证体验;浏览器

WebRTC 协议要求提供的流数据必须是 MediaStream 对象,因此屏幕采集的流也必须是 MediaStream 类型。咱们先以电脑端  Chrome 72 为例 ( 不一样浏览器写法会有点不同),捕捉屏幕画面代码是这样的:

async function startCapture(displayMediaOptions){
   let captureStream = null;
   try{  
    captureStream = await navigator.mediaDevices.getDisplayMedia(displayMediaOptions);
   }catch(err){  
     console.error("Error: "+ err);
   }
   return captureStream;
}

效果以下:

图片

 (示例demo地址:https://zegoim.github.io/expr...

 关键语法:

//  constraints 参数可参考https://developer.mozilla.org/zhCN/docs/Web/API/MediaDevices/getDisplayMedia
let promise = navigator.mediaDevices.getDisplayMedia(constraints);

屏幕捕捉兼容性问题及应对方案

做为 Web 前端开发,相信这个问题是你们比较关心的,目前屏幕捕捉接口兼容状况比较复杂,仅支持在如下桌面端浏览器中进行屏幕捕捉:

  • Chrome 58 或以上版本
  • Firefox 56 或以上版本
  • Edge 80 及以上版本
  • macOS 的 Safari  13 及以上版本

其中Chrome浏览器还能够进一步分为: 有插件和无插件。

  • 有插件: 须要在浏览器上额外安装插件, 利用 Chrome 提供的能力捕捉屏幕,插件方式能够在较低版本上实现捕捉;
  • 无插件: 不用额外安装任何插件, 但要求 Chrome 必须是 72 及以上版本。

Chrome 浏览器若是要支持音频分享, 无插件方式必需要是 Chrome 74 及以上版本,Safari 浏览器目前则只支持分享整个屏幕,没法选择应用程序和浏览器页面。

清楚浏览器兼容状况后,就能够针对浏览器进行判断了,大体思路是经过 navigator.appVersion 判断浏览器类型/平台/版本,并对接口作是否存在的判断,在正式业务开始前,提早感知浏览器是否支持该能力。

代码写起来是纯体力活,若是不想对浏览器类型和版本一一处理,ZEGO 即构科技的 zego-express-engine-webrtc.js 帮你们作好了内部兼容, 并提供检测接口方便快速上手

​​​​​​​点击查看: https://doc-zh.zego.im/articl...

浏览器实现自定义尺寸分享

咱们看浏览器提供的接口, 不管是什么浏览器类型或版本,最小粒度只能捕捉到一个页面,若是要分享的页面或者程序有比较敏感的信息,不但愿所有被分享出去,咱们应该怎么办呢? 

只看浏览器接口是没有办法实现的,不过 MediaStream 对象还能够从 video 或者 canvas 这类媒体标签上获取。若是把捕捉到的流媒体对象渲染到画布上,再从画布上截取咱们想要分享的部分画面,就能够实现指定尺寸分享了。

实现伪代码以下:

// 获取屏幕捕捉流
let screenStream = await navigator.mediaDevices.getDisplayMedia(displayMediaOptions);

// 建立画布
const ctx = canvas.getContext('2d');

// 滚动渲染视频
let timer = null;
function videoDrawInCanvas(){
timer = setTimeout(async () => {
videoDrawInCanvas( ctx, source, canvas, videoX, videoY, videoWidth, videoHeight);
}, 60);
}

// 获取从新绘制的画布流
const canvasMedidaStream = canvas.captureStream(25);

效果以下:

图片

能够看到这种方式的确是可行的,ZEGO WebRTC 团队也提供了对应的 demo 和源码, 免费给你们参考和体验,并封装了对应的库 rangeShare.js,帮助你们快速上手直接使用,可点击连接查看:[ https://zegodev.github.io/zeg...]()。

实践过程当中咱们发现,还有一些问题也很是值得你们注意:

  • 问题一:canvas 渲染对浏览器 cpu 消耗是比较高的, 性能很差的设备可能会致使整个页面卡顿;
  • 问题二:虽然画面能够从新绘制, 可是从新绘制的流是纯视频的,若是捕捉的流是包含音频,会致使音频丢失。

对于问题一:ZEGO WebRTC 团队 通过大量设备测试,在 rangeShare.js 库中把参数调整到尽量适配更多设备。同时 demo 中提供了估算 cpu 占用的代码, 在 cpu 消耗过大状况下,能够提示本设备 cpu 占用太高,开发者可根据提示选择更换设备,或关闭其余 cpu 占用较高的进程。

对于问题二:rangeShare.js 也帮你把这个问题考虑到了,屏幕捕捉到的流传进来时,若检测到包含音频,会自动缓存音轨,并在输出的时候和画布流混合。

总结

以上就是关于在 Web 端实现屏幕共享的技术解读,而随着 5G 技术的到来和硬件设备性能的提高,浏览器上实现流媒体的低延迟传输和流媒体数据处理已经有较成熟的方案,好比浏览器上实现屏幕捕捉。

音视频能表达的信息相比文字图片更丰富,因此音视频传输正变得更普及,同时现代浏览器也在不断的更新音视频操做相关 API,浏览器能作的事情也许比咱们想象中的更多。

ZEGO WebRTC 团队会持续跟你们分享 Web 端关于音视频方面有意思的技术问题,若有出入,欢迎你们指正和交流。