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;
}
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);
}
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); // 与上面重复
}