WebRTC带宽估计

2023-11-06

整体架构

 

上面这张图是一个比较老的架构图,但是也基本能说明整体架构,早期webrtc版本带宽估计是放到接收端处理,目前最新版本带宽估计放到了发送端,但是接收端计算得到的带宽并没有废弃,而是通过rtcp remb反馈给发送端。

在发送端带宽估计由3个元素结合决定,基于丢包率估算的带宽(丢包率通过rtcp rr得到)、接收端的remb反馈的带宽、发送端带宽估计(方法类似于接收端的带宽估计,具体逻辑下面会介绍到),取三者带宽的最小值作为最终带宽估计值。

接口说明

rr

https://tools.ietf.org/html/rfc3550#section-6.4.2

 

接收端会通过rtcp rr将丢包率和丢包累计值反馈给发送端,发送端据此更新丢包率和rtt,具体逻辑后面会介绍

remb

https://tools.ietf.org/html/draft-alvestrand-rmcat-remb-03

 

todo:字段具体计算方式待研究,可以参考源码remb.cc -->Remb::Parse

 

transport-cc

https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01

详细说明可以参见上面两篇文章,总结来看发送端会在session的层面统一对rtp包进行计算transport-cc sequence num,区别于之前的sequence num,原因是transport-cc目的是计算两点之间的带宽,两点通信可以传输多个视频流(通过ssrc来标识)。

基于丢包的带宽估计

丢包率计算方法

协议理解

 

  1. 接收端维护两个计数器,每收到一个RTP包都更新:

    1. transmitted,接收到的RTP包的总数;

    2. retransmitted,接收到重传RTP包的数量;

  2. 某时刻收到的有序包的数量Count = transmitted-retransmitte ,当前时刻为Count2,上一时刻为Count1;

  3. 接收端以一定的频率发送RTCP包(RR、REMB、NACK等)时,会统计两次发送间隔之间(fraction)的接收包信息

    1. 两次发送间隔之间理论上应该收到的包数量=当前接收到的最大包序号-上个时刻最大有序包序号  uint16_t exp_since_last = (received_seq_max_ - last_report_seq_max_);

    2. 两次发送间隔之间实际接收到有序包的数量=当前时刻收到的有序包的数量-上一个时刻收到的有序包的数量  uint32_t rec_since_last = Count2 - Count1

    3. 丢包数=理论上应收的包数-实际收到的包数  int32_t missing = exp_since_last - rec_since_last,missing即为两次发送间隔之间的丢包数量,会累加并通过RR包通知发送端

  4. 接收端发送的RR包中包含两个丢包,一个是fraction_lost,是两次统计间隔间的丢包率(以256为基数换算成8bit),一个是cumulative number of packets lost,是总的累积丢包。

代码理解

基本数据结构

struct RtpPacketCounter {

uint32_t packets;      // Number of packets.

}

struct StreamDataCounters {

RtpPacketCounter transmitted;    // Number of transmitted packets/bytes.

  RtpPacketCounter retransmitted;  // Number of retransmitted packets/bytes.

}

class StreamStatisticianImpl : publicStreamStatistician {

   StreamDataCounters receive_counters_;

}

更新transmitted和retransmitted

 

丢包率计算

 

todo:整体的流程和协议理解的基本一样,唯一没弄清楚的是实际收到的去重包的数量为啥要加上retransmitted_packets,加上不是就变成了所有实际收到的包吗?

丢包率带宽估计

必要性

基于丢包率进行带宽估计的必要性,先看下《draft-alvestrand-rmcat-congestion-03》文档的一段话。基于delay-based的带宽估计仅适用于中间路由器buffer队列足够大的情况,在小缓存场景rtt(包括绝对rtt和相对rtt)变化都不明显。

 

除了论文中提到的小缓存场景,在实际应用中,有一种情况是运营商限速,抽象来看,此种场景类似于无缓存或小缓存的路由器行为。在此种场景下,一旦带宽高于带宽限制就会有丢包,一旦带宽低于带宽限制丢包就停止。由于中间无缓存或缓存较小,所以无论原始包还是重传包RTT不会有明显变化(包括绝对值和相对值)因此不会触发GCC基于RTT变化的带宽调整,适合采用基于丢包率的带宽估计。同时GCC在不丢包时主动上探,丢包时立刻下探,导致带宽估计波动,照成视频卡顿。所以在RTT变化不明显(缓存小或无),应抑制带宽频繁的上探和下探,防止带宽估计波动较大。

算法

As_hat(i) =As_hat(i-1),2%<=丢包率<=10%,保持不变

As_hat(i) = As_hat(i-1)(1-0.5p),丢包率>10%,下降,p是丢包率

As_hat(i) = 1.05*As_hat(i-1),丢包率<2%,上升

 

同时As_hat(i)是有上限和下限的,下限TFRC是一种TCP友好的速率控制公式,这个公式产生的带宽相对与 TCP 来说相当公平,且速率较为平稳。 上限A_hat(i)是基于delay-based估算的带宽值。

基于延时梯度的带宽估计

