美文网首页WebRTCWebRTC技术内幕Webrtc技术专栏
WebRTC基于TransportCC和Trendline Fi

WebRTC基于TransportCC和Trendline Fi

作者: weizhenwei | 来源:发表于2018-08-19 12:31 被阅读880次

    1引言

    众所周知,WebRTC的拥塞控制和码率估计算法采用GCC算法[1]。该算法充分考虑了网络丢包和网络延迟对码率估计的不同影响,分别基于丢包率和网络延迟进行码率估计,最后综合这另种码率得出最优值。在算法实现上,基于丢包率的码率估计在发送端进行,基于网络延迟的码率估计在接收端进行。最后在发送端计算出最优值,作用于Codec和PacedSender模块。GCC算法能够较好地基于网络实时状况估计网络带宽,为网络实时通信应用打下坚实基础[2][3][4]。

    然而,随着时间推移,在实际测试中发现GCC算法逐渐显出一些弊端,比如不能适应所有网络模型,应对网络峰值能力差,等等。为此,Google官方从M55版本引进最新的拥塞控制算法Sendside-BWE,把所有码率计算模块都移到发送端进行,并采用全新的Trendline滤波器取代之前的Kalman滤波器[5]。实测表明,新的算法实现能够更好更快地进行码率估计和网络过载恢复。

    本文基于WebRTC的M66版本和相关RFC,深度分析学习最新Sendside-BWE算法的实现。

    2 GCC算法回顾

    关于GCC算法已经有很多分析和论述[6][7],本文只回顾其算法框架,并分析其在实际应用中存在的问题。

    图1 GCC算法整体结构

    GCC算法分两部分:发送端基于丢包率的码率控制和接收端基于延迟的码率控制。基于丢包率的码率控制运行在发送端,依靠RTCP RR报文进行工作。WebRTC在发送端收到来自接收端的RTCP RR报文,根据其Report Block中携带的丢包率信息,动态调整发送端码率As。基于延迟的码率控制运行在接收端,WebRTC根据数据包到达的时间延迟,通过到达时间滤波器,估算出网络延迟m(t),然后经过过载检测器判断当前网络的拥塞状况,最后在码率控制器根据规则计算出远端估计最大码率Ar。得到Ar之后,通过RTCP REMB报文返回发送端。发送端综合As、Ar和预配置的上下限,计算出最终的目标码率A,该码率会作用到Encoder、RTP和PacedSender等模块,控制发送端的码率。

    发送端基于丢包率的码率估计计算公式:

    图2 GCC发送端基于丢包率的码率估计

    接收端基于延迟的码率估计计算公式:

    图3 GCC接收端基于延迟的码率估计

    GCC算法充分考虑丢包率和延迟对码率的影响,在实时通讯应用(如视频会议)中能够发挥良好效果。然而,在某些特定应用场景下(比如实时在线编辑),GCC算法的表现不太让人满意,主要体现在它应对峰值流量的能力上,具体表现在:1)算法一开始基于Increase状态增加码率,当检测到Decrease状态时调用Ar[t(i)] = Alpha * Rr[t(i)],这个时候实时码率Rr(ti)可能远小于Ar[t(i-1)],这样在后续过程中Ar处于较低水平;此时若有视频关键帧冲击,则数据包大量在PacedSender的队列中排队,造成较大排队延迟。2)基于1)中论述的情况,码率估计模块反馈给Codec的编码码率很低,但编码器需要编码关键帧时,内部的码率控制模块控制出的最小码率仍然大于反馈码率。这两种情况都会造成较大的发送端排队延迟,进而在接收端造成较大的JitterBuffer延迟,最终导致端到端延迟到达500ms的水平,这在实时在线编辑应用中是无法容忍的。

    基于此,Google官方从WebRTC M55开始引入新的码率估计算法,把所有码率计算模块都移动到发送端,并采用全新的Trendline滤波器,基于码率探测机制快速准确地估计出实时码率。

    3 Sendside-BWE算法框架

    从本节开始系统分析Sendside-BWE算法的框架和实现,图4显示该算法的基本实现框架,以及和GCC算法的对比。

    图4 Sendside-BWE算法和GCC算法的实现和对比[8]

    图4中棕色线是Sendside-BWE算法的数据控制流回路:发送端在发送RTP数据包时,在RTP头部扩展中设置传输层序列号TransportSequenceNumber;数据包到达接收端后记录该序列号和包到达时间,然后接收端基于此构造TransportCC报文返回到发送端;发送端解析该报文,并执行Sendside-BWE算法,计算得到基于延迟的码率Ar;最终Ar和基于丢包率的码率As进行比较得到最终目标码率,作用到PacedSender和Codec模块,形成一个完整的反馈回路。图4中红色线是GCC算法的数据控制流回路:发送端在发送RTP数据包时,在RTP头部扩展中设置绝对发送时间AbsSendTime;数据包到达接收端后记录该绝对到达时间,然后基于此执行GCC算法得到Ar,最后构造REMB报文把Ar发送回发送端;发送端基于Ar和As得到最终目标码率,作用到PacedSender和Codec模块,形成一个完整的反馈回路。

    从中可以看出,Sendside-BWE算法充分复用GCC算法的框架和实现,整个反馈回路基本类似:发送端在RTP头部扩展中记录码率估计元数据,码率估计模块基于此元数据估计出码率As,在发送端基于丢包率计算Ar,发送端综合As和Ar得到最终目标码率,并作用于Codec和PacedSender模块。所不同的是:对于GCC算法,RTP报文头部添加AbsSendTime扩展,在接收端执行基于延迟的码率估计,网络延迟滤波器采用Kalman Filter,返回给发送端的是REMB报文;对于Sendside-BWE算法,RTP报文头部添加TransportSequenceNumber扩展,在发送端执行基于延迟的码率估计,网络延迟滤波器采用Trandline,返回给发送端的是TransportCC报文。表5总结出GCC算法和Sendside-BWE算法的异同。

    表5 GCC和Sendside-BWE关键模块异同

    需要注意的是,从WebRTC M55开始启用Sendside-BWE后,其GCC算法就只做前向兼容而没有进一步的功能开发、性能优化和bug修正。因此,GCC是过去,Sendside-BWE是未来。

    4 Sendside-BWE算法实现

    本节论述Sendside-BWE算法的实现细节,在论述上力求不过度注释代码,以免陷入细节无法自拔。本节按照如下顺序论述Sendside-BWE的实现细节:SDP协商,发送端发送RTP报文,接收端接受RTP报文及信息存储,接收端构造TransportCC报文,发送端解析TransportCC报文,发送端码率估计。

    4.1 Sendside-BWE在SDP层协商

    TransportCC和remb一样都是Codec的feedback params的一部分。为支持TransportCC,Codec在收集feedback params时需添加额外一条:

    codec->AddFeedbackParam(FeedbackParam(kRtcpFbParamTransportCc, kParamValueEmpty));

    其中,TransportCC在最终生成的SDP中体现为如下一条attribute:

    a=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01

    然后,SDP协商过程按照常规操作进行。

    4.2 发送端发送RTP报文

    发送端在发送RTP报文时,需要在RTP头部添加新的扩展TransportSequenceNumber,该扩展格式如图6所示。

    图6 TransportSequenceNumber扩展格式

    注意这里的传输层序列号,和RTP报文格式中的媒体层序列号不是同一个东西。传输层序列号关注数据的传输特性,主要作用是码率估计;媒体曾序列号关注数据的媒体特性,主要作用是组帧和抗丢包。它们的初始值不一样,赋值点也不一样,其中媒体层序列号在RTPSender::AssignSequenceNumber()处赋值,而传输层序列号在RTPSender::UpdateTransportSequenceNumber()处赋值。RTP报文在发送时构造该头部扩展的函数调用栈如下:

    => RTPSender::TimeToSendPacket();
     => RTPSender::PrepareAndSendPacket();
      => RTPSender::UpdateTransportSequenceNumber();
       => RTPSender::AddPacketToTransportFeedback();s
        => SendSideCongestionController::AddPacket();

    然后RTP报文走正常的构造发送路径发送到网络。

    4.3 接收端接收RTP并构造TransportCC报文

    接收端worker线程在收到RTP报文后,解析并检查其头部扩展,根据其是否有TransportSN扩展,决定采用Sendside-BWE还是GCC,注意这两种拥塞控制器是互斥的。对于Sendside-BWE,接收端代理解析扩展拿到传输层序列号,并记录RTP报文的到达时间,构造(transport-sn,arrival_time_ms)键值对,存储在队列中。整个过程的函数调用栈如下:

    => Call::DeliverRtp();
     => NotifyBweOfReceivedPacket();
     => RtpPacketReceived::GetHeader();
     => ReceiveSideCongestionController::OnReceivedPacket();
      => RemoteEstimatorProxy::IncomingPacket();
       => OnPacketArrival(transport-sn, arrival_time_ms):
          Packet_arrival_times_[seq] = arrival_time;

    RemoteEstimatorProxy作为Sendside-BWE在接收端的代理,其实现遵从WebRTC的模块机制,在Process线程以100ms为发送周期发送TransportCC报文[9],发送周期会根据当前码率动态调整,其取值范围在[50ms, 250ms]之间,其本身可用的发送码率为当前可用码率的5%。TransportFeedback报文是一种RTP 传输层feedback报文(pt=205),FMT为15。其格式如图7所示:

    图7 TransportCC报文格式

    TransportCC报文采用base + bitmap的思想,其各个字段的具体解释请参考文献[9],一个TransportCC报文能最多携带16个RTP报文的有效信息,每个RTP报文信息包括其传输层序列号和包到达时间。TransportCC报文在发送端构造和发送的函数调用栈如下:

    => RemoteEstimatorProxy::Process();
     => RemoteEstimatorProxy::BuildFeedbackPacket();
      => TransportFeedback::AddReceivedPacket()
       => PacketRouter::SendTransportFeedback(fbpacket);
        => RTCPSender::SendFeedbackPacket(fbpacket);

    然后按照常规RTCP报文流程发送到发送端。

    4.4 发送端接收TransportCC报文并解析

    接收端接收操作就是常规的RTCP接收、解析并回调的流程,在worker线程中:

    => WebRtcVideoChannel::OnRtcpReceived();
     => Call::DeliverRtcp();
      => RTCPReceiver::HandleTransportFeedback();
       => RTCPReceiver::TriggerCallbacksFromRtcpPacket();
        => TransportFeedbackObserver::OnTransportFeedback();
         => SendSideCongestionController::OnTransportFeedback();

    然后就是Send-side BWE算法在发送端的核心实现。

    4.5 SendSideCongestionController码率估计

    SendSideCongestionController是Sendside-BWE算法在发送端的核心实现,关于其的分析全部是细节描述。本节限于篇幅,仅勾勒出其大致的函数调用栈和流程说明。

     => SendSideCongestionController::OnTransportFeedback();
     => AcknowledBitrateEstimator::IncomingPacketFeedbackVector();
     => DelayBasedBwe::IncomingPacketFeedbackVector();
     => BitrateControllerImpl::OnDelayBasedBweResult();
     => SendSideCongestionController::MaybeTriggerOnNetworkChanged();
     => ProbeController::RequestProbe();

    在SendSideCongestionController的OnTransportFeedback()函数中,首先调用ALR码率估计器得到一个实时码率,然后以此为参数调用DelayBasedBwe计算得到最新的估计码率Ar,把Ar经过BitrateController对象和As综合,得到最新的目标码率。最后通过函数MaybeTriggerOnNetworkChanged()把最新目标码率作用到Codec和PacedSender模块。如果本次码率估计从网络过载中恢复,则调用ProbeController对象发起下一次码率探测。

    DelayBasedBwe对象是真正实现码率估计的地方,其内部调用函数栈如下:

    => DelayBasedBwe::IncomingPacketFeedbackVector();
    => DelayBasedBwe::IncomingPacketFeedback();
     => InterArrival::ComputeDeltas();
     => TrendlineEstimator::Update();
    => DelayBasedBwe::MaybeUpdateEstimate();
     => ProbeBitrateEstimator::FetchAndResetLastEstimatedBitrateBps();
     => AimdRateControl::SetEstimator();

    DelayBasedBwe首先调用IncomingPacketFeedback针对每个RTP报文信息进行码率估计,其内部逻辑和GCC算法的相关步骤一致,在此不再赘述。需要注意的是,其内部网络延迟滤波器采用TrendlineEstimator。然后DelayBasedBwe调用MaybeUpdateEstimate()根据本次判定的网络状态计算得到最终的Ar,如GCC算法一样。

    Trendline滤波器的原理就是最小二乘法线性回归求得网络延迟波动的斜率,每个散列点表示为(arrival_time, smoothed_delay),其中arrival_time为RTP包到达时间,smoothed_delay为平滑后的发送接收相对延迟。最后根据当前散列点集合,采用最小二乘法线性回归计算得到本次估计的网络延迟m(i)。其计算过程调用如下:

    => TrendlineEstimator::Update();
     => LinearFitSlope();
     => TrendlineEstimator::Detect();
      => TrendlineEstimator::UpdateThreshold();

    至此,关于Sendside-BWE算法的实现初步分析完毕。

    5 Sendside-BWE实测数据

    实际测试表明,和GCC算法相比,Sendside-BWE算法在快速码率估计、码率估计准确性、抗网络抖动等方面都具有非常大改善。由于保密原因,此处不能发布内部测试数据,仅贴出一组公开渠道获得的快速码率估计比较图[10]。

    图8 Sendside-BWE和GCC算法对比

    该图表明,Sendside-BWE算法能够在第一次TransportCC报文返回时即估计出实时网络带宽,相比GCC算法更快速更准确。

    6 总结

    本文在总结对比GCC和Sendside-BWE算法基础上,深入学习Sendside-BWE算法的框架和实现细节,为进一步学习WebRTC拥塞控制算法和优化算法细节打下坚实基础。

    参考文献

    [1] A Google Congestion Control Algorithm for Real-Time Communication. draft-alvestrand-rmcat-congestion-03
    [2] Understanding the Dynamic Behaviour of the Google Congestion Control for RTCWeb.
    [3] Experimental Investigation of the Google Congestion Control for Real-Time Flows.
    [4] Analysis and Design of the Google Congestion Control for Web Real-time Communication (WebRTC). MMSys’16, May 10-13, 2016, Klagenfurt, Austria
    [5] WebRTC视频接收缓冲区基于KalmanFilter的延迟模型.http://www.jianshu.com/p/bb34995c549a
    [6] WebRTC基于GCC的拥塞控制(上) - 算法分析 https://www.jianshu.com/p/0f7ee0e0b3be
    [7] WebRTC基于GCC的拥塞控制(下) - 实现分析 https://www.jianshu.com/p/5259a8659112
    [8] WebRTC的拥塞控制和带宽策略 https://mp.weixin.qq.com/s/Ej63-FTe5-2pkxyXoXBUTw
    [9] RTP Extensions for Transport-wide Congestion Control
    draft-holmer-rmcat-transport-wide-cc-extensions-01
    [10] Bandwidth Estimation in WebRTC (and the new Sender Side BWE) http://www.rtcbits.com/2017/01/bandwidth-estimation-in-webrtc-and-new.html

    相关文章

      网友评论

      • devzhaoyou:你好,能不能写写关于H264在Webrtc 下工作情况的文章,我们之前 把WebRTC 中 padding禁用,使用H264 编码,发现GCC带宽估测非常不准,限制1M的带宽,估测的带宽只有300kbps左右。另外测试发现VP8编码下并没有发送Padding。另外Padding包会占用 H264包的seq,一旦丢包,jitterbuffer中不断请求padding包,发送端又没有缓存padding包,造成H264在丢包状态下非常卡顿,所以请教您对这一块有没有什么研究:blush:
      • magicMushroom:写的很好~
      • 开发者头条_程序员必装的App:感谢分享!已推荐到《开发者头条》:https://toutiao.io/posts/cxav78 欢迎点赞支持!使用开发者头条 App 搜索 67767 即可订阅《weizhenwei的技术研究》

      本文标题:WebRTC基于TransportCC和Trendline Fi

      本文链接:https://www.haomeiwen.com/subject/xkrciftx.html