blob: f5c3eafbf3fbbd0cd7d58ec06b3069921dfb590c [file] [log] [blame]
wu@webrtc.org822fbd82013-08-15 23:38:54 +00001/*
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 06:47:31 +020011#include "modules/rtp_rtcp/source/receive_statistics_impl.h"
wu@webrtc.org822fbd82013-08-15 23:38:54 +000012
Oleh Prypin19929582019-04-23 08:50:04 +020013#include <cmath>
kwibergfd8be342016-05-14 19:44:11 -070014#include <cstdlib>
Danil Chapovalov8ce0d2b2018-11-23 11:03:25 +010015#include <memory>
Per Kjellanderee8cd202021-03-10 12:31:38 +010016#include <utility>
danilchapf5f793c2017-07-27 04:44:18 -070017#include <vector>
kwibergfd8be342016-05-14 19:44:11 -070018
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "modules/remote_bitrate_estimator/test/bwe_test_logging.h"
Danil Chapovalovb27a9f92021-05-17 14:22:02 +020020#include "modules/rtp_rtcp/source/rtcp_packet/report_block.h"
Niels Möller1f3206c2018-09-14 08:26:32 +020021#include "modules/rtp_rtcp/source/rtp_packet_received.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "modules/rtp_rtcp/source/rtp_rtcp_config.h"
23#include "modules/rtp_rtcp/source/time_util.h"
24#include "rtc_base/logging.h"
25#include "system_wrappers/include/clock.h"
wu@webrtc.org822fbd82013-08-15 23:38:54 +000026
27namespace webrtc {
Alessio Bazzica5cf8c2c2021-03-24 08:51:26 +010028namespace {
29constexpr int64_t kStatisticsTimeoutMs = 8000;
30constexpr int64_t kStatisticsProcessIntervalMs = 1000;
wu@webrtc.org822fbd82013-08-15 23:38:54 +000031
Alessio Bazzica5cf8c2c2021-03-24 08:51:26 +010032// Number of seconds since 1900 January 1 00:00 GMT (see
33// https://tools.ietf.org/html/rfc868).
34constexpr int64_t kNtpJan1970Millisecs = 2'208'988'800'000;
35} // namespace
wu@webrtc.org822fbd82013-08-15 23:38:54 +000036
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +000037StreamStatistician::~StreamStatistician() {}
wu@webrtc.org822fbd82013-08-15 23:38:54 +000038
Niels Möllerd7819652019-08-13 14:43:02 +020039StreamStatisticianImpl::StreamStatisticianImpl(uint32_t ssrc,
40 Clock* clock,
41 int max_reordering_threshold)
danilchapec86be02017-08-14 05:51:02 -070042 : ssrc_(ssrc),
43 clock_(clock),
Alessio Bazzica5cf8c2c2021-03-24 08:51:26 +010044 delta_internal_unix_epoch_ms_(clock_->CurrentNtpInMilliseconds() -
45 clock_->TimeInMilliseconds() -
46 kNtpJan1970Millisecs),
sprangcd349d92016-07-13 09:11:28 -070047 incoming_bitrate_(kStatisticsProcessIntervalMs,
48 RateStatistics::kBpsScale),
Danil Chapovalovebb50c22018-11-22 14:04:02 +010049 max_reordering_threshold_(max_reordering_threshold),
Niels Möller87da1092019-05-24 14:04:28 +020050 enable_retransmit_detection_(false),
Danil Chapovalovb27a9f92021-05-17 14:22:02 +020051 cumulative_loss_is_capped_(false),
wu@webrtc.org822fbd82013-08-15 23:38:54 +000052 jitter_q4_(0),
Qingsi Wang2370b082018-08-21 14:24:26 -070053 cumulative_loss_(0),
Niels Möller1a3859c2019-09-04 09:43:15 +020054 cumulative_loss_rtcp_offset_(0),
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +000055 last_receive_time_ms_(0),
wu@webrtc.org822fbd82013-08-15 23:38:54 +000056 last_received_timestamp_(0),
Niels Möller1a3859c2019-09-04 09:43:15 +020057 received_seq_first_(-1),
Danil Chapovalovb438b5a2018-12-05 14:55:46 +000058 received_seq_max_(-1),
Niels Möller1a3859c2019-09-04 09:43:15 +020059 last_report_cumulative_loss_(0),
Niels Möllerd7819652019-08-13 14:43:02 +020060 last_report_seq_max_(-1) {}
wu@webrtc.org822fbd82013-08-15 23:38:54 +000061
Danil Chapovalov2a5ce2b2018-02-07 09:38:31 +010062StreamStatisticianImpl::~StreamStatisticianImpl() = default;
63
Danil Chapovalovb438b5a2018-12-05 14:55:46 +000064bool StreamStatisticianImpl::UpdateOutOfOrder(const RtpPacketReceived& packet,
65 int64_t sequence_number,
66 int64_t now_ms) {
Danil Chapovalovb438b5a2018-12-05 14:55:46 +000067 // Check if |packet| is second packet of a stream restart.
68 if (received_seq_out_of_order_) {
Niels Möller1a3859c2019-09-04 09:43:15 +020069 // Count the previous packet as a received; it was postponed below.
70 --cumulative_loss_;
71
Danil Chapovalovb438b5a2018-12-05 14:55:46 +000072 uint16_t expected_sequence_number = *received_seq_out_of_order_ + 1;
73 received_seq_out_of_order_ = absl::nullopt;
74 if (packet.SequenceNumber() == expected_sequence_number) {
Niels Möller1a3859c2019-09-04 09:43:15 +020075 // Ignore sequence number gap caused by stream restart for packet loss
76 // calculation, by setting received_seq_max_ to the sequence number just
77 // before the out-of-order seqno. This gives a net zero change of
78 // |cumulative_loss_|, for the two packets interpreted as a stream reset.
79 //
80 // Fraction loss for the next report may get a bit off, since we don't
81 // update last_report_seq_max_ and last_report_cumulative_loss_ in a
82 // consistent way.
83 last_report_seq_max_ = sequence_number - 2;
84 received_seq_max_ = sequence_number - 2;
Danil Chapovalovb438b5a2018-12-05 14:55:46 +000085 return false;
86 }
87 }
88
89 if (std::abs(sequence_number - received_seq_max_) >
90 max_reordering_threshold_) {
91 // Sequence number gap looks too large, wait until next packet to check
92 // for a stream restart.
93 received_seq_out_of_order_ = packet.SequenceNumber();
Niels Möller1a3859c2019-09-04 09:43:15 +020094 // Postpone counting this as a received packet until we know how to update
95 // |received_seq_max_|, otherwise we temporarily decrement
96 // |cumulative_loss_|. The
97 // ReceiveStatisticsTest.StreamRestartDoesntCountAsLoss test expects
98 // |cumulative_loss_| to be unchanged by the reception of the first packet
99 // after stream reset.
100 ++cumulative_loss_;
Danil Chapovalovb438b5a2018-12-05 14:55:46 +0000101 return true;
102 }
103
104 if (sequence_number > received_seq_max_)
105 return false;
106
107 // Old out of order packet, may be retransmit.
108 if (enable_retransmit_detection_ && IsRetransmitOfOldPacket(packet, now_ms))
109 receive_counters_.retransmitted.AddPacket(packet);
110 return true;
111}
112
Niels Möller1a3859c2019-09-04 09:43:15 +0200113void StreamStatisticianImpl::UpdateCounters(const RtpPacketReceived& packet) {
Niels Möllerdbb988b2018-11-15 08:05:16 +0100114 RTC_DCHECK_EQ(ssrc_, packet.Ssrc());
Danil Chapovalov44727b42018-11-22 11:28:45 +0100115 int64_t now_ms = clock_->TimeInMilliseconds();
116
117 incoming_bitrate_.Update(packet.size(), now_ms);
Henrik Boströmcb755b02019-04-02 15:11:48 +0200118 receive_counters_.last_packet_received_timestamp_ms = now_ms;
Niels Möllerdbb988b2018-11-15 08:05:16 +0100119 receive_counters_.transmitted.AddPacket(packet);
Niels Möller1a3859c2019-09-04 09:43:15 +0200120 --cumulative_loss_;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000121
Danil Chapovalovb438b5a2018-12-05 14:55:46 +0000122 int64_t sequence_number =
123 seq_unwrapper_.UnwrapWithoutUpdate(packet.SequenceNumber());
Niels Möller1a3859c2019-09-04 09:43:15 +0200124
Danil Chapovalovb438b5a2018-12-05 14:55:46 +0000125 if (!ReceivedRtpPacket()) {
126 received_seq_first_ = sequence_number;
127 last_report_seq_max_ = sequence_number - 1;
Niels Möller1a3859c2019-09-04 09:43:15 +0200128 received_seq_max_ = sequence_number - 1;
Danil Chapovalov44727b42018-11-22 11:28:45 +0100129 receive_counters_.first_packet_time_ms = now_ms;
Danil Chapovalovb438b5a2018-12-05 14:55:46 +0000130 } else if (UpdateOutOfOrder(packet, sequence_number, now_ms)) {
Niels Möller1a3859c2019-09-04 09:43:15 +0200131 return;
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000132 }
Danil Chapovalovb438b5a2018-12-05 14:55:46 +0000133 // In order packet.
Niels Möller1a3859c2019-09-04 09:43:15 +0200134 cumulative_loss_ += sequence_number - received_seq_max_;
Danil Chapovalovb438b5a2018-12-05 14:55:46 +0000135 received_seq_max_ = sequence_number;
136 seq_unwrapper_.UpdateLast(sequence_number);
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000137
Danil Chapovalovb438b5a2018-12-05 14:55:46 +0000138 // If new time stamp and more than one in-order packet received, calculate
139 // new jitter statistics.
140 if (packet.Timestamp() != last_received_timestamp_ &&
141 (receive_counters_.transmitted.packets -
142 receive_counters_.retransmitted.packets) > 1) {
143 UpdateJitter(packet, now_ms);
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000144 }
Danil Chapovalovb438b5a2018-12-05 14:55:46 +0000145 last_received_timestamp_ = packet.Timestamp();
146 last_receive_time_ms_ = now_ms;
sprang@webrtc.org0e932572014-01-23 10:00:39 +0000147}
148
Niels Möllerdbb988b2018-11-15 08:05:16 +0100149void StreamStatisticianImpl::UpdateJitter(const RtpPacketReceived& packet,
Danil Chapovalov856cf222018-11-26 10:20:01 +0100150 int64_t receive_time_ms) {
151 int64_t receive_diff_ms = receive_time_ms - last_receive_time_ms_;
152 RTC_DCHECK_GE(receive_diff_ms, 0);
153 uint32_t receive_diff_rtp = static_cast<uint32_t>(
154 (receive_diff_ms * packet.payload_type_frequency()) / 1000);
155 int32_t time_diff_samples =
156 receive_diff_rtp - (packet.Timestamp() - last_received_timestamp_);
sprang@webrtc.org0e932572014-01-23 10:00:39 +0000157
kwibergfd8be342016-05-14 19:44:11 -0700158 time_diff_samples = std::abs(time_diff_samples);
sprang@webrtc.org0e932572014-01-23 10:00:39 +0000159
160 // lib_jingle sometimes deliver crazy jumps in TS for the same stream.
161 // If this happens, don't update jitter value. Use 5 secs video frequency
162 // as the threshold.
163 if (time_diff_samples < 450000) {
164 // Note we calculate in Q4 to avoid using float.
165 int32_t jitter_diff_q4 = (time_diff_samples << 4) - jitter_q4_;
166 jitter_q4_ += ((jitter_diff_q4 + 8) >> 4);
167 }
sprang@webrtc.org0e932572014-01-23 10:00:39 +0000168}
169
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000170void StreamStatisticianImpl::SetMaxReorderingThreshold(
171 int max_reordering_threshold) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000172 max_reordering_threshold_ = max_reordering_threshold;
173}
174
Niels Möller5304a322018-08-27 13:27:05 +0200175void StreamStatisticianImpl::EnableRetransmitDetection(bool enable) {
Niels Möller5304a322018-08-27 13:27:05 +0200176 enable_retransmit_detection_ = enable;
177}
178
Niels Möllerd77cc242019-08-22 09:40:25 +0200179RtpReceiveStats StreamStatisticianImpl::GetStats() const {
Niels Möllerd77cc242019-08-22 09:40:25 +0200180 RtpReceiveStats stats;
181 stats.packets_lost = cumulative_loss_;
182 // TODO(nisse): Can we return a float instead?
183 // Note: internal jitter value is in Q4 and needs to be scaled by 1/16.
184 stats.jitter = jitter_q4_ >> 4;
Alessio Bazzica5cf8c2c2021-03-24 08:51:26 +0100185 if (receive_counters_.last_packet_received_timestamp_ms.has_value()) {
186 stats.last_packet_received_timestamp_ms =
187 *receive_counters_.last_packet_received_timestamp_ms +
188 delta_internal_unix_epoch_ms_;
189 }
Niels Möllerd77cc242019-08-22 09:40:25 +0200190 stats.packet_counter = receive_counters_.transmitted;
191 return stats;
192}
193
Danil Chapovalovb27a9f92021-05-17 14:22:02 +0200194void StreamStatisticianImpl::MaybeAppendReportBlockAndReset(
195 std::vector<rtcp::ReportBlock>& report_blocks) {
196 int64_t now_ms = clock_->TimeInMilliseconds();
197 if (now_ms - last_receive_time_ms_ >= kStatisticsTimeoutMs) {
Niels Möller12ebfa62019-08-06 16:04:12 +0200198 // Not active.
Danil Chapovalovb27a9f92021-05-17 14:22:02 +0200199 return;
Niels Möller12ebfa62019-08-06 16:04:12 +0200200 }
201 if (!ReceivedRtpPacket()) {
Danil Chapovalovb27a9f92021-05-17 14:22:02 +0200202 return;
Danil Chapovalovc5267d22017-09-18 13:57:19 +0200203 }
Danil Chapovalovc5267d22017-09-18 13:57:19 +0200204
Danil Chapovalovb27a9f92021-05-17 14:22:02 +0200205 report_blocks.emplace_back();
206 rtcp::ReportBlock& stats = report_blocks.back();
207 stats.SetMediaSsrc(ssrc_);
Qingsi Wang2370b082018-08-21 14:24:26 -0700208 // Calculate fraction lost.
Danil Chapovalovb438b5a2018-12-05 14:55:46 +0000209 int64_t exp_since_last = received_seq_max_ - last_report_seq_max_;
210 RTC_DCHECK_GE(exp_since_last, 0);
Qingsi Wang2370b082018-08-21 14:24:26 -0700211
Niels Möller1a3859c2019-09-04 09:43:15 +0200212 int32_t lost_since_last = cumulative_loss_ - last_report_cumulative_loss_;
213 if (exp_since_last > 0 && lost_since_last > 0) {
Qingsi Wang2370b082018-08-21 14:24:26 -0700214 // Scale 0 to 255, where 255 is 100% loss.
Danil Chapovalovb27a9f92021-05-17 14:22:02 +0200215 stats.SetFractionLost(255 * lost_since_last / exp_since_last);
Qingsi Wang2370b082018-08-21 14:24:26 -0700216 }
Qingsi Wang2370b082018-08-21 14:24:26 -0700217
Danil Chapovalovb27a9f92021-05-17 14:22:02 +0200218 int packets_lost = cumulative_loss_ + cumulative_loss_rtcp_offset_;
219 if (packets_lost < 0) {
Niels Möller1a3859c2019-09-04 09:43:15 +0200220 // Clamp to zero. Work around to accomodate for senders that misbehave with
221 // negative cumulative loss.
Danil Chapovalovb27a9f92021-05-17 14:22:02 +0200222 packets_lost = 0;
Niels Möller1a3859c2019-09-04 09:43:15 +0200223 cumulative_loss_rtcp_offset_ = -cumulative_loss_;
224 }
Danil Chapovalovb27a9f92021-05-17 14:22:02 +0200225 if (packets_lost > 0x7fffff) {
226 // Packets lost is a 24 bit signed field, and thus should be clamped, as
227 // described in https://datatracker.ietf.org/doc/html/rfc3550#appendix-A.3
228 if (!cumulative_loss_is_capped_) {
229 cumulative_loss_is_capped_ = true;
230 RTC_LOG(LS_WARNING) << "Cumulative loss reached maximum value for ssrc "
231 << ssrc_;
232 }
233 packets_lost = 0x7fffff;
234 }
235 stats.SetCumulativeLost(packets_lost);
236 stats.SetExtHighestSeqNum(received_seq_max_);
Qingsi Wang2370b082018-08-21 14:24:26 -0700237 // Note: internal jitter value is in Q4 and needs to be scaled by 1/16.
Danil Chapovalovb27a9f92021-05-17 14:22:02 +0200238 stats.SetJitter(jitter_q4_ >> 4);
Qingsi Wang2370b082018-08-21 14:24:26 -0700239
Qingsi Wang2370b082018-08-21 14:24:26 -0700240 // Only for report blocks in RTCP SR and RR.
Niels Möller1a3859c2019-09-04 09:43:15 +0200241 last_report_cumulative_loss_ = cumulative_loss_;
Qingsi Wang2370b082018-08-21 14:24:26 -0700242 last_report_seq_max_ = received_seq_max_;
Danil Chapovalovb27a9f92021-05-17 14:22:02 +0200243 BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "cumulative_loss_pkts", now_ms,
Qingsi Wang2370b082018-08-21 14:24:26 -0700244 cumulative_loss_, ssrc_);
Danil Chapovalovb27a9f92021-05-17 14:22:02 +0200245 BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "received_seq_max_pkts", now_ms,
246 (received_seq_max_ - received_seq_first_),
247 ssrc_);
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000248}
249
Niels Möller9a9f18a2019-08-02 13:52:37 +0200250absl::optional<int> StreamStatisticianImpl::GetFractionLostInPercent() const {
Niels Möller1a3859c2019-09-04 09:43:15 +0200251 if (!ReceivedRtpPacket()) {
Niels Möller9a9f18a2019-08-02 13:52:37 +0200252 return absl::nullopt;
253 }
254 int64_t expected_packets = 1 + received_seq_max_ - received_seq_first_;
255 if (expected_packets <= 0) {
256 return absl::nullopt;
257 }
Niels Möller1a3859c2019-09-04 09:43:15 +0200258 if (cumulative_loss_ <= 0) {
259 return 0;
260 }
Niels Möller9a9f18a2019-08-02 13:52:37 +0200261 return 100 * static_cast<int64_t>(cumulative_loss_) / expected_packets;
262}
263
Niels Möller58b496b2019-08-12 12:16:31 +0200264StreamDataCounters StreamStatisticianImpl::GetReceiveStreamDataCounters()
265 const {
Niels Möller58b496b2019-08-12 12:16:31 +0200266 return receive_counters_;
asapersson@webrtc.orgd952c402014-11-27 07:38:56 +0000267}
268
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000269uint32_t StreamStatisticianImpl::BitrateReceived() const {
sprangcd349d92016-07-13 09:11:28 -0700270 return incoming_bitrate_.Rate(clock_->TimeInMilliseconds()).value_or(0);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000271}
272
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000273bool StreamStatisticianImpl::IsRetransmitOfOldPacket(
Danil Chapovalov44727b42018-11-22 11:28:45 +0100274 const RtpPacketReceived& packet,
275 int64_t now_ms) const {
Niels Möllerdbb988b2018-11-15 08:05:16 +0100276 uint32_t frequency_khz = packet.payload_type_frequency() / 1000;
Danil Chapovalov44727b42018-11-22 11:28:45 +0100277 RTC_DCHECK_GT(frequency_khz, 0);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000278
Danil Chapovalov44727b42018-11-22 11:28:45 +0100279 int64_t time_diff_ms = now_ms - last_receive_time_ms_;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000280
281 // Diff in time stamp since last received in order.
Niels Möllerdbb988b2018-11-15 08:05:16 +0100282 uint32_t timestamp_diff = packet.Timestamp() - last_received_timestamp_;
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000283 uint32_t rtp_time_stamp_diff_ms = timestamp_diff / frequency_khz;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000284
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000285 int64_t max_delay_ms = 0;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000286
Niels Möllereda00872018-05-23 13:54:51 +0200287 // Jitter standard deviation in samples.
Oleh Prypin19929582019-04-23 08:50:04 +0200288 float jitter_std = std::sqrt(static_cast<float>(jitter_q4_ >> 4));
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000289
Niels Möllereda00872018-05-23 13:54:51 +0200290 // 2 times the standard deviation => 95% confidence.
291 // And transform to milliseconds by dividing by the frequency in kHz.
292 max_delay_ms = static_cast<int64_t>((2 * jitter_std) / frequency_khz);
293
294 // Min max_delay_ms is 1.
295 if (max_delay_ms == 0) {
296 max_delay_ms = 1;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000297 }
298 return time_diff_ms > rtp_time_stamp_diff_ms + max_delay_ms;
299}
300
Niels Möllerd7819652019-08-13 14:43:02 +0200301std::unique_ptr<ReceiveStatistics> ReceiveStatistics::Create(Clock* clock) {
Per Kjellanderee8cd202021-03-10 12:31:38 +0100302 return std::make_unique<ReceiveStatisticsLocked>(
303 clock, [](uint32_t ssrc, Clock* clock, int max_reordering_threshold) {
304 return std::make_unique<StreamStatisticianLocked>(
305 ssrc, clock, max_reordering_threshold);
306 });
Niels Möllerd7819652019-08-13 14:43:02 +0200307}
308
Per Kjellanderee8cd202021-03-10 12:31:38 +0100309std::unique_ptr<ReceiveStatistics> ReceiveStatistics::CreateThreadCompatible(
310 Clock* clock) {
311 return std::make_unique<ReceiveStatisticsImpl>(
312 clock, [](uint32_t ssrc, Clock* clock, int max_reordering_threshold) {
313 return std::make_unique<StreamStatisticianImpl>(
314 ssrc, clock, max_reordering_threshold);
315 });
316}
317
318ReceiveStatisticsImpl::ReceiveStatisticsImpl(
319 Clock* clock,
320 std::function<std::unique_ptr<StreamStatisticianImplInterface>(
321 uint32_t ssrc,
322 Clock* clock,
323 int max_reordering_threshold)> stream_statistician_factory)
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000324 : clock_(clock),
Per Kjellanderee8cd202021-03-10 12:31:38 +0100325 stream_statistician_factory_(std::move(stream_statistician_factory)),
Victor Boivieb2f8c162021-04-28 12:02:37 +0200326 last_returned_ssrc_idx_(0),
Niels Möllerd7819652019-08-13 14:43:02 +0200327 max_reordering_threshold_(kDefaultMaxReorderingThreshold) {}
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000328
Niels Möller1f3206c2018-09-14 08:26:32 +0200329void ReceiveStatisticsImpl::OnRtpPacket(const RtpPacketReceived& packet) {
sprang@webrtc.orgc30e9e22014-09-08 08:20:18 +0000330 // StreamStatisticianImpl instance is created once and only destroyed when
331 // this whole ReceiveStatisticsImpl is destroyed. StreamStatisticianImpl has
332 // it's own locking so don't hold receive_statistics_lock_ (potential
333 // deadlock).
Niels Möller1a3859c2019-09-04 09:43:15 +0200334 GetOrCreateStatistician(packet.Ssrc())->UpdateCounters(packet);
sprang@webrtc.org0e932572014-01-23 10:00:39 +0000335}
336
Per Kjellanderee8cd202021-03-10 12:31:38 +0100337StreamStatistician* ReceiveStatisticsImpl::GetStatistician(
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000338 uint32_t ssrc) const {
Niels Möller87da1092019-05-24 14:04:28 +0200339 const auto& it = statisticians_.find(ssrc);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000340 if (it == statisticians_.end())
Per Kjellanderee8cd202021-03-10 12:31:38 +0100341 return nullptr;
342 return it->second.get();
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000343}
344
Per Kjellanderee8cd202021-03-10 12:31:38 +0100345StreamStatisticianImplInterface* ReceiveStatisticsImpl::GetOrCreateStatistician(
Niels Möller87da1092019-05-24 14:04:28 +0200346 uint32_t ssrc) {
Per Kjellanderee8cd202021-03-10 12:31:38 +0100347 std::unique_ptr<StreamStatisticianImplInterface>& impl = statisticians_[ssrc];
Niels Möller87da1092019-05-24 14:04:28 +0200348 if (impl == nullptr) { // new element
Per Kjellanderee8cd202021-03-10 12:31:38 +0100349 impl =
350 stream_statistician_factory_(ssrc, clock_, max_reordering_threshold_);
Victor Boivieb2f8c162021-04-28 12:02:37 +0200351 all_ssrcs_.push_back(ssrc);
Niels Möller87da1092019-05-24 14:04:28 +0200352 }
Per Kjellanderee8cd202021-03-10 12:31:38 +0100353 return impl.get();
Niels Möller87da1092019-05-24 14:04:28 +0200354}
355
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000356void ReceiveStatisticsImpl::SetMaxReorderingThreshold(
357 int max_reordering_threshold) {
Per Kjellanderee8cd202021-03-10 12:31:38 +0100358 max_reordering_threshold_ = max_reordering_threshold;
359 for (auto& statistician : statisticians_) {
Danil Chapovalovc5267d22017-09-18 13:57:19 +0200360 statistician.second->SetMaxReorderingThreshold(max_reordering_threshold);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000361 }
362}
363
Niels Möller87da1092019-05-24 14:04:28 +0200364void ReceiveStatisticsImpl::SetMaxReorderingThreshold(
365 uint32_t ssrc,
366 int max_reordering_threshold) {
367 GetOrCreateStatistician(ssrc)->SetMaxReorderingThreshold(
368 max_reordering_threshold);
369}
370
Niels Möller5304a322018-08-27 13:27:05 +0200371void ReceiveStatisticsImpl::EnableRetransmitDetection(uint32_t ssrc,
372 bool enable) {
Niels Möller87da1092019-05-24 14:04:28 +0200373 GetOrCreateStatistician(ssrc)->EnableRetransmitDetection(enable);
Niels Möller5304a322018-08-27 13:27:05 +0200374}
375
danilchap0bc84232017-08-11 08:12:54 -0700376std::vector<rtcp::ReportBlock> ReceiveStatisticsImpl::RtcpReportBlocks(
danilchapf5f793c2017-07-27 04:44:18 -0700377 size_t max_blocks) {
danilchapf5f793c2017-07-27 04:44:18 -0700378 std::vector<rtcp::ReportBlock> result;
Victor Boivieb2f8c162021-04-28 12:02:37 +0200379 result.reserve(std::min(max_blocks, all_ssrcs_.size()));
380
381 size_t ssrc_idx = 0;
382 for (size_t i = 0; i < all_ssrcs_.size() && result.size() < max_blocks; ++i) {
383 ssrc_idx = (last_returned_ssrc_idx_ + i + 1) % all_ssrcs_.size();
384 const uint32_t media_ssrc = all_ssrcs_[ssrc_idx];
385 auto statistician_it = statisticians_.find(media_ssrc);
386 RTC_DCHECK(statistician_it != statisticians_.end());
Danil Chapovalovb27a9f92021-05-17 14:22:02 +0200387 statistician_it->second->MaybeAppendReportBlockAndReset(result);
Victor Boivieb2f8c162021-04-28 12:02:37 +0200388 }
389 last_returned_ssrc_idx_ = ssrc_idx;
danilchapf5f793c2017-07-27 04:44:18 -0700390 return result;
391}
392
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000393} // namespace webrtc