blob: 0e5e40f5022b231a40941521a70eb87fe840d4ea [file] [log] [blame]
wu@webrtc.org822fbd82013-08-15 23:38:541/*
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 04:47:3111#include "modules/rtp_rtcp/source/receive_statistics_impl.h"
wu@webrtc.org822fbd82013-08-15 23:38:5412
Oleh Prypin19929582019-04-23 06:50:0413#include <cmath>
kwibergfd8be342016-05-15 02:44:1114#include <cstdlib>
Danil Chapovalov8ce0d2b2018-11-23 10:03:2515#include <memory>
Per Kjellanderee8cd202021-03-10 11:31:3816#include <utility>
danilchapf5f793c2017-07-27 11:44:1817#include <vector>
kwibergfd8be342016-05-15 02:44:1118
Tomas Lundqvistb50599b2022-10-17 14:44:5219#include "api/units/time_delta.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3120#include "modules/remote_bitrate_estimator/test/bwe_test_logging.h"
Danil Chapovalovb27a9f92021-05-17 12:22:0221#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h"
Niels Möller1f3206c2018-09-14 06:26:3222#include "modules/rtp_rtcp/source/rtp_packet_received.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3123#include "modules/rtp_rtcp/source/rtp_rtcp_config.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3124#include "rtc_base/logging.h"
Nico Grunbaum7eac6ca2022-01-24 21:49:5825#include "rtc_base/time_utils.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3126#include "system_wrappers/include/clock.h"
wu@webrtc.org822fbd82013-08-15 23:38:5427
28namespace webrtc {
Alessio Bazzica5cf8c2c2021-03-24 07:51:2629namespace {
Danil Chapovalov21973002023-05-31 11:21:0130constexpr TimeDelta kStatisticsTimeout = TimeDelta::Seconds(8);
31constexpr TimeDelta kStatisticsProcessInterval = TimeDelta::Seconds(1);
32
33TimeDelta UnixEpochDelta(Clock& clock) {
34 Timestamp now = clock.CurrentTime();
35 NtpTime ntp_now = clock.ConvertTimestampToNtpTime(now);
36 return TimeDelta::Millis(ntp_now.ToMs() - now.ms() -
37 rtc::kNtpJan1970Millisecs);
38}
39
Alessio Bazzica5cf8c2c2021-03-24 07:51:2640} // namespace
wu@webrtc.org822fbd82013-08-15 23:38:5441
stefan@webrtc.org286fe0b2013-08-21 20:58:2142StreamStatistician::~StreamStatistician() {}
wu@webrtc.org822fbd82013-08-15 23:38:5443
Jared Siskinc018bae2023-04-19 23:24:0344StreamStatisticianImpl::StreamStatisticianImpl(uint32_t ssrc,
45 Clock* clock,
Niels Möllerd7819652019-08-13 12:43:0246 int max_reordering_threshold)
danilchapec86be02017-08-14 12:51:0247 : ssrc_(ssrc),
48 clock_(clock),
Danil Chapovalov21973002023-05-31 11:21:0149 delta_internal_unix_epoch_(UnixEpochDelta(*clock_)),
Danil Chapovalov950e2312023-07-24 10:44:0550 incoming_bitrate_(/*max_window_size=*/kStatisticsProcessInterval),
Danil Chapovalovebb50c22018-11-22 13:04:0251 max_reordering_threshold_(max_reordering_threshold),
Niels Möller87da1092019-05-24 12:04:2852 enable_retransmit_detection_(false),
Danil Chapovalovb27a9f92021-05-17 12:22:0253 cumulative_loss_is_capped_(false),
wu@webrtc.org822fbd82013-08-15 23:38:5454 jitter_q4_(0),
Qingsi Wang2370b082018-08-21 21:24:2655 cumulative_loss_(0),
Niels Möller1a3859c2019-09-04 07:43:1556 cumulative_loss_rtcp_offset_(0),
wu@webrtc.org822fbd82013-08-15 23:38:5457 last_received_timestamp_(0),
Niels Möller1a3859c2019-09-04 07:43:1558 received_seq_first_(-1),
Danil Chapovalovb438b5a2018-12-05 14:55:4659 received_seq_max_(-1),
Niels Möller1a3859c2019-09-04 07:43:1560 last_report_cumulative_loss_(0),
Tomas Lundqvistb50599b2022-10-17 14:44:5261 last_report_seq_max_(-1),
62 last_payload_type_frequency_(0) {}
wu@webrtc.org822fbd82013-08-15 23:38:5463
Danil Chapovalov2a5ce2b2018-02-07 08:38:3164StreamStatisticianImpl::~StreamStatisticianImpl() = default;
65
Danil Chapovalovb438b5a2018-12-05 14:55:4666bool StreamStatisticianImpl::UpdateOutOfOrder(const RtpPacketReceived& packet,
67 int64_t sequence_number,
Danil Chapovalov21973002023-05-31 11:21:0168 Timestamp now) {
Artem Titov913cfa72021-07-28 21:57:3369 // Check if `packet` is second packet of a stream restart.
Danil Chapovalovb438b5a2018-12-05 14:55:4670 if (received_seq_out_of_order_) {
Niels Möller1a3859c2019-09-04 07:43:1571 // Count the previous packet as a received; it was postponed below.
72 --cumulative_loss_;
73
Danil Chapovalovb438b5a2018-12-05 14:55:4674 uint16_t expected_sequence_number = *received_seq_out_of_order_ + 1;
75 received_seq_out_of_order_ = absl::nullopt;
76 if (packet.SequenceNumber() == expected_sequence_number) {
Niels Möller1a3859c2019-09-04 07:43:1577 // Ignore sequence number gap caused by stream restart for packet loss
78 // calculation, by setting received_seq_max_ to the sequence number just
79 // before the out-of-order seqno. This gives a net zero change of
Artem Titov913cfa72021-07-28 21:57:3380 // `cumulative_loss_`, for the two packets interpreted as a stream reset.
Niels Möller1a3859c2019-09-04 07:43:1581 //
82 // Fraction loss for the next report may get a bit off, since we don't
83 // update last_report_seq_max_ and last_report_cumulative_loss_ in a
84 // consistent way.
85 last_report_seq_max_ = sequence_number - 2;
86 received_seq_max_ = sequence_number - 2;
Danil Chapovalovb438b5a2018-12-05 14:55:4687 return false;
88 }
89 }
90
91 if (std::abs(sequence_number - received_seq_max_) >
92 max_reordering_threshold_) {
93 // Sequence number gap looks too large, wait until next packet to check
94 // for a stream restart.
95 received_seq_out_of_order_ = packet.SequenceNumber();
Niels Möller1a3859c2019-09-04 07:43:1596 // Postpone counting this as a received packet until we know how to update
Artem Titov913cfa72021-07-28 21:57:3397 // `received_seq_max_`, otherwise we temporarily decrement
98 // `cumulative_loss_`. The
Niels Möller1a3859c2019-09-04 07:43:1599 // ReceiveStatisticsTest.StreamRestartDoesntCountAsLoss test expects
Artem Titov913cfa72021-07-28 21:57:33100 // `cumulative_loss_` to be unchanged by the reception of the first packet
Niels Möller1a3859c2019-09-04 07:43:15101 // after stream reset.
102 ++cumulative_loss_;
Danil Chapovalovb438b5a2018-12-05 14:55:46103 return true;
104 }
105
106 if (sequence_number > received_seq_max_)
107 return false;
108
109 // Old out of order packet, may be retransmit.
Danil Chapovalov21973002023-05-31 11:21:01110 if (enable_retransmit_detection_ && IsRetransmitOfOldPacket(packet, now))
Danil Chapovalovb438b5a2018-12-05 14:55:46111 receive_counters_.retransmitted.AddPacket(packet);
112 return true;
113}
114
Niels Möller1a3859c2019-09-04 07:43:15115void StreamStatisticianImpl::UpdateCounters(const RtpPacketReceived& packet) {
Niels Möllerdbb988b2018-11-15 07:05:16116 RTC_DCHECK_EQ(ssrc_, packet.Ssrc());
Danil Chapovalov0f1a2c52023-05-26 09:30:26117 Timestamp now = clock_->CurrentTime();
Danil Chapovalov44727b42018-11-22 10:28:45118
Danil Chapovalov950e2312023-07-24 10:44:05119 incoming_bitrate_.Update(packet.size(), now);
Niels Möllerdbb988b2018-11-15 07:05:16120 receive_counters_.transmitted.AddPacket(packet);
Niels Möller1a3859c2019-09-04 07:43:15121 --cumulative_loss_;
wu@webrtc.org822fbd82013-08-15 23:38:54122
Evan Shrubsole7b4c8ad2023-01-09 14:34:34123 // Use PeekUnwrap and later update the state to avoid updating the state for
124 // out of order packets.
125 int64_t sequence_number = seq_unwrapper_.PeekUnwrap(packet.SequenceNumber());
Niels Möller1a3859c2019-09-04 07:43:15126
Danil Chapovalovb438b5a2018-12-05 14:55:46127 if (!ReceivedRtpPacket()) {
128 received_seq_first_ = sequence_number;
129 last_report_seq_max_ = sequence_number - 1;
Niels Möller1a3859c2019-09-04 07:43:15130 received_seq_max_ = sequence_number - 1;
Danil Chapovalov0f1a2c52023-05-26 09:30:26131 receive_counters_.first_packet_time = now;
Danil Chapovalov21973002023-05-31 11:21:01132 } else if (UpdateOutOfOrder(packet, sequence_number, now)) {
Niels Möller1a3859c2019-09-04 07:43:15133 return;
wu@webrtc.org822fbd82013-08-15 23:38:54134 }
Danil Chapovalovb438b5a2018-12-05 14:55:46135 // In order packet.
Niels Möller1a3859c2019-09-04 07:43:15136 cumulative_loss_ += sequence_number - received_seq_max_;
Danil Chapovalovb438b5a2018-12-05 14:55:46137 received_seq_max_ = sequence_number;
Evan Shrubsole7b4c8ad2023-01-09 14:34:34138 // Update the internal state of `seq_unwrapper_`.
139 seq_unwrapper_.Unwrap(packet.SequenceNumber());
wu@webrtc.org822fbd82013-08-15 23:38:54140
Danil Chapovalovb438b5a2018-12-05 14:55:46141 // If new time stamp and more than one in-order packet received, calculate
142 // new jitter statistics.
143 if (packet.Timestamp() != last_received_timestamp_ &&
144 (receive_counters_.transmitted.packets -
145 receive_counters_.retransmitted.packets) > 1) {
Danil Chapovalov21973002023-05-31 11:21:01146 UpdateJitter(packet, now);
wu@webrtc.org822fbd82013-08-15 23:38:54147 }
Danil Chapovalovb438b5a2018-12-05 14:55:46148 last_received_timestamp_ = packet.Timestamp();
Danil Chapovalov21973002023-05-31 11:21:01149 last_receive_time_ = now;
sprang@webrtc.org0e932572014-01-23 10:00:39150}
151
Niels Möllerdbb988b2018-11-15 07:05:16152void StreamStatisticianImpl::UpdateJitter(const RtpPacketReceived& packet,
Danil Chapovalov21973002023-05-31 11:21:01153 Timestamp receive_time) {
154 RTC_DCHECK(last_receive_time_.has_value());
155 TimeDelta receive_diff = receive_time - *last_receive_time_;
156 RTC_DCHECK_GE(receive_diff, TimeDelta::Zero());
157 uint32_t receive_diff_rtp =
158 (receive_diff * packet.payload_type_frequency()).seconds<uint32_t>();
Danil Chapovalov856cf222018-11-26 09:20:01159 int32_t time_diff_samples =
160 receive_diff_rtp - (packet.Timestamp() - last_received_timestamp_);
sprang@webrtc.org0e932572014-01-23 10:00:39161
kwibergfd8be342016-05-15 02:44:11162 time_diff_samples = std::abs(time_diff_samples);
sprang@webrtc.org0e932572014-01-23 10:00:39163
Anton Podavalovea405632022-10-19 16:58:22164 ReviseFrequencyAndJitter(packet.payload_type_frequency());
165
sprang@webrtc.org0e932572014-01-23 10:00:39166 // lib_jingle sometimes deliver crazy jumps in TS for the same stream.
167 // If this happens, don't update jitter value. Use 5 secs video frequency
168 // as the threshold.
169 if (time_diff_samples < 450000) {
170 // Note we calculate in Q4 to avoid using float.
171 int32_t jitter_diff_q4 = (time_diff_samples << 4) - jitter_q4_;
172 jitter_q4_ += ((jitter_diff_q4 + 8) >> 4);
173 }
sprang@webrtc.org0e932572014-01-23 10:00:39174}
175
Anton Podavalovea405632022-10-19 16:58:22176void StreamStatisticianImpl::ReviseFrequencyAndJitter(
177 int payload_type_frequency) {
178 if (payload_type_frequency == last_payload_type_frequency_) {
179 return;
180 }
181
182 if (payload_type_frequency != 0) {
183 if (last_payload_type_frequency_ != 0) {
184 // Value in "jitter_q4_" variable is a number of samples.
Danil Chapovalov21973002023-05-31 11:21:01185 // I.e. jitter = timestamp (s) * frequency (Hz).
Anton Podavalovea405632022-10-19 16:58:22186 // Since the frequency has changed we have to update the number of samples
187 // accordingly. The new value should rely on a new frequency.
188
189 // If we don't do such procedure we end up with the number of samples that
Danil Chapovalov21973002023-05-31 11:21:01190 // cannot be converted into TimeDelta correctly
191 // (i.e. jitter = jitter_q4_ >> 4 / payload_type_frequency).
Anton Podavalovea405632022-10-19 16:58:22192 // In such case, the number of samples has a "mix".
193
194 // Doing so we pretend that everything prior and including the current
195 // packet were computed on packet's frequency.
196 jitter_q4_ = static_cast<int>(static_cast<uint64_t>(jitter_q4_) *
197 payload_type_frequency /
198 last_payload_type_frequency_);
199 }
200 // If last_payload_type_frequency_ is not present, the jitter_q4_
201 // variable has its initial value.
202
203 // Keep last_payload_type_frequency_ up to date and non-zero (set).
204 last_payload_type_frequency_ = payload_type_frequency;
205 }
206}
207
stefan@webrtc.org7bb8f022013-09-06 13:40:11208void StreamStatisticianImpl::SetMaxReorderingThreshold(
209 int max_reordering_threshold) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11210 max_reordering_threshold_ = max_reordering_threshold;
211}
212
Niels Möller5304a322018-08-27 11:27:05213void StreamStatisticianImpl::EnableRetransmitDetection(bool enable) {
Niels Möller5304a322018-08-27 11:27:05214 enable_retransmit_detection_ = enable;
215}
216
Niels Möllerd77cc242019-08-22 07:40:25217RtpReceiveStats StreamStatisticianImpl::GetStats() const {
Niels Möllerd77cc242019-08-22 07:40:25218 RtpReceiveStats stats;
219 stats.packets_lost = cumulative_loss_;
Niels Möllerd77cc242019-08-22 07:40:25220 // Note: internal jitter value is in Q4 and needs to be scaled by 1/16.
221 stats.jitter = jitter_q4_ >> 4;
Tomas Lundqvistb50599b2022-10-17 14:44:52222 if (last_payload_type_frequency_ > 0) {
223 // Divide value in fractional seconds by frequency to get jitter in
224 // fractional seconds.
225 stats.interarrival_jitter =
Danil Chapovalov21973002023-05-31 11:21:01226 TimeDelta::Seconds(stats.jitter) / last_payload_type_frequency_;
Tomas Lundqvistb50599b2022-10-17 14:44:52227 }
Danil Chapovalov21973002023-05-31 11:21:01228 if (last_receive_time_.has_value()) {
Danil Chapovalov54e95bc2023-06-02 12:54:45229 stats.last_packet_received =
230 *last_receive_time_ + delta_internal_unix_epoch_;
Alessio Bazzica5cf8c2c2021-03-24 07:51:26231 }
Niels Möllerd77cc242019-08-22 07:40:25232 stats.packet_counter = receive_counters_.transmitted;
233 return stats;
234}
235
Danil Chapovalovb27a9f92021-05-17 12:22:02236void StreamStatisticianImpl::MaybeAppendReportBlockAndReset(
237 std::vector<rtcp::ReportBlock>& report_blocks) {
Danil Chapovalov21973002023-05-31 11:21:01238 if (!ReceivedRtpPacket()) {
Danil Chapovalovb27a9f92021-05-17 12:22:02239 return;
Niels Möller12ebfa62019-08-06 14:04:12240 }
Danil Chapovalov21973002023-05-31 11:21:01241 Timestamp now = clock_->CurrentTime();
242 if (now - *last_receive_time_ >= kStatisticsTimeout) {
243 // Not active.
Danil Chapovalovb27a9f92021-05-17 12:22:02244 return;
Danil Chapovalovc5267d22017-09-18 11:57:19245 }
Danil Chapovalovc5267d22017-09-18 11:57:19246
Danil Chapovalovb27a9f92021-05-17 12:22:02247 report_blocks.emplace_back();
248 rtcp::ReportBlock& stats = report_blocks.back();
249 stats.SetMediaSsrc(ssrc_);
Qingsi Wang2370b082018-08-21 21:24:26250 // Calculate fraction lost.
Danil Chapovalovb438b5a2018-12-05 14:55:46251 int64_t exp_since_last = received_seq_max_ - last_report_seq_max_;
252 RTC_DCHECK_GE(exp_since_last, 0);
Qingsi Wang2370b082018-08-21 21:24:26253
Niels Möller1a3859c2019-09-04 07:43:15254 int32_t lost_since_last = cumulative_loss_ - last_report_cumulative_loss_;
255 if (exp_since_last > 0 && lost_since_last > 0) {
Qingsi Wang2370b082018-08-21 21:24:26256 // Scale 0 to 255, where 255 is 100% loss.
Danil Chapovalovb27a9f92021-05-17 12:22:02257 stats.SetFractionLost(255 * lost_since_last / exp_since_last);
Qingsi Wang2370b082018-08-21 21:24:26258 }
Qingsi Wang2370b082018-08-21 21:24:26259
Danil Chapovalovb27a9f92021-05-17 12:22:02260 int packets_lost = cumulative_loss_ + cumulative_loss_rtcp_offset_;
261 if (packets_lost < 0) {
Alfred E. Heggestadbe902372023-06-23 08:22:25262 // Clamp to zero. Work around to accommodate for senders that misbehave with
Niels Möller1a3859c2019-09-04 07:43:15263 // negative cumulative loss.
Danil Chapovalovb27a9f92021-05-17 12:22:02264 packets_lost = 0;
Niels Möller1a3859c2019-09-04 07:43:15265 cumulative_loss_rtcp_offset_ = -cumulative_loss_;
266 }
Danil Chapovalovb27a9f92021-05-17 12:22:02267 if (packets_lost > 0x7fffff) {
268 // Packets lost is a 24 bit signed field, and thus should be clamped, as
269 // described in https://datatracker.ietf.org/doc/html/rfc3550#appendix-A.3
270 if (!cumulative_loss_is_capped_) {
271 cumulative_loss_is_capped_ = true;
272 RTC_LOG(LS_WARNING) << "Cumulative loss reached maximum value for ssrc "
273 << ssrc_;
274 }
275 packets_lost = 0x7fffff;
276 }
277 stats.SetCumulativeLost(packets_lost);
278 stats.SetExtHighestSeqNum(received_seq_max_);
Qingsi Wang2370b082018-08-21 21:24:26279 // Note: internal jitter value is in Q4 and needs to be scaled by 1/16.
Danil Chapovalovb27a9f92021-05-17 12:22:02280 stats.SetJitter(jitter_q4_ >> 4);
Qingsi Wang2370b082018-08-21 21:24:26281
Qingsi Wang2370b082018-08-21 21:24:26282 // Only for report blocks in RTCP SR and RR.
Niels Möller1a3859c2019-09-04 07:43:15283 last_report_cumulative_loss_ = cumulative_loss_;
Qingsi Wang2370b082018-08-21 21:24:26284 last_report_seq_max_ = received_seq_max_;
Danil Chapovalov21973002023-05-31 11:21:01285 BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "cumulative_loss_pkts", now.ms(),
Qingsi Wang2370b082018-08-21 21:24:26286 cumulative_loss_, ssrc_);
Danil Chapovalov21973002023-05-31 11:21:01287 BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "received_seq_max_pkts", now.ms(),
Danil Chapovalovb27a9f92021-05-17 12:22:02288 (received_seq_max_ - received_seq_first_),
289 ssrc_);
wu@webrtc.org822fbd82013-08-15 23:38:54290}
291
Niels Möller9a9f18a2019-08-02 11:52:37292absl::optional<int> StreamStatisticianImpl::GetFractionLostInPercent() const {
Niels Möller1a3859c2019-09-04 07:43:15293 if (!ReceivedRtpPacket()) {
Niels Möller9a9f18a2019-08-02 11:52:37294 return absl::nullopt;
295 }
296 int64_t expected_packets = 1 + received_seq_max_ - received_seq_first_;
297 if (expected_packets <= 0) {
298 return absl::nullopt;
299 }
Niels Möller1a3859c2019-09-04 07:43:15300 if (cumulative_loss_ <= 0) {
301 return 0;
302 }
Niels Möller9a9f18a2019-08-02 11:52:37303 return 100 * static_cast<int64_t>(cumulative_loss_) / expected_packets;
304}
305
Niels Möller58b496b2019-08-12 10:16:31306StreamDataCounters StreamStatisticianImpl::GetReceiveStreamDataCounters()
307 const {
Niels Möller58b496b2019-08-12 10:16:31308 return receive_counters_;
asapersson@webrtc.orgd952c402014-11-27 07:38:56309}
310
stefan@webrtc.org286fe0b2013-08-21 20:58:21311uint32_t StreamStatisticianImpl::BitrateReceived() const {
Danil Chapovalov950e2312023-07-24 10:44:05312 return incoming_bitrate_.Rate(clock_->CurrentTime())
313 .value_or(DataRate::Zero())
314 .bps<uint32_t>();
stefan@webrtc.org286fe0b2013-08-21 20:58:21315}
316
stefan@webrtc.org7bb8f022013-09-06 13:40:11317bool StreamStatisticianImpl::IsRetransmitOfOldPacket(
Danil Chapovalov44727b42018-11-22 10:28:45318 const RtpPacketReceived& packet,
Danil Chapovalov21973002023-05-31 11:21:01319 Timestamp now) const {
320 int frequency_hz = packet.payload_type_frequency();
321 RTC_DCHECK(last_receive_time_.has_value());
Harald Alvestrand7dbf5542023-07-24 14:25:47322 RTC_CHECK_GT(frequency_hz, 0);
Danil Chapovalov21973002023-05-31 11:21:01323 TimeDelta time_diff = now - *last_receive_time_;
stefan@webrtc.org7bb8f022013-09-06 13:40:11324
325 // Diff in time stamp since last received in order.
Niels Möllerdbb988b2018-11-15 07:05:16326 uint32_t timestamp_diff = packet.Timestamp() - last_received_timestamp_;
Danil Chapovalov21973002023-05-31 11:21:01327 TimeDelta rtp_time_stamp_diff =
328 TimeDelta::Seconds(timestamp_diff) / frequency_hz;
stefan@webrtc.org7bb8f022013-09-06 13:40:11329
Niels Möllereda00872018-05-23 11:54:51330 // Jitter standard deviation in samples.
Oleh Prypin19929582019-04-23 06:50:04331 float jitter_std = std::sqrt(static_cast<float>(jitter_q4_ >> 4));
stefan@webrtc.org7bb8f022013-09-06 13:40:11332
Niels Möllereda00872018-05-23 11:54:51333 // 2 times the standard deviation => 95% confidence.
Danil Chapovalov21973002023-05-31 11:21:01334 // Min max_delay is 1ms.
335 TimeDelta max_delay = std::max(
336 TimeDelta::Seconds(2 * jitter_std / frequency_hz), TimeDelta::Millis(1));
Niels Möllereda00872018-05-23 11:54:51337
Danil Chapovalov21973002023-05-31 11:21:01338 return time_diff > rtp_time_stamp_diff + max_delay;
stefan@webrtc.org7bb8f022013-09-06 13:40:11339}
340
Niels Möllerd7819652019-08-13 12:43:02341std::unique_ptr<ReceiveStatistics> ReceiveStatistics::Create(Clock* clock) {
Per Kjellanderee8cd202021-03-10 11:31:38342 return std::make_unique<ReceiveStatisticsLocked>(
343 clock, [](uint32_t ssrc, Clock* clock, int max_reordering_threshold) {
344 return std::make_unique<StreamStatisticianLocked>(
345 ssrc, clock, max_reordering_threshold);
346 });
Niels Möllerd7819652019-08-13 12:43:02347}
348
Per Kjellanderee8cd202021-03-10 11:31:38349std::unique_ptr<ReceiveStatistics> ReceiveStatistics::CreateThreadCompatible(
350 Clock* clock) {
351 return std::make_unique<ReceiveStatisticsImpl>(
352 clock, [](uint32_t ssrc, Clock* clock, int max_reordering_threshold) {
353 return std::make_unique<StreamStatisticianImpl>(
354 ssrc, clock, max_reordering_threshold);
355 });
356}
357
358ReceiveStatisticsImpl::ReceiveStatisticsImpl(
359 Clock* clock,
360 std::function<std::unique_ptr<StreamStatisticianImplInterface>(
361 uint32_t ssrc,
362 Clock* clock,
363 int max_reordering_threshold)> stream_statistician_factory)
stefan@webrtc.org286fe0b2013-08-21 20:58:21364 : clock_(clock),
Per Kjellanderee8cd202021-03-10 11:31:38365 stream_statistician_factory_(std::move(stream_statistician_factory)),
Victor Boivieb2f8c162021-04-28 10:02:37366 last_returned_ssrc_idx_(0),
Niels Möllerd7819652019-08-13 12:43:02367 max_reordering_threshold_(kDefaultMaxReorderingThreshold) {}
stefan@webrtc.org286fe0b2013-08-21 20:58:21368
Niels Möller1f3206c2018-09-14 06:26:32369void ReceiveStatisticsImpl::OnRtpPacket(const RtpPacketReceived& packet) {
sprang@webrtc.orgc30e9e22014-09-08 08:20:18370 // StreamStatisticianImpl instance is created once and only destroyed when
371 // this whole ReceiveStatisticsImpl is destroyed. StreamStatisticianImpl has
372 // it's own locking so don't hold receive_statistics_lock_ (potential
373 // deadlock).
Niels Möller1a3859c2019-09-04 07:43:15374 GetOrCreateStatistician(packet.Ssrc())->UpdateCounters(packet);
sprang@webrtc.org0e932572014-01-23 10:00:39375}
376
Per Kjellanderee8cd202021-03-10 11:31:38377StreamStatistician* ReceiveStatisticsImpl::GetStatistician(
stefan@webrtc.org286fe0b2013-08-21 20:58:21378 uint32_t ssrc) const {
Niels Möller87da1092019-05-24 12:04:28379 const auto& it = statisticians_.find(ssrc);
stefan@webrtc.org286fe0b2013-08-21 20:58:21380 if (it == statisticians_.end())
Per Kjellanderee8cd202021-03-10 11:31:38381 return nullptr;
382 return it->second.get();
wu@webrtc.org822fbd82013-08-15 23:38:54383}
384
Per Kjellanderee8cd202021-03-10 11:31:38385StreamStatisticianImplInterface* ReceiveStatisticsImpl::GetOrCreateStatistician(
Niels Möller87da1092019-05-24 12:04:28386 uint32_t ssrc) {
Per Kjellanderee8cd202021-03-10 11:31:38387 std::unique_ptr<StreamStatisticianImplInterface>& impl = statisticians_[ssrc];
Niels Möller87da1092019-05-24 12:04:28388 if (impl == nullptr) { // new element
Per Kjellanderee8cd202021-03-10 11:31:38389 impl =
390 stream_statistician_factory_(ssrc, clock_, max_reordering_threshold_);
Victor Boivieb2f8c162021-04-28 10:02:37391 all_ssrcs_.push_back(ssrc);
Niels Möller87da1092019-05-24 12:04:28392 }
Per Kjellanderee8cd202021-03-10 11:31:38393 return impl.get();
Niels Möller87da1092019-05-24 12:04:28394}
395
stefan@webrtc.org7bb8f022013-09-06 13:40:11396void ReceiveStatisticsImpl::SetMaxReorderingThreshold(
397 int max_reordering_threshold) {
Per Kjellanderee8cd202021-03-10 11:31:38398 max_reordering_threshold_ = max_reordering_threshold;
399 for (auto& statistician : statisticians_) {
Danil Chapovalovc5267d22017-09-18 11:57:19400 statistician.second->SetMaxReorderingThreshold(max_reordering_threshold);
stefan@webrtc.org7bb8f022013-09-06 13:40:11401 }
402}
403
Niels Möller87da1092019-05-24 12:04:28404void ReceiveStatisticsImpl::SetMaxReorderingThreshold(
405 uint32_t ssrc,
406 int max_reordering_threshold) {
407 GetOrCreateStatistician(ssrc)->SetMaxReorderingThreshold(
408 max_reordering_threshold);
409}
410
Niels Möller5304a322018-08-27 11:27:05411void ReceiveStatisticsImpl::EnableRetransmitDetection(uint32_t ssrc,
412 bool enable) {
Niels Möller87da1092019-05-24 12:04:28413 GetOrCreateStatistician(ssrc)->EnableRetransmitDetection(enable);
Niels Möller5304a322018-08-27 11:27:05414}
415
danilchap0bc84232017-08-11 15:12:54416std::vector<rtcp::ReportBlock> ReceiveStatisticsImpl::RtcpReportBlocks(
danilchapf5f793c2017-07-27 11:44:18417 size_t max_blocks) {
danilchapf5f793c2017-07-27 11:44:18418 std::vector<rtcp::ReportBlock> result;
Victor Boivieb2f8c162021-04-28 10:02:37419 result.reserve(std::min(max_blocks, all_ssrcs_.size()));
420
421 size_t ssrc_idx = 0;
422 for (size_t i = 0; i < all_ssrcs_.size() && result.size() < max_blocks; ++i) {
423 ssrc_idx = (last_returned_ssrc_idx_ + i + 1) % all_ssrcs_.size();
424 const uint32_t media_ssrc = all_ssrcs_[ssrc_idx];
425 auto statistician_it = statisticians_.find(media_ssrc);
426 RTC_DCHECK(statistician_it != statisticians_.end());
Danil Chapovalovb27a9f92021-05-17 12:22:02427 statistician_it->second->MaybeAppendReportBlockAndReset(result);
Victor Boivieb2f8c162021-04-28 10:02:37428 }
429 last_returned_ssrc_idx_ = ssrc_idx;
danilchapf5f793c2017-07-27 11:44:18430 return result;
431}
432
wu@webrtc.org822fbd82013-08-15 23:38:54433} // namespace webrtc