webrtc-m79-RTCP包的路由

1 简介

        RTCP的主要包含一些控制信息,包含但不限于QOS、 播放控制等。

PacketReceiver::DeliveryStatus Call::DeliverPacket(
    MediaType media_type,
    rtc::CopyOnWriteBuffer packet,
    int64_t packet_time_us) {
  RTC_DCHECK_RUN_ON(&configuration_sequence_checker_);
  if (IsRtcp(packet.cdata(), packet.size()))
    return DeliverRtcp(media_type, packet.cdata(), packet.size()); //

  return DeliverRtp(media_type, std::move(packet), packet_time_us);
}


PacketReceiver::DeliveryStatus Call::DeliverRtcp(MediaType media_type,
                                                 const uint8_t* packet,
                                                 size_t length) {
  TRACE_EVENT0("webrtc", "Call::DeliverRtcp");
  // TODO(pbos): Make sure it's a valid packet.
  //             Return DELIVERY_UNKNOWN_SSRC if it can be determined that
  //             there's no receiver of the packet.
  if (received_bytes_per_second_counter_.HasSample()) {
    // First RTP packet has been received.
    received_bytes_per_second_counter_.Add(static_cast(length));
    received_rtcp_bytes_per_second_counter_.Add(static_cast(length));
  }
  bool rtcp_delivered = false;
  if (media_type == MediaType::ANY || media_type == MediaType::VIDEO) {
    ReadLockScoped read_lock(*receive_crit_);
    for (VideoReceiveStream* stream : video_receive_streams_) {
      if (stream->DeliverRtcp(packet, length)) // VideoReceiveStream::DeliverRtcp
        rtcp_delivered = true;
    }
  }
  if (media_type == MediaType::ANY || media_type == MediaType::AUDIO) {
    ReadLockScoped read_lock(*receive_crit_);
    for (AudioReceiveStream* stream : audio_receive_streams_) {
      stream->DeliverRtcp(packet, length); // AudioReceiveStream::DeliverRtcp 
      rtcp_delivered = true;
    }
  }
  if (media_type == MediaType::ANY || media_type == MediaType::VIDEO) {
    ReadLockScoped read_lock(*send_crit_);
    for (VideoSendStream* stream : video_send_streams_) {
      stream->DeliverRtcp(packet, length);
      rtcp_delivered = true;
    }
  }
  if (media_type == MediaType::ANY || media_type == MediaType::AUDIO) {
    ReadLockScoped read_lock(*send_crit_);
    for (auto& kv : audio_send_ssrcs_) {
      kv.second->DeliverRtcp(packet, length);
      rtcp_delivered = true;
    }
  }

  if (rtcp_delivered) {
    event_log_->Log(std::make_unique(
        rtc::MakeArrayView(packet, length)));
  }

  return rtcp_delivered ? DELIVERY_OK : DELIVERY_PACKET_ERROR;
}

2 视频

bool VideoReceiveStream::DeliverRtcp(const uint8_t* packet, size_t length) {
  return rtp_video_stream_receiver_.DeliverRtcp(packet, length); // RtpVideoStreamReceiver::DeliverRtcp 
}

