blob: e47f92fe97b56a1254baa499d44c8abf3bfa5166 [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
henrik.lundin@webrtc.org9c55f0f2014-06-09 08:10:28 +000011#include "webrtc/modules/audio_coding/neteq/statistics_calculator.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000012
13#include <assert.h>
pbos@webrtc.org12dc1a32013-08-05 16:22:53 +000014#include <string.h> // memset
Henrik Lundin1bb8cf82015-08-25 13:08:04 +020015#include <algorithm>
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000016
henrik.lundin@webrtc.org9c55f0f2014-06-09 08:10:28 +000017#include "webrtc/modules/audio_coding/neteq/decision_logic.h"
18#include "webrtc/modules/audio_coding/neteq/delay_manager.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020019#include "webrtc/rtc_base/checks.h"
20#include "webrtc/rtc_base/safe_conversions.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010021#include "webrtc/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}
33} // namespace
34
henrikg91d6ede2015-09-17 00:24:34 -070035// Allocating the static const so that it can be passed by reference to
36// RTC_DCHECK.
Henrik Lundin1bb8cf82015-08-25 13:08:04 +020037const size_t StatisticsCalculator::kLenWaitingTimes;
38
Henrik Lundin1f4ffe02015-08-19 10:46:50 +020039StatisticsCalculator::PeriodicUmaLogger::PeriodicUmaLogger(
40 const std::string& uma_name,
41 int report_interval_ms,
42 int max_value)
43 : uma_name_(uma_name),
44 report_interval_ms_(report_interval_ms),
45 max_value_(max_value),
46 timer_(0) {
47}
48
49StatisticsCalculator::PeriodicUmaLogger::~PeriodicUmaLogger() = default;
50
51void StatisticsCalculator::PeriodicUmaLogger::AdvanceClock(int step_ms) {
52 timer_ += step_ms;
53 if (timer_ < report_interval_ms_) {
54 return;
55 }
56 LogToUma(Metric());
57 Reset();
58 timer_ -= report_interval_ms_;
henrikg91d6ede2015-09-17 00:24:34 -070059 RTC_DCHECK_GE(timer_, 0);
Henrik Lundin1f4ffe02015-08-19 10:46:50 +020060}
61
62void StatisticsCalculator::PeriodicUmaLogger::LogToUma(int value) const {
asapersson53805322015-12-21 01:46:20 -080063 RTC_HISTOGRAM_COUNTS_SPARSE(uma_name_, value, 1, max_value_, 50);
Henrik Lundin1f4ffe02015-08-19 10:46:50 +020064}
65
66StatisticsCalculator::PeriodicUmaCount::PeriodicUmaCount(
67 const std::string& uma_name,
68 int report_interval_ms,
69 int max_value)
70 : PeriodicUmaLogger(uma_name, report_interval_ms, max_value) {
71}
72
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(
91 const std::string& uma_name,
92 int report_interval_ms,
93 int max_value)
94 : PeriodicUmaLogger(uma_name, report_interval_ms, max_value) {
95}
96
97StatisticsCalculator::PeriodicUmaAverage::~PeriodicUmaAverage() {
98 // Log the average for the current (incomplete) interval.
99 LogToUma(Metric());
100}
101
102void StatisticsCalculator::PeriodicUmaAverage::RegisterSample(int value) {
103 sum_ += value;
104 ++counter_;
105}
106
107int StatisticsCalculator::PeriodicUmaAverage::Metric() const {
henrik.lundine5942132016-02-09 00:35:53 -0800108 return counter_ == 0 ? 0 : static_cast<int>(sum_ / counter_);
Henrik Lundin1f4ffe02015-08-19 10:46:50 +0200109}
110
111void StatisticsCalculator::PeriodicUmaAverage::Reset() {
112 sum_ = 0.0;
113 counter_ = 0;
114}
115
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000116StatisticsCalculator::StatisticsCalculator()
117 : preemptive_samples_(0),
118 accelerate_samples_(0),
119 added_zero_samples_(0),
minyue@webrtc.org7d721ee2015-02-18 10:01:53 +0000120 expanded_speech_samples_(0),
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000121 expanded_noise_samples_(0),
122 discarded_packets_(0),
123 lost_timestamps_(0),
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53 +0000124 timestamps_since_last_report_(0),
Henrik Lundin1f4ffe02015-08-19 10:46:50 +0200125 secondary_decoded_samples_(0),
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200126 discarded_secondary_packets_(0),
Henrik Lundin1f4ffe02015-08-19 10:46:50 +0200127 delayed_packet_outage_counter_(
128 "WebRTC.Audio.DelayedPacketOutageEventsPerMinute",
129 60000, // 60 seconds report interval.
130 100),
131 excess_buffer_delay_("WebRTC.Audio.AverageExcessBufferDelayMs",
132 60000, // 60 seconds report interval.
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200133 1000) {}
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000134
Henrik Lundin1bb8cf82015-08-25 13:08:04 +0200135StatisticsCalculator::~StatisticsCalculator() = default;
136
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000137void StatisticsCalculator::Reset() {
138 preemptive_samples_ = 0;
139 accelerate_samples_ = 0;
140 added_zero_samples_ = 0;
minyue@webrtc.org7d721ee2015-02-18 10:01:53 +0000141 expanded_speech_samples_ = 0;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000142 expanded_noise_samples_ = 0;
minyue@webrtc.org2c1bcf22015-02-17 10:17:09 +0000143 secondary_decoded_samples_ = 0;
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200144 discarded_secondary_packets_ = 0;
Henrik Lundin1bb8cf82015-08-25 13:08:04 +0200145 waiting_times_.clear();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000146}
147
148void StatisticsCalculator::ResetMcu() {
149 discarded_packets_ = 0;
150 lost_timestamps_ = 0;
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53 +0000151 timestamps_since_last_report_ = 0;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000152}
153
Peter Kastingdce40cf2015-08-24 14:52:23 -0700154void StatisticsCalculator::ExpandedVoiceSamples(size_t num_samples) {
minyue@webrtc.org7d721ee2015-02-18 10:01:53 +0000155 expanded_speech_samples_ += num_samples;
Steve Anton2dbc69f2017-08-24 17:15:13 -0700156 lifetime_stats_.concealed_samples += num_samples;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000157}
158
Peter Kastingdce40cf2015-08-24 14:52:23 -0700159void StatisticsCalculator::ExpandedNoiseSamples(size_t num_samples) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000160 expanded_noise_samples_ += num_samples;
Steve Anton2dbc69f2017-08-24 17:15:13 -0700161 lifetime_stats_.concealed_samples += num_samples;
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_);
Steve Anton2dbc69f2017-08-24 17:15:13 -0700167 lifetime_stats_.concealed_samples += num_samples;
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_);
Steve Anton2dbc69f2017-08-24 17:15:13 -0700173 lifetime_stats_.concealed_samples += num_samples;
henrik.lundin2979f552017-05-05 05:04:16 -0700174}
175
Peter Kastingdce40cf2015-08-24 14:52:23 -0700176void StatisticsCalculator::PreemptiveExpandedSamples(size_t num_samples) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000177 preemptive_samples_ += num_samples;
Steve Anton2dbc69f2017-08-24 17:15:13 -0700178 lifetime_stats_.concealed_samples += num_samples;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000179}
180
Peter Kastingdce40cf2015-08-24 14:52:23 -0700181void StatisticsCalculator::AcceleratedSamples(size_t num_samples) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000182 accelerate_samples_ += num_samples;
183}
184
Peter Kastingdce40cf2015-08-24 14:52:23 -0700185void StatisticsCalculator::AddZeros(size_t num_samples) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000186 added_zero_samples_ += num_samples;
187}
188
Peter Kastingdce40cf2015-08-24 14:52:23 -0700189void StatisticsCalculator::PacketsDiscarded(size_t num_packets) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000190 discarded_packets_ += num_packets;
191}
192
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200193void StatisticsCalculator::SecondaryPacketsDiscarded(size_t num_packets) {
194 discarded_secondary_packets_ += num_packets;
195}
196
Peter Kastingdce40cf2015-08-24 14:52:23 -0700197void StatisticsCalculator::LostSamples(size_t num_samples) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000198 lost_timestamps_ += num_samples;
199}
200
Peter Kastingdce40cf2015-08-24 14:52:23 -0700201void StatisticsCalculator::IncreaseCounter(size_t num_samples, int fs_hz) {
202 const int time_step_ms =
203 rtc::CheckedDivExact(static_cast<int>(1000 * num_samples), fs_hz);
Henrik Lundin1f4ffe02015-08-19 10:46:50 +0200204 delayed_packet_outage_counter_.AdvanceClock(time_step_ms);
205 excess_buffer_delay_.AdvanceClock(time_step_ms);
Peter Kastingb7e50542015-06-11 12:55:50 -0700206 timestamps_since_last_report_ += static_cast<uint32_t>(num_samples);
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53 +0000207 if (timestamps_since_last_report_ >
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000208 static_cast<uint32_t>(fs_hz * kMaxReportPeriod)) {
209 lost_timestamps_ = 0;
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53 +0000210 timestamps_since_last_report_ = 0;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000211 discarded_packets_ = 0;
212 }
Steve Anton2dbc69f2017-08-24 17:15:13 -0700213 lifetime_stats_.total_samples_received += num_samples;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000214}
215
minyue@webrtc.org2c1bcf22015-02-17 10:17:09 +0000216void StatisticsCalculator::SecondaryDecodedSamples(int num_samples) {
217 secondary_decoded_samples_ += num_samples;
218}
219
Henrik Lundinbef77e22015-08-18 14:58:09 +0200220void StatisticsCalculator::LogDelayedPacketOutageEvent(int outage_duration_ms) {
asaperssona2c58e22016-03-07 01:52:59 -0800221 RTC_HISTOGRAM_COUNTS("WebRTC.Audio.DelayedPacketOutageEventMs",
222 outage_duration_ms, 1 /* min */, 2000 /* max */,
223 100 /* bucket count */);
Henrik Lundin1f4ffe02015-08-19 10:46:50 +0200224 delayed_packet_outage_counter_.RegisterSample();
Henrik Lundinbef77e22015-08-18 14:58:09 +0200225}
226
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000227void StatisticsCalculator::StoreWaitingTime(int waiting_time_ms) {
Henrik Lundin1f4ffe02015-08-19 10:46:50 +0200228 excess_buffer_delay_.RegisterSample(waiting_time_ms);
henrikg91d6ede2015-09-17 00:24:34 -0700229 RTC_DCHECK_LE(waiting_times_.size(), kLenWaitingTimes);
henrik.lundin1e346b22015-08-27 13:41:02 -0700230 if (waiting_times_.size() == kLenWaitingTimes) {
Henrik Lundin1bb8cf82015-08-25 13:08:04 +0200231 // Erase first value.
232 waiting_times_.pop_front();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000233 }
Henrik Lundin1bb8cf82015-08-25 13:08:04 +0200234 waiting_times_.push_back(waiting_time_ms);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000235}
236
237void StatisticsCalculator::GetNetworkStatistics(
238 int fs_hz,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700239 size_t num_samples_in_buffers,
240 size_t samples_per_packet,
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000241 const DelayManager& delay_manager,
242 const DecisionLogic& decision_logic,
243 NetEqNetworkStatistics *stats) {
244 if (fs_hz <= 0 || !stats) {
245 assert(false);
246 return;
247 }
248
249 stats->added_zero_samples = added_zero_samples_;
Peter Kastingb7e50542015-06-11 12:55:50 -0700250 stats->current_buffer_size_ms =
251 static_cast<uint16_t>(num_samples_in_buffers * 1000 / fs_hz);
kwibergd3edd772017-03-01 18:52:48 -0800252 const int ms_per_packet = rtc::dchecked_cast<int>(
Peter Kastingdce40cf2015-08-24 14:52:23 -0700253 decision_logic.packet_length_samples() / (fs_hz / 1000));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000254 stats->preferred_buffer_size_ms = (delay_manager.TargetLevel() >> 8) *
255 ms_per_packet;
256 stats->jitter_peaks_found = delay_manager.PeakFound();
henrik.lundin0d838572016-10-13 03:35:55 -0700257 stats->clockdrift_ppm =
258 rtc::saturated_cast<int32_t>(delay_manager.EstimatedClockDriftPpm());
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000259
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53 +0000260 stats->packet_loss_rate =
261 CalculateQ14Ratio(lost_timestamps_, timestamps_since_last_report_);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000262
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53 +0000263 stats->accelerate_rate =
264 CalculateQ14Ratio(accelerate_samples_, timestamps_since_last_report_);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000265
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53 +0000266 stats->preemptive_rate =
267 CalculateQ14Ratio(preemptive_samples_, timestamps_since_last_report_);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000268
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53 +0000269 stats->expand_rate =
minyue@webrtc.org7d721ee2015-02-18 10:01:53 +0000270 CalculateQ14Ratio(expanded_speech_samples_ + expanded_noise_samples_,
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53 +0000271 timestamps_since_last_report_);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000272
minyue@webrtc.org7d721ee2015-02-18 10:01:53 +0000273 stats->speech_expand_rate =
274 CalculateQ14Ratio(expanded_speech_samples_,
Peter Kasting728d9032015-06-11 14:31:38 -0700275 timestamps_since_last_report_);
minyue@webrtc.org7d721ee2015-02-18 10:01:53 +0000276
minyue@webrtc.org2c1bcf22015-02-17 10:17:09 +0000277 stats->secondary_decoded_rate =
278 CalculateQ14Ratio(secondary_decoded_samples_,
279 timestamps_since_last_report_);
280
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200281 const size_t discarded_secondary_samples =
282 discarded_secondary_packets_ * samples_per_packet;
283 stats->secondary_discarded_rate = CalculateQ14Ratio(
284 discarded_secondary_samples,
lliuuff2824b2017-08-28 13:01:45 -0700285 static_cast<uint32_t>(discarded_secondary_samples +
286 secondary_decoded_samples_));
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200287
Henrik Lundin1bb8cf82015-08-25 13:08:04 +0200288 if (waiting_times_.size() == 0) {
289 stats->mean_waiting_time_ms = -1;
290 stats->median_waiting_time_ms = -1;
291 stats->min_waiting_time_ms = -1;
292 stats->max_waiting_time_ms = -1;
293 } else {
294 std::sort(waiting_times_.begin(), waiting_times_.end());
295 // Find mid-point elements. If the size is odd, the two values
296 // |middle_left| and |middle_right| will both be the one middle element; if
297 // the size is even, they will be the the two neighboring elements at the
298 // middle of the list.
299 const int middle_left = waiting_times_[(waiting_times_.size() - 1) / 2];
300 const int middle_right = waiting_times_[waiting_times_.size() / 2];
301 // Calculate the average of the two. (Works also for odd sizes.)
302 stats->median_waiting_time_ms = (middle_left + middle_right) / 2;
303 stats->min_waiting_time_ms = waiting_times_.front();
304 stats->max_waiting_time_ms = waiting_times_.back();
305 double sum = 0;
306 for (auto time : waiting_times_) {
307 sum += time;
308 }
309 stats->mean_waiting_time_ms = static_cast<int>(sum / waiting_times_.size());
310 }
311
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000312 // Reset counters.
313 ResetMcu();
314 Reset();
315}
316
Steve Anton2dbc69f2017-08-24 17:15:13 -0700317NetEqLifetimeStatistics StatisticsCalculator::GetLifetimeStatistics() const {
318 return lifetime_stats_;
319}
320
Peter Kastingdce40cf2015-08-24 14:52:23 -0700321uint16_t StatisticsCalculator::CalculateQ14Ratio(size_t numerator,
Peter Kastingb7e50542015-06-11 12:55:50 -0700322 uint32_t denominator) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000323 if (numerator == 0) {
324 return 0;
325 } else if (numerator < denominator) {
326 // Ratio must be smaller than 1 in Q14.
327 assert((numerator << 14) / denominator < (1 << 14));
Peter Kastingb7e50542015-06-11 12:55:50 -0700328 return static_cast<uint16_t>((numerator << 14) / denominator);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000329 } else {
330 // Will not produce a ratio larger than 1, since this is probably an error.
331 return 1 << 14;
332 }
333}
334
335} // namespace webrtc