老的webrtc gcc算法,大概流程:
这两个拥塞控制算法分别是在发送端和接收端实现的, 接收端的拥塞控制算法所计算出的估计带宽, 会通过RTCP的remb反馈到发送端, 发送端综合两个控制算法的结果得到一个最终的发送码率,并以此码率发送数据包。
Loss-Based Controller在发送端负责基于丢包的拥塞控制,它的输入比较简单, 只需要根据从接收端反馈的丢包率, 就可以做带宽估算; 上图右侧比较复杂, 做的是基于延迟的带宽估计, 这也是本文后面主要介绍的部分。在最近的WebRTC实现中, GCC把它的两种拥塞控制算法都移到了发送端来实现, 但是两种算法本身并没有改变,只是在发送端需要计算延迟, 因而需要一些额外的feedback信息, 为此WebRTC扩展了RTCP协议, 其中最主要的是增加了Transport-CC Feedback,该包携带了接收端接收到的每个媒体包的到达时间。
基于延迟的拥塞控制比较复杂, WebRTC使用延迟梯度来判断网络的拥塞程度,延迟梯段的概念后文会详细介绍;其算法分为几个部分:
- 到达时间滤波器
- 过载检测器
- 速率控制器
在获得两个拥塞控制算法分别结算到的发送码率之后, GCC最终的发送码率取的是两种算法的最小值。下面我们详细介绍WebRTC的拥塞控制算法GCC。
一、基于丢包的带宽估计
基于丢包的拥塞控制比较简单, 其基本思想是根据丢包的多少来判断网络的拥塞程度, 丢包越多则认为网络越拥塞, 那么我们就要降低发送速率来缓解网络拥塞;如果没有丢包,这说明网络状况很好, 这时候就可以提高发送码率, 向上探测是否有更多的带宽可用。实现该算法有两点:一是获得接收端的丢包率, 一是确定降低码率和提升码率的阈值。
WebRTC通过RTCP协议的Receive Report反馈包来获取接收端的丢包率。Receive Report包中有一个fraction lost 字段, 包含了接收端的丢包率,如下图所示。
发送端接收RR报文,并根据丢包率调整估计带宽As
- 如果丢包率 < 2%,估计带宽在以前的基础上增长5%;
- 如果丢包率在[2%, 10%]之间,估计带宽保持不变;
- 如果丢包率 > 10%,估计带宽在以前的基础上降低(丢包率 * 50%)
而这部分的丢包则需要通过其他的如NACK或FEC等手段来恢复。
二、基于延迟梯度的带宽估计
WebRTC实现的基于延迟梯度的带宽估计有两种版本:
- 最早一种是在接受端实现,评估的带宽结果通过RTCP REMB消息反馈到发送端。 在此种实现中, 为了准确计算延迟梯度,WebRTC添加了一种RTP扩展头部abs-send-time, 用来表示每个RTP包的精确发送时间, 从而避免发送端延迟给网络传播延迟的估计带来误差。这种模式也是RFC和google的paper中描述的模式。
- 在新近的WebRTC的实现中,所有的带宽估计都放在了发送端, 也就说发送端除了做基于丢包的带宽估计, 同时也做基于延迟梯度的带宽估计。 为了能够在接受端做基于延迟梯度的带宽估计, WebRTC扩展了RTP/RTCP协议, 其一是增加了RTP扩展头部, 添加了一个session级别的sequence number, 目的是基于一个session做反馈信息的统计, 而不紧紧是一条音频流或视频流; 其二是增加了一个RTCP反馈信息transport-cc-feedback, 该消息负责反馈接受端收到的所有媒体包的到达时间。接收端根据包间的接受延迟和发送间隔可以计算出延迟梯度,从而估计带宽。
关于如何根据延迟梯度推断当前网络状况, 后面会分几点详细展开讲, 总体来说分为以下几个步骤:
- 到达时间滤波器
- 过载检测器
- 速率控制器
其过程就是, 到达时间滤波器根据包间的到达时延和发送间隔,计算出延迟变化, 这里会用到卡尔曼滤波对延迟变化做平滑以消除网络噪音带来的误差;延迟变化会作为过载检测器的输入,由过载检测器判断当前网络的状态,有三种网络状态返回overuse/underuse/normal,检测的依据是比较延迟变化和一个阈值, 其中该阈值非常关键且是动态调整的。最后根据网络状态的变化, 速率控制器根据一个带宽估计公式计算带宽估计值。