bool RtpVideoStreamReceiver::DeliverRtcp(const uint8_t* rtcp_packet,
                                         size_t rtcp_packet_length) {
  RTC_DCHECK_RUN_ON(&worker_task_checker_);

  if (!receiving_) {
    return false;
  }

  rtp_rtcp_->IncomingRtcpPacket(rtcp_packet, rtcp_packet_length); // ModuleRtpRtcpImpl::IncomingRtcpPacket 

  int64_t rtt = 0;
  rtp_rtcp_->RTT(config_.rtp.remote_ssrc, &rtt, nullptr, nullptr, nullptr); // ModuleRtpRtcpImpl::RTT
  if (rtt == 0) {
    // Waiting for valid rtt.
    return true;
  }
  uint32_t ntp_secs = 0;
  uint32_t ntp_frac = 0;
  uint32_t rtp_timestamp = 0;
  uint32_t recieved_ntp_secs = 0;
  uint32_t recieved_ntp_frac = 0;
  // ntp_secs 就是最近一次接收到的SR包中的NTP时间中的单位为秒的部分
  // ntp_frac 就是最近一次接收到的SR包中的NTP时间中的单位为1/2^32秒的部分
  // recieved_ntp_secs 表示接收到这个SR包的时候,本地时间的NTP表示中的单位为秒的部分
  // recieved_ntp_frac 表示接收到这个SR包的时候,本地时间的NTP表示中的单位为1/2^32秒的部分
  // rtp_timestamp 表示最近一次接收到的SR包中的 RTP 时间戳
  if (rtp_rtcp_->RemoteNTP(&ntp_secs, &ntp_frac, &recieved_ntp_secs,
                           &recieved_ntp_frac, &rtp_timestamp) != 0) { // ModuleRtpRtcpImpl::RemoteNTP
    // Waiting for RTCP.
    return true;
  }
  
  // 接收到最近一次SR包的本地时间的NTP表示,由于发送端和接收端没有进行时间同步,所以SR包中的NTP时间和本地的NTP时间很有可能有较大的的偏差
  NtpTime recieved_ntp(recieved_ntp_secs, recieved_ntp_frac);
  // 从最近一次收到SR包到现在所流逝的时间
  int64_t time_since_recieved =
      clock_->CurrentNtpInMilliseconds() - recieved_ntp.ToMs();
  // Don't use old SRs to estimate time.
  if (time_since_recieved <= 1) {
    ntp_estimator_.UpdateRtcpTimestamp(rtt, ntp_secs, ntp_frac, rtp_timestamp); // RemoteNtpTimeEstimator::UpdateRtcpTimestamp
  }

  return true;
}

										// 接收 RTCP 包
										void ModuleRtpRtcpImpl::IncomingRtcpPacket(const uint8_t* rtcp_packet,
										                                           const size_t length) {
										  rtcp_receiver_.IncomingPacket(rtcp_packet, length); // RTCPReceiver::IncomingPacket
										}
										
										void RTCPReceiver::IncomingPacket(const uint8_t* packet, size_t packet_size) {
										  if (packet_size == 0) {
										    RTC_LOG(LS_WARNING) << "Incoming empty RTCP packet";
										    return;
										  }
										
										  PacketInformation packet_information;
										  if (!ParseCompoundPacket(packet, packet + packet_size, &packet_information))
										    return;
										  TriggerCallbacksFromRtcpPacket(packet_information);
										}


										// 计算 RTT 
										int32_t ModuleRtpRtcpImpl::RTT(const uint32_t remote_ssrc,
										                               int64_t* rtt,
										                               int64_t* avg_rtt,
										                               int64_t* min_rtt,
										                               int64_t* max_rtt) const {
										  int32_t ret = rtcp_receiver_.RTT(remote_ssrc, rtt, avg_rtt, min_rtt, max_rtt); // RTCPReceiver::RTT
										  if (rtt && *rtt == 0) {
										    // Try to get RTT from RtcpRttStats class.
										    *rtt = rtt_ms();
										  }
										  return ret;
										}
										
										int32_t RTCPReceiver::RTT(uint32_t remote_ssrc,
										                          int64_t* last_rtt_ms,
										                          int64_t* avg_rtt_ms,
										                          int64_t* min_rtt_ms,
										                          int64_t* max_rtt_ms) const {
										  rtc::CritScope lock(&rtcp_receiver_lock_);
										
										  auto it = received_report_blocks_.find(main_ssrc_);
										  if (it == received_report_blocks_.end())
										    return -1;
										
										  auto it_info = it->second.find(remote_ssrc);
										  if (it_info == it->second.end())
										    return -1;
										
										  const ReportBlockData* report_block_data = &it_info->second;
										
										  if (report_block_data->num_rtts() == 0)
										    return -1;
										
										  if (last_rtt_ms)
										    *last_rtt_ms = report_block_data->last_rtt_ms();
										
										  if (avg_rtt_ms) {
										    *avg_rtt_ms =
										        report_block_data->sum_rtt_ms() / report_block_data->num_rtts();
										  }
										
										  if (min_rtt_ms)
										    *min_rtt_ms = report_block_data->min_rtt_ms();
										
										  if (max_rtt_ms)
										    *max_rtt_ms = report_block_data->max_rtt_ms();
										
										  return 0;
										}



										// ntp 相关计算
										int32_t ModuleRtpRtcpImpl::RemoteNTP(uint32_t* received_ntpsecs,
										                                     uint32_t* received_ntpfrac,
										                                     uint32_t* rtcp_arrival_time_secs,
										                                     uint32_t* rtcp_arrival_time_frac,
										                                     uint32_t* rtcp_timestamp) const {
										  return rtcp_receiver_.NTP(received_ntpsecs, received_ntpfrac,  // RTCPReceiver::NTP
										                            rtcp_arrival_time_secs, rtcp_arrival_time_frac,
										                            rtcp_timestamp)
										             ? 0
										             : -1;
										}
										
										bool RTCPReceiver::NTP(uint32_t* received_ntp_secs,
										                       uint32_t* received_ntp_frac,
										                       uint32_t* rtcp_arrival_time_secs,
										                       uint32_t* rtcp_arrival_time_frac,
										                       uint32_t* rtcp_timestamp) const {
										  rtc::CritScope lock(&rtcp_receiver_lock_);
										  if (!last_received_sr_ntp_.Valid())
										    return false;
										
										  // NTP from incoming SenderReport.
										  if (received_ntp_secs)
										    *received_ntp_secs = remote_sender_ntp_time_.seconds();
										  if (received_ntp_frac)
										    *received_ntp_frac = remote_sender_ntp_time_.fractions();
										
										  // Rtp time from incoming SenderReport.
										  if (rtcp_timestamp)
										    *rtcp_timestamp = remote_sender_rtp_time_;
										
										  // Local NTP time when we received a RTCP packet with a send block.
										  if (rtcp_arrival_time_secs)
										    *rtcp_arrival_time_secs = last_received_sr_ntp_.seconds();
										  if (rtcp_arrival_time_frac)
										    *rtcp_arrival_time_frac = last_received_sr_ntp_.fractions();
										
										  return true;
										}



