前端实践:像素级同步、低延时、超低流量的屏幕共享工具 Syncit

avatar

在由声网举办的 RTC 2020 编程挑战赛春季赛中,像素级、低流量的屏幕共享工具「Syncit」获得了第二赛道的第一名。项目作者余彦臻同时还是拥有 6500+Star 的开源项目 rrweb 的作者。 在此前 CSDN 对获奖者的采访中我们了解到,从事前端开发的余彦臻,在平时工作中会用到 Teamviewer 等远程桌面工具。但是,大部分只需远程控制对方的浏览器,不需要操作系统级别的控制。于是他从浏览器入手,开发出了这款既关注隐私保护和易用性,又能不占用过多网络带宽的屏幕共享与远程控制工具「Syncit」。 Syncit 传递的数据是文本格式的快照和 op-log。通过观测网页视图的交互和变化,来实现分享和反向控制的能力。数据的传输基于 WebRTC + Agora RTM SDK 实现,可以将时延降到更低,保证使用的流畅性。

6 月 20 日(本周六),余彦臻将在 RTC meetup 直播中详细分享开发 Syncit 项目过程中遇到的难点与实践经验,包括如何实现可感知内容的全新隐私保护能力,如何沙盒化的远程控制能力,以及低时延传输层的实现等。

在此之前我们可以通过本文简单了解一下「Syncit」的基本功能与实现思路。

基本功能

远程屏幕共享

我们需要做到像素级同步、低延时、超低流量占用。实现思路是将 Web 视图的变化与交互行为转换为序列化的快照和 op-log,由本端传输至对端后重放。对端始终处于沙盒中,以避免安全问题。

隐私保护

为了保护隐私,在屏幕共享过程中,需要可以做到灵活遮挡一些内容。Syncit 所遮挡的是内容,而不是固定的位置。视图中的每个部分都是结构化的 DOM,不仅精确屏蔽视图,同时屏蔽对应区域内的交互事件。

反向远程控制

我们要实现类似 Teamviewer for the Web 的反向远程控制,但无需安装客户端。Syncit 会采集对端的交互事件后在源端进行重放,并且控制权无法从当前 Web 页面逃逸,带来更好的安全性。

适合哪些场景?

远程客服

你可以在 Web 应用接入 Syncit,当用户遇到问题时,客服人员可以通过 Web 浏览器端,提供远程协助。该功能也可以与远程客服视频等功能结合,实现更好的应用体验。

弱网环境下的 Web 分享

由于用户所处网络环境复杂,有可能处于弱网环境下,丢包率较高。所以 Syncit 可适用于面向各种网络环境下的各类终端,通过 Web 浏览器进行信息互通、共享,并且“画质”不降级。类似的场景包括在线教育、远程办公等。

Syncit 适用于所有 Web 场景,随着 Web 应用不断进化,它的适用场景会不断变多。

Syncit 的功能设计

直播模式

简单来说,Syncit 的基础是将 Web 视图序列化成了一个文本格式的快照,再将可能对 Web 视图产生变化的各类操作都记录成了 op-log。只需要重建快照,再一次重放 op-log 中的操作,就可以实现 Web 视图的精确回放。其中涉及到的录制、序列化、回放、沙盒等细节。我们会在 6 月 20 日的直播中详细讲解沙盒化的实现。届时,大家可以在 Github 中阅读详细的说明。

进一步地,要实现直播的效果,Syncit 还包含了 encoder, buffer, transporter 等组件,示意图如下:

每一个组件都是可插拔的,例如:

  • 可以实现 encoder/decoder,对传输的数据进行加密、压缩等操作。(比赛版本中因为 Agora 实时消息 SDK 中包含了 deflate 压缩,所以没有启用额外的 encoder)

  • 可以实现 buffer,对传输中的数据进行缓存,当出现网络异常或时序错乱时可以进行重试和排序。(比赛版本中的 buffer 是一个内存中非持久化的实现)

  • 可以实现 transporter,通过暴露标准的接口让数据在源端和对端之间通信。(比赛版本使用了 Agora 实时消息 SDK 封装 transporter,代码中也包含了一个基于 localStorage 模拟的 transporter 用于快速测试)

由于传输的数据中 op-log 的部分对顺序非常敏感,所以 buffer 中的重试和排序是非常重要的实现,可以保障屏幕共享的稳定性。

buffer 对于用户侧的感受是一个 1 秒(可控)的延迟,这就意味着只要传输的数据时延不超过 1 秒,buffer 都可以将其缓冲为观看无延迟的状态。

控制模式

控制模式在直播模式的基础上实现。在直播模式时我们已经通过重建快照在对端构建了一个沙盒视图,当开启控制模式后,我们会开始监听对端用户在沙盒中的交互,再传输至源端进行实施。

在源端和对端会持续的维护一个完全同步的 DOM 映射,这样可以将每个交互记录为一个序列化的数据进行传输。

举个例子

假设源端页面是一个按钮,点击后 alert 一条消息

  1. 在对端重建快照,出现一个同样的按钮,但该按钮在沙盒中,点击后并不会触发 alert。

  2. 监听对端沙盒中的交互事件,对端用户点击沙盒中的按钮后,收集到点击事件和点击对象。

  3. 将点击事件和点击对象传输至源端,通过程序触发对应的点击事件。

  4. 源端 alert 一条消息。

  5. 源端最新的视图变化继续同步至对端。

示意图如下:

作者、直播与源码

作者将在周六的直播分享 Syncit 的实现细节。同时,公开 Syncit 源码。欢迎大家扫码报名,在直播间与作者交流更多技术细节。感兴趣的同学,可扫码报名。