从无到有,聊聊我们的视频会议之路

2023年1月18日

编者按:自从新冠疫情爆发以来,大家经常需要居家工作和线上开会,因此音视频会议软件变得越来越重要。LiveVideoStack Meet 青岛站邀请到了易软天创的李文睿老师,为我们介绍在喧喧这款聊天软件中,从无到有的视频会议之路。

文 / 李文睿

整理 / LiveVideoStack

大家好!我是李文睿,来自青岛易软天创网络科技有限公司。我所在的小团队大概有 3 人,该团队是禅道团队中负责研发喧喧聊天软件的小组。

今天,我分享的主题是:在喧喧这款聊天软件中,从无到有的视频会议之路。

1.1 单机可运行、轻量、跨平台、私有部署

首先,介绍我们的企业聊天软件 —— 喧喧。喧喧是一款单机可运行的、轻量的、跨平台的、私有部署的聊天软件。之所以说喧喧是单机可运行的、轻量的、私有部署的软件,是因为喧喧的整体架构足够轻,可以私有部署到用户的单台服务器上。

图片

接下来,介绍一下喧喧的功能。由于喧喧是企业协同聊天软件,所以我们把精力更多地放在了针对企业和协同场景的功能开发上。首先,喧喧具有音视频聊天、桌面共享的功能,还支持移动客户端和万人级别的聊天。其次,卡片消息功能能够让用户处理由第三方或自身推送的流程事务。同时,右键菜单功能可将消息转为禅道需求、bug 或第三方系统中的数据。此外,喧喧还有一套扩展机制,第三方开发者可以通过扩展机制为喧喧定义新的功能、嵌入 web 应用等。喧喧还有单点登录功能。

图片

喧喧还有内置 Web 应用的功能,可使用 WebHook 向用户发送通知消息,并支持 Office 等格式的文件预览。之前提到,喧喧支持各种芯片架构,即可在 ARM、MIPS、X86、X86-64 架构服务器上稳定运行。喧喧还有 LDAP 和登录 IP 限制的功能,这两个功能都是企业办公场景下的刚需。此外,喧喧还有加密存储文件的功能。由于截图也是聊天软件中的重要功能之一,我们还为喧喧开发了一款炫酷的截图工具 ——ZenShot,该工具已在 GitHub 上开源。

图片

接下来,介绍喧喧的架构。架构主要分为三大块,第一块是后端处理服务器,其使用 PHP 实现,这是因为我们团队中的程序员大多是使用世界上最好语言 PHP 的程序员,并且我们需要将喧喧集成到其他产品中,而其他产品也使用 PHP 实现。但 PHP 也有短板,喧喧作为一个聊天软件,需要维持与客户端的连接,但在维持连接的场景下,PHP 的性能不高,且处理起来比较麻烦。为了解决这个问题,我们做了一个消息中转服务器,以达到维持连接和提升服务性能的目的。消息中转服务器使用 Go 和 Go 的 WebSocket 库 gorilla 实现,保证了服务器和客户端间的连接。最后是客户端,客户端是全平台的,支持 Mac、Windows、Linux 等平台。移动客户端也可跨平台,支持 Android 和 iOS。另外只要有浏览器,也可以使用喧喧的网页端。

1.2 Electron

为什么喧喧能够做到全平台兼容呢?是因为我们使用了 Electron。Electron 的前身是 GitHub 旗下的编辑器 Atom 的 GUI 框架。虽然 Atom 编辑器已经寿终正寝,但 Electron 却可以说是如日中天。

图片

大家的电脑上可能已经有好几个 Electron,比如著名的编辑器 VS Code,这是用 Electron 实现的。此外,交互设计工具 Figma、Markdown 编辑器 Typora 和 Evernote 的桌面端也都是用 Electron 实现的。

图片

甚至还有人使用 Electron 运行完整的 Windows 95 操作系统,这个项目十分有意思,可在 GitHub 上找到。由此可以看出,Electron 确实十分强大。

图片

图中的是从 Electron 官网摘抄的一句话:Electron 允许使用 Web 技术构建跨平台的桌面应用。这是因为 Electron 可以理解为一个 Chrome 浏览器,Chrome 通常代表了最新的 Web 标准,所以 Electron 可以使用大多数的新的 Web API 和 Web 技术。此外,Electron 还进行了系统 API 的集成,开发时仅需使用 JS 进行调用,对开发人员十分友好,无需操心各系统下的平台差异性。当然,Electron 也有短板,Electron 可以认为是一个 Chrome,Chrome 的内存消耗很大,使用 Electron 的软件的体积通常会达到至少一百兆。但是,Electron 的好处也是明显的,我们可以使用 Web 技术开发各种桌面应用,一个前端工程师也可以用其做一个桌面应用。因此,如果大家需要开发新的桌面应用,我会推荐 Electron。

1.3 “Dirty Hack”

然后,还想跟大家分享一些有点 hack 的有趣的细节。

图片

后端服务器和消息中转服务器以及消息中转服务器和客户端之间的数据传递方式是有趣的,我称之为 HTTP Over WebSocket,即经由 WebSocket 转发的 HTTP 协议通信。客户端通过 WebSocket 向消息中转服务器发送消息请求,该消息请求会原封不动地 POST 给后端服务器,得到回复后,再分发给需要被通知的客户端。这样就实现了基于 PHP 后端的高性能的 WebSocket 服务。

图片

