github:https://github.com/bigonelby/webrtcUml/tree/master/latest
这个图展示了webrtc中的带宽检测模块
这里的起点是RtpTransportControllerSend,前文已经提到,RTCP最终接收到的包,最终回到了RtcpBandwidthObserver这个接口中,而实现这个接口的正是RtpTransportControllerSend
继续介绍之前首先看看webrtc中优秀的架构设计。在webrtc中,基本都是基于接口开发,这使得整个架子非常有弹性,很容易扩展。比如网络拥塞控制模块,核心作用的就是NetworkControllerInterface这个接口,这个接口是由其工厂创建出来的,即NetworkControllerFactoryInterface,同样也是一个接口。这是一个典型的工厂模式。webrtc为我们提供了一个默认的工厂,即controller_factory_fallback_,其实体是GoogCcNetworkControllerFactory,即默认采用GCC。当然我们也可以覆盖这整个的逻辑,只要传入一个自定义的工厂就可以了,如果传入了,则会赋值给变量controller_factory_override_,这样我们就可以创建出自定义的NetworkControllerInterface,从而构建自定义的CC模块了
继续看数据流,输入就是RtcpBandwidthObserver中的两个方法:OnReceivedEstimatedBitrate和OnReceivedRtcpReceiverReport,这两个方法分别对应了REMB和RR包的解析。那么这两个方法所提供的信息,被传递到NetworkControllerInterface中,即OnRemoteBitrateReport,OnRoundTripTimeUpdate以及OnTransportLossReport。在GCC中,这些信息最终传递给SendSideBandwidthEstimation,同样通过三个Update方法传入,分别是UpdateReceiverEstimate,UpdatePacketsLost以及UpdateRtt。后面SendSideBandwidthEstimation模块决策码率时依赖这些输入的参数。
再来看看如何获取决策出的码率。起点还是RtpTransportControllerSend,其内部会启动一个周期任务,即StartProcessPeriodicTasks,这个任务用到了工具类RepeatingTaskHandle。这个周期任务的主要工作就是UpdateControllerWithTimeInterval,这个方法会调用NetworkControllerInterface中的OnProcessInterval方法。这个方法会返回决策出的目标码率,即结构体NetworkControlUpdate,这个结构体里的成员TargetTransferRate中有两个关键的成员,即target_rate和stable_target_rate,就是最终决策出的码率。
以上可以看出RtpTransportControllerSend模块,会周期性的向NetworkControllerInterface模块获取决策出的码率。这些码率是怎样决策出来的呢?实际上就是SendSideBandwidthEstimation模块了。上面提到周期性的调用OnProcessInterval方法,这个方法进一步调用到SendSideBandwidthEstimation中的UpdateEstimate方法,在这个方法中会决策出目标码率,并调用UpdateTargetBitrate进行目标码率的更新。这里的决策算法大致就是按照丢包率决策,丢包小于2%,则码率变为原来的1.08;如果在2%-10%则保持上一次不变;如果大于10%,则新码率为:上次码率 * (1 - 0.5 * loss)
以前webrtc的版本,只有这一种决策方式,决策好的target_bitrate就返回给上层了。不过现在似乎增加了新的机制,即AcknowledgeBitrateEstimatorInterface,这个机制的具体算法还不太清楚,每次收到TransportCC包的时候,会输入到这个模块,通过IncomingPacketFeedbackVector输入,底层决策的是BitrateEstimator。通过接口bitrate可以返回决策出的bitrate值。因此webrtc现在除了之前决策出的target_rate,还有这个决策出的值,即AcknowledgedRate,通过SendSideBandwidthEstimation的SetAcknowledgedRate接口,将此参数输入。
最终交由LinkCapacityTracker模块,对决策出的target_rate以及acknowledgedrate共同加权平均决策出一个值,这个值通过LinkCapacityTracker的estimate可以得到,通过SendSideBandwidthEstimation的GetEstimatedLinkCapacity亦可以得到,此值作为TargetTransferRate的stable_target_rate返回
这实际上给我们一个启示,如果我们想引入另一个算法,是否可以和AckknowledgeBitrateEstimatorInterface平行呢?完全采用类似的方式,对需要的输入参数进行解析,决策出bitrate值,然后再LinkCapacityTracker中,增加这个值得加权平均,这样可能是比较好的方式
以上NetworkControllerInterface得到了决策出的bitrate,并返回给RtpTransportControllerSend,之后处理的模块就是CongestionControlHandler了,那么决策出的码率又将进行怎么样的分配,以及最后如何设置到各发送流的编码,发送模块呢?后面继续聊