动手点关注
干货不迷路
传统的数据传输方式大多是利用一个链路、选择设备的默认网卡进行传输,使用这种方式实现实时音视频通话时,如果默认网络出现问题(如断网、弱网等),用户的通信就会发生中断或者卡顿,影响用户体验。
多链路传输,顾名思义,就是使用多个链路进行传输数据的一种技术。近年来,单设备上支持多个可用网卡的技术越来越普遍,比如我们的手机就同时支持无线网卡和 4G/5G 网卡,有些双卡手机还能同时支持两个 4G/5G 网卡。而多链路技术就是充分利用用户设备上的多个网络资源进行数据传输,当某一个网络出现问题时,其他可用网络可以继续不间断地传输数据,避免因单一网络问题导致通话中断或者卡顿,提升用户通话的可用性和流畅性。
目前,多链路传输技术已经在火山引擎 RTC 打磨基本成熟,并在抖音和飞书会议等业务场景落地,有效地降低了用户的通话卡顿率,提升了用户的体验。
1. 行业现状和挑战
多链路技术在一些行业已经实现了应用,如 Apple 的 MPTCP(Multi-Path TCP) 就是一种多链路技术,Apple 把它用在了 Siri、Apple Maps、Apple Music 等应用上,用来解决用户在户外移动时,系统网络经常在 Wifi 和蜂窝网络之间切换导致的应用使用不流畅的问题。我们在使用微信的音视频通话功能时,微信也会开启音频双发功能,即使用 Wifi 网络和蜂窝网络同时发送音频数据,以提高用户的通话体验。
使用多链路传输技术让数据传输多了一层“可靠性”的保障,还能让网络切换变得更加丝滑,当然,在享受多个网络传输带来的好处时,我们也需要解决一些多链路技术实现上的问题。
一是多链路传输的架构比单链路传输复杂,比如需要考虑多个链路传输带来的数据包冗余、去重问题,多个链路的带宽、质量如何评估准确问题等;二是需要 平衡用户体验和流量、电量消耗,利用多个链路传输数据时,不可避免地会引起流量消耗变大,尤其是用户蜂窝流量变大,而流量消耗变大不仅会影响到带宽消耗和挤占,还会影响用户手机的功耗消耗,严重影响用户的使用体验。
业界目前的多链路使用方式主要有两种:一种是完全冗余的双链路传输,即,只要开启双链路,无论在什么情况下,都会传输双份数据。这种方式的缺点是明显的,它不判断 用户网络的好坏 “无脑”进行双链路传输 ,会明显带来流量和功耗的增长,可能导致 用户 手机发热等问题,影响用户体验;另外一种是 在 两条链路之间切换使用,这种方式能避免第一种完全冗余传输方式带来的功耗和流量增加,但这种方式也有缺点,比如两条链路在切换使用时,可能造成不平滑和卡顿,并且这种 传输 方式也不能充分利用两条链路 资源带来的“增加可靠保障”的好处。
火山引擎 RTC 在完全冗余模式基础上,研发了一个兼顾用户体验和流量、功耗消耗的传输模式:弱网冗余传输。弱网冗余传输,顾名思义,就是在 RTC 系统检测到弱网时才开启双链路的能力进行传输数据。这种模式既能在用户弱网时充分利用两条链路传输数据,使用户体验基本不会受弱网影响;又能在用户网络正常时使用单链路传输,减少对用户流量和功耗的消耗。
2. 多链路传输技术演进
2.1 完全冗余传输
完全冗余传输是指数据,包含音视频、信令、消息等数据,通过两条独立的路径在客户端和服务端之间传输,主链路的数据会完全复制一份到备选链路。完全冗余传输依靠多路径架构、多径协议、去重算法实现,其中多径协议和去重算法是关键部分。完全冗余传输可以有效地避免因单个路径产生问题而导致的通信中断问题,从而提升用户通话的可用性。
2.1.1 架构设计
架构设计上,完全冗余传输只存在于 SDK 连接模块和边缘媒体节点之间。在发送端,SDK 传输模块负责把上层的数据进行冗余,并通过两个通道同时发送出去,边缘媒体节点负责在接收到数据时,把数据进行去重还原,然后交给上层的服务。在接收端,边缘媒体节点负责对数据进行冗余发送,而 SDK 传输模块则负责对接收数据进行去重和还原,并把数据交给上层模块。
完全冗余的多链路传输架构
2.1.2 多径协议
多径协议的设计至少要满足两个要求,一是能区分冗余多径包和正常数据包(如 RTP/RTCP 包、STUN 包等),二是能对冗余包进行去重。
于是我们设计了如上 4 个字节的多径包头部:Packet Type 字段用来识别冗余的多径包,并和正常的 RTP/RTCP、STUN 包进行区分;Packet Sequence Number 则用来对多径包进行编号,用于去重;最后一个为保留字段。
例如,一个多径下的 RTP 包格式如下:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0xc8 | packet sequence number | default to 0 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|1| CC |M| PT | sequence number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| timestamp |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| synchronization source (SSRC) identifier |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
| 0x10 | 0x00 | length=0 |
+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
| RTP payload |
| .... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2.1.3 去重算法
我们利用传输模块保存一个 65536(16bit) 长度的 bit 数组 bitArrary,初始化状态为 0,采用滑动窗口的方式过滤重复序号的数据包。
去重算法图示
如上图,resetSeq 为窗口最左端值,latestSeq 为窗口最右端值,resetSeq 到 latestSeq 之间为有效判断窗口,即windowSize,设置为 30000。当模块收到一个包时,记此包 seqNum 为 curSeq,做如下处理:
如果此包是模块收到的第一个包,则置 latestSeq = seqNum,resetSeq = latestSeq - windowSize,并通知上层收到一个新包;
如果此包不是模块收到的第一个包,则判断 curSeq 与 latestSeq 之间的距离,如果大于 windowSize,则认为此包为一个无效包(sequence number跳变太大),进行丢弃;如果不大于 windowSize,则认为是一个有效包;
接第二步,如果 curSeq < latestSeq,判断 bitArray 中 curSeq 对应的 bit 位是否为 1。如果不是,则说明我们收到了一个新包,置此位为 1,并告知上层;如果已经为 1,则表示我们收到了一个重复包,直接丢弃。如果curSeq > latestSeq,则也认为是收到新包,告知上层,并移动窗口,置 latestSeq = seqNum,resetSeq = latestSeq - windowSize。
2.1.4 效果
我们模拟了各种网络环境来测试完全冗余的多链路传输(以下简称“完全双发”)对音视频质量、设备性能、功耗的影响。
以下测试数据为在 Wifi 和蜂窝双链路网络均开启的情况下,对主链路(Wifi)增加弱网时的音视频通话测试结果。
用户体验
整体来看,当开启完全双发后,单个路径的弱网对整体音画质、端到端延时表现基本没有影响,用户仍然能获得高质量的音视频通话体验;关闭完全双发后,单个路径的弱网会导致明显的卡顿和延时问题。
开启/关闭完全双发后,单路径弱网对音画质的影响
如上图,开启完全双发后,音质(MOS 分)、画质(视频帧率)在不同弱网环境下的表现稳定,音质、画质基本不受弱网影响。关闭完全双发后,音质、画质会随着弱网场景的不同受到不同程度的影响,特别是在 200kbps 限速时,音质、画质下降严重。
开启/关闭完全双发后,单路径弱网对音视频端到端延时的影响
如上图,开启完全双发后,端到端延时在不同弱网环境下的表现良好且稳定,基本不受弱网影响。关闭完全双发后,当出现高丢包、高延时弱网时,端到端延时明显增加,用户体验明显下降。
CPU 和内存性能
在各种网络环境下,开启或关闭完全双发对 CPU 和内存的消耗没有太大差别。
开启/关闭完全双发后,单路径弱网对音视频端到端延时的影响
功耗
测试结果显示,开启完全双发会对设备功耗造成一定影响,增加通话的电量消耗。
开启/关闭完全双发对手机电量消耗的影响(图为使用 iphone 11 的测试结果)
我们使用同款手机进行持续的音视频通话,开启完全双发比关闭双发消耗的电量更多、更快,在通话 1 小时后,开启双发比关闭双发多消耗了 4% 的电量。
2.1.5 方案优劣
完全冗余的多链路传输可以有效解决因单一网络出现问题而造成的音视频卡顿、延时问题,提升用户体验,并且它的实现方式比较简单。然而,它的缺点也很明显,一是对流量消耗大,特别是在视频场景,会消耗比较多的用户移动流量;二是对功耗的开销也较大。因此,完全双发并不符合实际业务上的需求和用户体验,我们需要在尽量减少流量消耗和功耗消耗的情况下来提升用户通话体验。
2.2 弱网冗余传输
完全冗余传输是无论在什么情况下,数据都会被复制一份到另外一个链路上传输,这么做会导致消耗用户比较多的流量和功耗。实际上,用户大部分情况下的网络是正常的,并不需要开启冗余传输,对于正常网络来说,开启冗余传输反而是一种浪费,效果是负面的。因此,我们需要更加有针对性地来开启多链路传输,这样既能提升用户的通话体验,也能节省流量和功耗。
弱网冗余传输,顾名思义,就是在完全冗余传输的基础上加上弱网的判断,即,只有在弱网时才开启多链路传输,它的关键在于对弱网判断的及时性和精准性,系统需要准确判断出现弱网并及时开启多链路传输(以下简称“弱网双发”),这样才能有效避免网络卡顿问题。
2.2.1 架构设计
弱网双发使用的多径协议、去重算法和完全双发基本相同,不同点主要在于,弱网双发在完全双发的基础上添加了弱网条件的判断,只有当检测到主链路发生弱网时系统才会开启双发(使用移动网络发送数据),否则不开启,这样既保证了正常网络下不额外消耗流量和电量,又做到了弱网下提升用户体验。
完全冗余与弱网冗余的多链路传输流程比较
2.2.2 效果
我们比较了不同弱网下,采用完全双发、弱网双发和关闭双发对对音视频质量、设备性能、功耗的影响。
用户体验
整体来看,无论是完全双发还是弱网双发,单个路径的弱网对整体音质、端到端延时表现基本没有影响,而关闭双发后,单个路径的弱网对音质、延时表现影响较大,音质明显下降,延时明显升高。在相同弱网条件下,完全双发的端到端延时比弱网双发更低。
完全双发、弱网双发、关闭双发时单路径弱网对音画质的影响
完全双发、弱网双发、关闭双发时单路径弱网对端到端延时的影响
CPU 和内存性能
在各种网络环境下,完全双发、弱网双发、关闭双发对 CPU 和内存的消耗并没有太大差别。
功耗
不管是完全双发还是弱网双发,都会增加通话的电量消耗,但弱网双发的耗电量比完全双发小,能比较有效地降低功耗消耗。
完全双发、弱网双发、关闭双发对手机电量消耗的影响
2.2.3 方案优劣
相比完全冗余传输,弱网冗余传输只有在检测到主链路弱网时才开启对应数据的双发,因此更节省流量;同时,因减少了在移动网络的数据发送,相应地也就减少了电量消耗。不过,由于判断弱网本身需要时间,弱网判断的准确性也会影响效果,因此,弱网双发的端到端延时比完全双发略大一些,但在一般的实时音视频使用场景中,这种延时差异对用户来说体验不大。
3. 多链路传输技术的实践与收益
目前,弱网双发已经在飞书会议、抖音社交等业务上线,以下是抖音社交业务开启弱网双发后较对照组的表现:
可以看到,开启音频弱网双发策略后,线上的音频卡顿率有了明显的下降,且性能指标几乎不受影响。
下面两段视频可以让我们更直观地感受到开启弱网双发对用户音视频体验的提升效果(模拟 50% 丢包网络环境,上方为本地实时采集画面,下方为对端传输画面)。
开启弱网双发,对端地球仪和本地一样运转流畅
关闭弱网双发,对端地球仪明显运转卡顿
4. 未来展望
以上是多链路传输技术在火山引擎 RTC 的演进和实践。
不过,上文提到的两种多链路设计方式均是在连接底层实现的多链路传输模式,这种多链路传输模式对于上层的模块完全透明,上层的拥塞控制、重传、FEC、PACER、编解码等模块,并不“知道”底层是单链路还是多链路的传输模式,因此会带来两个问题:
(1)上层的拥塞控制模块不感知底层的链路,无法独立评估每一个链路的带宽和拥塞情况,也就无法根据每个链路的质量来更精确的分配数据;
(2)数据的冗余发送在连接层实现,连接层无法感知数据更多的属性,也就无法实现更丰富的传输策略,比如如果我们只想用备用链路来传输关键帧、FEC 等数据,上面两种架构就较难实现这种策略。
未来,我们还会使用一种更进阶的架构来代替弱网冗余传输架构,并持续优化音频、视频的多链路传输策略,做到使用最小的额外带宽和功耗,最大限度地提升用户的音视频通话体验。
加入我们
火山引擎 RTC,致力于提供全球互联网范围内高质量、低延时的实时音视频通信能力,帮助开发者快速构建语音通话、视频通话、互动直播、转推直播等丰富场景功能,目前已覆盖互娱、教育、会议、游戏、汽车、金融、IoT 等丰富实时音视频互动场景,服务数亿用户。
RTC 音视频 SDK 架构师热招中!扫描下方二维码,或点击阅读原文,欢迎同学们加入我们团队!