// 在 RemoteNtpTimeEstimator::UpdateRtcpTimestamp 函数中进行数据更新,更新数据的具体过程是:
// 首先计算接收端在接收到SR包时的本地时间(单位为ms):receiver_arrival_time_ms;
// 然后将SR包中的NTP时间戳转化成时间单位也为ms的数据: sender_send_time_ms;
// 根据之前所计算的发送端和接收端之间的RTT,可以估计出该SR包到达对端的NTP时间(也就是绝对时间):sender_arrival_time_ms = sender_send_time_ms + rtt / 2;
// 不过这里SR到达对端的NTP时间是以发送SR包的NTP时间为基准来进行估计的,并不是以接收SR包的所在机器的NTP为基准的(两台机器的NTP时间在没有校时的情况下大概率是不同的)进行估计的。
// 将(receiver_arrival_time_ms - sender_arrival_time_ms)的差保存到中值滤波器中,那后面怎么使用这个中值滤波器中的值呢?
// 通过下面的代码进行分析:
// 其中 sender_capture_ntp_ms 就是发送SR的端中的 RTP 时间戳根据线性回归所计算出来的发送端的 NTP时间戳(单位为ms);
// 从中值滤波器中获取 remote_to_local_clocks_offset ,(sender_capture_ntp_ms + remote_to_local_clocks_offset) 可以估计出SR包到达接收端的本地时间 receiver_capture_ms ,
// 在知道接收端的本地时间后,如何得到该本地时间对应的NTP时间?那就是计算出本地NTP时间与本地时间的差值(这个差值是固定的),然后用该差值加上本地时间即可,也就是:
// receiver_capture_ntp_ms = receiver_capture_ms + (clock_->CurrentNtpInMilliseconds() - clock_->TimeInMilliseconds())
// 但是值得注意的是:中值滤波器的输入值是考虑了RTT的。


