webrtc twcc接收端代码分析(webrtc-m76)

接收端twcc主要功能就是通过fb通知发送端每一个rtp的接收时间。
基本逻辑:当接收端接收到每一个rtp包的时候,记录当前的接受时间和包序号,然后按一定策略定时的发送到发送端,然后发送端可以根据的发送,接收时间统计延迟,为后续估算提供数据点。

代码分析 remote_estimator_proxy.cc文件

webrtc::RemoteEstimatorProxy类主要作用,保存窗口期的rtp包接收时间,组合成feedback rtcp反馈包,然后定时发送。

一. 缓存数据

	//接收到rtp时候,会通过此接口,输入接收时间等信息  
	//对外接口,然后判断数据有效性后调用OnPacketArrival  
	void RemoteEstimatorProxy::IncomingPacket(int64_t arrival_time_ms,size_t payload_size,const RTPHeader& header)  

	//函数功能:把seq存储到缓存中,
    // 1.去掉时间窗口期(500ms)外的。 2. 去掉超过最大缓存数量(kMaxNumberOfPackets)的
    // 保存缓存中最小的seq值到periodic_window_start_seq_,

	void RemoteEstimatorProxy::OnPacketArrival(uint16_t sequence_number,int64_t arrival_time, absl::optional<FeedbackRequest> feedback_request) {
	  ...
      //消除seq回绕
	  int64_t seq = unwrapper_.Unwrap(sequence_number);
	
      //send_periodic_feedback_:反馈模式,是否定时反馈 
	  //删除periodic_window_start_seq_前500ms(send_config_.back_window-ms)的包,periodic_window_start_seq_保存的缓存中的最小seq
	  if (send_periodic_feedback_) {
	    if (periodic_window_start_seq_ &&
	        packet_arrival_times_.lower_bound(*periodic_window_start_seq_) ==
	            packet_arrival_times_.end()) {
	      // Start new feedback packet, cull old packets.
		  //删除超出当前时间窗口的包 500ms前的
		  //如果删除的包中存在对应seq,我感觉应该不需要这个包了,删除完成后,直接退出函数
          //因为500ms前这个seq包已经到达过,乱序包也不会存在这么长时间,如果真是乱序,重传的这么长的时间会影响后面的估算			  
	      for (auto it = packet_arrival_times_.begin();
	           it != packet_arrival_times_.end() && it->first < seq &&
	           arrival_time - it->second >= send_config_.back_window->ms();) {
	        it = packet_arrival_times_.erase(it);
	      }
	    }
	
		//保存待发送反馈的最小值seq
	    if (!periodic_window_start_seq_ || seq < *periodic_window_start_seq_) {
	      periodic_window_start_seq_ = seq;
	    }
	  }
	
	  // We are only interested in the first time a packet is received.
	  if (packet_arrival_times_.find(seq) != packet_arrival_times_.end())
	    return;
	
	  packet_arrival_times_[seq] = arrival_time;
	
	  //最多存储kMaxNumberOfPackets个数的包,清除以前的  
	  auto first_arrival_time_to_keep = packet_arrival_times_.lower_bound(
	      packet_arrival_times_.rbegin()->first - kMaxNumberOfPackets);
	  if (first_arrival_time_to_keep != packet_arrival_times_.begin()) {
	    packet_arrival_times_.erase(packet_arrival_times_.begin(),
	                                first_arrival_time_to_keep);
	    if (send_periodic_feedback_) {
	      // |packet_arrival_times_| cannot be empty since we just added one element
	      // and the last element is not deleted.
	      RTC_DCHECK(!packet_arrival_times_.empty());
	      periodic_window_start_seq_ = packet_arrival_times_.begin()->first;
	    }
	  }
	
      //
      //发送请求
	  if (feedback_request) {
	    // Send feedback packet immediately.
	    SendFeedbackOnRequest(seq, *feedback_request);
	  }
	}

二. 发送feedback

把缓存的数据构造成FeedBack(可能分解成多个数据包),然后发送出去(feedback_sender_发送接口)
void RemoteEstimatorProxy::SendPeriodicFeedbacks() {  
  for (auto begin_iterator =
           packet_arrival_times_.lower_bound(*periodic_window_start_seq_);
       begin_iterator != packet_arrival_times_.cend();
       begin_iterator =
           packet_arrival_times_.lower_bound(*periodic_window_start_seq_)) {
    rtcp::TransportFeedback feedback_packet;
	//当达到反馈包最大大小时候,返回下一次使用的开始seq
    periodic_window_start_seq_ = BuildFeedbackPacket(
        feedback_packet_count_++, media_ssrc_, *periodic_window_start_seq_,
        begin_iterator, packet_arrival_times_.cend(), &feedback_packet);

    
    RTC_DCHECK(feedback_sender_ != nullptr);
    feedback_sender_->SendTransportFeedback(&feedback_packet);	    
  }
}

三. 计算发送间隔

//当前码率计算发送间隔, 必选介于 50ms -250ms之间(send_config_.min_interval,send_config_.max_interval),这些值可以通过sdp设置的
void RemoteEstimatorProxy::OnBitrateChanged(int bitrate_bps) {
  // TwccReportSize = Ipv4(20B) + UDP(8B) + SRTP(10B) +
  // AverageTwccReport(30B)
  // TwccReport size at 50ms interval is 24 byte.
  // TwccReport size at 250ms interval is 36 byte.
  // AverageTwccReport = (TwccReport(50ms) + TwccReport(250ms)) / 2
  //每个fb twcc包的大小的均值
  constexpr int kTwccReportSize = 20 + 8 + 10 + 30;
  const double kMinTwccRate =
      kTwccReportSize * 8.0 * 1000.0 / send_config_.max_interval->ms();
  const double kMaxTwccRate =
      kTwccReportSize * 8.0 * 1000.0 / send_config_.min_interval->ms();

  //计算发送间隔,限制到50ms-250ms之间
  // Let TWCC reports occupy 5% of total bandwidth.
  rtc::CritScope cs(&lock_);
  send_interval_ms_ = static_cast<int>(
      0.5 + kTwccReportSize * 8.0 * 1000.0 /
                rtc::SafeClamp(0.05 * bitrate_bps, kMinTwccRate, kMaxTwccRate));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值