blob: 1ae4221a64eab18684abee2b66cc1a335f0168a5 [file] [log] [blame]
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:211/*
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/audio_coding/neteq/statistics_calculator.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:2112
pbos@webrtc.org12dc1a32013-08-05 16:22:5313#include <string.h> // memset
Jonas Olssona4d87372019-07-05 17:08:3314
Henrik Lundin1bb8cf82015-08-25 11:08:0415#include <algorithm>
Philipp Hanckec4fe8252025-05-06 22:39:5416#include <cstdint>
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:2117
Ali Tofigh714e3cb2022-07-20 10:53:0718#include "absl/strings/string_view.h"
Philipp Hanckec4fe8252025-05-06 22:39:5419#include "api/neteq/neteq.h"
20#include "api/neteq/tick_timer.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3121#include "rtc_base/checks.h"
Karl Wiberge40468b2017-11-22 09:42:2622#include "rtc_base/numerics/safe_conversions.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3123#include "system_wrappers/include/metrics.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:2124
25namespace webrtc {
26
henrik.lundin2979f552017-05-05 12:04:1627namespace {
28size_t AddIntToSizeTWithLowerCap(int a, size_t b) {
29 const size_t ret = b + a;
30 // If a + b is negative, resulting in a negative wrap, cap it to zero instead.
31 static_assert(sizeof(size_t) >= sizeof(int),
32 "int must not be wider than size_t for this to work");
33 return (a < 0 && ret > b) ? 0 : ret;
34}
Henrik Lundin2a8bd092019-04-26 07:47:0735
36constexpr int kInterruptionLenMs = 150;
henrik.lundin2979f552017-05-05 12:04:1637} // namespace
38
henrikg91d6ede2015-09-17 07:24:3439// Allocating the static const so that it can be passed by reference to
40// RTC_DCHECK.
Henrik Lundin1bb8cf82015-08-25 11:08:0441const size_t StatisticsCalculator::kLenWaitingTimes;
42
Henrik Lundin1f4ffe02015-08-19 08:46:5043StatisticsCalculator::PeriodicUmaLogger::PeriodicUmaLogger(
Ali Tofigh714e3cb2022-07-20 10:53:0744 absl::string_view uma_name,
Henrik Lundin1f4ffe02015-08-19 08:46:5045 int report_interval_ms,
46 int max_value)
47 : uma_name_(uma_name),
48 report_interval_ms_(report_interval_ms),
49 max_value_(max_value),
Yves Gerey665174f2018-06-19 13:03:0550 timer_(0) {}
Henrik Lundin1f4ffe02015-08-19 08:46:5051
52StatisticsCalculator::PeriodicUmaLogger::~PeriodicUmaLogger() = default;
53
54void StatisticsCalculator::PeriodicUmaLogger::AdvanceClock(int step_ms) {
55 timer_ += step_ms;
56 if (timer_ < report_interval_ms_) {
57 return;
58 }
59 LogToUma(Metric());
60 Reset();
61 timer_ -= report_interval_ms_;
henrikg91d6ede2015-09-17 07:24:3462 RTC_DCHECK_GE(timer_, 0);
Henrik Lundin1f4ffe02015-08-19 08:46:5063}
64
65void StatisticsCalculator::PeriodicUmaLogger::LogToUma(int value) const {
asapersson53805322015-12-21 09:46:2066 RTC_HISTOGRAM_COUNTS_SPARSE(uma_name_, value, 1, max_value_, 50);
Henrik Lundin1f4ffe02015-08-19 08:46:5067}
68
69StatisticsCalculator::PeriodicUmaCount::PeriodicUmaCount(
Ali Tofigh714e3cb2022-07-20 10:53:0770 absl::string_view uma_name,
Henrik Lundin1f4ffe02015-08-19 08:46:5071 int report_interval_ms,
72 int max_value)
Yves Gerey665174f2018-06-19 13:03:0573 : PeriodicUmaLogger(uma_name, report_interval_ms, max_value) {}
Henrik Lundin1f4ffe02015-08-19 08:46:5074
75StatisticsCalculator::PeriodicUmaCount::~PeriodicUmaCount() {
76 // Log the count for the current (incomplete) interval.
77 LogToUma(Metric());
78}
79
80void StatisticsCalculator::PeriodicUmaCount::RegisterSample() {
81 ++counter_;
82}
83
84int StatisticsCalculator::PeriodicUmaCount::Metric() const {
85 return counter_;
86}
87
88void StatisticsCalculator::PeriodicUmaCount::Reset() {
89 counter_ = 0;
90}
91
92StatisticsCalculator::PeriodicUmaAverage::PeriodicUmaAverage(
Ali Tofigh714e3cb2022-07-20 10:53:0793 absl::string_view uma_name,
Henrik Lundin1f4ffe02015-08-19 08:46:5094 int report_interval_ms,
95 int max_value)
Yves Gerey665174f2018-06-19 13:03:0596 : PeriodicUmaLogger(uma_name, report_interval_ms, max_value) {}
Henrik Lundin1f4ffe02015-08-19 08:46:5097
98StatisticsCalculator::PeriodicUmaAverage::~PeriodicUmaAverage() {
99 // Log the average for the current (incomplete) interval.
100 LogToUma(Metric());
101}
102
103void StatisticsCalculator::PeriodicUmaAverage::RegisterSample(int value) {
104 sum_ += value;
105 ++counter_;
106}
107
108int StatisticsCalculator::PeriodicUmaAverage::Metric() const {
henrik.lundine5942132016-02-09 08:35:53109 return counter_ == 0 ? 0 : static_cast<int>(sum_ / counter_);
Henrik Lundin1f4ffe02015-08-19 08:46:50110}
111
112void StatisticsCalculator::PeriodicUmaAverage::Reset() {
113 sum_ = 0.0;
114 counter_ = 0;
115}
116
Jakob Ivarssona6e55562024-09-30 11:21:43117StatisticsCalculator::StatisticsCalculator(TickTimer* tick_timer)
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21118 : preemptive_samples_(0),
119 accelerate_samples_(0),
minyue@webrtc.org7d721ee2015-02-18 10:01:53120 expanded_speech_samples_(0),
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21121 expanded_noise_samples_(0),
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53122 timestamps_since_last_report_(0),
Henrik Lundin1f4ffe02015-08-19 08:46:50123 secondary_decoded_samples_(0),
minyue-webrtc0c3ca752017-08-23 13:59:38124 discarded_secondary_packets_(0),
Henrik Lundin1f4ffe02015-08-19 08:46:50125 delayed_packet_outage_counter_(
126 "WebRTC.Audio.DelayedPacketOutageEventsPerMinute",
127 60000, // 60 seconds report interval.
128 100),
129 excess_buffer_delay_("WebRTC.Audio.AverageExcessBufferDelayMs",
130 60000, // 60 seconds report interval.
Minyue Li34d990f2018-10-16 14:55:52131 1000),
132 buffer_full_counter_("WebRTC.Audio.JitterBufferFullPerMinute",
133 60000, // 60 seconds report interval.
Jakob Ivarssona6e55562024-09-30 11:21:43134 100),
135 expand_uma_logger_("WebRTC.Audio.ExpandRatePercent",
136 10, // Report once every 10 s.
137 tick_timer),
138 speech_expand_uma_logger_("WebRTC.Audio.SpeechExpandRatePercent",
139 10, // Report once every 10 s.
140 tick_timer) {}
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21141
Henrik Lundin1bb8cf82015-08-25 11:08:04142StatisticsCalculator::~StatisticsCalculator() = default;
143
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21144void StatisticsCalculator::Reset() {
145 preemptive_samples_ = 0;
146 accelerate_samples_ = 0;
minyue@webrtc.org7d721ee2015-02-18 10:01:53147 expanded_speech_samples_ = 0;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21148 expanded_noise_samples_ = 0;
minyue@webrtc.org2c1bcf22015-02-17 10:17:09149 secondary_decoded_samples_ = 0;
minyue-webrtc0c3ca752017-08-23 13:59:38150 discarded_secondary_packets_ = 0;
Henrik Lundin1bb8cf82015-08-25 11:08:04151 waiting_times_.clear();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21152}
153
154void StatisticsCalculator::ResetMcu() {
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53155 timestamps_since_last_report_ = 0;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21156}
157
Gustaf Ullberg9a2e9062017-09-18 07:28:20158void StatisticsCalculator::ExpandedVoiceSamples(size_t num_samples,
159 bool is_new_concealment_event) {
Jakob Ivarsson09c043a2024-10-02 09:25:29160 if (!decoded_output_played_) {
161 return;
162 }
minyue@webrtc.org7d721ee2015-02-18 10:01:53163 expanded_speech_samples_ += num_samples;
Evan Shrubsoleef95b202025-02-24 14:55:04164 ConcealedSamplesCorrection(dchecked_cast<int>(num_samples), true);
Gustaf Ullberg9a2e9062017-09-18 07:28:20165 lifetime_stats_.concealment_events += is_new_concealment_event;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21166}
167
Gustaf Ullberg9a2e9062017-09-18 07:28:20168void StatisticsCalculator::ExpandedNoiseSamples(size_t num_samples,
169 bool is_new_concealment_event) {
Jakob Ivarsson09c043a2024-10-02 09:25:29170 if (!decoded_output_played_) {
171 return;
172 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21173 expanded_noise_samples_ += num_samples;
Evan Shrubsoleef95b202025-02-24 14:55:04174 ConcealedSamplesCorrection(dchecked_cast<int>(num_samples), false);
Gustaf Ullberg9a2e9062017-09-18 07:28:20175 lifetime_stats_.concealment_events += is_new_concealment_event;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21176}
177
henrik.lundin2979f552017-05-05 12:04:16178void StatisticsCalculator::ExpandedVoiceSamplesCorrection(int num_samples) {
Jakob Ivarsson09c043a2024-10-02 09:25:29179 if (!decoded_output_played_) {
180 return;
181 }
henrik.lundin2979f552017-05-05 12:04:16182 expanded_speech_samples_ =
183 AddIntToSizeTWithLowerCap(num_samples, expanded_speech_samples_);
Alex Narest7ff6ca52018-02-07 17:46:33184 ConcealedSamplesCorrection(num_samples, true);
henrik.lundin2979f552017-05-05 12:04:16185}
186
187void StatisticsCalculator::ExpandedNoiseSamplesCorrection(int num_samples) {
Jakob Ivarsson09c043a2024-10-02 09:25:29188 if (!decoded_output_played_) {
189 return;
190 }
henrik.lundin2979f552017-05-05 12:04:16191 expanded_noise_samples_ =
192 AddIntToSizeTWithLowerCap(num_samples, expanded_noise_samples_);
Alex Narest7ff6ca52018-02-07 17:46:33193 ConcealedSamplesCorrection(num_samples, false);
Henrik Lundinac0a5032017-09-25 10:22:46194}
195
Henrik Lundin2a8bd092019-04-26 07:47:07196void StatisticsCalculator::DecodedOutputPlayed() {
197 decoded_output_played_ = true;
198}
199
200void StatisticsCalculator::EndExpandEvent(int fs_hz) {
Jakob Ivarsson09c043a2024-10-02 09:25:29201 if (!decoded_output_played_) {
202 return;
203 }
Henrik Lundin2a8bd092019-04-26 07:47:07204 RTC_DCHECK_GE(lifetime_stats_.concealed_samples,
205 concealed_samples_at_event_end_);
206 const int event_duration_ms =
207 1000 *
208 (lifetime_stats_.concealed_samples - concealed_samples_at_event_end_) /
209 fs_hz;
210 if (event_duration_ms >= kInterruptionLenMs && decoded_output_played_) {
211 lifetime_stats_.interruption_count++;
212 lifetime_stats_.total_interruption_duration_ms += event_duration_ms;
Henrik Lundine835fc02019-11-21 08:34:29213 RTC_HISTOGRAM_COUNTS("WebRTC.Audio.AudioInterruptionMs", event_duration_ms,
214 /*min=*/150, /*max=*/5000, /*bucket_count=*/50);
Henrik Lundin2a8bd092019-04-26 07:47:07215 }
216 concealed_samples_at_event_end_ = lifetime_stats_.concealed_samples;
217}
218
Alex Narest7ff6ca52018-02-07 17:46:33219void StatisticsCalculator::ConcealedSamplesCorrection(int num_samples,
220 bool is_voice) {
Jakob Ivarsson09c043a2024-10-02 09:25:29221 if (!decoded_output_played_) {
222 return;
223 }
Henrik Lundinac0a5032017-09-25 10:22:46224 if (num_samples < 0) {
225 // Store negative correction to subtract from future positive additions.
226 // See also the function comment in the header file.
227 concealed_samples_correction_ -= num_samples;
Ivo Creusenbf4a2212019-04-24 12:06:24228 if (!is_voice) {
229 silent_concealed_samples_correction_ -= num_samples;
Alex Narest7ff6ca52018-02-07 17:46:33230 }
Henrik Lundinac0a5032017-09-25 10:22:46231 return;
232 }
233
234 const size_t canceled_out =
235 std::min(static_cast<size_t>(num_samples), concealed_samples_correction_);
236 concealed_samples_correction_ -= canceled_out;
237 lifetime_stats_.concealed_samples += num_samples - canceled_out;
Alex Narest7ff6ca52018-02-07 17:46:33238
Ivo Creusenbf4a2212019-04-24 12:06:24239 if (!is_voice) {
240 const size_t silent_canceled_out = std::min(
241 static_cast<size_t>(num_samples), silent_concealed_samples_correction_);
242 silent_concealed_samples_correction_ -= silent_canceled_out;
243 lifetime_stats_.silent_concealed_samples +=
244 num_samples - silent_canceled_out;
Alex Narest7ff6ca52018-02-07 17:46:33245 }
henrik.lundin2979f552017-05-05 12:04:16246}
247
Peter Kastingdce40cf2015-08-24 21:52:23248void StatisticsCalculator::PreemptiveExpandedSamples(size_t num_samples) {
Jakob Ivarsson09c043a2024-10-02 09:25:29249 if (!decoded_output_played_) {
250 return;
251 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21252 preemptive_samples_ += num_samples;
Ivo Creusend1c2f782018-09-13 12:39:55253 operations_and_state_.preemptive_samples += num_samples;
Ivo Creusenbf4a2212019-04-24 12:06:24254 lifetime_stats_.inserted_samples_for_deceleration += num_samples;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21255}
256
Peter Kastingdce40cf2015-08-24 21:52:23257void StatisticsCalculator::AcceleratedSamples(size_t num_samples) {
Jakob Ivarsson09c043a2024-10-02 09:25:29258 if (!decoded_output_played_) {
259 return;
260 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21261 accelerate_samples_ += num_samples;
Ivo Creusend1c2f782018-09-13 12:39:55262 operations_and_state_.accelerate_samples += num_samples;
Ivo Creusenbf4a2212019-04-24 12:06:24263 lifetime_stats_.removed_samples_for_acceleration += num_samples;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21264}
265
Jakob Ivarsson098c4ea2022-04-18 18:31:51266void StatisticsCalculator::GeneratedNoiseSamples(size_t num_samples) {
Jakob Ivarsson09c043a2024-10-02 09:25:29267 if (!decoded_output_played_) {
268 return;
269 }
Jakob Ivarsson098c4ea2022-04-18 18:31:51270 lifetime_stats_.generated_noise_samples += num_samples;
271}
272
Peter Kastingdce40cf2015-08-24 21:52:23273void StatisticsCalculator::PacketsDiscarded(size_t num_packets) {
Jakob Ivarsson1a5a8132022-05-25 20:00:14274 lifetime_stats_.packets_discarded += num_packets;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21275}
276
minyue-webrtc0c3ca752017-08-23 13:59:38277void StatisticsCalculator::SecondaryPacketsDiscarded(size_t num_packets) {
278 discarded_secondary_packets_ += num_packets;
Ivo Creusenbf4a2212019-04-24 12:06:24279 lifetime_stats_.fec_packets_discarded += num_packets;
280}
281
282void StatisticsCalculator::SecondaryPacketsReceived(size_t num_packets) {
283 lifetime_stats_.fec_packets_received += num_packets;
minyue-webrtc0c3ca752017-08-23 13:59:38284}
285
Peter Kastingdce40cf2015-08-24 21:52:23286void StatisticsCalculator::IncreaseCounter(size_t num_samples, int fs_hz) {
Jakob Ivarsson09c043a2024-10-02 09:25:29287 if (!decoded_output_played_) {
288 return;
289 }
Peter Kastingdce40cf2015-08-24 21:52:23290 const int time_step_ms =
Evan Shrubsolea0ea43e2025-04-15 14:52:55291 CheckedDivExact(static_cast<int>(1000 * num_samples), fs_hz);
Henrik Lundin1f4ffe02015-08-19 08:46:50292 delayed_packet_outage_counter_.AdvanceClock(time_step_ms);
293 excess_buffer_delay_.AdvanceClock(time_step_ms);
Minyue Li34d990f2018-10-16 14:55:52294 buffer_full_counter_.AdvanceClock(time_step_ms);
Peter Kastingb7e50542015-06-11 19:55:50295 timestamps_since_last_report_ += static_cast<uint32_t>(num_samples);
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53296 if (timestamps_since_last_report_ >
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21297 static_cast<uint32_t>(fs_hz * kMaxReportPeriod)) {
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53298 timestamps_since_last_report_ = 0;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21299 }
Steve Anton2dbc69f2017-08-25 00:15:13300 lifetime_stats_.total_samples_received += num_samples;
Jakob Ivarssona6e55562024-09-30 11:21:43301 expand_uma_logger_.UpdateSampleCounter(lifetime_stats_.concealed_samples,
302 fs_hz);
Jakob Ivarsson09c043a2024-10-02 09:25:29303 uint64_t speech_concealed_samples = 0;
304 if (lifetime_stats_.concealed_samples >
305 lifetime_stats_.silent_concealed_samples) {
306 speech_concealed_samples = lifetime_stats_.concealed_samples -
307 lifetime_stats_.silent_concealed_samples;
308 }
309 speech_expand_uma_logger_.UpdateSampleCounter(speech_concealed_samples,
310 fs_hz);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21311}
312
Jesús de Vicente Peñafc6df052024-06-04 08:05:31313void StatisticsCalculator::JitterBufferDelay(size_t num_samples,
314 uint64_t waiting_time_ms,
315 uint64_t target_delay_ms,
316 uint64_t unlimited_target_delay_ms,
317 uint64_t processing_delay_us) {
Gustaf Ullbergb0a02072017-10-02 10:00:34318 lifetime_stats_.jitter_buffer_delay_ms += waiting_time_ms * num_samples;
Artem Titove618cc92020-03-11 10:18:54319 lifetime_stats_.jitter_buffer_target_delay_ms +=
320 target_delay_ms * num_samples;
Ivo Creusen1a84b562022-07-19 14:33:10321 lifetime_stats_.jitter_buffer_minimum_delay_ms +=
322 unlimited_target_delay_ms * num_samples;
Chen Xing0acffb52019-01-15 14:46:29323 lifetime_stats_.jitter_buffer_emitted_count += num_samples;
Jesús de Vicente Peñafc6df052024-06-04 08:05:31324 lifetime_stats_.total_processing_delay_us +=
325 num_samples * processing_delay_us;
Gustaf Ullbergb0a02072017-10-02 10:00:34326}
327
minyue@webrtc.org2c1bcf22015-02-17 10:17:09328void StatisticsCalculator::SecondaryDecodedSamples(int num_samples) {
329 secondary_decoded_samples_ += num_samples;
330}
331
Ivo Creusendc6d5532018-09-27 09:43:42332void StatisticsCalculator::FlushedPacketBuffer() {
333 operations_and_state_.packet_buffer_flushes++;
Minyue Li34d990f2018-10-16 14:55:52334 buffer_full_counter_.RegisterSample();
Ivo Creusendc6d5532018-09-27 09:43:42335}
336
Jakob Ivarsson44507082019-03-05 15:59:03337void StatisticsCalculator::ReceivedPacket() {
338 ++lifetime_stats_.jitter_buffer_packets_received;
339}
340
341void StatisticsCalculator::RelativePacketArrivalDelay(size_t delay_ms) {
342 lifetime_stats_.relative_packet_arrival_delay_ms += delay_ms;
343}
344
Jakob Ivarsson352ce5c2018-11-27 11:52:16345void StatisticsCalculator::LogDelayedPacketOutageEvent(int num_samples,
346 int fs_hz) {
347 int outage_duration_ms = num_samples / (fs_hz / 1000);
asaperssona2c58e22016-03-07 09:52:59348 RTC_HISTOGRAM_COUNTS("WebRTC.Audio.DelayedPacketOutageEventMs",
349 outage_duration_ms, 1 /* min */, 2000 /* max */,
350 100 /* bucket count */);
Henrik Lundin1f4ffe02015-08-19 08:46:50351 delayed_packet_outage_counter_.RegisterSample();
Jakob Ivarsson352ce5c2018-11-27 11:52:16352 lifetime_stats_.delayed_packet_outage_samples += num_samples;
Jakob Ivarsson2bd87812023-04-25 19:01:15353 ++lifetime_stats_.delayed_packet_outage_events;
Henrik Lundinbef77e22015-08-18 12:58:09354}
355
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21356void StatisticsCalculator::StoreWaitingTime(int waiting_time_ms) {
Henrik Lundin1f4ffe02015-08-19 08:46:50357 excess_buffer_delay_.RegisterSample(waiting_time_ms);
henrikg91d6ede2015-09-17 07:24:34358 RTC_DCHECK_LE(waiting_times_.size(), kLenWaitingTimes);
henrik.lundin1e346b22015-08-27 20:41:02359 if (waiting_times_.size() == kLenWaitingTimes) {
Henrik Lundin1bb8cf82015-08-25 11:08:04360 // Erase first value.
361 waiting_times_.pop_front();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21362 }
Henrik Lundin1bb8cf82015-08-25 11:08:04363 waiting_times_.push_back(waiting_time_ms);
Ivo Creusend1c2f782018-09-13 12:39:55364 operations_and_state_.last_waiting_time_ms = waiting_time_ms;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21365}
366
Niels Möller6b4d9622020-09-14 08:47:50367void StatisticsCalculator::GetNetworkStatistics(size_t samples_per_packet,
Yves Gerey665174f2018-06-19 13:03:05368 NetEqNetworkStatistics* stats) {
Henrik Lundindccfc402017-09-25 10:30:58369 RTC_DCHECK(stats);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21370
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53371 stats->accelerate_rate =
372 CalculateQ14Ratio(accelerate_samples_, timestamps_since_last_report_);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21373
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53374 stats->preemptive_rate =
375 CalculateQ14Ratio(preemptive_samples_, timestamps_since_last_report_);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21376
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53377 stats->expand_rate =
minyue@webrtc.org7d721ee2015-02-18 10:01:53378 CalculateQ14Ratio(expanded_speech_samples_ + expanded_noise_samples_,
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53379 timestamps_since_last_report_);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21380
Yves Gerey665174f2018-06-19 13:03:05381 stats->speech_expand_rate = CalculateQ14Ratio(expanded_speech_samples_,
382 timestamps_since_last_report_);
minyue@webrtc.org7d721ee2015-02-18 10:01:53383
Yves Gerey665174f2018-06-19 13:03:05384 stats->secondary_decoded_rate = CalculateQ14Ratio(
385 secondary_decoded_samples_, timestamps_since_last_report_);
minyue@webrtc.org2c1bcf22015-02-17 10:17:09386
minyue-webrtc0c3ca752017-08-23 13:59:38387 const size_t discarded_secondary_samples =
388 discarded_secondary_packets_ * samples_per_packet;
Yves Gerey665174f2018-06-19 13:03:05389 stats->secondary_discarded_rate =
390 CalculateQ14Ratio(discarded_secondary_samples,
391 static_cast<uint32_t>(discarded_secondary_samples +
392 secondary_decoded_samples_));
minyue-webrtc0c3ca752017-08-23 13:59:38393
Henrik Lundin1bb8cf82015-08-25 11:08:04394 if (waiting_times_.size() == 0) {
395 stats->mean_waiting_time_ms = -1;
396 stats->median_waiting_time_ms = -1;
397 stats->min_waiting_time_ms = -1;
398 stats->max_waiting_time_ms = -1;
399 } else {
400 std::sort(waiting_times_.begin(), waiting_times_.end());
401 // Find mid-point elements. If the size is odd, the two values
Artem Titovd00ce742021-07-28 18:00:17402 // `middle_left` and `middle_right` will both be the one middle element; if
Henrik Lundin1bb8cf82015-08-25 11:08:04403 // the size is even, they will be the the two neighboring elements at the
404 // middle of the list.
405 const int middle_left = waiting_times_[(waiting_times_.size() - 1) / 2];
406 const int middle_right = waiting_times_[waiting_times_.size() / 2];
407 // Calculate the average of the two. (Works also for odd sizes.)
408 stats->median_waiting_time_ms = (middle_left + middle_right) / 2;
409 stats->min_waiting_time_ms = waiting_times_.front();
410 stats->max_waiting_time_ms = waiting_times_.back();
411 double sum = 0;
412 for (auto time : waiting_times_) {
413 sum += time;
414 }
415 stats->mean_waiting_time_ms = static_cast<int>(sum / waiting_times_.size());
416 }
417
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21418 // Reset counters.
419 ResetMcu();
420 Reset();
421}
422
Steve Anton2dbc69f2017-08-25 00:15:13423NetEqLifetimeStatistics StatisticsCalculator::GetLifetimeStatistics() const {
424 return lifetime_stats_;
425}
426
Ivo Creusend1c2f782018-09-13 12:39:55427NetEqOperationsAndState StatisticsCalculator::GetOperationsAndState() const {
428 return operations_and_state_;
429}
430
Peter Kastingdce40cf2015-08-24 21:52:23431uint16_t StatisticsCalculator::CalculateQ14Ratio(size_t numerator,
Peter Kastingb7e50542015-06-11 19:55:50432 uint32_t denominator) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21433 if (numerator == 0) {
434 return 0;
435 } else if (numerator < denominator) {
436 // Ratio must be smaller than 1 in Q14.
Mirko Bonadei25ab3222021-07-08 18:08:20437 RTC_DCHECK_LT((numerator << 14) / denominator, (1 << 14));
Peter Kastingb7e50542015-06-11 19:55:50438 return static_cast<uint16_t>((numerator << 14) / denominator);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21439 } else {
440 // Will not produce a ratio larger than 1, since this is probably an error.
441 return 1 << 14;
442 }
443}
444
445} // namespace webrtc