// rtt 是在发送端计算出来的RTT
// ntp_secs 就是最近一次接收到的SR包中的NTP时间中的单位为秒的部分
// ntp_frac 就是最近一次接收到的SR包中的NTP时间中的单位为1/2^32秒的部分
// rtp_timestamp 表示最近一次接收到的SR包中的 RTP 时间戳
bool RemoteNtpTimeEstimator::UpdateRtcpTimestamp(int64_t rtt,
                                                 uint32_t ntp_secs,
                                                 uint32_t ntp_frac,
                                                 uint32_t rtcp_timestamp) {
  bool new_rtcp_sr = false;
  if (!rtp_to_ntp_.UpdateMeasurements(ntp_secs, ntp_frac, rtcp_timestamp, // RtpToNtpEstimator::UpdateMeasurements
                                      &new_rtcp_sr)) {
    return false;
  }
  if (!new_rtcp_sr) {
    // No new RTCP SR since last time this function was called.
    return true;
  }

  // Update extrapolator with the new arrival time.
  // The extrapolator assumes the TimeInMilliseconds time.
  int64_t receiver_arrival_time_ms = clock_->TimeInMilliseconds();
  int64_t sender_send_time_ms = Clock::NtpToMs(ntp_secs, ntp_frac);
  int64_t sender_arrival_time_ms = sender_send_time_ms + rtt / 2;
  int64_t remote_to_local_clocks_offset =
      receiver_arrival_time_ms - sender_arrival_time_ms;
  ntp_clocks_offset_estimator_.Insert(remote_to_local_clocks_offset);
  return true;
}



// ntp_secs 就是最近一次接收到的SR包中的NTP时间中的单位为秒的部分
// ntp_frac 就是最近一次接收到的SR包中的NTP时间中的单位为1/2^32秒的部分
// rtp_timestamp 表示最近一次接收到的SR包中的 RTP 
// 注意:发送SR包的肯定是发送者,但如果SR包中也有report block 就证明这个发送者也是接收者,
// 与这个接收者对应的发送者端就可以根据SR包中的report block计算RTT
bool RtpToNtpEstimator::UpdateMeasurements(uint32_t ntp_secs,
                                           uint32_t ntp_frac,
                                           uint32_t rtp_timestamp,
                                           bool* new_rtcp_sr) {
  *new_rtcp_sr = false;

  int64_t unwrapped_rtp_timestamp = unwrapper_.Unwrap(rtp_timestamp);
	// 构建一个度量信息,分析 unwrapper_ 的代码,可以知道 unwrapped_rtp_timestamp 就是不回绕的时间戳。
	// 举个例子,回绕的时间戳是:(2^32 - 3600) -> 0 -> 3600,不回绕的时间戳就是:(2^32 - 3600) -> 2^32 -> (2^32 + 3600)
  RtcpMeasurement new_measurement(ntp_secs, ntp_frac, unwrapped_rtp_timestamp);

  if (Contains(measurements_, new_measurement)) {
    // RTCP SR report already added.
    return true;
  }

  if (!new_measurement.ntp_time.Valid())
    return false;

  int64_t ntp_ms_new = new_measurement.ntp_time.ToMs();
  bool invalid_sample = false;
  if (!measurements_.empty()) {
    int64_t old_rtp_timestamp = measurements_.front().unwrapped_rtp_timestamp;
    int64_t old_ntp_ms = measurements_.front().ntp_time.ToMs();
    if (ntp_ms_new <= old_ntp_ms ||
        ntp_ms_new > old_ntp_ms + kMaxAllowedRtcpNtpIntervalMs) {
      invalid_sample = true;
    } else if (unwrapped_rtp_timestamp <= old_rtp_timestamp) {
      RTC_LOG(LS_WARNING)
          << "Newer RTCP SR report with older RTP timestamp, dropping";
      invalid_sample = true;
    } else if (unwrapped_rtp_timestamp - old_rtp_timestamp > (1 << 25)) {
      // Sanity check. No jumps too far into the future in rtp.
      invalid_sample = true;
    }
  }

  if (invalid_sample) {
    ++consecutive_invalid_samples_;
    if (consecutive_invalid_samples_ < kMaxInvalidSamples) {
      return false;
    }
    RTC_LOG(LS_WARNING) << "Multiple consecutively invalid RTCP SR reports, "
                           "clearing measurements.";
    measurements_.clear();
    params_ = absl::nullopt;
  }
  consecutive_invalid_samples_ = 0;

  // Insert new RTCP SR report.
  if (measurements_.size() == kNumRtcpReportsToUse)
    measurements_.pop_back();
	// 将度量信息进行保存
  measurements_.push_front(new_measurement);
  *new_rtcp_sr = true;

  // List updated, calculate new parameters.
  UpdateParameters(); // 
  return true;
}


