- 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_);
- }
- }
计算抖动:
本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓
- 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;
- }
丢包率 = 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;
- }
本文福利, 免费领取C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)↓↓↓↓↓↓见下面↓↓文章底部点击免费领取↓↓