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