热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

如何基于WebRTC搭建一个简单的视频会议

前言WebRTC,它是由谷歌推广的实时音视频技术栈,是音视频领域搜索热度最高的技术。它有多重身份,既是W3C的标准,也是一
前言 

WebRTC,它是由谷歌推广的实时音视频技术栈,是音视频领域搜索热度最高的技术。它有多重身份,既是W3C的标准,也是一个开源项目,还有一个对应的IETF工作组(RTCWEB)。在WebRTC出现之前,音视频通信是高不可攀的领域,需要大量的专业积累才能入门,而现在,越来越多的开发者通过WebRTC来深入了解RTC技术。

WebRTC技术的本质是构建点对点的实时通信,目前主流的浏览器,包括Chrome, Firefox, Edge等,天然就支持WebRTC协议。对入门开发者来说,选用这几款浏览器,连开发客户端的时间都省了。最简单的Web视频会议,只需要架设一个Web服务器,服务器兼具信令交换的能力(信令服务也可以独立部署),两个浏览器通过Web Server交换会话信息,就能建立P2P通道来传输媒体流,进行1v1的视频会议。如下图所示:

 

两个浏览器向Web服务器请求页面,并进行SDP交换,然后在浏览器之间直接建立P2P Transport,进行媒体流传输。这是最简单的WebRTC应用形式。这种简单的媒体流直联的方式,线上有很多教程,也可以参考WebRTC的demo (https://webrtc.github.io/samples/),这里不展开。

 

如果拓展到多方的视频会议,架构是这样的:

 

可以看到,这种”简单”的视频会议,有两个风险点:

  1. P2P在两个客户端之间建立,不可避免的涉及到NAT穿透的问题,打洞的成功率直接影响P2P的可用性,在会议场景是不能接受的。

  2. 在多人场景下,本地的媒体流以拷贝的形式发送给每个对端,对网络带宽是个极大的浪费,上行网络的带宽瓶颈决定了会议的方数上限,影响体验,也不利于扩展。

     

要解决这两个问题,就要引入媒体服务器。看下面的架构图:

加入媒体服务器后,每个浏览器只和服务器建立媒体传输通道。

  • 媒体服务器架设在公网,P2P的可用性有保障。

  • 每个浏览器只向服务器发送一路本地媒体流,由服务器负责转发给远端,避免了带宽浪费。

对于视频会议来说,这是更优的架构选择。

 

常用的媒体服务器主要分为SFU(Selected Forward Unit)和MCU(Multipoint Control Unit),SFU只负责媒体流转发,不做太多复杂的媒体处理,并发能力会强一些。MCU除了媒体流的接收/发送,还会进行转码和混流,对服务器的性能要求比较高,在实时传输系统中,转码会带来额外的延时,在选型时也必须考虑。多人视频会议场景下的SFU/MCU架构示意如图:

 

SFU对接入的媒体流进行全网转发,MCU对接收到的媒体流做转码后,只转发一路合成后的媒体流。它们的优势和劣势总结如下表:

 

WebRTC的生态中,有许多优秀的开源媒体服务器,下面列出部分关注度高的项目:

 

大家可以根据自己的需求,选择合适的项目来搭建媒体服务器。对于实时性和高并发有强要求的会议场景,笔者还是推荐采用SFU架构,下面的进阶篇中也会基于SFU展开介绍。

 

另外,如果不满足于浏览器入会,有扩展客户端覆盖的需求,上述的开源项目中,也有相应的native的客户端库,比如mediaSoup,有提供一个libmediasoupclient的C++ library,这个库本身是基于libwebrtc的,大家可以基于这个库来搭建iOS/Andriod/PC的客户端,需要一定的时间摸索编译环境,但不会太复杂。

 

这还不是WebRTC生态的全部,在客户端扩展方面,WebRTC是一直走在路上的,各种前沿的混合开发框架项目中,都能看到它的身影,比如RN/Flutter/Cordova等等,在Github上都有WebRTC开发库,愿意实践的开发者可以尝试,不过,要用这些开发框架做到产品化,还是需要一定积累的,需要踩一些坑。

 

到这里,我们完成了基础的视频会议搭建,或许在通话时会面对这样那样的质量问题,但至少实现了听得见、看得到,浅尝辄止的目标已达成。下面的进阶篇,就留给打算深入学习RTC的小伙伴(需要一些音视频基础)。

 

视频会议的基础是实时音视频通信(RTC)技术,在上一篇解决了听得见、看得到的问题之后,在接下来的进阶篇中,我们重点关注下如何能让音视频通信稳定、流畅、可靠,也就是关乎视频会议的质量体验问题。

 

大家可能都会有这样的体会,视频会议总是很难保持稳定,偶尔会视频卡住,或者声音断续,或是今天可以正常完会,改天就不好。其实实时音视频通信的原理就是信号的采集,处理和传输,而其中传输部分是最难把控的,为了做到实时性,我们要摒弃长时延、可靠的TCP,选择不可靠,但有可能做到实时的UDP。在公共互联网上用UDP搭建传输网络,它的不可靠的因子会被放大,比如时延,抖动,丢包等,都有可能影响视频会议的体验。

 

下面的章节中,我们重点介绍实时音视频通信中的Quality of Service(QoS)。QoS可以狭义地理解为链路分组数据传输的质量指标,相对的另一个指标是Quality of Experience(QoE),它是用户对设备,网络和系统总体的端到端主观体验。

 

 QoS那些事 

 

WebRTC中已经具备了一些保障QoS的策略,比如ARQ,FEC,Jitter Buffer,Congestion Control等,让我们结合前面的SFU架构来展开探讨。

 

QoS策略的主要任务是对抗影响数据传输的网络变量,比如时延,抖动,丢包,带宽等。我们简单介绍下QoS的常规武器

  • ARQ:自动重传请求,是数据链路层的错误纠正协议之一,WebRTC中用到是协议中的NACK机制,即接收端监测到数据包SeqN丢失后,发送对该数据包的重传请求,由发送端执行重传。

  • FEC:前向纠错,是增加数据通讯可靠度的方法,利用原始数据编码进行冗余信息的传输,当传输中出现丢包,允许接收端根据冗余信息重建。WebRTC利用UlpFEC进行数据保护,冗余系数由链路上的丢包率决定。

  • Jitter Buffer:抖动缓冲,通过在接收端维护一个数据缓冲区,可以对抗一定程度的网络抖动,丢包和乱序,需要考虑的是接收延时和卡顿之间的平衡。

  • Congestion Control:拥塞控制, WebRTC利用GCC算法来控制传输,通过兼顾丢包和时延的算法来估计网络可用带宽,并以此估算值来控制源端发送码率,避免网络拥堵。

 

在典型的SFU传输链路中,媒体流(RTP数据包)由Sender发送到Receiver,媒体控制流(RTCP包)由Receiver反馈给Sender。控制流中包括了NACK, PLI, REMB, Receiver Report等反馈信息。这些反馈信息是配合QoS策略的辅助手段。

 

有了这些QoS策略的加持,WebRTC的视频通话能够对抗一定程度的网络状况,正常情况下的通话质量可以保障。但是,这种默认的策略也存在明显的改进空间,比如:

  • QoS的策略是在端到端之间生效的,接收端发现丢包后,才会向发送端发送NACK请求重传,全链路的路径(rtt)过长,影响数据重传和恢复的效率。

  • 接收端在发现无法恢复视频帧后,才会发送PLI(Picture Lost Indicator)向源端请求关键帧,直到下一个关键帧到达前,所有链路上的视频帧都无法正常解码,影响接收端的视频帧率,较大概率造成卡顿。

  • 针对这两个典型的问题,我们可以分别尝试改进。

如上图所示,在改进的SFU传输架构中,重传请求不再是全链路反馈,而是在客户端和服务器之间进行。一方面,服务器具备了NACK请求的能力,及时发现上行链路的丢包,及时向发送到请求重传。另一方面,服务器能够及时响应接收端的NACK请求。丢包重传的效率提升,有助于减少端到端延时,改善音视频体验。

对于弱网下视频帧率较低的问题,除了优化传输过程中的FEC+NACK策略之外,还可以从源端编码器入手调整。

 

常规的RTC系统中的编码GOP是IPPP…P,每一个P帧都作为参考帧,一旦某一帧有数据包缺失,其后的所有P帧都无法正常解码,抗误码扰动的能力比较差。

 

一种改进的思路是,改变编码器的参考帧选择,采用长参考帧Long-Term Reference (LTR) frames机制,比如:

 

可以看到,引入LTR后,P帧不再是单一的前向参考,而是会有选择性的参考一些固定的帧,只要这部分固定的参考帧能够完整被接收,就能确保其他的完整帧能够正常解码,提高接收端的视频帧率,保障流畅。这种编码方式是比较适合于RTC系统的,能够对抗更大的网络抖动。

 

应用在视频会议中,需要接收端实时反馈的配合。接收端借助于RTCP,实时反馈能够正常解码的帧信息,发送端可以利用收集到的这些信息,选择合适的参考帧序列(需要兼顾编码效率),这样端到端的配合,能够最大程度的提升实时传输系统的体验。

 

这种反馈与编码协同的机制,同样适用于多人的会议场景。只不过,在多人场景中,我们要面对更加棘手的多端拥塞控制问题。

 

前面介绍过WebRTC自带的端到端拥塞控制,在会议场景下,拥塞控制需要综合考虑各个客户端的情况,如下图所示:

 

在多人会议情况下,各个接收端的带宽能力是不相同的,每条链路的带宽估计值都会反馈到发送端,由发送端来统一决策,控制编码和发送码率。这会带来两个潜在的问题:

  • 多条链路的带宽反馈导致发送端的决策困难,编码/发送码率容易抖动。

  • 某一个接收端的网络带宽不足(如图中的300k下行),发送端就会降低码率以适配当前带宽,导致每个接收端的体验都会下降,这显然是不合理的。

 

解决这些问题,我们就要来改进拥塞控制模型。大致的思路是,在SFU上实现带宽估计反馈,以及下行的拥塞控制。将端到端的拥塞策略,演进为分段的拥塞控制策略。

 

理想情况下,发送端会根据上行的带宽估计值控制源端编码和发送码率,SFU则会利用下行的带宽估计值,来控制下发给各接收端的最高码率。

 

然而,现实问题是,当SFU只有一路视频可以转发时,如何根据各链路的带宽情况进行下发控制,有点巧妇难为无米之炊的感觉。

 

这里要借助于两种源端编码策略 - Simulcast和SVC。

 

Simulcast:同步广播,指的是同时编码/发送多路视频流,比如常规发送一路720p,外加一路180p的流,这样在SFU下发给接收端的时候,可以根据下行带宽的限制,选择下发不同分辨率的流,照顾到每个端的体验。应用Simulcast的系统示意:

 

SVC:可伸缩编码,使用基于层次的方法,提供时间或空间可伸缩编码组合。在RTC的应用中,通常会选用时域SVC,通过改变帧率来实现伸缩性。SFU可以根据下行的实际带宽,从同一路SVC视频流中解析出不同的时域分层,分别传输给各个接收端,同样可以实现差异化的视频流转发。

 

Simulcast和SVC在实际应用中各有优劣,Simulcast多路流的分辨率跨度大,主观体验不佳;SVC的时域分层会影响帧率,容易出现卡顿。

 

 实时传输网络 

 

前一节重点介绍了WebRTC QoS的基本配置,以及进阶的实践方向。有了这些武器,可以在上下行网络质量有波动时,还能保障较好的音视频体验。

 

在视频会议的搭建过程中,QoS策略的保障是一方面,传输链路的选择也同样重要。

 

到目前为止,我们介绍的视频会议架构还是中心服务器转发,摆在我们面前有几个显而易见的问题:

  • 用户远距离接入,尤其是跨国、跨地区时,传输链路质量没有保障。

  • 国内的跨运营商之间接入,网络抖动大,影响会议质量。

  • 单点服务器的容量和负载受限制。

     

如果希望我们的视频会议是稳定、可靠的,解决上面的所有问题,必须构建一个具备智能调度的实时传输网络。

整体网络传输的调度见上图,几点简要的说明:

  • 分区域/分运营商部署SFU服务器,用户通过接入服务实现就近接入,保障了最后一公里的质量。

  • 灵活/按需部署路由节点,通过路由分配服务,能够根据实时网络质量选择最优的传输路径。

  • 分布式的SFU更有利于会议方数的扩展和服务扩容

  • 需要保障传输s网络内部的数据传输质量,可以尝试QUIC。

     

结合上述两点,有了可靠的传输网络,加上QoS保障的上下行质量,才能实现让人放心的视频会议体验。

 

 其    他 

 

除了网络传输和QoS之外,视频会议的质量体验也和客户端的表现相关,一些端侧的疑难杂症,比如设备可用性,回声消除,双讲抑制等等,一定程度上决定了会议产品的成败。

 


推荐阅读
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 关于我们EMQ是一家全球领先的开源物联网基础设施软件供应商,服务新产业周期的IoT&5G、边缘计算与云计算市场,交付全球领先的开源物联网消息服务器和流处理数据 ... [详细]
  • http:my.oschina.netleejun2005blog136820刚看到群里又有同学在说HTTP协议下的Get请求参数长度是有大小限制的,最大不能超过XX ... [详细]
  • Google Play推出全新的应用内评价API,帮助开发者获取更多优质用户反馈。用户每天在Google Play上发表数百万条评论,这有助于开发者了解用户喜好和改进需求。开发者可以选择在适当的时间请求用户撰写评论,以获得全面而有用的反馈。全新应用内评价功能让用户无需返回应用详情页面即可发表评论,提升用户体验。 ... [详细]
  • FeatureRequestIsyourfeaturerequestrelatedtoaproblem?Please ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法
    本文介绍了解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法,包括检查location配置是否正确、pass_proxy是否需要加“/”等。同时,还介绍了修改nginx的error.log日志级别为debug,以便查看详细日志信息。 ... [详细]
  • 移动端常用单位——rem的使用方法和注意事项
    本文介绍了移动端常用的单位rem的使用方法和注意事项,包括px、%、em、vw、vh等其他常用单位的比较。同时还介绍了如何通过JS获取视口宽度并动态调整rem的值,以适应不同设备的屏幕大小。此外,还提到了rem目前在移动端的主流地位。 ... [详细]
  • 统一知识图谱学习和建议:更好地理解用户偏好
    本文介绍了一种将知识图谱纳入推荐系统的方法,以提高推荐的准确性和可解释性。与现有方法不同的是,本方法考虑了知识图谱的不完整性,并在知识图谱中传输关系信息,以更好地理解用户的偏好。通过大量实验,验证了本方法在推荐任务和知识图谱完成任务上的优势。 ... [详细]
  • EPICS Archiver Appliance存储waveform记录的尝试及资源需求分析
    本文介绍了EPICS Archiver Appliance存储waveform记录的尝试过程,并分析了其所需的资源容量。通过解决错误提示和调整内存大小,成功存储了波形数据。然后,讨论了储存环逐束团信号的意义,以及通过记录多圈的束团信号进行参数分析的可能性。波形数据的存储需求巨大,每天需要近250G,一年需要90T。然而,储存环逐束团信号具有重要意义,可以揭示出每个束团的纵向振荡频率和模式。 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • 安卓select模态框样式改变_微软Office风格的多端(Web、安卓、iOS)组件库——Fabric UI...
    介绍FabricUI是微软开源的一套Office风格的多端组件库,共有三套针对性的组件,分别适用于web、android以及iOS,Fab ... [详细]
  • 解决Cydia数据库错误:could not open file /var/lib/dpkg/status 的方法
    本文介绍了解决iOS系统中Cydia数据库错误的方法。通过使用苹果电脑上的Impactor工具和NewTerm软件,以及ifunbox工具和终端命令,可以解决该问题。具体步骤包括下载所需工具、连接手机到电脑、安装NewTerm、下载ifunbox并注册Dropbox账号、下载并解压lib.zip文件、将lib文件夹拖入Books文件夹中,并将lib文件夹拷贝到/var/目录下。以上方法适用于已经越狱且出现Cydia数据库错误的iPhone手机。 ... [详细]
  • imx6ull开发板驱动MT7601U无线网卡的方法和步骤详解
    本文详细介绍了在imx6ull开发板上驱动MT7601U无线网卡的方法和步骤。首先介绍了开发环境和硬件平台,然后说明了MT7601U驱动已经集成在linux内核的linux-4.x.x/drivers/net/wireless/mediatek/mt7601u文件中。接着介绍了移植mt7601u驱动的过程,包括编译内核和配置设备驱动。最后,列举了关键词和相关信息供读者参考。 ... [详细]
  • 本文介绍了在Linux下安装和配置Kafka的方法,包括安装JDK、下载和解压Kafka、配置Kafka的参数,以及配置Kafka的日志目录、服务器IP和日志存放路径等。同时还提供了单机配置部署的方法和zookeeper地址和端口的配置。通过实操成功的案例,帮助读者快速完成Kafka的安装和配置。 ... [详细]
author-avatar
QueenieYam任嘉明
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有