1/*
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
11#include "webrtc/modules/audio_coding/neteq/statistics_calculator.h"
12
13#include <assert.h>
14#include <string.h>  // memset
15
16#include "webrtc/modules/audio_coding/neteq/decision_logic.h"
17#include "webrtc/modules/audio_coding/neteq/delay_manager.h"
18
19namespace webrtc {
20
21StatisticsCalculator::StatisticsCalculator()
22    : preemptive_samples_(0),
23      accelerate_samples_(0),
24      added_zero_samples_(0),
25      expanded_voice_samples_(0),
26      expanded_noise_samples_(0),
27      discarded_packets_(0),
28      lost_timestamps_(0),
29      last_report_timestamp_(0),
30      len_waiting_times_(0),
31      next_waiting_time_index_(0) {
32  memset(waiting_times_, 0, kLenWaitingTimes * sizeof(waiting_times_[0]));
33}
34
35void StatisticsCalculator::Reset() {
36  preemptive_samples_ = 0;
37  accelerate_samples_ = 0;
38  added_zero_samples_ = 0;
39  expanded_voice_samples_ = 0;
40  expanded_noise_samples_ = 0;
41}
42
43void StatisticsCalculator::ResetMcu() {
44  discarded_packets_ = 0;
45  lost_timestamps_ = 0;
46  last_report_timestamp_ = 0;
47}
48
49void StatisticsCalculator::ResetWaitingTimeStatistics() {
50  memset(waiting_times_, 0, kLenWaitingTimes * sizeof(waiting_times_[0]));
51  len_waiting_times_ = 0;
52  next_waiting_time_index_ = 0;
53}
54
55void StatisticsCalculator::ExpandedVoiceSamples(int num_samples) {
56  expanded_voice_samples_ += num_samples;
57}
58
59void StatisticsCalculator::ExpandedNoiseSamples(int num_samples) {
60  expanded_noise_samples_ += num_samples;
61}
62
63void StatisticsCalculator::PreemptiveExpandedSamples(int num_samples) {
64  preemptive_samples_ += num_samples;
65}
66
67void StatisticsCalculator::AcceleratedSamples(int num_samples) {
68  accelerate_samples_ += num_samples;
69}
70
71void StatisticsCalculator::AddZeros(int num_samples) {
72  added_zero_samples_ += num_samples;
73}
74
75void StatisticsCalculator::PacketsDiscarded(int num_packets) {
76  discarded_packets_ += num_packets;
77}
78
79void StatisticsCalculator::LostSamples(int num_samples) {
80  lost_timestamps_ += num_samples;
81}
82
83void StatisticsCalculator::IncreaseCounter(int num_samples, int fs_hz) {
84  last_report_timestamp_ += num_samples;
85  if (last_report_timestamp_ >
86      static_cast<uint32_t>(fs_hz * kMaxReportPeriod)) {
87    lost_timestamps_ = 0;
88    last_report_timestamp_ = 0;
89    discarded_packets_ = 0;
90  }
91}
92
93void StatisticsCalculator::StoreWaitingTime(int waiting_time_ms) {
94  assert(next_waiting_time_index_ < kLenWaitingTimes);
95  waiting_times_[next_waiting_time_index_] = waiting_time_ms;
96  next_waiting_time_index_++;
97  if (next_waiting_time_index_ >= kLenWaitingTimes) {
98    next_waiting_time_index_ = 0;
99  }
100  if (len_waiting_times_ < kLenWaitingTimes) {
101    len_waiting_times_++;
102  }
103}
104
105void StatisticsCalculator::GetNetworkStatistics(
106    int fs_hz,
107    int num_samples_in_buffers,
108    int samples_per_packet,
109    const DelayManager& delay_manager,
110    const DecisionLogic& decision_logic,
111    NetEqNetworkStatistics *stats) {
112  if (fs_hz <= 0 || !stats) {
113    assert(false);
114    return;
115  }
116
117  stats->added_zero_samples = added_zero_samples_;
118  stats->current_buffer_size_ms = num_samples_in_buffers * 1000 / fs_hz;
119  const int ms_per_packet = decision_logic.packet_length_samples() /
120      (fs_hz / 1000);
121  stats->preferred_buffer_size_ms = (delay_manager.TargetLevel() >> 8) *
122      ms_per_packet;
123  stats->jitter_peaks_found = delay_manager.PeakFound();
124  stats->clockdrift_ppm = delay_manager.AverageIAT();
125
126  stats->packet_loss_rate = CalculateQ14Ratio(lost_timestamps_,
127                                              last_report_timestamp_);
128
129  const unsigned discarded_samples = discarded_packets_ * samples_per_packet;
130  stats->packet_discard_rate = CalculateQ14Ratio(discarded_samples,
131                                                 last_report_timestamp_);
132
133  stats->accelerate_rate = CalculateQ14Ratio(accelerate_samples_,
134                                             last_report_timestamp_);
135
136  stats->preemptive_rate = CalculateQ14Ratio(preemptive_samples_,
137                                             last_report_timestamp_);
138
139  stats->expand_rate = CalculateQ14Ratio(expanded_voice_samples_ +
140                                         expanded_noise_samples_,
141                                         last_report_timestamp_);
142
143  // Reset counters.
144  ResetMcu();
145  Reset();
146}
147
148void StatisticsCalculator::WaitingTimes(std::vector<int>* waiting_times) {
149  if (!waiting_times) {
150    return;
151  }
152  waiting_times->assign(waiting_times_, waiting_times_ + len_waiting_times_);
153  ResetWaitingTimeStatistics();
154}
155
156int StatisticsCalculator::CalculateQ14Ratio(uint32_t numerator,
157                                            uint32_t denominator) {
158  if (numerator == 0) {
159    return 0;
160  } else if (numerator < denominator) {
161    // Ratio must be smaller than 1 in Q14.
162    assert((numerator << 14) / denominator < (1 << 14));
163    return (numerator << 14) / denominator;
164  } else {
165    // Will not produce a ratio larger than 1, since this is probably an error.
166    return 1 << 14;
167  }
168}
169
170}  // namespace webrtc
171