基于延时梯度的带宽估计是WebRTC GCC最为核心的拥塞控制算法,此算法在最新版的WebRTC有两种实现方式,一种是在接收端、另一种在发送端,两者唯一区别是到达时间滤波器不同,接收端是卡尔曼滤波器,发送端是trendline滤波器,其他完全相同

到达时间模型

 

包组

在 WebRTC 中,延迟梯度不是一个个包来计算的,而是通过将包分组,然后计算这些包组之间的延迟,这样做可以减少计算次数,同时减少误差。包组的划分原则为2个

  1. 在一个burst_time间隔内的一系列的包构成一个组。建议burst_time为5ms

  2. 任意到达时间间隔小于 burst_time 并且组间延迟差 d(i)< 0 的组都被考虑做为当前组的一部分。

延时梯度

d(i) = t(i) - t(i-1) - (T(i) - T(i-1))

其中T(i)是当前包组的最后一个离开的时间,t(i)是当前包组最后一个达到的时间,所有乱序的包都会被到达时间模型所忽略。

可以想象,当d(i)>0,到达时间差大于发送时间差,网络有拥塞,反之网络状况好转。GCC拥塞控制大体上也是基于这种思路估算当前网络拥塞情况。

到达时间滤波器

卡尔曼滤波器

todo,待补充

trendline滤波器

分析trendline最方便的方法是直接看WebRTC源码,见trendline_estimator.cc

滤波器参数

Trendline 滤波器的三个重要参数分别是:窗口大小、平滑系数、延迟梯度趋势的增益。

窗口大小决定收到多少包组之后开始计算延迟梯度趋势;平滑系数用于累计延迟梯度的一次指数平滑计算;对累计延迟梯度平滑值进行最小二乘法线性回归之后求得延迟梯度趋势,会乘以增益并和阈值作比较,以检测带宽使用状态。下面是 WebRTC 中这三个参数的默认值。

 

LinearFitSlope

该函数使用最小二乘法求解线性回归,输入 window_size_ 个样本点(arrival_time_ms, smoothed_delay),输出延迟梯度变化趋势的拟合直线斜率 trendline_slope。

update函数

voidTrendlineEstimator::Update(double recv_delta_ms,

                                double send_delta_ms,

                                int64_t arrival_time_ms)

 

此函数重点关注下面三件事

  1. 计算当前的延迟梯度累计值,如代码里的accumulated_delay_

  2. 计算延迟梯度累计值的一次指数平滑值,如代码里的smoothed_delay_,同时也是最小二乘法的y

  3. 最小二乘法线性回归求延迟梯度趋势斜率a,如代码里的trendline_

这个预测的斜率值 trendline_可以表征网络的拥塞程度(网络缓冲区,即路由器数据包排队的消涨情况)

trendline_过大,表征d(i)>0网络拥塞

trendline_适中,表征d(i)=0网络正常

trendline_过小,表征d(i)<0网络空闲

过载检测器

 

上面这张图其实是【Gcc-analysis】中对卡尔曼滤波器的分析示意图,不过卡尔曼滤波器和trendline滤波器最终解决的问题是一样的,卡尔曼算出m(ti),trendline算出斜率trendline_,然后和自适应阈值-r(ti)~r(ti)相比较得出当前网络状态(overuse、underuse、normal)。相比较的过程非常简,但是难点在于阈值的设定上。

自适应阈值

 

为什么阈值不是静态的而是要变化自适应的

 

【Gcc-analysis】给出了两个理由,不过第一个理由貌似用自适应阈值也很难解决,应该采用丢包率来评估带宽,主要应该还是第二个理由。第二个问题应该是GCC和BBR拥塞控制算法一个核心要解决的问题。TCP的拥塞控制算法主要依据是丢包重传,而当网络出现丢包往往是中间路由器buffer被填满的时候,此时网络传输延时比较大。而像GCC和BBR这种基于延时来判断网络拥塞的算法,期望达到的效果是在延时最低而网络吞吐量达到最大,很难竞争过TCP的这种流氓算法,如果一味避让最终必然会被饿死,所以GCC在设计时,在和TCP竞争时会适当提高阈值。

自适应阈值带来的效果

网络带宽变化时

 

与tcp竞争时

 

【Gcc-analysis】文档中给出了详细测试分析,通过上面两张图可以看出在自适应阈值的情况下,吞吐量、延时、丢包率都会有明显改善。

算法

  

detalT是包组到达的时间差

当m(ti)在阈值范围内时(-r~r),减小阈值,反之则增大阈值,kr决定了阈值增大和减小的速度,【Gcc-analysis】建议kd=0.00018,ku=0.01,【Gcc-analysis】有详细的推导过程。阈值上涨速度要大于阈值下降速度,保证和TCP竞争的公平性。

源码

过载检测

 

过载触发条件需要同时满足4个条件

  1. 延时梯度>当前阈值

  2. 过载时间(发送的时间差)> 10ms

  3. 过载次数>1

  4. 当前斜率值大于之前计算的斜率值,延时不断恶化

阈值更新

 