我们的数据使用 JSON 传输,JSON 是一个较低效的文本数据交换格式。虽然 JSON 方便使用,但是每次传输的体积较大,比如这一串 JSON 里有效的数据量大概只占了三分之一。为了优化数据传输,我们研究了一套 JSON 的压缩机制。我们先定义了接口的数据格式和默认值,然后做了字典,用索引代替已知的长字符串。通过这种方法,我们将图中上半部分的 JSON 压缩成了图中下半部分的 JSON,缩小了大概一半的体积,并且编解码过程的效率较高。此外,我们还集成了 RoadRunner(一款使用 Go 的协程来调度 PHP 程序的、高性能 PHP 应用服务器),还将其集成到了同样是 Go 实现的消息中转服务器中。这能极大地提升性能,帮助实现单服务器在万人级别的场景下的稳定运行。

2.1 为什么要做音视频

接下来进入正题,开始走音视频之路,谈谈我们为什么要做音视频。最初,我们是一群快乐的 Zoom 付费用户,Zoom 在 2019 年前是方便使用的视频工具,公司每次需要与外地同事开会时,都会首选 Zoom。再后来,由于网络环境的恶化和 Zoom 运营的态度转变,Zoom 在中国的运营没有以前直接,出现了代理商,服务体验变差。再之后,新冠疫情爆发,2020 年后,我们经常需要居家办公,为了解决每次线上开会体验不佳的问题,我们寻求了很多办法。我们首先在网上找了很多其他的视频软件,包括当时刚起步的腾讯会议,但最终没有找到满意的视频软件,所以本着一定要解决工作中的痛苦的精神,我们最后选择成为在聊天软件中做音视频的 “痛苦的” 开发者,开始做音视频。

2.2 集成 Intel OWT

我们先在 GitHub 上找灵感,思考集成哪款音视频服务,最终找到了 Intel 的 OWT 音视频媒体服务器,并尝试集成这款服务。

图片

OWT 服务支持 MCU 和 SFU 两种模式,由于当时我们刚入门,所以直接选用了 MCU 模式。所谓 MCU 模式,就是服务器接收所有用户推送的媒体流并进行混流,将它们合并到一条流中,再分发给用户,这样每个用户只需推送一个流和拉一个流。这种模式对服务器的配置要求比较高,但是能够节约带宽资源。

在集成 OWT 时,我们花费了很多力气,折腾了差不多一周后,我们初步实现了音频会议的功能,但中间的过程非常痛苦。比如,OWT 本身需要编译,在编译时我们需要拉取其他的代码,例如 Google 的 WebRTC 的代码,受限于网络,我们经常遇到构建失败的情况,最后不得不购买一台国外的服务器来专门编译 OWT。此外,我们还发现将其分发给用户也是一件困难的事情,因为喧喧是一款私有部署的聊天软件,但让用户亲自部署 OWT 是不现实的,于是我们尝试将其 Docker 化,但 OWT 的运行环境较大,我们在去年才将其精简、压缩成了 161 兆大小。

图片

这是刚做喧喧音频时音频功能的截图,当时花了一周的时间在内网中做了相关的尝试。

图片

后来,我们很快实现了视频会议功能。这得益于 MCU 模式的特点,不需要担心视频布局问题,可以很轻松地实现推流和拉流,并由 OWT 做好一切内容。

2.3 屏幕共享和移动端

然后,我们还实现了屏幕共享功能和移动端的开发。屏幕共享功能和视频会议功能是同期实现的,屏幕共享功能中使用了 MediaDevice 之类的 Web API,可以获取屏幕的视频流,并将其推送到服务端。在开发移动端时,我们则花费了较大的力气。

图片

这是当时喧喧桌面共享功能的截图。

图片

移动端使用 Flutter 实现,使用 Flutter 与使用 Electron 的目的一样,希望只编写一次代码就可在多个平台下同时运行。Flutter 对 RTC 的支持是足够的,有很多第三方库辅助我们实现相关功能。我们一共花了两周多的时间,实现了移动端音视频。

2.4 集成 SRS

后来,我们不断收到用户反馈,用户说不使用音视频服务时,该服务也会占用资源,而使用该服务时,资源占用很高、体积大,于是我们开始思考解决办法。我们发现,OWT 使用了 RabbitMQ 和 MongoDB,这二者在闲时也会占用资源,于是我们考虑更换音视频后端。最终我们决定使用 SRS,SRS 是一款国产的开源的音视频项目。

图片

在迁移时,我们发现 SRS 仅支持 SFU 模式,于是需要从 MCU 模式切换到 SFU 模式,这样的改变会带来一些变化。首先是布局的变化,在 SFU 模式下,我们需要亲自排布视频并在客户端上呈现,而不由服务端进行排布,对此我们只需开发一些前端的功能,而这是容易实现的。但同时也存在一些问题,以后再跟大家详细介绍。

图片

SRS 的文档非常全面,在 GitHub 上面,其 Wiki 有 797 条。得益于详尽的文档和之前集成 OWT 的经验,我们很快地完成了 SRS 的迁移。

图片

这是近期喧喧音视频的界面,我们将其做成了独立的窗口。

03 万能的 WebRTC

WebRTC 技术在飞速地发展,近期我们使用 WebRTC 实现了客户端之间点对点的大文件传输功能。具体地,通过使用 WebRTC 的 DataChannel 和 PeerConnection 直接传输大文件。由此看出,WebRTC 的应用广泛,各大浏览器对 WebRTC 的支持也很全面。我们期待用 WebRTC 做更多的事情,比如桌面共享和控制、甚至元宇宙,当然,还要做更好的会议功能。

我今天的分享到此结束,谢谢大家!

 
还可输入800
全部评论
作者介绍

LiveVideoStack

音视频技术社区

文章

粉丝

视频

阅读排行
  • 2周
  • 4周
  • 16周
热门视频

HLS性能优化之旅

熊子良/资深研发工程师

贝壳找房联络中心的RTC实践

安海波/语音架构师