webrtc/modules/audio_coding/neteq/delay_peak_detector.cc
Jakob Ivarsson 39b934ba2e Add NetEq config flag that enables RTX handling.
When enabled, the delay manager is updated with reordered packets. It also makes the peak detector ignore the reordered packets.

Change-Id: I2bdc99764cc76b15e613ed3dc75f83aaf66eee4e
Bug: webrtc:10178
Reviewed-on: https://webrtc-review.googlesource.com/c/116481
Commit-Queue: Jakob Ivarsson‎ <jakobi@webrtc.org>
Reviewed-by: Minyue Li <minyue@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#26187}
2019-01-10 10:04:34 +00:00

134 lines
4.7 KiB
C++

/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "modules/audio_coding/neteq/delay_peak_detector.h"
#include <algorithm>
#include "rtc_base/checks.h"
#include "system_wrappers/include/field_trial.h"
namespace webrtc {
// The DelayPeakDetector keeps track of severe inter-arrival times, called
// delay peaks. When a peak is observed, the "height" (the time elapsed since
// the previous packet arrival) and the peak "period" (the time since the last
// observed peak) is recorded in a vector. When enough peaks have been observed,
// peak-mode is engaged and the DelayManager asks the DelayPeakDetector for
// the worst peak height.
DelayPeakDetector::~DelayPeakDetector() = default;
DelayPeakDetector::DelayPeakDetector(const TickTimer* tick_timer,
bool ignore_reordered_packets)
: peak_found_(false),
peak_detection_threshold_(0),
tick_timer_(tick_timer),
ignore_reordered_packets_(ignore_reordered_packets),
frame_length_change_experiment_(
field_trial::IsEnabled("WebRTC-Audio-NetEqFramelengthExperiment")) {
RTC_DCHECK(!peak_period_stopwatch_);
}
void DelayPeakDetector::Reset() {
peak_period_stopwatch_.reset();
peak_found_ = false;
peak_history_.clear();
}
// Calculates the threshold in number of packets.
void DelayPeakDetector::SetPacketAudioLength(int length_ms) {
if (length_ms > 0) {
if (frame_length_change_experiment_) {
peak_detection_threshold_ = std::max(2, kPeakHeightMs / length_ms);
} else {
peak_detection_threshold_ = kPeakHeightMs / length_ms;
}
}
if (frame_length_change_experiment_) {
peak_history_.clear();
}
}
bool DelayPeakDetector::peak_found() {
return peak_found_;
}
int DelayPeakDetector::MaxPeakHeight() const {
int max_height = -1; // Returns -1 for an empty history.
std::list<Peak>::const_iterator it;
for (it = peak_history_.begin(); it != peak_history_.end(); ++it) {
max_height = std::max(max_height, it->peak_height_packets);
}
return max_height;
}
uint64_t DelayPeakDetector::MaxPeakPeriod() const {
auto max_period_element = std::max_element(
peak_history_.begin(), peak_history_.end(),
[](Peak a, Peak b) { return a.period_ms < b.period_ms; });
if (max_period_element == peak_history_.end()) {
return 0; // |peak_history_| is empty.
}
RTC_DCHECK_GT(max_period_element->period_ms, 0);
return max_period_element->period_ms;
}
bool DelayPeakDetector::Update(int inter_arrival_time,
bool reordered,
int target_level) {
if (ignore_reordered_packets_ && reordered) {
return CheckPeakConditions();
}
if (inter_arrival_time > target_level + peak_detection_threshold_ ||
inter_arrival_time > 2 * target_level) {
// A delay peak is observed.
if (!peak_period_stopwatch_) {
// This is the first peak. Reset the period counter.
peak_period_stopwatch_ = tick_timer_->GetNewStopwatch();
} else if (peak_period_stopwatch_->ElapsedMs() > 0) {
if (peak_period_stopwatch_->ElapsedMs() <= kMaxPeakPeriodMs) {
// This is not the first peak, and the period is valid.
// Store peak data in the vector.
Peak peak_data;
peak_data.period_ms = peak_period_stopwatch_->ElapsedMs();
peak_data.peak_height_packets = inter_arrival_time;
peak_history_.push_back(peak_data);
while (peak_history_.size() > kMaxNumPeaks) {
// Delete the oldest data point.
peak_history_.pop_front();
}
peak_period_stopwatch_ = tick_timer_->GetNewStopwatch();
} else if (peak_period_stopwatch_->ElapsedMs() <= 2 * kMaxPeakPeriodMs) {
// Invalid peak due to too long period. Reset period counter and start
// looking for next peak.
peak_period_stopwatch_ = tick_timer_->GetNewStopwatch();
} else {
// More than 2 times the maximum period has elapsed since the last peak
// was registered. It seams that the network conditions have changed.
// Reset the peak statistics.
Reset();
}
}
}
return CheckPeakConditions();
}
bool DelayPeakDetector::CheckPeakConditions() {
size_t s = peak_history_.size();
if (s >= kMinPeaksToTrigger &&
peak_period_stopwatch_->ElapsedMs() <= 2 * MaxPeakPeriod()) {
peak_found_ = true;
} else {
peak_found_ = false;
}
return peak_found_;
}
} // namespace webrtc