1/*
2 *  Copyright (c) 2012 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/delay_peak_detector.h"
12
13#include <algorithm>  // max
14
15namespace webrtc {
16
17// The DelayPeakDetector keeps track of severe inter-arrival times, called
18// delay peaks. When a peak is observed, the "height" (the time elapsed since
19// the previous packet arrival) and the peak "period" (the time since the last
20// observed peak) is recorded in a vector. When enough peaks have been observed,
21// peak-mode is engaged and the DelayManager asks the DelayPeakDetector for
22// the worst peak height.
23
24DelayPeakDetector::~DelayPeakDetector() = default;
25
26DelayPeakDetector::DelayPeakDetector()
27  : peak_found_(false),
28    peak_detection_threshold_(0),
29    peak_period_counter_ms_(-1) {
30}
31
32void DelayPeakDetector::Reset() {
33  peak_period_counter_ms_ = -1;  // Indicate that next peak is the first.
34  peak_found_ = false;
35  peak_history_.clear();
36}
37
38// Calculates the threshold in number of packets.
39void DelayPeakDetector::SetPacketAudioLength(int length_ms) {
40  if (length_ms > 0) {
41    peak_detection_threshold_ = kPeakHeightMs / length_ms;
42  }
43}
44
45bool DelayPeakDetector::peak_found() {
46  return peak_found_;
47}
48
49int DelayPeakDetector::MaxPeakHeight() const {
50  int max_height = -1;  // Returns -1 for an empty history.
51  std::list<Peak>::const_iterator it;
52  for (it = peak_history_.begin(); it != peak_history_.end(); ++it) {
53    max_height = std::max(max_height, it->peak_height_packets);
54  }
55  return max_height;
56}
57
58int DelayPeakDetector::MaxPeakPeriod() const {
59  int max_period = -1;  // Returns -1 for an empty history.
60  std::list<Peak>::const_iterator it;
61  for (it = peak_history_.begin(); it != peak_history_.end(); ++it) {
62    max_period = std::max(max_period, it->period_ms);
63  }
64  return max_period;
65}
66
67bool DelayPeakDetector::Update(int inter_arrival_time, int target_level) {
68  if (inter_arrival_time > target_level + peak_detection_threshold_ ||
69      inter_arrival_time > 2 * target_level) {
70    // A delay peak is observed.
71    if (peak_period_counter_ms_ == -1) {
72      // This is the first peak. Reset the period counter.
73      peak_period_counter_ms_ = 0;
74    } else if (peak_period_counter_ms_ <= kMaxPeakPeriodMs) {
75      // This is not the first peak, and the period is valid.
76      // Store peak data in the vector.
77      Peak peak_data;
78      peak_data.period_ms = peak_period_counter_ms_;
79      peak_data.peak_height_packets = inter_arrival_time;
80      peak_history_.push_back(peak_data);
81      while (peak_history_.size() > kMaxNumPeaks) {
82        // Delete the oldest data point.
83        peak_history_.pop_front();
84      }
85      peak_period_counter_ms_ = 0;
86    } else if (peak_period_counter_ms_ <= 2 * kMaxPeakPeriodMs) {
87      // Invalid peak due to too long period. Reset period counter and start
88      // looking for next peak.
89      peak_period_counter_ms_ = 0;
90    } else {
91      // More than 2 times the maximum period has elapsed since the last peak
92      // was registered. It seams that the network conditions have changed.
93      // Reset the peak statistics.
94      Reset();
95    }
96  }
97  return CheckPeakConditions();
98}
99
100void DelayPeakDetector::IncrementCounter(int inc_ms) {
101  if (peak_period_counter_ms_ >= 0) {
102    peak_period_counter_ms_ += inc_ms;
103  }
104}
105
106bool DelayPeakDetector::CheckPeakConditions() {
107  size_t s = peak_history_.size();
108  if (s >= kMinPeaksToTrigger &&
109      peak_period_counter_ms_ <= 2 * MaxPeakPeriod()) {
110    peak_found_ = true;
111  } else {
112    peak_found_ = false;
113  }
114  return peak_found_;
115}
116}  // namespace webrtc
117