阈值更新公式前文已经提及,唯一不同的点,kd默认为0.039,ku设置为0.0087。

速率控制

前几节所介绍的内容总结来看既是通过延时梯度+trendline滤波器,估算延时梯度斜率值,并与自适应阈值比较得出当前网络状态(underuse、overuse、normal),本节则是以此作为输入事件,再结合当前网络控制状态(decr、incr、hold)+当前码率值,得出估算码率值

速率控制状态机

 

overuse

decrease

decrease

decrease

normal

increase

increase

hold

underuse

hold

hold

hold

关于状态机的理解

一个典型的状态转换图

 

overuse转换为decrease,normal向上一个状态转换都还好理解,为什么underuse信号需要转换为hold?

当有under use信号产生时,表示当前网络正在排空中间路由器buffer,为了保证将当前网络的buffer排空,评估出当前网络的最大带宽+最小延时,所以under use信号下一个状态均是hold,维持当前码率不变直到normal信号产生。

如果按照buffer角度看这3个信号

overuse-->buffer再堆积

underuse-->buffer再减少

normal--->没有buffer的状态

状态转换详细说明

速率控制三个状态和三个signal

  1. 三个状态:hold、increase、decrease

  2. 三个信号:underuse、overuse、normal

GCC草案中码率估算方法

收敛区间

GCC的码率控制,有点类似于TCP的cubic算法,当接近临近值时,码率增速放缓,当远离临近值时,增速增大。

如果我们之前在 Decrease 状态,且当前的输入的 bitrate 的值 R_hat(i) 逼近 在 Decrease 状态下 输入的 bitrate 的平均值(在队列排空之后,这个 bitrate 如果和排空过程中的 bitrate 差不多,则这个 bitrate 近乎达到了通道的最大的 bitrate。),则我们离收敛不远了。这个不远,我们定义为3个标准差之内。我们建议使用0.95作为指数平滑系数来测量输入的 bitrate 的平均值和标准差,因为我们认为它可以覆盖在 Decrease 状态下的多个场景。

GCC草案中码率估算方法

R_hat(i),对应代码里的acked_bitrate_bps,发送的总包大小/duration得出的测量值,其中duration建议在0.5~1s之间

A_hat(i),估计值,我们必须确保我们的估计值不会远离发送端实际的发送码率。我们需要将可用带宽估计值限制到一个范围:A_hat(i) < 1.5 * R_hat(i)

increase:乘性增加+加性增加,在3个标准差内采用加,在3个标准差之外采用乘

  1. 乘性增加:

    1. 在乘性增加期间,这个估计值 A_hat(i) 大概每次增加 8%。

    2. eta = 1.08^min(time_since_last_update_ms / 1000, 1.0)     

    3. A_hat(i) = eta * A_hat(i-1)

  2. 加性增加:

    1. 在线性增加期间,每过 response_time 的间隔时间,这个估计值 A_hat(i-1) 会增加大约半个数据包的大小。

    2. response_time_ms = 100 + rtt_ms,其中100ms代表的是过载检测器的处理时间

    3. beta = 0.5 * min(time_since_last_update_ms / response_time_ms, 1.0)  

    4. A_hat(i) = A_hat(i-1) + max(1000, beta * expected_packet_size_bits)

decrease

  1. A_hat(i) = alpha * R_hat(i),alpha在范围[0.8 0.95]之间,建议为0.85

hold

  1. hold状态是为了进入increase状态之前,排空已有的队列

  2. 当我们检测到 under-use 信号,我们检测到网络路径上的队列正在清空,这表明我们的可用带宽估计值 A_hat 低于实际的可用带宽。(但是此时输入的 bitrate 正处于带宽最大值)。此时,系统将要进入 Hold 状态,此时接收端的可用带宽估计值会维持不变,直到队列长度稳定。这是一种控制低延迟的方法。延迟的减小可能是由于这里的带宽估计值减小,也有可能由于一些交叉网络的连接减少了。 我们建议每个 response_time 间隔都要更新一个 A_hat(i)

代码中码率估算方法

收敛区间

上文已经介绍,GCC的码率控制有点类似于TCP的cubic,当码率增长到收敛区间附近,码率增长会缓慢,当远离收敛区间则码率增长会快速,那么在码率上涨期间,收敛区间的判断则变得尤为重要。

何为收敛区间,在长肥管的场景下,整个传输链路bottleneck带宽则是最大传输带宽, GCC草案建议最大带宽上下的3个标准差则认为是收敛区间。那么最终问题就归结为如何得到最大传输带宽,可以想象下在中间路由器buffer填满的情况下,当前的带宽则是最大传输带宽,回到GCC的场景下,正好对应overuse信号产生进入Decrease状态。所以GCC在decrease状态下计算最大码率和最大码率标准差。

  

在码率上涨期间,则根据最大码率均值和标准差来判断到底是加性增加还是乘性增加。

这个和GCC草案一致

加性增加

  

总结:每个response time(rtt+100ms)增加一个包大小,这个值如果换算为每秒小于4kbps,则取4kbps,也就是每秒最少增加4kbps

注意:

每秒增加4kbps,这个值是否适合vipkid?需要实际验证才行

需要注意的是GCC草案中是每个response time增加半个包的大小和实际代码不一致

乘性增加

 

每次增加为当前码率的8%和1kbps最大值,注意是每次(大约是rtt时间)不是每秒,如果按照40kbps和rtt=200ms估算,每秒大约增加5*40*0.08=16kbps

这个和GCC草案实现是一致的。

降低

 

这个和GCC草案基本一致

代码实现

上面已经零星介绍过一些主要函数的实现方法,下面重点从整体代码结构的角度将GCC整体的代码流程加以介绍

代码分支M67

整体代码架构

  

RTCPReceiver:rtcp包分发者,不同类型rtcp包分发给不同观察者(RtcpPacketTypeCounterObserver、RtcpBandwidthObserver、RtcpIntraFrameObserver、TransportFeedbackObserver、VideoBitrateAllocationObserver)

SendSideCongestionController:发送端的带宽估计模块,主要是基于transport cc的feedback进行基于延迟的带宽估计

BitrateControllerImpl和SendSideBandwidthEstimation:发送端的实际带宽控制模块,会结合rr、remb、transport cc feedback综合考虑,估算出理想的带宽值。

rr:更新丢包率和rtt---->SendSideBandwidthEstimation::UpdateReceiverBlock

remb:更新接收端估算的带宽--->SendSideBandwidthEstimation::UpdateReceiverEstimate

transport-cc:将接收端计算出来的rtt延时上报给发送端,然后发送端采用接收端几乎一样的算法估算带宽(滤波器发生了变更,kalman-->trendline)---->SendSideBandwidthEstimation::UpdateDelayBasedEstimate

发送端发送包时的逻辑

开始发送的时候,在生成transport cc sequence number的时候将包添加到sendSideCongestionController中,实际发送的时候,将包发送时间记录到sendSideCongestionController中。

当RTCP包到来时,在RTCPReceiver中的处理流程如下

rr

RTCPReceiver::TriggerCallbacksFromRtcpPacket--->

BitrateControllerImpl::OnReceivedRtcpReceiverReport-->

BitrateControllerImpl::OnReceivedRtcpReceiverReport-->

SendSideBandwidthEstimation::UpdateReceiverBlock

  1. UpdatePacketsLost

  2. UpdateRtt

remb

RTCPReceiver::TriggerCallbacksFromRtcpPacket--->

BitrateControllerImpl::OnReceivedEstimatedBitrate-->

SendSideBandwidthEstimation::UpdateReceiverEstimate,设置接收端的带宽反馈结果

transport cc feedback

RTCPReceiver::TriggerCallbacksFromRtcpPacket--->

SendSideCongestionController::OnTransportFeedback--->

BitrateControllerImpl::OnDelayBasedBweResult-->

SendSideBandwidthEstimation::UpdateDelayBasedEstimate

SendSideBandwidthEstimation模块分析

此模块的输入是rr、remb、本地基于延迟的带宽估计模块结果,输出是估计带宽、丢包率、rtt

rr,根据report block更新丢包率和rtt,同时触发一次码率更新逻辑(UpdateEstimate)

rr-->UpdateReceiverBlock

  1. UpdatePacketsLost

    1. UpdateEstimate

      1. 基于丢包率,估算当前码率调整方式

      2. CapBitrateToThresholds,远端计算的带宽估计值、发送端基于延迟计算的带宽估计值、基于丢包率估算的带宽值、配置的最大最小带宽值,选择一个最小值。

    2. UpdateUmaStatsPacketsLost

  2. UpdateRtt

remb,

remb-->UpdateReceiverEstimate

  1. CapBitrateToThresholds,算法同上

transport cc feedback-->UpdateDelayBasedEstimate

  1. CapBitrateToThresholds,算法同上

CapBitrateToThresholds

bitrate=min(bitrate_in, remb_bitrate, delay_based_bitrate_bps_)

同时bitrate要受到max_bitrate_configured_和min_bitrate_configured_的限制,计算最终的估计bitrate。

rr-->

process()-->UpdateEstimate

  1. 如果当前没有丢包,并且在2s以内,bitrate_in = max(remb, delay_based_bitrate_bps_),调用CapBitrateToThresholds

  2. UpdateMinHistory,维护一个码率按照升序排队的队列

    1. 删除过期值

    2. 从后面开始删除比当前码率值大的值

    3. 将当前码率值pushback到队列中

    4. 当前码率也是即将变成旧值的码率,新码率即将被估算出来

  3. 如果未收到rr,CapBitrateToThresholds

  4. 判断和上一次rr反馈的结果还在时间间隔内

    1. 当前码率<码率阈值 || 丢包率<2%

      1. 设置码率为1.08*本轮间隔最小值

      2. 注意这块的逻辑,当丢包率<2%时,其实并没有判断remb和基于延时计算的带宽,直接增加带宽

    2. 当前码率>码率阈值

      1. 丢包率在2%和10%之间,do nothing,丢包率的最大最小阈值是在代码里写死的,这个区间在国内环境是是否适用?

      2. 丢包率>10%,如果之前没有因为丢包而降低带宽,同时上次降低带宽同时时间周期没有超过300ms+rtt,则将带宽设置为current_bitrate_bps_*(1-0.5*丢包率)

  5. 如果反馈消息超时到达,再超时的实验性开关开启的条件下,将带宽设置为原来的80%

  6. CapBitrateToThresholds,注意这块,将基于丢包计算出的带宽作为输入,再结合当前remb、基于延时估算出的带宽、码率阈值的配置,得出最终码率值

