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 
15 namespace 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 
24 DelayPeakDetector::~DelayPeakDetector() = default;
25 
DelayPeakDetector()26 DelayPeakDetector::DelayPeakDetector()
27   : peak_found_(false),
28     peak_detection_threshold_(0),
29     peak_period_counter_ms_(-1) {
30 }
31 
Reset()32 void 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.
SetPacketAudioLength(int length_ms)39 void DelayPeakDetector::SetPacketAudioLength(int length_ms) {
40   if (length_ms > 0) {
41     peak_detection_threshold_ = kPeakHeightMs / length_ms;
42   }
43 }
44 
peak_found()45 bool DelayPeakDetector::peak_found() {
46   return peak_found_;
47 }
48 
MaxPeakHeight() const49 int 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 
MaxPeakPeriod() const58 int 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 
Update(int inter_arrival_time,int target_level)67 bool 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 
IncrementCounter(int inc_ms)100 void DelayPeakDetector::IncrementCounter(int inc_ms) {
101   if (peak_period_counter_ms_ >= 0) {
102     peak_period_counter_ms_ += inc_ms;
103   }
104 }
105 
CheckPeakConditions()106 bool 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