1、累计收包、重传包等信息,并计算抖动:
void StreamStatisticianImpl::UpdateCounters(const RTPHeader& header,
size_t packet_length,
bool retransmitted)
{
rtc::CritScope cs(&stream_lock_);
/*
判断包是否有序
判断标准:当前收包seq位于区间:[received_seq_max_ - max_reordering_threshold, received_seq_max_] 之外
max_reordering_threshold,默认为50
*/
bool in_order = InOrderPacketInternal(header.sequenceNumber);
ssrc_ = header.ssrc;
// 累计所收到的包数、字节数
incoming_bitrate_.Update(packet_length);
// 累计所收到的包数、header/padding/payload字节数(packet_length是包总长度)
receive_counters_.transmitted.AddPacket(packet_length, header);
// 累计所收到的无序重传包数、字节数
if (!in_order && retransmitted)
{
receive_counters_.retransmitted.AddPacket(packet_length, header);
}
// 记录所收到的第一个包的seq、当前时间
if (receive_counters_.transmitted.packets == 1)
{
received_seq_first_ = header.sequenceNumber;
receive_counters_.first_packet_time_ms = clock_->TimeInMilliseconds();
}
// 收到有序包
// Count only the new packets received. That is, if packets 1, 2, 3, 5, 4, 6
// are received, 4 will be ignored.
if (in_order)
{
// Current time in samples.
NtpTime receive_time(*clock_);
// Wrong if we use RetransmitOfOldPacket.
// 回绕
if (receive_counters_.transmitted.packets > 1 && received_seq_max_ > header.sequenceNumber)
{
// Wrap around detected.
received_seq_wraps_++;
}
// 记录最新 seq
received_seq_max_ = header.sequenceNumber;
// 计算最新抖动
if (header.timestamp != last_received_timestamp_ &&
(receive_counters_.transmitted.packets - receive_counters_.retransmitted.packets) > 1)
{
UpdateJitter(header, receive_time);
}
// 记录最近 所收到的最新包头携带的时间戳、收到最新包时的本地NTP时间与当前时间
last_received_timestamp_ = header.timestamp;
last_receive_time_ntp_ = receive_time;
last_receive_time_ms_ = clock_->TimeInMilliseconds();
}
size_t packet_oh = header.headerLength + header.paddingLength;
// Our measured overhead. Filter from RFC 5104 4.2.1.2:
// avg_OH (new) = 15/16*avg_OH (old) + 1/16*pckt_OH,
received_packet_overhead_ = (15 * received_packet_overhead_ + packet_oh) >> 4;
}
判断包是否有序:
bool StreamStatisticianImpl::InOrderPacketInternal(uint16_t sequence_number) const
{
// First packet is always in order.
if (last_receive_time_ms_ == 0)
return true;
if (IsNewerSequenceNumber(sequence_number, received_seq_max_))
{
return true;
}
else
{
// If we have a restart of the remote side this packet is still in order.
return !IsNewerSequenceNumber(sequence_number, received_seq_max_ - max_reordering_threshold_);
}
}
计算抖动:
void StreamStatisticianImpl::UpdateJitter(const RTPHeader& header, NtpTime receive_time)
{
// 将NTP时间戳:receive_time(本地当前NTP时间)转变成RTP时间戳
uint32_t receive_time_rtp = NtpToRtp(receive_time, header.payload_type_frequency);
// 将NTP时间戳:last_receive_time_ntp_(最近收到最新包时的本地NTP时间)转变成RTP时间戳
uint32_t last_receive_time_rtp = NtpToRtp(last_receive_time_ntp_, header.payload_type_frequency);
// 第一种计算抖动的方法:jitter_q4_
/*
计算(最近两次收到最新包时的本地NTP时间差)与(最近两次收到最新包头携带的时间戳)之差
即:计算抖动值,理想情况下,抖动值为0
*/
int32_t time_diff_samples = (receive_time_rtp - last_receive_time_rtp) -
(header.timestamp - last_received_timestamp_);
time_diff_samples = std::abs(time_diff_samples);
// lib_jingle sometimes deliver crazy jumps in TS for the same stream.
// If this happens, don't update jitter value. Use 5 secs video frequency
// as the threshold.
// 更新 jitter_q4_
if (time_diff_samples < 450000)
{
// Note we calculate in Q4 to avoid using float.
int32_t jitter_diff_q4 = (time_diff_samples << 4) - jitter_q4_;
jitter_q4_ += ((jitter_diff_q4 + 8) >> 4);
}
// 第二种计算抖动的方法:jitter_q4_transmission_time_offset_
// transmission_time_offset:一段时间间隔,代表属于同一帧的RTP的实际发送时间距离帧的capture time的偏移量
// 即计算(最近两次收到最新包时的本地NTP时间差)与(最近两次收到最新包实际发送到网络的时间戳)之差
int32_t time_diff_samples_ext = (receive_time_rtp - last_receive_time_rtp) -
((header.timestamp + header.extension.transmissionTimeOffset) -
(last_received_timestamp_ + last_received_transmission_time_offset_));
time_diff_samples_ext = std::abs(time_diff_samples_ext);
// 计算 jitter_q4_transmission_time_offset_
if (time_diff_samples_ext < 450000)
{
int32_t jitter_diffQ4TransmissionTimeOffset = (time_diff_samples_ext << 4) - jitter_q4_transmission_time_offset_;
jitter_q4_transmission_time_offset_ += ((jitter_diffQ4TransmissionTimeOffset + 8) >> 4);
}
}
二、丢包统计
每发送一次RTP包,就会进行一次丢包统计(即丢包统计的周期:5000ms)。
1、调用流程
void ModuleRtpRtcpImpl::Process()
int32_t RTCPSender::SendRTCP(…)
int32_t RTCPSender::SendCompoundRTCP(…)
void RTCPSender::PrepareReport(…)
void RTCPSender::PrepareReport(const std::set<RTCPPacketType>& packetTypes,
const FeedbackState& feedback_state)
{
...
...
...
if (receive_statistics_)
{
StatisticianMap statisticians = receive_statistics_->GetActiveStatisticians();
RTC_DCHECK(report_blocks_.empty());
for (auto& it : statisticians)
{
AddReportBlock(feedback_state, it.first, it.second);
}
}
}
bool RTCPSender::AddReportBlock(const FeedbackState& feedback_state,
uint32_t ssrc,
StreamStatistician* statistician)
{
RtcpStatistics stats;
if (!statistician->GetStatistics(&stats, true))
return false;
...
...
...
}
bool StreamStatisticianImpl::GetStatistics(RtcpStatistics* statistics, bool reset)
{
{
rtc::CritScope cs(&stream_lock_);
/*
received_seq_first_:所收到的第一个包的seq
payload_bytes:所收到的包中payload部分字节总数
*/
if (received_seq_first_ == 0 && receive_counters_.transmitted.payload_bytes == 0)
{
// We have not received anything.
return false;
}
/* 不重新进行丢包统计 */
if (!reset)
{
/* 收到的包总数 与 重传报数 之差 */
if (last_report_inorder_packets_ == 0)
{
// No report.
return false;
}
// 直接使用上一次的report
*statistics = last_reported_statistics_;
return true;
}
// 丢包统计
*statistics = CalculateRtcpStatistics();
}
NotifyRtcpCallback();
return true;
}
2、丢包统计
丢包率 = 255 * 丢包数 / 预期收到的包总数
-
丢包数:期望收到的包总数 - 实际收到的包总数
-
期望收到的包总数 = 当前收到的最新包seq - 截止到上一次report时收到的最新包seq
-
实际收到的包总数 = 正常包总数 + 重传包总数
-
正常包总数(不包括重传包)= 截止到目前收到的包总数与重传包总数之差 - 截止到上一次report时收到的包总数与重传包总数之差
-
重传包数 = 截止到目前收到的重传包总数 - 截止到上一次report时收到的重传包总数
RtcpStatistics StreamStatisticianImpl::CalculateRtcpStatistics()
{
RtcpStatistics stats;
// 第一次进行统计
if (last_report_inorder_packets_ == 0)
{
// 设置截止到上一次report时,收到的最新包
// First time we send a report.
last_report_seq_max_ = received_seq_first_ - 1;
}
/*
计算从上一次report到当前这段时间内,预期收到的包总数
期望收到的包总数 = 当前收到的最新包seq - 截止到上一次report时收到的最新包seq
*/
uint16_t exp_since_last = (received_seq_max_ - last_report_seq_max_);
// 遇到seq回绕
if (last_report_seq_max_ > received_seq_max_)
{
exp_since_last = 0;
}
/*
计算从上一次report到当前这段时间内,所收到的包数(不包括重传包)
包数(不包括重传包)= 截止到目前收到的包总数与重传包总数之差 - 截止到上一次report时收到的包总数与重传包总数之差
*/
uint32_t rec_since_last =
(receive_counters_.transmitted.packets -
receive_counters_.retransmitted.packets) - last_report_inorder_packets_;
// With NACK we don't know the expected retransmissions during the last
// second. We know how many "old" packets we have received. We just count
// the number of old received to estimate the loss, but it still does not
// guarantee an exact number since we run this based on time triggered by
// sending of an RTP packet. This should have a minimum effect.
// With NACK we don't count old packets as received since they are
// re-transmitted. We use RTT to decide if a packet is re-ordered or
// re-transmitted.
/*
计算从上一次report到当前这段时间内,收到的重传包总数
重传包数 = 截止到目前收到的重传包总数 - 截止到上一次report时收到的重传包总数
*/
uint32_t retransmitted_packets = receive_counters_.retransmitted.packets - last_report_old_packets_;
/*
计算从上一次report到当前这段时间内,实际收到的包总数
实际收到的包总数 = 正常包总数 + 重传包总数
*/
rec_since_last += retransmitted_packets;
// 计算丢包数:期望收到的包总数 - 实际收到的包总数
int32_t missing = 0;
if (exp_since_last > rec_since_last)
{
missing = (exp_since_last - rec_since_last);
}
/*
计算丢包率
丢包率 = 255 * 丢包数 / 预期收到的包总数
255表示100%丢包
*/
uint8_t local_fraction_lost = 0;
if (exp_since_last)
{
local_fraction_lost = static_cast<uint8_t>(255 * missing / exp_since_last);
}
stats.fraction_lost = local_fraction_lost;
// 累计到目前为止的丢包总数
cumulative_loss_ += missing;
stats.cumulative_lost = cumulative_loss_;
/*
扩展最近收到的最新包seq
received_seq_wraps_:发生seq回绕的次数
*/
stats.extended_max_sequence_number = (received_seq_wraps_ << 16) + received_seq_max_;
// 抖动
// Note: internal jitter value is in Q4 and needs to be scaled by 1/16.
stats.jitter = jitter_q4_ >> 4;
// Store this report.
last_reported_statistics_ = stats;
// 截止到目前为止,收到的包总数与重传包总数之差
last_report_inorder_packets_ = receive_counters_.transmitted.packets - receive_counters_.retransmitted.packets;
// 记录本次report时的重传包总数、最新包seq
last_report_old_packets_ = receive_counters_.retransmitted.packets;
last_report_seq_max_ = received_seq_max_;
return stats;
}