iOS WebRTC 杂谈之 带宽预测及REMB码率实时调整

本文关键词: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

二、函数调用逻辑

RTCP控制码率函数调用关系.png

当发送端接收到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参数,
目标码率和编码码率确定后,会根据实际码率进行丢帧处理,关于丢帧算法没有具体的研究便直接略过了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,723评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,080评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,604评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,440评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,431评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,499评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,893评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,541评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,751评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,547评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,619评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,320评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,890评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,896评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,137评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,796评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,335评论 2 342

推荐阅读更多精彩内容