SendSideCongestionController模块分析

这个模块主要是根据transport cc feedback进行带宽估计,主要是基于延时进行估计,大体功能相当于之前的接收方带宽估计模块,会将带宽估计的结果上报给SendSideBandwidthEstimation的更新函数UpdateDelayBasedEstimate更新估计结果

主要包含模块如下:

TransportFeedBackAdapter:记录每个包对应的创建、发送、接收时间和状态

AcknowledgedBitrateEstimator:根据反馈包处理,计算一个时间范围内的收包码率

delay_based_bwe:整个delay based bandwidth estimation模块,基于延时的带宽估计模块,从接收端移到发送端唯一区别是更改了滤波器,卡尔曼滤波器-->线性滤波器

主要模块功能如下:

interArrival:主要对到达时间进行小范围统计、采样,并根据一定的时间间隔计算出对应的延迟、传输大小变化

trendlineEstimator:线性滤波器,相当于卡尔曼滤波器+overuse detector

AimdRateControl:相当于TCP拥塞控制,慢启动、拥塞避免

TransportFeedbackAdapter

transportFeedbackAdapter模块中包含了一个记录所有包收发的sendTimeHistory模块,这个模块记录如下内容:

  1. 包的序号,这里是transport cc的sequence number(调用点是RTPSender::prepareAndSendPacket)

  2. transport cc包序号生成时间,addPacket的时候生成

  3. 实际包发送时间,onSentPacket

  4. 在transport cc feedback到来时,计算每个packet chunk中的每个包的到达时间

AcknowledgedBitrateEstimator

这个模块主要是统计单位时间内(500ms)接收方接收的码率,并输出给下游组件(delay based estimator),作为其初始带宽估计值和本次计算的输入值

当第一次进行估计的时候,初始窗口为500ms,后续每次时间窗口为150ms

每次根据feedback统计时间窗口内的平均码率,没超过时间窗口的时候会使用旧的估计值进行计算,实际计算并不是单纯的根据统计到的值进行计算,还会增加一个贝叶斯对统计的值进行估算,根据估计值和观测值重新计算估计值

SendSideCongestionController代码调用栈

RTCPReceiver::IncomingPacket

RTCPReceiver::TriggerCallbacksFromRtcpPacket

SendSideCongestionController::OnTransportFeedback

  1. TransportFeedbackAdapter::OnTransportFeedback--->记录transport cc feedback vector

    1. vector<PacketFeedback> TransportFeedbackAdapter::GetPacketFeedbackVector

  2. AcknowledgedBitrateEstimator::IncomingPacketFeedbackVector-->估算初始码率

    1. 大体逻辑是在包发送之前,记录了每个包的bytes,同时根据包的arrive time时间差作为时间,用包总大小/时间差即可估算平均码率,当然这个统计是基于某个时间窗口期内的。代码中将本次估算结果作为输入+贝叶斯估算,将估算出来的最终结果作为本次码率的最终估算值。最终结果保存在bitrate_estimate_,可以通过BitrateEstimator::bitrate_bps获取到,这个结果是作为基于延时估算的初始输入和每次参考值

    2. 贝叶斯估计的作用?

    3. BitrateEstimator::Update,更新估算的码率值

  3. DelayBasedBwe::IncomingPacketFeedbackVector-->基于延时梯度+trendline滤波器+变化阈值-->网络状态,网络状态+前一次码率-->估算当前码率

    1. 遍历所有packet

      1. IncomingPacketFeedback

        1. InterArrival::ComputeDeltas

          1. 估计当前包的时间梯度值,包括发送时间和接收时间

          2. 根据kTimestampGroupLengthTicks将包进行分组,记下每个分组的最后一个发送时间和接收时间,这些时间都是按照升序排好序的

          3. 发送时间detal=用当前分组的最后一个包的发送时间-前一个分组最后一个包的发送时间,接收时间类似

        2. TrendlineEstimator::Update,根据时间梯度,计算当前网络负载状态,状态信息通过TrendlineEstimator::State()来获取

        3. delay_detector_->State(),根据当前滤波器估计prev状态(normal、under、over)

    2. 如果当前反馈包反馈的数据是非常久之前的OnLongFeedbackDelay

      1. AimdRateControl::SetEstimate

      2. 更新target_bitrate_bps,并返回

    3. DelayBasedBwe::MaybeUpdateEstimate

      1. DelayBasedBwe::UpdateEstimate,aimd模块以当前滤波器估计的带宽状态和AcknowledgedBitrateEstimator模块估算的码率为输入更新当前估计带宽值

        1. AimdRateControl::Update-->输入是滤波器得出的当前网络状态+acked_bitrate_bps,输出是估算码率

          1. AimdRateControl::ChangeBitrate--->输入是当前码率值+滤波器得出的当前网络状态+acked_bitrate_bps,输出是新估算的码率

            1. AimdRateControl::ChangeState:首先执行上述码率控制状态转换,得出当前码率控制状态,这个状态转换是rate_control_state_作为状态,网络使用状态作为事件执行状态变迁

              1. rate_control_state_-->(kRcHold/kRcIncrease/kRcDecrease)

              2. input.bw_state-->(kBwNormal/kBwOverusing/kBwUnderusing)

            2. switch rate_control_state_ case,根据当前码率控制状态,在目前码率基础上得出新码率

              1. kRcHold,维持码率不变

              2. kRcIncrease,增长有点类似于tcp的cubic思路,分为加增和乘增,靠近拥塞避免阈值则加增,远离后则乘增

              3. kRcDecrease

