本文关键词:WebRTC拥塞控制,goog-remb,带宽预测。
一、概念
RTP和RTCP。
实时传输协议RTP标准定义了两个子协议,数据传输协议RTP和控制协议RTCP。RTP协议定义了传输音频和视频的标准数据包格式,其报文中包含同步信源SSRC;RTCP通常和RTP一起使用,用于反馈和同步媒体流,其所占带宽非常小,只有RTP包的5%左右。根据所携带的控制信息的不同,RTCP信息包可分为RR(接收者报告包)、SR(源报告包)、SDES(源描述包)、BYE(离开申明)和APP(特殊应用包)五类。今天要说的码率实时控制就用到了RR。
RTCP中的 RR SR
RR(Receiver Reports)接受者报告
SR(Sender Reports)发送者报告
RTCP RR包的格式及字段说明在这里传送门;
RTCP SR包的格式及字段说明在这里传送门;
SR指的是包含了发送端信息的packets,由接收端接收后调用process()处理,RR指的是接收端向发送端发送的反馈包,包含丢包、延时等信息,发送端接收后调用process()方法,调整自己的发送码率。
goog-remb
二、函数调用逻辑
当发送端接收到RR包时,经过解析后,bitrate_controller_impl的BitrateControllerImpl::OnReceivedRtcpReceiverReport方法会被触发,然后会调用SendSideBandwidthEstimation的UpdateReceiverBlock方法,将RR包的丢包率fraction_loss,rtt,number_of_packets,当前时间now_ms传过去,UpdateReceiverBlock会根据这些参数预测实际带宽。
void BitrateControllerImpl::OnReceivedRtcpReceiverReport(
uint8_t fraction_loss,
int64_t rtt,
int number_of_packets,
int64_t now_ms) {
{
rtc::CritScope cs(&critsect_);
bandwidth_estimation_.UpdateReceiverBlock(fraction_loss, rtt,
number_of_packets, now_ms);
}
MaybeTriggerOnNetworkChanged();
}
void SendSideBandwidthEstimation::UpdateReceiverBlock(uint8_t fraction_loss,
int64_t rtt,
int number_of_packets,
int64_t now_ms) {
............
............
// Update RTT.
last_round_trip_time_ms_ = rtt;
............
............
UpdateEstimate(now_ms);
}
void SendSideBandwidthEstimation::UpdateEstimate(int64_t now_ms) {
......
......
bitrate_ = capped_bitrate;
}
在worker_thread中运行着一个ProcessThreadImpl::Process() ,由Clock进行计时,操作CongestionController::Process(),会一直轮询bitrate_是否发生变化;同时CongestionController::Process()里面又会调用bitrate_controller_impl里的Process(),它会一直轮询SendSideBandwidthEstimation::UpdateEstimate()方法。如果bitrate_发生了变化,CongestionController::Process()会调用PacedSender:: SetEstimatedBitrate(),pace节拍器会按照预测码率进行分片发送;同时bitrate_controller_impl::Process()会触发BitrateAllocator::OnNetworkChanged(),进而修改编码码率。
void CongestionController::MaybeTriggerOnNetworkChanged() {
// TODO(perkj): |observer_| can be nullptr if the ctor that accepts a
// BitrateObserver is used. Remove this check once the ctor is removed.
if (!observer_)
return;
uint32_t bitrate_bps;
uint8_t fraction_loss;
int64_t rtt;
bool estimate_changed = bitrate_controller_->GetNetworkParameters(
&bitrate_bps, &fraction_loss, &rtt);
if (estimate_changed) {
pacer_->SetEstimatedBitrate(bitrate_bps);
probe_controller_->SetEstimatedBitrate(bitrate_bps);
retransmission_rate_limiter_->SetMaxRate(bitrate_bps);
}
......
......
}
BitrateAllocator这个类在每个RTCP模块上注册了多个RtcpBirateObserver,将得到的bitrate进行计算,然后将结果推送到编码器。
goog-remb
bitrate_controller_impl类提供bitrate_controller模块的所有接口,用来操作带宽估计。当发送端收到REMB的带宽调整时,bitrate_controller_impl的OnReceivedEstimatedBitrate(uint32_t bitrate)方法会被调用,然后会调用BitrateControllerImpl::OnReceiverEstimatedBitrate(uint32_t bitrate),BitrateControllerImpl里有个SendSideBandwidthEstimation bandwidth_estimation_,然后会调用SendSideBandwidthEstimation的UpdateReceiverEstimate方法更新本地记录的接收端带宽预测bitrate_。这个bitrate_是通过bitrate_ = CapBitrateToThresholds(now_ms, bitrate_);计算得来的。
// Received RTCP REMB or TMMBR.
void OnReceivedEstimatedBitrate(uint32_t bitrate) override {
printf("OnReceivedEstimatedBitrate:%d",bitrate);
owner_->OnReceiverEstimatedBitrate(bitrate);
}
// This is called upon reception of REMB or TMMBR.
void BitrateControllerImpl::OnReceiverEstimatedBitrate(uint32_t bitrate) {
{
rtc::CritScope cs(&critsect_);
bandwidth_estimation_.UpdateReceiverEstimate(clock_->TimeInMilliseconds(),
bitrate);
BWE_TEST_LOGGING_PLOT(1, "REMB[kbps]", clock_->TimeInMilliseconds(),
bitrate / 1000);
}
MaybeTriggerOnNetworkChanged();
}
// Call when we receive a RTCP message with TMMBR or REMB.
void SendSideBandwidthEstimation::UpdateReceiverEstimate(
int64_t now_ms, uint32_t bandwidth) {
bwe_incoming_ = bandwidth;
bitrate_ = CapBitrateToThresholds(now_ms, bitrate_);
printf("接收端估计最大带宽:%d 计算后的码率:%d",bandwidth,bitrate_);
}
最终发送端的码率的确定,还要依赖RR包反馈的RTT和fraction_loss参数,
目标码率和编码码率确定后,会根据实际码率进行丢帧处理,关于丢帧算法没有具体的研究便直接略过了。