实时音视频通话在当前的生活中是无时不刻存在的,包括社交、安防、交通等等各个方面都需要。用户场景复杂多变、要求严苛、网络环境不一致等给实时音视频通话带来很大条件。我们在这方向稍微做了一些工作,虽然和其他大厂的优化工作相比,我们还处于劣势,还有很多可以优化和改进的,但是目前的一些进展和工作内容和大家分享一下。
我们知道网络传输目前有 TCP 和 UDP 两种,相关优缺点如下脑图;而影响网络传输质量也有很多原因:包括网络拥塞、网络丢包等等。这些因素直接决定当前实时视频通话的质量,也会给用户带来很大的体验影响。这也是我们为什么要进行优化的基本原因了。
对于实时音视频通话来说:网络的复杂性、异构性、协议部分不规范性、网络异常,网络错误等各种网络环境被破坏的特性都称之为弱网。弱网环境无法提供高质量的网络传输,对于接收端就是无法收到连续的媒体包,造成声音异常、视频马赛克、花屏、黑屏等现象,对于音视频实时通话来说是非常致命的,直接影响到用户的体验,造成产品质量问题或者客诉问题。
对于实时音视频通话来说要求最高的条件低延迟和高质量,这一对特性的存在就是天生的矛盾结合体。高质量就要求发送端尽可能发送高分辨率,高质量的音视频流,对于带宽和网络环境要求比较高,不允许有各种丢包、高抖动的现象存在;而低延迟则对于网络环境没有那么严苛,是允许存在一定丢包量、允许一定范围内的接收抖动的,否则只能用空间换时间,导致音视频实时性时效,无法达到低延迟的要求。所以这是一对矛与盾的故事。只能在矛上寻求突破,在盾上给予保护,才能满足这样苛刻的条件。
webrtc FEC 的实现方式有三种:RED(rfc2198)、ULPFEC(rfc5109)、FLEXFEC(还未通过)。但是 Ulpfec 是套用了 RED 的壳进行传输的,所以我们采用的是 ULPFEC 进行 FEC 保护。
其基本原理是:在发送端,针对媒体包增加一定冗余 FEC 包,FEC 包是通过异或 XOR 得到的。如果在网络传输过程中丢掉了一部分媒体包,则在接收端通过接收到的媒体包和 FEC 包进行异或 XOR 得到丢失的媒体包,这样就不用发送 NACK 重发包占用网络资源了。
由于这部分在 WebRTC 中已经实现的比较好,只需要进行兼容性测试即可,这部分没有作为重点优化对象,沿用 WebRTC 中内容即可。
NACK 代表否定确认。 它是 WebRTC 中的错误恢复机制之一。NACK 是接收端表明它没有收到特定数据包的一种方式。
NACK 消息通过 RTCP 发送给媒体的发送方,后者需要根据其在缓存中的可用性以及对重传有用性的估计(是否可以使用)来决定是否重传丢失的数据包 它曾经收到。发送端维护一个缓冲队列,如果重发包在缓冲队列中则从缓冲队列中取出再次发送;如果没有在缓冲队列中,则不再发送,这样解码端就无法收到重发包了。
由于当前系统中采用的仍然是旧版本中的 NACK 流程,具体流程如下:
NACK 是一个未到达数据包的确认过程,原先流程中有很多嵌套功能,或者流程复杂的地方,因此我们再理解的基础上做了两次优化,其两轮优化的大概流程图如下:
还有一个 NACK 无法回避的问题时:如果网络丢包率比较高,或者网络抖动,网络异构导致网络各种乱序到达情况比较严重,比如抖动超过 200ms 时,某些丢失的数据包迟迟不到达,则该包会重复发送多次,这样会导致网络拥塞的现象,特别是分辨率比较高时,极容易造成视频帧无法完整解码,出现马赛克或者黑屏现象。
因此我们再次基础上增加和修改了一些判断条件,进行缓存队列和清空队列判断条件优化,以及获取完整视频帧流程部分调整和优化,尽量减缓以上情况的影响,提升用户体验。
我们在进行视频实时通话时,在设备端按照不同的帧率采集数据设置的参数,这样发送端就维护一个最大帧率参数集。之后采集的图像进行编码,分包发送到网络中。但是如果网络发生了变化,仍然按照当前的码率逐帧发送到上行网络时,亦或者采集端编码性能不稳定无法消耗采集的图像帧序列,发送端将采取降帧率或者丢帧的方式缓解发送端的发送压力。
在 WebRTC 中当编码后的传输码率过载或负载不均时,通过调用 MediaOptimization 类相关接口降低或升高帧率进而减小或者升高码率,从而有效利用当前带宽,防止网络更差,或者网络带宽负载不够,影响用户体验。
发送端:基于丢包率估算当前可用带宽
接受端:基于包到达时间计算可用带宽
综合:接收端发送 REMB 反馈给发送端,然后基于发送端的带宽估算和接收端的带宽估算决定最终的发送速率。
发送端的带宽估计算法基本原理:是读取 RTCP 中的丢包率信息,进而通过算法来动态计算当前网络中基本情况,并判断是否增加或减少带宽资源。如果判断需要减少带宽时,则采用 TFRC 算法来平滑处理,减弱突然增加或者减少的风险。
接收端的带宽估计算法基本原理:读取收到 RTP 数据统计进而估算当前网络带宽;WebRTC 中采用卡尔曼滤波帧对当前帧的接收时间戳和发送时间戳完成基本统计和计算,从而估算当前网络带宽拥塞情况和利用率,评估和修正带宽大小,进而影响网络带宽。
我们做的工作主要的优化点如下:
NACK 两轮优化:包括之前版本算法的整体提升(重构原来 R4X 相关代码,采用和 iOS 相同的 NACK 获取算法,并在此基础上进行缓存队列和清空判断条件调整优化、获取完整解码帧相关流程优化、长时间缓存帧丢弃策略调整等方案)、Jitterbuffer 参数的优化调整;
FEC、动态分辨率、NACK 整体策略优化:针对不同的网络条件,依据丢包率、RTT 等相关参数,以及 5s 内的抖动平均值等,设计一套动态调整当前组合的整体方案,既增加一定冗余防止 FEC 高丢包时时效现象,也可以在高丢包时逐步降低分辨率达到流畅播放的体验。
网络风暴抑制优化:WebRTC 中有重发包的网络抑制策略,重发包占比为 35%时候不再发送 NACK 重发包和 FEC 冗余包,但是这个占比对于 720P、30%以上丢包时非常不友好,因此大量实际验证测试,重发包和 FEC 冗余包占比为 30%时,能够合理规避网络风暴现象,同时满足 NACK 请求重发的策略,达到 720P、30%丢包仍然可以获取 15~25 帧率,实现流畅播放。
整体方案进行了部分实验室场景的测试和验收:包括 IP 和 SIP 通话,720P 和 VGA 分辨率验证,相比之前的版本,在一定程度上提高的用户体验。特别是有线网络条件下 IP 直播时提升明显,总体主观的分有了明显提升。同时对抗延迟也从无到有,能够覆盖 300ms 一下环境。该方案得到用到实际环境中,得到用户认可,并在和竞争对手 PK 过程中,全面领先。
需要更加快速准确定位到当前网络状态,一旦出现拥塞可以快速调整当前发送策略。已经有视频专项开始预研。
WebRTC 中 NACK 模块作为独立的 module 集成到 VIE 模块中,和 Jitterbuffer 模块解耦,实现实时监控网络丢包,并独立发送。
优点:可以实时获取到 NACK 列表; 和 JitterBuffer 解耦,获取更便捷、更迅速。已经有视频专项开始预研。
2020-10-24 参加声网 RTE2020 互联网实时互联网大会,声网已经实现 720P 2.0M 带宽下 65%的丢包,流畅播放了。
1.深度强化算法那在拥塞控制中的应用;
2.实时 H264 视频编码器算法的深度优化。
这些是我们之后要去调研学习的地方,也期待有相关经验的童鞋可以一起探讨学习。