GCC算法效果

WebRTC GCC算法效果

 

  1. 开始阶段,probe bitrate会发送大量探测包来估算初始码率,结合twcc、丢包率估算的码率,大概需要10s的时间码率即可达到期望值
  2. 网络恶化,twcc、丢包率估算的码率会同时下降,取两者最小值作为估算值,大概需要3s的时间,码率即可降为期望值
  3. 网络恢复,大概需要50s的时间,码率恢复为期望值

razor GCC算法效果

 

  1. 开始阶段,相比WebRTC上涨较慢,大约需要30s评估出最大带宽
  2. 网络恶化,和WebRTC相近,大约需要3s带宽下降
  3. 网络恢复,大概需要30s,码率恢复为最大值,其中前6s为加性增阶段,后24s为乘性增阶段

总结

WebRTC的带宽估计会参考3个因素,丢包率、接收端带宽估计、发送端带宽估计,然后取三者最小值作为最终的估计码率。WebRTC的带宽估计是整个QoS优化的非常重要的一个环节,在弱网优化场景,会根据带宽估计作为输入,执行大小流、SVC、带宽分配、优先级等弱网降级策略。

参考文献

GCC草案:https://tools.ietf.org/html/draft-alvestrand-rmcat-congestion-03

Gcc-analysis:https://c3lab.poliba.it/images/6/65/Gcc-analysis.pdf

RTP3550协议:https://tools.ietf.org/html/rfc3550#section-6.4.2

remb rtcp协议:https://tools.ietf.org/html/draft-alvestrand-rmcat-remb-03

transport-cc协议:https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01

RTCP feedback定义:https://tools.ietf.org/html/rfc4585

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

