blob: 52d3fa90f1c20c466ff2cee1ee500adb1c972126 [file] [log] [blame]
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +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/audio_coding/neteq/statistics_calculator.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000012
pbos@webrtc.org12dc1a32013-08-05 16:22:53 +000013#include <string.h> // memset
Jonas Olssona4d87372019-07-05 19:08:33 +020014
Henrik Lundin1bb8cf82015-08-25 13:08:04 +020015#include <algorithm>
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000016
Ali Tofigh714e3cb2022-07-20 12:53:07 +020017#include "absl/strings/string_view.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "modules/audio_coding/neteq/delay_manager.h"
19#include "rtc_base/checks.h"
Karl Wiberge40468b2017-11-22 10:42:26 +010020#include "rtc_base/numerics/safe_conversions.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "system_wrappers/include/metrics.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000022
23namespace webrtc {
24
henrik.lundin2979f552017-05-05 05:04:16 -070025namespace {
26size_t AddIntToSizeTWithLowerCap(int a, size_t b) {
27 const size_t ret = b + a;
28 // If a + b is negative, resulting in a negative wrap, cap it to zero instead.
29 static_assert(sizeof(size_t) >= sizeof(int),
30 "int must not be wider than size_t for this to work");
31 return (a < 0 && ret > b) ? 0 : ret;
32}
Henrik Lundin2a8bd092019-04-26 09:47:07 +020033
34constexpr int kInterruptionLenMs = 150;
henrik.lundin2979f552017-05-05 05:04:16 -070035} // namespace
36
henrikg91d6ede2015-09-17 00:24:34 -070037// Allocating the static const so that it can be passed by reference to
38// RTC_DCHECK.
Henrik Lundin1bb8cf82015-08-25 13:08:04 +020039const size_t StatisticsCalculator::kLenWaitingTimes;
40
Henrik Lundin1f4ffe02015-08-19 10:46:50 +020041StatisticsCalculator::PeriodicUmaLogger::PeriodicUmaLogger(
Ali Tofigh714e3cb2022-07-20 12:53:07 +020042 absl::string_view uma_name,
Henrik Lundin1f4ffe02015-08-19 10:46:50 +020043 int report_interval_ms,
44 int max_value)
45 : uma_name_(uma_name),
46 report_interval_ms_(report_interval_ms),
47 max_value_(max_value),
Yves Gerey665174f2018-06-19 15:03:05 +020048 timer_(0) {}
Henrik Lundin1f4ffe02015-08-19 10:46:50 +020049
50StatisticsCalculator::PeriodicUmaLogger::~PeriodicUmaLogger() = default;
51
52void StatisticsCalculator::PeriodicUmaLogger::AdvanceClock(int step_ms) {
53 timer_ += step_ms;
54 if (timer_ < report_interval_ms_) {
55 return;
56 }
57 LogToUma(Metric());
58 Reset();
59 timer_ -= report_interval_ms_;
henrikg91d6ede2015-09-17 00:24:34 -070060 RTC_DCHECK_GE(timer_, 0);
Henrik Lundin1f4ffe02015-08-19 10:46:50 +020061}
62
63void StatisticsCalculator::PeriodicUmaLogger::LogToUma(int value) const {
asapersson53805322015-12-21 01:46:20 -080064 RTC_HISTOGRAM_COUNTS_SPARSE(uma_name_, value, 1, max_value_, 50);
Henrik Lundin1f4ffe02015-08-19 10:46:50 +020065}
66
67StatisticsCalculator::PeriodicUmaCount::PeriodicUmaCount(
Ali Tofigh714e3cb2022-07-20 12:53:07 +020068 absl::string_view uma_name,
Henrik Lundin1f4ffe02015-08-19 10:46:50 +020069 int report_interval_ms,
70 int max_value)
Yves Gerey665174f2018-06-19 15:03:05 +020071 : PeriodicUmaLogger(uma_name, report_interval_ms, max_value) {}
Henrik Lundin1f4ffe02015-08-19 10:46:50 +020072
73StatisticsCalculator::PeriodicUmaCount::~PeriodicUmaCount() {
74 // Log the count for the current (incomplete) interval.
75 LogToUma(Metric());
76}
77
78void StatisticsCalculator::PeriodicUmaCount::RegisterSample() {
79 ++counter_;
80}
81
82int StatisticsCalculator::PeriodicUmaCount::Metric() const {
83 return counter_;
84}
85
86void StatisticsCalculator::PeriodicUmaCount::Reset() {
87 counter_ = 0;
88}
89
90StatisticsCalculator::PeriodicUmaAverage::PeriodicUmaAverage(
Ali Tofigh714e3cb2022-07-20 12:53:07 +020091 absl::string_view uma_name,
Henrik Lundin1f4ffe02015-08-19 10:46:50 +020092 int report_interval_ms,
93 int max_value)
Yves Gerey665174f2018-06-19 15:03:05 +020094 : PeriodicUmaLogger(uma_name, report_interval_ms, max_value) {}
Henrik Lundin1f4ffe02015-08-19 10:46:50 +020095
96StatisticsCalculator::PeriodicUmaAverage::~PeriodicUmaAverage() {
97 // Log the average for the current (incomplete) interval.
98 LogToUma(Metric());
99}
100
101void StatisticsCalculator::PeriodicUmaAverage::RegisterSample(int value) {
102 sum_ += value;
103 ++counter_;
104}
105
106int StatisticsCalculator::PeriodicUmaAverage::Metric() const {
henrik.lundine5942132016-02-09 00:35:53 -0800107 return counter_ == 0 ? 0 : static_cast<int>(sum_ / counter_);
Henrik Lundin1f4ffe02015-08-19 10:46:50 +0200108}
109
110void StatisticsCalculator::PeriodicUmaAverage::Reset() {
111 sum_ = 0.0;
112 counter_ = 0;
113}
114
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000115StatisticsCalculator::StatisticsCalculator()
116 : preemptive_samples_(0),
117 accelerate_samples_(0),
minyue@webrtc.org7d721ee2015-02-18 10:01:53 +0000118 expanded_speech_samples_(0),
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000119 expanded_noise_samples_(0),
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53 +0000120 timestamps_since_last_report_(0),
Henrik Lundin1f4ffe02015-08-19 10:46:50 +0200121 secondary_decoded_samples_(0),
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200122 discarded_secondary_packets_(0),
Henrik Lundin1f4ffe02015-08-19 10:46:50 +0200123 delayed_packet_outage_counter_(
124 "WebRTC.Audio.DelayedPacketOutageEventsPerMinute",
125 60000, // 60 seconds report interval.
126 100),
127 excess_buffer_delay_("WebRTC.Audio.AverageExcessBufferDelayMs",
128 60000, // 60 seconds report interval.
Minyue Li34d990f2018-10-16 16:55:52 +0200129 1000),
130 buffer_full_counter_("WebRTC.Audio.JitterBufferFullPerMinute",
131 60000, // 60 seconds report interval.
132 100) {}
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000133
Henrik Lundin1bb8cf82015-08-25 13:08:04 +0200134StatisticsCalculator::~StatisticsCalculator() = default;
135
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000136void StatisticsCalculator::Reset() {
137 preemptive_samples_ = 0;
138 accelerate_samples_ = 0;
minyue@webrtc.org7d721ee2015-02-18 10:01:53 +0000139 expanded_speech_samples_ = 0;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000140 expanded_noise_samples_ = 0;
minyue@webrtc.org2c1bcf22015-02-17 10:17:09 +0000141 secondary_decoded_samples_ = 0;
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200142 discarded_secondary_packets_ = 0;
Henrik Lundin1bb8cf82015-08-25 13:08:04 +0200143 waiting_times_.clear();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000144}
145
146void StatisticsCalculator::ResetMcu() {
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53 +0000147 timestamps_since_last_report_ = 0;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000148}
149
Gustaf Ullberg9a2e9062017-09-18 09:28:20 +0200150void StatisticsCalculator::ExpandedVoiceSamples(size_t num_samples,
151 bool is_new_concealment_event) {
minyue@webrtc.org7d721ee2015-02-18 10:01:53 +0000152 expanded_speech_samples_ += num_samples;
Alex Narest7ff6ca52018-02-07 18:46:33 +0100153 ConcealedSamplesCorrection(rtc::dchecked_cast<int>(num_samples), true);
Gustaf Ullberg9a2e9062017-09-18 09:28:20 +0200154 lifetime_stats_.concealment_events += is_new_concealment_event;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000155}
156
Gustaf Ullberg9a2e9062017-09-18 09:28:20 +0200157void StatisticsCalculator::ExpandedNoiseSamples(size_t num_samples,
158 bool is_new_concealment_event) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000159 expanded_noise_samples_ += num_samples;
Alex Narest7ff6ca52018-02-07 18:46:33 +0100160 ConcealedSamplesCorrection(rtc::dchecked_cast<int>(num_samples), false);
Gustaf Ullberg9a2e9062017-09-18 09:28:20 +0200161 lifetime_stats_.concealment_events += is_new_concealment_event;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000162}
163
henrik.lundin2979f552017-05-05 05:04:16 -0700164void StatisticsCalculator::ExpandedVoiceSamplesCorrection(int num_samples) {
165 expanded_speech_samples_ =
166 AddIntToSizeTWithLowerCap(num_samples, expanded_speech_samples_);
Alex Narest7ff6ca52018-02-07 18:46:33 +0100167 ConcealedSamplesCorrection(num_samples, true);
henrik.lundin2979f552017-05-05 05:04:16 -0700168}
169
170void StatisticsCalculator::ExpandedNoiseSamplesCorrection(int num_samples) {
171 expanded_noise_samples_ =
172 AddIntToSizeTWithLowerCap(num_samples, expanded_noise_samples_);
Alex Narest7ff6ca52018-02-07 18:46:33 +0100173 ConcealedSamplesCorrection(num_samples, false);
Henrik Lundinac0a5032017-09-25 12:22:46 +0200174}
175
Henrik Lundin2a8bd092019-04-26 09:47:07 +0200176void StatisticsCalculator::DecodedOutputPlayed() {
177 decoded_output_played_ = true;
178}
179
180void StatisticsCalculator::EndExpandEvent(int fs_hz) {
181 RTC_DCHECK_GE(lifetime_stats_.concealed_samples,
182 concealed_samples_at_event_end_);
183 const int event_duration_ms =
184 1000 *
185 (lifetime_stats_.concealed_samples - concealed_samples_at_event_end_) /
186 fs_hz;
187 if (event_duration_ms >= kInterruptionLenMs && decoded_output_played_) {
188 lifetime_stats_.interruption_count++;
189 lifetime_stats_.total_interruption_duration_ms += event_duration_ms;
Henrik Lundine835fc02019-11-21 09:34:29 +0100190 RTC_HISTOGRAM_COUNTS("WebRTC.Audio.AudioInterruptionMs", event_duration_ms,
191 /*min=*/150, /*max=*/5000, /*bucket_count=*/50);
Henrik Lundin2a8bd092019-04-26 09:47:07 +0200192 }
193 concealed_samples_at_event_end_ = lifetime_stats_.concealed_samples;
194}
195
Alex Narest7ff6ca52018-02-07 18:46:33 +0100196void StatisticsCalculator::ConcealedSamplesCorrection(int num_samples,
197 bool is_voice) {
Henrik Lundinac0a5032017-09-25 12:22:46 +0200198 if (num_samples < 0) {
199 // Store negative correction to subtract from future positive additions.
200 // See also the function comment in the header file.
201 concealed_samples_correction_ -= num_samples;
Ivo Creusenbf4a2212019-04-24 14:06:24 +0200202 if (!is_voice) {
203 silent_concealed_samples_correction_ -= num_samples;
Alex Narest7ff6ca52018-02-07 18:46:33 +0100204 }
Henrik Lundinac0a5032017-09-25 12:22:46 +0200205 return;
206 }
207
208 const size_t canceled_out =
209 std::min(static_cast<size_t>(num_samples), concealed_samples_correction_);
210 concealed_samples_correction_ -= canceled_out;
211 lifetime_stats_.concealed_samples += num_samples - canceled_out;
Alex Narest7ff6ca52018-02-07 18:46:33 +0100212
Ivo Creusenbf4a2212019-04-24 14:06:24 +0200213 if (!is_voice) {
214 const size_t silent_canceled_out = std::min(
215 static_cast<size_t>(num_samples), silent_concealed_samples_correction_);
216 silent_concealed_samples_correction_ -= silent_canceled_out;
217 lifetime_stats_.silent_concealed_samples +=
218 num_samples - silent_canceled_out;
Alex Narest7ff6ca52018-02-07 18:46:33 +0100219 }
henrik.lundin2979f552017-05-05 05:04:16 -0700220}
221
Peter Kastingdce40cf2015-08-24 14:52:23 -0700222void StatisticsCalculator::PreemptiveExpandedSamples(size_t num_samples) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000223 preemptive_samples_ += num_samples;
Ivo Creusend1c2f782018-09-13 14:39:55 +0200224 operations_and_state_.preemptive_samples += num_samples;
Ivo Creusenbf4a2212019-04-24 14:06:24 +0200225 lifetime_stats_.inserted_samples_for_deceleration += num_samples;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000226}
227
Peter Kastingdce40cf2015-08-24 14:52:23 -0700228void StatisticsCalculator::AcceleratedSamples(size_t num_samples) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000229 accelerate_samples_ += num_samples;
Ivo Creusend1c2f782018-09-13 14:39:55 +0200230 operations_and_state_.accelerate_samples += num_samples;
Ivo Creusenbf4a2212019-04-24 14:06:24 +0200231 lifetime_stats_.removed_samples_for_acceleration += num_samples;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000232}
233
Jakob Ivarsson098c4ea2022-04-18 20:31:51 +0200234void StatisticsCalculator::GeneratedNoiseSamples(size_t num_samples) {
235 lifetime_stats_.generated_noise_samples += num_samples;
236}
237
Peter Kastingdce40cf2015-08-24 14:52:23 -0700238void StatisticsCalculator::PacketsDiscarded(size_t num_packets) {
Jakob Ivarsson1a5a8132022-05-25 22:00:14 +0200239 lifetime_stats_.packets_discarded += num_packets;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000240}
241
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200242void StatisticsCalculator::SecondaryPacketsDiscarded(size_t num_packets) {
243 discarded_secondary_packets_ += num_packets;
Ivo Creusenbf4a2212019-04-24 14:06:24 +0200244 lifetime_stats_.fec_packets_discarded += num_packets;
245}
246
247void StatisticsCalculator::SecondaryPacketsReceived(size_t num_packets) {
248 lifetime_stats_.fec_packets_received += num_packets;
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200249}
250
Peter Kastingdce40cf2015-08-24 14:52:23 -0700251void StatisticsCalculator::IncreaseCounter(size_t num_samples, int fs_hz) {
252 const int time_step_ms =
253 rtc::CheckedDivExact(static_cast<int>(1000 * num_samples), fs_hz);
Henrik Lundin1f4ffe02015-08-19 10:46:50 +0200254 delayed_packet_outage_counter_.AdvanceClock(time_step_ms);
255 excess_buffer_delay_.AdvanceClock(time_step_ms);
Minyue Li34d990f2018-10-16 16:55:52 +0200256 buffer_full_counter_.AdvanceClock(time_step_ms);
Peter Kastingb7e50542015-06-11 12:55:50 -0700257 timestamps_since_last_report_ += static_cast<uint32_t>(num_samples);
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53 +0000258 if (timestamps_since_last_report_ >
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000259 static_cast<uint32_t>(fs_hz * kMaxReportPeriod)) {
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53 +0000260 timestamps_since_last_report_ = 0;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000261 }
Steve Anton2dbc69f2017-08-24 17:15:13 -0700262 lifetime_stats_.total_samples_received += num_samples;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000263}
264
Ivo Creusen1a84b562022-07-19 16:33:10 +0200265void StatisticsCalculator::JitterBufferDelay(
266 size_t num_samples,
267 uint64_t waiting_time_ms,
268 uint64_t target_delay_ms,
269 uint64_t unlimited_target_delay_ms) {
Gustaf Ullbergb0a02072017-10-02 12:00:34 +0200270 lifetime_stats_.jitter_buffer_delay_ms += waiting_time_ms * num_samples;
Artem Titove618cc92020-03-11 11:18:54 +0100271 lifetime_stats_.jitter_buffer_target_delay_ms +=
272 target_delay_ms * num_samples;
Ivo Creusen1a84b562022-07-19 16:33:10 +0200273 lifetime_stats_.jitter_buffer_minimum_delay_ms +=
274 unlimited_target_delay_ms * num_samples;
Chen Xing0acffb52019-01-15 15:46:29 +0100275 lifetime_stats_.jitter_buffer_emitted_count += num_samples;
Gustaf Ullbergb0a02072017-10-02 12:00:34 +0200276}
277
minyue@webrtc.org2c1bcf22015-02-17 10:17:09 +0000278void StatisticsCalculator::SecondaryDecodedSamples(int num_samples) {
279 secondary_decoded_samples_ += num_samples;
280}
281
Ivo Creusendc6d5532018-09-27 11:43:42 +0200282void StatisticsCalculator::FlushedPacketBuffer() {
283 operations_and_state_.packet_buffer_flushes++;
Minyue Li34d990f2018-10-16 16:55:52 +0200284 buffer_full_counter_.RegisterSample();
Ivo Creusendc6d5532018-09-27 11:43:42 +0200285}
286
Jakob Ivarsson44507082019-03-05 16:59:03 +0100287void StatisticsCalculator::ReceivedPacket() {
288 ++lifetime_stats_.jitter_buffer_packets_received;
289}
290
291void StatisticsCalculator::RelativePacketArrivalDelay(size_t delay_ms) {
292 lifetime_stats_.relative_packet_arrival_delay_ms += delay_ms;
293}
294
Jakob Ivarsson352ce5c2018-11-27 12:52:16 +0100295void StatisticsCalculator::LogDelayedPacketOutageEvent(int num_samples,
296 int fs_hz) {
297 int outage_duration_ms = num_samples / (fs_hz / 1000);
asaperssona2c58e22016-03-07 01:52:59 -0800298 RTC_HISTOGRAM_COUNTS("WebRTC.Audio.DelayedPacketOutageEventMs",
299 outage_duration_ms, 1 /* min */, 2000 /* max */,
300 100 /* bucket count */);
Henrik Lundin1f4ffe02015-08-19 10:46:50 +0200301 delayed_packet_outage_counter_.RegisterSample();
Jakob Ivarsson352ce5c2018-11-27 12:52:16 +0100302 lifetime_stats_.delayed_packet_outage_samples += num_samples;
Henrik Lundinbef77e22015-08-18 14:58:09 +0200303}
304
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000305void StatisticsCalculator::StoreWaitingTime(int waiting_time_ms) {
Henrik Lundin1f4ffe02015-08-19 10:46:50 +0200306 excess_buffer_delay_.RegisterSample(waiting_time_ms);
henrikg91d6ede2015-09-17 00:24:34 -0700307 RTC_DCHECK_LE(waiting_times_.size(), kLenWaitingTimes);
henrik.lundin1e346b22015-08-27 13:41:02 -0700308 if (waiting_times_.size() == kLenWaitingTimes) {
Henrik Lundin1bb8cf82015-08-25 13:08:04 +0200309 // Erase first value.
310 waiting_times_.pop_front();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000311 }
Henrik Lundin1bb8cf82015-08-25 13:08:04 +0200312 waiting_times_.push_back(waiting_time_ms);
Ivo Creusend1c2f782018-09-13 14:39:55 +0200313 operations_and_state_.last_waiting_time_ms = waiting_time_ms;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000314}
315
Niels Möller6b4d9622020-09-14 10:47:50 +0200316void StatisticsCalculator::GetNetworkStatistics(size_t samples_per_packet,
Yves Gerey665174f2018-06-19 15:03:05 +0200317 NetEqNetworkStatistics* stats) {
Henrik Lundindccfc402017-09-25 12:30:58 +0200318 RTC_DCHECK(stats);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000319
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53 +0000320 stats->accelerate_rate =
321 CalculateQ14Ratio(accelerate_samples_, timestamps_since_last_report_);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000322
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53 +0000323 stats->preemptive_rate =
324 CalculateQ14Ratio(preemptive_samples_, timestamps_since_last_report_);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000325
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53 +0000326 stats->expand_rate =
minyue@webrtc.org7d721ee2015-02-18 10:01:53 +0000327 CalculateQ14Ratio(expanded_speech_samples_ + expanded_noise_samples_,
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53 +0000328 timestamps_since_last_report_);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000329
Yves Gerey665174f2018-06-19 15:03:05 +0200330 stats->speech_expand_rate = CalculateQ14Ratio(expanded_speech_samples_,
331 timestamps_since_last_report_);
minyue@webrtc.org7d721ee2015-02-18 10:01:53 +0000332
Yves Gerey665174f2018-06-19 15:03:05 +0200333 stats->secondary_decoded_rate = CalculateQ14Ratio(
334 secondary_decoded_samples_, timestamps_since_last_report_);
minyue@webrtc.org2c1bcf22015-02-17 10:17:09 +0000335
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200336 const size_t discarded_secondary_samples =
337 discarded_secondary_packets_ * samples_per_packet;
Yves Gerey665174f2018-06-19 15:03:05 +0200338 stats->secondary_discarded_rate =
339 CalculateQ14Ratio(discarded_secondary_samples,
340 static_cast<uint32_t>(discarded_secondary_samples +
341 secondary_decoded_samples_));
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200342
Henrik Lundin1bb8cf82015-08-25 13:08:04 +0200343 if (waiting_times_.size() == 0) {
344 stats->mean_waiting_time_ms = -1;
345 stats->median_waiting_time_ms = -1;
346 stats->min_waiting_time_ms = -1;
347 stats->max_waiting_time_ms = -1;
348 } else {
349 std::sort(waiting_times_.begin(), waiting_times_.end());
350 // Find mid-point elements. If the size is odd, the two values
Artem Titovd00ce742021-07-28 20:00:17 +0200351 // `middle_left` and `middle_right` will both be the one middle element; if
Henrik Lundin1bb8cf82015-08-25 13:08:04 +0200352 // the size is even, they will be the the two neighboring elements at the
353 // middle of the list.
354 const int middle_left = waiting_times_[(waiting_times_.size() - 1) / 2];
355 const int middle_right = waiting_times_[waiting_times_.size() / 2];
356 // Calculate the average of the two. (Works also for odd sizes.)
357 stats->median_waiting_time_ms = (middle_left + middle_right) / 2;
358 stats->min_waiting_time_ms = waiting_times_.front();
359 stats->max_waiting_time_ms = waiting_times_.back();
360 double sum = 0;
361 for (auto time : waiting_times_) {
362 sum += time;
363 }
364 stats->mean_waiting_time_ms = static_cast<int>(sum / waiting_times_.size());
365 }
366
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000367 // Reset counters.
368 ResetMcu();
369 Reset();
370}
371
Steve Anton2dbc69f2017-08-24 17:15:13 -0700372NetEqLifetimeStatistics StatisticsCalculator::GetLifetimeStatistics() const {
373 return lifetime_stats_;
374}
375
Ivo Creusend1c2f782018-09-13 14:39:55 +0200376NetEqOperationsAndState StatisticsCalculator::GetOperationsAndState() const {
377 return operations_and_state_;
378}
379
Peter Kastingdce40cf2015-08-24 14:52:23 -0700380uint16_t StatisticsCalculator::CalculateQ14Ratio(size_t numerator,
Peter Kastingb7e50542015-06-11 12:55:50 -0700381 uint32_t denominator) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000382 if (numerator == 0) {
383 return 0;
384 } else if (numerator < denominator) {
385 // Ratio must be smaller than 1 in Q14.
Mirko Bonadei25ab3222021-07-08 20:08:20 +0200386 RTC_DCHECK_LT((numerator << 14) / denominator, (1 << 14));
Peter Kastingb7e50542015-06-11 12:55:50 -0700387 return static_cast<uint16_t>((numerator << 14) / denominator);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000388 } else {
389 // Will not produce a ratio larger than 1, since this is probably an error.
390 return 1 << 14;
391 }
392}
393
394} // namespace webrtc