void RtpToNtpEstimator::UpdateParameters() {
  if (measurements_.size() < 2)
    return;

  std::vector x;
  std::vector y;
  x.reserve(measurements_.size());
  y.reserve(measurements_.size());
  for (auto it = measurements_.begin(); it != measurements_.end(); ++it) {
    x.push_back(it->unwrapped_rtp_timestamp);
    y.push_back(it->ntp_time.ToMs());
  }
  double slope, offset;
	// 线性回归
  if (!LinearRegression(x, y, &slope, &offset)) {
    return;
  }
	// 保存斜率和截距
  params_.emplace(1 / slope, offset);
}

3 音频

void AudioReceiveStream::DeliverRtcp(const uint8_t* packet, size_t length) {
  // TODO(solenberg): Tests call this function on a network thread, libjingle
  // calls on the worker thread. We should move towards always using a network
  // thread. Then this check can be enabled.
  // RTC_DCHECK(!thread_checker_.IsCurrent());
  channel_receive_->ReceivedRTCPPacket(packet, length); // webrtc::voe::ChannelReceive::ReceivedRTCPPacket
}


void ChannelReceive::ReceivedRTCPPacket(const uint8_t* data, size_t length) {
  // Store playout timestamp for the received RTCP packet
  UpdatePlayoutTimestamp(true);

  // Deliver RTCP packet to RTP/RTCP module for parsing
  _rtpRtcpModule->IncomingRtcpPacket(data, length); // ModuleRtpRtcpImpl::IncomingRtcpPacket

  int64_t rtt = GetRTT(); // ChannelReceive::GetRTT
  if (rtt == 0) {
    // Waiting for valid RTT.
    return;
  }

  uint32_t ntp_secs = 0;
  uint32_t ntp_frac = 0;
  uint32_t rtp_timestamp = 0;
  if (0 != _rtpRtcpModule->RemoteNTP(&ntp_secs, &ntp_frac, NULL, NULL, // ModuleRtpRtcpImpl::RemoteNTP 与上面重复 
                                     &rtp_timestamp)) {
    // Waiting for RTCP.
    return;
  }

  {
    rtc::CritScope lock(&ts_stats_lock_);
    ntp_estimator_.UpdateRtcpTimestamp(rtt, ntp_secs, ntp_frac, rtp_timestamp); // RemoteNtpTimeEstimator::UpdateRtcpTimestamp
  }
}



void ModuleRtpRtcpImpl::IncomingRtcpPacket(const uint8_t* rtcp_packet,
                                           const size_t length) {
  rtcp_receiver_.IncomingPacket(rtcp_packet, length); // 与上面重复
}

4 相关类图

4.1 Call类图

webrtc-m79-RTCP包的路由_第1张图片

4.2 VideoRecieveStream类图

webrtc-m79-RTCP包的路由_第2张图片

4.3 AudioReceiveStream类图

webrtc-m79-RTCP包的路由_第3张图片

4.4 RTCP相关类图

webrtc-m79-RTCP包的路由_第4张图片

你可能感兴趣的:(webrtc)