WebRTC带宽估计 的相关文章

  • f103 hal RTC_alarm使用方法

    1 初始化RTC RTC handle span class token punctuation span Instance span class token operator 61 span span class token consta
  • 树莓派RTC

    文章目录 一 RTC准备二 RTC芯片三 为什么使用hwclock显示找不到硬件总结 一 RTC准备 在使能树莓派RTC之前 xff0c 需要先为树莓派RTC模块安装电池 xff08 一般为纽扣电池 xff09 二 RTC芯片 树莓派4B使
  • STM32 RTC晶振不起振原因

    今天下载程序后发现程序像死机一样 xff0c 然后仿真发现 xff0c 程序一直在等待RTC晶振就绪 xff0c 最终超时死机 然后检查的电路看都没问题 xff0c 最后通过查阅资料和咨询厂家了解到可能是晶振匹配电容的原因 如下为记录 xf
  • Undefined symbol RTC_DateStruct (referred from main.o).

    被自己蠢哭了 我是两个工程文件合在一起用的 一个工程中的 c文件变量定义之后是在另一个 c文件中共用的所以用了 extern RTC TimeTypeDef RTC TimeStruct extern RTC DateTypeDef RTC
  • 1.0 DS1302-外部RTC

    一 综述 DS1302是美国DALLAS公司推出的具有涓细电流充电能力的低功耗实时时钟芯片 xff0c 因为应用非常广泛 xff0c 结果就导致了大量的国产仿制品 xff0c GC1302是一款国产DS1302仿制芯片 xff0c 使用方法
  • 解决服务器时间Local time和RTC time不一致的问题

    今天遇到了一个问题 xff0c 发现程序读取的时间比实际的时间快了几分钟 执行 timedatectl status 发现 Local time比实际的快 xff0c 但是RTC time是准确的 各种google也没搞懂怎么回事 xff0
  • hallib_RTC

    RTC 一 配置参数 1 2 只有使能RTC之后才能选LSE 二 编写应用代码 1 在mspinit里面加上这个函数 xff0c 打开秒中断 xff0c 这个函数在 h文件里面 span class token function HAL R
  • stm32f407 RTC不更新问题排查

    1 问题 在做stm32f407rtc实验时 xff0c 代码是用cubemx生成的 xff0c 通过串口打印出时间值 xff0c 1s打印一次 但是结果与料想中的不一致 发现打印出来的值一直不更新 按下复位键 xff0c 后时间会更新一次
  • stm32 RTC_WaitForSynchro()死循环

    1 RTC WaitForSynchro 死循环 xff0c 发现是没有执行RTC Configuration 增加函数 xff0c 但不知道对之后的时钟准确性有什么影响 Function Name RTC Configuration De
  • STM32CubeMX之RTC电子钟

    STM32CubeMX之RTC电子钟 1 简介 实时时钟是一个独立的定时器 RTC模块拥有一组连续计数的计数器 在相应软件配置下 可提供时钟日历的功能 修改计数器的值可以重新设置系统当前的时间和日期 2 特性 可编程的预分频系数 分频系数最
  • 基于线性预测的语音编码原理解析

    早期的音频系统都是基于声音的模拟信号实现的 在声音的录制 编辑和播放过程中很容易引入各种噪声 从而导致信号的失真 随着信息技术的发展 数字信号处理技术在越来越多领域得到了应用 数字信号更是具备了易于存储和远距离传输 没有累积失真 抗干扰能力
  • 拥抱国产化,推动产业互联网,拍乐云做了什么?

    新一轮科学技术进步法的修订中提出要健全科技创新保障措施 完善创新体系 为促进实现高水平科技自立自强提供法治保障 随着国家对信息安全 科学自主的要求越来越高 音视频技术作为视频会议 应急指挥 办公协同 远程银行等行业场景的基础技术支撑 其独立
  • 揭开“视频超分”黑科技的神秘面纱

    在看电影时 有一幕大家应该都非常熟悉 警察从证据图片中选取一块区域放大 再放大 直到一个很小的目标变得清晰可见 从而发现重要的线索 现实中是不是真的有这样的技术 可以把模糊的小图变得清晰 答案是 一定程度上可以 这项黑科技就是超分辨率技术
  • 高质量、高并发的实时通信架构设计与探索

    中国互联网络信息中心 CNNIC 近日发布的第 47 次 中国互联网络发展状况统计报告 显示 截至 2020 年 12 月 我国网民规模达 9 89 亿 随着社会信息化水平持续提升及电子设备加速普及 手机网民规模持续增长 基本实现对全体网民
  • ClearCase 中是否有 RTC 等效的“挂起模式”?

    我发现 RTC 中的 暂停更改设置 非常有用 而且由于我们也在使用 ClearCase 数十个用户 我想知道 ClearCase 中是否也提供该功能 如果不是 它可以由 script trigger hook 生成吗 我们使用UCM 我想解
  • 为什么 RTC 中没有显示我的待处理更改?

    场景 我刚刚连接到流 并创建了一个新的存储库工作区 我加载了它的两个组件 并修改了一些代码 如果我打开 挂起的更改 视图 我在那里看不到任何挂起的更改 并且选择了 显示完整视图 因此我应该看到传入 传出和挂起的更改集 我的文件已保存 我可以
  • 如何查明工作项更改集文件项是否是新添加或修改的?

    我有一些更改集对象 我需要查明更改集中的文件是否是新添加或修改的 下面是我用来获取更改集的代码 IChangeSetHandle changeSets convertToChangeSetHandles extracted changeSe
  • Polarion ALM 工具 [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我们正在公司寻找完整的 ALM 解决方案 我们正在研究 Polarion ALM 和 RTC 有人听说过 Polarion 完整的 ALM 工具吗 如
  • Eclipse 将编译器合规性更新到 1.7

    我在更新 Eclipse 工作区的编译器合规性时遇到一些问题 我实际上使用的是 RTC 但它本质上是 Eclipse 目前 它使用 1 6 的 jdk 因此我可以将 JDK 合规性更改为 1 6 的限制 但是 我在我的项目中使用 jdk 1
  • 在 RTC 中交付后如何丢弃更改集

    我意外地交付了更改集 其中包括一些在 RTC 中具有本地系统特定配置的附加配置文件 有没有办法在交付后放弃这些更改 我的意思是 这些变化不应该随着其他团队成员的变化而发生 如果有的话请提供任何指示 有没有办法在交付后放弃这些更改 不完全是

随机推荐

  • STAR法则,被这个理由拒绝这么多次,必须搞明白!

    首先 STAR法则是一种常常被HR使用的工具 用来收集与面试者工作相关的具体信息和能力 一个概念 STAR法则 即为Situation Task Action Result的缩写 具体含义是 Situation情境 HR希望你描述一个你遇到
  • chromecast投屏_如何将手机或者ipad投屏到电脑上

    最玩游戏近老想把ipad投屏到电脑上 于是小编了解了一下现在好用的投屏APP 发现了傲软投屏 这是一款能够同时兼容iOS和安卓系统的同屏软件 支持在Windows及Mac上使用 只要您的安卓系统在5 0及以上 支持Chromecast协议
  • 蓝桥杯 算法训练:最小距离(Java)

    题目 数轴上有n个数字 求最近的两个数 即min abs x y 格式 第一行包含一个整数n 接下来一行 表示n整数 样例输入 6 7 3 4 11 9 17 样例输出 1 思路 刚开始打算使用普通的两两数组元素进行比较 但是发现到达第9个
  • 前端H5使用canvas画爱心以及笑脸

    目录 canvas简介 画爱心 效果 画笑脸 效果 结语 canvas简介 canvas是HTML5中推出的新功能 可以在页面上生成一个画布 使用js可以在画布上绘制一些图形 画爱心 画爱心我们需要用到bezierCurveTo方法 可以绘
  • 算法 - 折半查找(C#)

    递归实现 csharp view plain copy print
  • 什么是服务器信息怎么看,怎么查看服务器信息

    怎么查看服务器信息 内容精选 换一换 在您申请了云耀云服务器后 可以通过管理控制台查看和管理您的云耀云服务器 本节介绍如何查看云耀云服务器的详细配置 包括云耀云服务器名称 镜像信息 系统盘 数据盘 安全组 弹性公网IP等信息 登录管理控制台
  • 网盘服务器安装监控系统,服务器监控程序一键安装

    服务器监控程序一键安装 内容精选 换一换 依照配置并导入样例工程中导入和修改样例后 即可在开发环境中 右击 JDBCExample java 选择 Run JDBCExample main 运行对应的应用程序工程 使用Windows访问MR
  • 互联网公司常见性能测试(压测)面试题

    一 性能测试流程 1 首先制定性能测试计划 确定各项指标的目标 期望 2 申请压力机 3 制定性能测试方案 4 执行脚本 如用jmeter命令执行jmx文件 监控数据 zabbix CAT 5 分析数据 并出性能测试报告 二 性能测试关键指
  • Pycharm和Anaconda的关系

    Pycharm和Anaconda的关系 学习记录 知识点输出有风险 相信需谨慎 1 python 所存在的问题两个 第一个 自身缺少numpy matplotlib scipy scikit learn 等一系列包 需要安装pip来导入这些
  • STM32F103RC通过DHT11获取温湿度

    文章目录 bsp dht1 c bsp dht1 h 例子下载 bsp dht1 c file bsp TimBase c author stylle version V1 0 date 2021 xx xx brief DTH11温湿度获
  • Android Studio的NDK的配置

    有时会遇到NDK的配置错误 NDK配置如下 最好不要选择最新版本 我看网上攻略大多是使用21 0 6113669这个版本
  • git 撤回 (git版本回退处理)

    项目中 我们会遇到 提交的项目代码有问题 需要执行撤回命令 但是发现撤回之后还是会运行失败 下边是一个好方法 亲测比 git reset hard 版本号 有效 下面我们详细解说一下 一 已提交 没有push 回滚 当我们本地已经 执行了g
  • 【记关于github应用认证重定向到localhost的疑问】

    要做一个关于github 的OAuth第三方登录 在配置重定向url的时候填写的是本地的测试端口localhos 8080 然后登录认证后可以重定向到本地接口 关于这个重定向我就不理解为啥它可以知道我的IP地址 然后搜索发现这个重定向是告诉
  • JAVA jdk1.8安装图文解说

    对于 jdk 的安装 网上有很多种图文解说 但是老鸟发现它们大都不严谨 非常不适合小白 本节课 老鸟就给大家做个小白教程 无论你多么菜 你一定可以安装上 否则你加我微信 我给你打五毛钱 立帖为证 jdk 有很多版本 我们应该安装哪个呢 如果
  • Python单链表

    用Python写了一个单链表 具有和Python的列表list相似的一些函数 Single link list class Node def init self item self elem item self next None clas
  • php的socket通信以及出现的错误,php的Socket通信以及出现的错误

    php的Socket通信以及出现的错误 flag 1 do conn socket socket accept sock msg Send Message Hello World if socket write conn socket ms
  • grep正则表达式后面的单引号和双引号的区别?

    单引号 可以说是所见即所得 即将单引号内的内容原样输出 或者描述为单引号里面看到的是什么就会输出什么 单引号 是全引用 被单引号括起的内容不管是常量还是变量者不会发生替换 双引号 把双引号内的内容输出出来 如果内容中有命令 变量等 会先把变
  • 【华为机试在线训练】Day 6

    题目描述 定义一个二维数组N M 其中2 lt N lt 10 2 lt M lt 10 如5 5数组下所示 int maze 5 5 0 1 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 1 1 0 0 0 0 1 0 它表
  • 建议收藏:不能不刷的100道数字IC笔/面试题!

    一 IC设计流程及相应EDA开发工具 前端设计 逻辑设计 1 规格制定 根据客户需求 具体的功能和性能要求 制定芯片规格Spec 2 详细设计 设计方案 具体实现架构 模块划分 3 HDL编码 将实际的硬件电路功能通过HDL语言描述出来 形
  • WebRTC带宽估计

    整体架构 上面这张图是一个比较老的架构图 但是也基本能说明整体架构 早期webrtc版本带宽估计是放到接收端处理 目前最新版本带宽估计放到了发送端 但是接收端计算得到的带宽并没有废弃 而是通过rtcp remb反馈给发送端 在发送端带宽估计