blob: 807d7ee4011190aaf2fd7a48ccde3c404b7f90e7 [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
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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "modules/audio_coding/neteq/delay_manager.h"
18#include "rtc_base/checks.h"
Karl Wiberge40468b2017-11-22 10:42:26 +010019#include "rtc_base/numerics/safe_conversions.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "system_wrappers/include/metrics.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000021
22namespace webrtc {
23
henrik.lundin2979f552017-05-05 05:04:16 -070024namespace {
25size_t AddIntToSizeTWithLowerCap(int a, size_t b) {
26 const size_t ret = b + a;
27 // If a + b is negative, resulting in a negative wrap, cap it to zero instead.
28 static_assert(sizeof(size_t) >= sizeof(int),
29 "int must not be wider than size_t for this to work");
30 return (a < 0 && ret > b) ? 0 : ret;
31}
32} // namespace
33
henrikg91d6ede2015-09-17 00:24:34 -070034// Allocating the static const so that it can be passed by reference to
35// RTC_DCHECK.
Henrik Lundin1bb8cf82015-08-25 13:08:04 +020036const size_t StatisticsCalculator::kLenWaitingTimes;
37
Henrik Lundin1f4ffe02015-08-19 10:46:50 +020038StatisticsCalculator::PeriodicUmaLogger::PeriodicUmaLogger(
39 const std::string& uma_name,
40 int report_interval_ms,
41 int max_value)
42 : uma_name_(uma_name),
43 report_interval_ms_(report_interval_ms),
44 max_value_(max_value),
Yves Gerey665174f2018-06-19 15:03:05 +020045 timer_(0) {}
Henrik Lundin1f4ffe02015-08-19 10:46:50 +020046
47StatisticsCalculator::PeriodicUmaLogger::~PeriodicUmaLogger() = default;
48
49void StatisticsCalculator::PeriodicUmaLogger::AdvanceClock(int step_ms) {
50 timer_ += step_ms;
51 if (timer_ < report_interval_ms_) {
52 return;
53 }
54 LogToUma(Metric());
55 Reset();
56 timer_ -= report_interval_ms_;
henrikg91d6ede2015-09-17 00:24:34 -070057 RTC_DCHECK_GE(timer_, 0);
Henrik Lundin1f4ffe02015-08-19 10:46:50 +020058}
59
60void StatisticsCalculator::PeriodicUmaLogger::LogToUma(int value) const {
asapersson53805322015-12-21 01:46:20 -080061 RTC_HISTOGRAM_COUNTS_SPARSE(uma_name_, value, 1, max_value_, 50);
Henrik Lundin1f4ffe02015-08-19 10:46:50 +020062}
63
64StatisticsCalculator::PeriodicUmaCount::PeriodicUmaCount(
65 const std::string& uma_name,
66 int report_interval_ms,
67 int max_value)
Yves Gerey665174f2018-06-19 15:03:05 +020068 : PeriodicUmaLogger(uma_name, report_interval_ms, max_value) {}
Henrik Lundin1f4ffe02015-08-19 10:46:50 +020069
70StatisticsCalculator::PeriodicUmaCount::~PeriodicUmaCount() {
71 // Log the count for the current (incomplete) interval.
72 LogToUma(Metric());
73}
74
75void StatisticsCalculator::PeriodicUmaCount::RegisterSample() {
76 ++counter_;
77}
78
79int StatisticsCalculator::PeriodicUmaCount::Metric() const {
80 return counter_;
81}
82
83void StatisticsCalculator::PeriodicUmaCount::Reset() {
84 counter_ = 0;
85}
86
87StatisticsCalculator::PeriodicUmaAverage::PeriodicUmaAverage(
88 const std::string& uma_name,
89 int report_interval_ms,
90 int max_value)
Yves Gerey665174f2018-06-19 15:03:05 +020091 : PeriodicUmaLogger(uma_name, report_interval_ms, max_value) {}
Henrik Lundin1f4ffe02015-08-19 10:46:50 +020092
93StatisticsCalculator::PeriodicUmaAverage::~PeriodicUmaAverage() {
94 // Log the average for the current (incomplete) interval.
95 LogToUma(Metric());
96}
97
98void StatisticsCalculator::PeriodicUmaAverage::RegisterSample(int value) {
99 sum_ += value;
100 ++counter_;
101}
102
103int StatisticsCalculator::PeriodicUmaAverage::Metric() const {
henrik.lundine5942132016-02-09 00:35:53 -0800104 return counter_ == 0 ? 0 : static_cast<int>(sum_ / counter_);
Henrik Lundin1f4ffe02015-08-19 10:46:50 +0200105}
106
107void StatisticsCalculator::PeriodicUmaAverage::Reset() {
108 sum_ = 0.0;
109 counter_ = 0;
110}
111
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000112StatisticsCalculator::StatisticsCalculator()
113 : preemptive_samples_(0),
114 accelerate_samples_(0),
115 added_zero_samples_(0),
minyue@webrtc.org7d721ee2015-02-18 10:01:53 +0000116 expanded_speech_samples_(0),
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000117 expanded_noise_samples_(0),
118 discarded_packets_(0),
119 lost_timestamps_(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;
139 added_zero_samples_ = 0;
minyue@webrtc.org7d721ee2015-02-18 10:01:53 +0000140 expanded_speech_samples_ = 0;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000141 expanded_noise_samples_ = 0;
minyue@webrtc.org2c1bcf22015-02-17 10:17:09 +0000142 secondary_decoded_samples_ = 0;
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200143 discarded_secondary_packets_ = 0;
Henrik Lundin1bb8cf82015-08-25 13:08:04 +0200144 waiting_times_.clear();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000145}
146
147void StatisticsCalculator::ResetMcu() {
148 discarded_packets_ = 0;
149 lost_timestamps_ = 0;
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53 +0000150 timestamps_since_last_report_ = 0;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000151}
152
Gustaf Ullberg9a2e9062017-09-18 09:28:20 +0200153void StatisticsCalculator::ExpandedVoiceSamples(size_t num_samples,
154 bool is_new_concealment_event) {
minyue@webrtc.org7d721ee2015-02-18 10:01:53 +0000155 expanded_speech_samples_ += num_samples;
Alex Narest7ff6ca52018-02-07 18:46:33 +0100156 ConcealedSamplesCorrection(rtc::dchecked_cast<int>(num_samples), true);
Gustaf Ullberg9a2e9062017-09-18 09:28:20 +0200157 lifetime_stats_.concealment_events += is_new_concealment_event;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000158}
159
Gustaf Ullberg9a2e9062017-09-18 09:28:20 +0200160void StatisticsCalculator::ExpandedNoiseSamples(size_t num_samples,
161 bool is_new_concealment_event) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000162 expanded_noise_samples_ += num_samples;
Alex Narest7ff6ca52018-02-07 18:46:33 +0100163 ConcealedSamplesCorrection(rtc::dchecked_cast<int>(num_samples), false);
Gustaf Ullberg9a2e9062017-09-18 09:28:20 +0200164 lifetime_stats_.concealment_events += is_new_concealment_event;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000165}
166
henrik.lundin2979f552017-05-05 05:04:16 -0700167void StatisticsCalculator::ExpandedVoiceSamplesCorrection(int num_samples) {
168 expanded_speech_samples_ =
169 AddIntToSizeTWithLowerCap(num_samples, expanded_speech_samples_);
Alex Narest7ff6ca52018-02-07 18:46:33 +0100170 ConcealedSamplesCorrection(num_samples, true);
henrik.lundin2979f552017-05-05 05:04:16 -0700171}
172
173void StatisticsCalculator::ExpandedNoiseSamplesCorrection(int num_samples) {
174 expanded_noise_samples_ =
175 AddIntToSizeTWithLowerCap(num_samples, expanded_noise_samples_);
Alex Narest7ff6ca52018-02-07 18:46:33 +0100176 ConcealedSamplesCorrection(num_samples, false);
Henrik Lundinac0a5032017-09-25 12:22:46 +0200177}
178
Alex Narest7ff6ca52018-02-07 18:46:33 +0100179void StatisticsCalculator::ConcealedSamplesCorrection(int num_samples,
180 bool is_voice) {
Henrik Lundinac0a5032017-09-25 12:22:46 +0200181 if (num_samples < 0) {
182 // Store negative correction to subtract from future positive additions.
183 // See also the function comment in the header file.
184 concealed_samples_correction_ -= num_samples;
Alex Narest7ff6ca52018-02-07 18:46:33 +0100185 if (is_voice) {
186 voice_concealed_samples_correction_ -= num_samples;
187 }
Henrik Lundinac0a5032017-09-25 12:22:46 +0200188 return;
189 }
190
191 const size_t canceled_out =
192 std::min(static_cast<size_t>(num_samples), concealed_samples_correction_);
193 concealed_samples_correction_ -= canceled_out;
194 lifetime_stats_.concealed_samples += num_samples - canceled_out;
Alex Narest7ff6ca52018-02-07 18:46:33 +0100195
196 if (is_voice) {
197 const size_t voice_canceled_out = std::min(
198 static_cast<size_t>(num_samples), voice_concealed_samples_correction_);
199 voice_concealed_samples_correction_ -= voice_canceled_out;
200 lifetime_stats_.voice_concealed_samples += num_samples - voice_canceled_out;
201 }
henrik.lundin2979f552017-05-05 05:04:16 -0700202}
203
Peter Kastingdce40cf2015-08-24 14:52:23 -0700204void StatisticsCalculator::PreemptiveExpandedSamples(size_t num_samples) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000205 preemptive_samples_ += num_samples;
Ivo Creusend1c2f782018-09-13 14:39:55 +0200206 operations_and_state_.preemptive_samples += num_samples;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000207}
208
Peter Kastingdce40cf2015-08-24 14:52:23 -0700209void StatisticsCalculator::AcceleratedSamples(size_t num_samples) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000210 accelerate_samples_ += num_samples;
Ivo Creusend1c2f782018-09-13 14:39:55 +0200211 operations_and_state_.accelerate_samples += num_samples;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000212}
213
Peter Kastingdce40cf2015-08-24 14:52:23 -0700214void StatisticsCalculator::AddZeros(size_t num_samples) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000215 added_zero_samples_ += num_samples;
216}
217
Peter Kastingdce40cf2015-08-24 14:52:23 -0700218void StatisticsCalculator::PacketsDiscarded(size_t num_packets) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000219 discarded_packets_ += num_packets;
220}
221
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200222void StatisticsCalculator::SecondaryPacketsDiscarded(size_t num_packets) {
223 discarded_secondary_packets_ += num_packets;
224}
225
Peter Kastingdce40cf2015-08-24 14:52:23 -0700226void StatisticsCalculator::LostSamples(size_t num_samples) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000227 lost_timestamps_ += num_samples;
228}
229
Peter Kastingdce40cf2015-08-24 14:52:23 -0700230void StatisticsCalculator::IncreaseCounter(size_t num_samples, int fs_hz) {
231 const int time_step_ms =
232 rtc::CheckedDivExact(static_cast<int>(1000 * num_samples), fs_hz);
Henrik Lundin1f4ffe02015-08-19 10:46:50 +0200233 delayed_packet_outage_counter_.AdvanceClock(time_step_ms);
234 excess_buffer_delay_.AdvanceClock(time_step_ms);
Minyue Li34d990f2018-10-16 16:55:52 +0200235 buffer_full_counter_.AdvanceClock(time_step_ms);
Peter Kastingb7e50542015-06-11 12:55:50 -0700236 timestamps_since_last_report_ += static_cast<uint32_t>(num_samples);
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53 +0000237 if (timestamps_since_last_report_ >
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000238 static_cast<uint32_t>(fs_hz * kMaxReportPeriod)) {
239 lost_timestamps_ = 0;
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53 +0000240 timestamps_since_last_report_ = 0;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000241 discarded_packets_ = 0;
242 }
Steve Anton2dbc69f2017-08-24 17:15:13 -0700243 lifetime_stats_.total_samples_received += num_samples;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000244}
245
Gustaf Ullbergb0a02072017-10-02 12:00:34 +0200246void StatisticsCalculator::JitterBufferDelay(size_t num_samples,
247 uint64_t waiting_time_ms) {
248 lifetime_stats_.jitter_buffer_delay_ms += waiting_time_ms * num_samples;
249}
250
minyue@webrtc.org2c1bcf22015-02-17 10:17:09 +0000251void StatisticsCalculator::SecondaryDecodedSamples(int num_samples) {
252 secondary_decoded_samples_ += num_samples;
253}
254
Ivo Creusendc6d5532018-09-27 11:43:42 +0200255void StatisticsCalculator::FlushedPacketBuffer() {
256 operations_and_state_.packet_buffer_flushes++;
Minyue Li34d990f2018-10-16 16:55:52 +0200257 buffer_full_counter_.RegisterSample();
Ivo Creusendc6d5532018-09-27 11:43:42 +0200258}
259
Henrik Lundinbef77e22015-08-18 14:58:09 +0200260void StatisticsCalculator::LogDelayedPacketOutageEvent(int outage_duration_ms) {
asaperssona2c58e22016-03-07 01:52:59 -0800261 RTC_HISTOGRAM_COUNTS("WebRTC.Audio.DelayedPacketOutageEventMs",
262 outage_duration_ms, 1 /* min */, 2000 /* max */,
263 100 /* bucket count */);
Henrik Lundin1f4ffe02015-08-19 10:46:50 +0200264 delayed_packet_outage_counter_.RegisterSample();
Henrik Lundinbef77e22015-08-18 14:58:09 +0200265}
266
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000267void StatisticsCalculator::StoreWaitingTime(int waiting_time_ms) {
Henrik Lundin1f4ffe02015-08-19 10:46:50 +0200268 excess_buffer_delay_.RegisterSample(waiting_time_ms);
henrikg91d6ede2015-09-17 00:24:34 -0700269 RTC_DCHECK_LE(waiting_times_.size(), kLenWaitingTimes);
henrik.lundin1e346b22015-08-27 13:41:02 -0700270 if (waiting_times_.size() == kLenWaitingTimes) {
Henrik Lundin1bb8cf82015-08-25 13:08:04 +0200271 // Erase first value.
272 waiting_times_.pop_front();
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000273 }
Henrik Lundin1bb8cf82015-08-25 13:08:04 +0200274 waiting_times_.push_back(waiting_time_ms);
Ivo Creusend1c2f782018-09-13 14:39:55 +0200275 operations_and_state_.last_waiting_time_ms = waiting_time_ms;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000276}
277
Yves Gerey665174f2018-06-19 15:03:05 +0200278void StatisticsCalculator::GetNetworkStatistics(int fs_hz,
279 size_t num_samples_in_buffers,
280 size_t samples_per_packet,
281 NetEqNetworkStatistics* stats) {
Henrik Lundindccfc402017-09-25 12:30:58 +0200282 RTC_DCHECK_GT(fs_hz, 0);
283 RTC_DCHECK(stats);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000284
285 stats->added_zero_samples = added_zero_samples_;
Peter Kastingb7e50542015-06-11 12:55:50 -0700286 stats->current_buffer_size_ms =
287 static_cast<uint16_t>(num_samples_in_buffers * 1000 / fs_hz);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000288
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53 +0000289 stats->packet_loss_rate =
290 CalculateQ14Ratio(lost_timestamps_, timestamps_since_last_report_);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000291
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53 +0000292 stats->accelerate_rate =
293 CalculateQ14Ratio(accelerate_samples_, timestamps_since_last_report_);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000294
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53 +0000295 stats->preemptive_rate =
296 CalculateQ14Ratio(preemptive_samples_, timestamps_since_last_report_);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000297
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53 +0000298 stats->expand_rate =
minyue@webrtc.org7d721ee2015-02-18 10:01:53 +0000299 CalculateQ14Ratio(expanded_speech_samples_ + expanded_noise_samples_,
henrik.lundin@webrtc.org5e3d7c72014-10-08 12:10:53 +0000300 timestamps_since_last_report_);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000301
Yves Gerey665174f2018-06-19 15:03:05 +0200302 stats->speech_expand_rate = CalculateQ14Ratio(expanded_speech_samples_,
303 timestamps_since_last_report_);
minyue@webrtc.org7d721ee2015-02-18 10:01:53 +0000304
Yves Gerey665174f2018-06-19 15:03:05 +0200305 stats->secondary_decoded_rate = CalculateQ14Ratio(
306 secondary_decoded_samples_, timestamps_since_last_report_);
minyue@webrtc.org2c1bcf22015-02-17 10:17:09 +0000307
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200308 const size_t discarded_secondary_samples =
309 discarded_secondary_packets_ * samples_per_packet;
Yves Gerey665174f2018-06-19 15:03:05 +0200310 stats->secondary_discarded_rate =
311 CalculateQ14Ratio(discarded_secondary_samples,
312 static_cast<uint32_t>(discarded_secondary_samples +
313 secondary_decoded_samples_));
minyue-webrtc0c3ca752017-08-23 15:59:38 +0200314
Henrik Lundin1bb8cf82015-08-25 13:08:04 +0200315 if (waiting_times_.size() == 0) {
316 stats->mean_waiting_time_ms = -1;
317 stats->median_waiting_time_ms = -1;
318 stats->min_waiting_time_ms = -1;
319 stats->max_waiting_time_ms = -1;
320 } else {
321 std::sort(waiting_times_.begin(), waiting_times_.end());
322 // Find mid-point elements. If the size is odd, the two values
323 // |middle_left| and |middle_right| will both be the one middle element; if
324 // the size is even, they will be the the two neighboring elements at the
325 // middle of the list.
326 const int middle_left = waiting_times_[(waiting_times_.size() - 1) / 2];
327 const int middle_right = waiting_times_[waiting_times_.size() / 2];
328 // Calculate the average of the two. (Works also for odd sizes.)
329 stats->median_waiting_time_ms = (middle_left + middle_right) / 2;
330 stats->min_waiting_time_ms = waiting_times_.front();
331 stats->max_waiting_time_ms = waiting_times_.back();
332 double sum = 0;
333 for (auto time : waiting_times_) {
334 sum += time;
335 }
336 stats->mean_waiting_time_ms = static_cast<int>(sum / waiting_times_.size());
337 }
338
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000339 // Reset counters.
340 ResetMcu();
341 Reset();
342}
343
Henrik Lundindccfc402017-09-25 12:30:58 +0200344void StatisticsCalculator::PopulateDelayManagerStats(
345 int ms_per_packet,
346 const DelayManager& delay_manager,
347 NetEqNetworkStatistics* stats) {
348 RTC_DCHECK(stats);
349 stats->preferred_buffer_size_ms =
350 (delay_manager.TargetLevel() >> 8) * ms_per_packet;
351 stats->jitter_peaks_found = delay_manager.PeakFound();
352 stats->clockdrift_ppm =
353 rtc::saturated_cast<int32_t>(delay_manager.EstimatedClockDriftPpm());
354}
355
Steve Anton2dbc69f2017-08-24 17:15:13 -0700356NetEqLifetimeStatistics StatisticsCalculator::GetLifetimeStatistics() const {
357 return lifetime_stats_;
358}
359
Ivo Creusend1c2f782018-09-13 14:39:55 +0200360NetEqOperationsAndState StatisticsCalculator::GetOperationsAndState() const {
361 return operations_and_state_;
362}
363
Peter Kastingdce40cf2015-08-24 14:52:23 -0700364uint16_t StatisticsCalculator::CalculateQ14Ratio(size_t numerator,
Peter Kastingb7e50542015-06-11 12:55:50 -0700365 uint32_t denominator) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000366 if (numerator == 0) {
367 return 0;
368 } else if (numerator < denominator) {
369 // Ratio must be smaller than 1 in Q14.
370 assert((numerator << 14) / denominator < (1 << 14));
Peter Kastingb7e50542015-06-11 12:55:50 -0700371 return static_cast<uint16_t>((numerator << 14) / denominator);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000372 } else {
373 // Will not produce a ratio larger than 1, since this is probably an error.
374 return 1 << 14;
375 }
376}
377
378} // namespace webrtc