Remove inter-arrival delay mode from DelayManager.

Also remove the delay peak detector which is no longer used.

This should be a no-op since relative arrival delay mode is used by default.

Bug: webrtc:10333
Change-Id: Ifa326b762d52f16f9dc5f3da2874139faf1022da
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/164462
Reviewed-by: Ivo Creusen <ivoc@webrtc.org>
Commit-Queue: Jakob Ivarsson <jakobi@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30179}
This commit is contained in:
Jakob Ivarsson 2020-01-07 17:07:40 +01:00 committed by Commit Bot
parent 57218b4e22
commit bd5874accf
14 changed files with 18 additions and 714 deletions

View File

@ -951,8 +951,6 @@ rtc_library("neteq") {
"neteq/decoder_database.h",
"neteq/delay_manager.cc",
"neteq/delay_manager.h",
"neteq/delay_peak_detector.cc",
"neteq/delay_peak_detector.h",
"neteq/dsp_helper.cc",
"neteq/dsp_helper.h",
"neteq/dtmf_buffer.cc",
@ -2027,7 +2025,6 @@ if (rtc_include_tests) {
"neteq/decision_logic_unittest.cc",
"neteq/decoder_database_unittest.cc",
"neteq/delay_manager_unittest.cc",
"neteq/delay_peak_detector_unittest.cc",
"neteq/dsp_helper_unittest.cc",
"neteq/dtmf_buffer_unittest.cc",
"neteq/dtmf_tone_generator_unittest.cc",
@ -2035,7 +2032,6 @@ if (rtc_include_tests) {
"neteq/histogram_unittest.cc",
"neteq/merge_unittest.cc",
"neteq/mock/mock_decoder_database.h",
"neteq/mock/mock_delay_peak_detector.h",
"neteq/mock/mock_dtmf_buffer.h",
"neteq/mock/mock_dtmf_tone_generator.h",
"neteq/mock/mock_expand.h",

View File

@ -33,11 +33,9 @@ constexpr int kDefaultTargetLevelWindowMs = 100;
namespace webrtc {
DecisionLogic::DecisionLogic(NetEqController::Config config)
: delay_peak_detector_(config.tick_timer, config.enable_rtx_handling),
delay_manager_(DelayManager::Create(config.max_packets_in_buffer,
: delay_manager_(DelayManager::Create(config.max_packets_in_buffer,
config.base_min_delay_ms,
config.enable_rtx_handling,
&delay_peak_detector_,
config.tick_timer)),
tick_timer_(config.tick_timer),
disallow_time_stretching_(!config.allow_time_stretching),

View File

@ -16,7 +16,6 @@
#include "api/neteq/tick_timer.h"
#include "modules/audio_coding/neteq/buffer_level_filter.h"
#include "modules/audio_coding/neteq/delay_manager.h"
#include "modules/audio_coding/neteq/delay_peak_detector.h"
#include "rtc_base/constructor_magic.h"
#include "rtc_base/experiments/field_trial_parser.h"
@ -97,7 +96,7 @@ class DecisionLogic : public NetEqController {
int GetBaseMinimumDelay() const override {
return delay_manager_->GetBaseMinimumDelay();
}
bool PeakFound() const override { return delay_manager_->PeakFound(); }
bool PeakFound() const override { return false; }
int GetFilteredBufferLevel() const override {
return buffer_level_filter_.filtered_current_level();
@ -172,7 +171,6 @@ class DecisionLogic : public NetEqController {
// Checks if num_consecutive_expands_ >= kMaxWaitForPacket.
bool MaxWaitForPacket() const;
DelayPeakDetector delay_peak_detector_;
std::unique_ptr<DelayManager> delay_manager_;
BufferLevelFilter buffer_level_filter_;
const TickTimer* tick_timer_;

View File

@ -17,7 +17,6 @@
#include "modules/audio_coding/neteq/buffer_level_filter.h"
#include "modules/audio_coding/neteq/decoder_database.h"
#include "modules/audio_coding/neteq/delay_manager.h"
#include "modules/audio_coding/neteq/delay_peak_detector.h"
#include "modules/audio_coding/neteq/packet_buffer.h"
#include "modules/audio_coding/neteq/statistics_calculator.h"
#include "test/gtest.h"

View File

@ -19,7 +19,6 @@
#include <numeric>
#include <string>
#include "modules/audio_coding/neteq/delay_peak_detector.h"
#include "modules/audio_coding/neteq/histogram.h"
#include "modules/include/module_common_types_public.h"
#include "rtc_base/checks.h"
@ -103,16 +102,13 @@ namespace webrtc {
DelayManager::DelayManager(size_t max_packets_in_buffer,
int base_minimum_delay_ms,
int histogram_quantile,
HistogramMode histogram_mode,
bool enable_rtx_handling,
DelayPeakDetector* peak_detector,
const TickTimer* tick_timer,
std::unique_ptr<Histogram> histogram)
: first_packet_received_(false),
max_packets_in_buffer_(max_packets_in_buffer),
histogram_(std::move(histogram)),
histogram_quantile_(histogram_quantile),
histogram_mode_(histogram_mode),
tick_timer_(tick_timer),
base_minimum_delay_ms_(base_minimum_delay_ms),
effective_minimum_delay_ms_(base_minimum_delay_ms),
@ -123,13 +119,9 @@ DelayManager::DelayManager(size_t max_packets_in_buffer,
last_timestamp_(0),
minimum_delay_ms_(0),
maximum_delay_ms_(0),
peak_detector_(*peak_detector),
last_pack_cng_or_dtmf_(1),
frame_length_change_experiment_(
field_trial::IsEnabled("WebRTC-Audio-NetEqFramelengthExperiment")),
enable_rtx_handling_(enable_rtx_handling),
extra_delay_ms_(GetExtraDelayMs()) {
assert(peak_detector); // Should never be NULL.
RTC_CHECK(histogram_);
RTC_DCHECK_GE(base_minimum_delay_ms_, 0);
@ -140,16 +132,14 @@ std::unique_ptr<DelayManager> DelayManager::Create(
size_t max_packets_in_buffer,
int base_minimum_delay_ms,
bool enable_rtx_handling,
DelayPeakDetector* peak_detector,
const TickTimer* tick_timer) {
const HistogramMode mode = RELATIVE_ARRIVAL_DELAY;
DelayHistogramConfig config = GetDelayHistogramConfig();
const int quantile = config.quantile;
std::unique_ptr<Histogram> histogram = std::make_unique<Histogram>(
kDelayBuckets, config.forget_factor, config.start_forget_weight);
return std::make_unique<DelayManager>(
max_packets_in_buffer, base_minimum_delay_ms, quantile, mode,
enable_rtx_handling, peak_detector, tick_timer, std::move(histogram));
max_packets_in_buffer, base_minimum_delay_ms, quantile,
enable_rtx_handling, tick_timer, std::move(histogram));
}
DelayManager::~DelayManager() {}
@ -193,19 +183,16 @@ absl::optional<int> DelayManager::Update(uint16_t sequence_number,
// Inter-arrival time (IAT) in integer "packet times" (rounding down). This
// is the value added to the inter-arrival time histogram.
int iat_ms = packet_iat_stopwatch_->ElapsedMs();
int iat_packets = iat_ms / packet_len_ms;
// Check for discontinuous packet sequence and re-ordering.
if (IsNewerSequenceNumber(sequence_number, last_seq_no_ + 1)) {
// Compensate for gap in the sequence numbers. Reduce IAT with the
// expected extra time due to lost packets.
int packet_offset =
static_cast<uint16_t>(sequence_number - last_seq_no_ - 1);
iat_packets -= packet_offset;
iat_ms -= packet_offset * packet_len_ms;
} else if (!IsNewerSequenceNumber(sequence_number, last_seq_no_)) {
int packet_offset =
static_cast<uint16_t>(last_seq_no_ + 1 - sequence_number);
iat_packets += packet_offset;
iat_ms += packet_offset * packet_len_ms;
reordered = true;
}
@ -218,25 +205,13 @@ absl::optional<int> DelayManager::Update(uint16_t sequence_number,
relative_delay = CalculateRelativePacketArrivalDelay();
}
switch (histogram_mode_) {
case RELATIVE_ARRIVAL_DELAY: {
const int index = relative_delay.value() / kBucketSizeMs;
if (index < histogram_->NumBuckets()) {
// Maximum delay to register is 2000 ms.
histogram_->Add(index);
}
break;
}
case INTER_ARRIVAL_TIME: {
// Saturate IAT between 0 and maximum value.
iat_packets =
std::max(std::min(iat_packets, histogram_->NumBuckets() - 1), 0);
histogram_->Add(iat_packets);
break;
}
const int index = relative_delay.value() / kBucketSizeMs;
if (index < histogram_->NumBuckets()) {
// Maximum delay to register is 2000 ms.
histogram_->Add(index);
}
// Calculate new |target_level_| based on updated statistics.
target_level_ = CalculateTargetLevel(iat_packets, reordered);
target_level_ = CalculateTargetLevel();
LimitTargetLevel();
} // End if (packet_len_ms > 0).
@ -310,32 +285,15 @@ void DelayManager::LimitTargetLevel() {
target_level_ = std::max(target_level_, 1 << 8);
}
int DelayManager::CalculateTargetLevel(int iat_packets, bool reordered) {
int DelayManager::CalculateTargetLevel() {
int limit_probability = histogram_quantile_;
int bucket_index = histogram_->Quantile(limit_probability);
int target_level;
switch (histogram_mode_) {
case RELATIVE_ARRIVAL_DELAY: {
target_level = 1;
if (packet_len_ms_ > 0) {
target_level += bucket_index * kBucketSizeMs / packet_len_ms_;
}
base_target_level_ = target_level;
break;
}
case INTER_ARRIVAL_TIME: {
target_level = std::max(bucket_index, 1);
base_target_level_ = target_level;
// Update detector for delay peaks.
bool delay_peak_found =
peak_detector_.Update(iat_packets, reordered, target_level);
if (delay_peak_found) {
target_level = std::max(target_level, peak_detector_.MaxPeakHeight());
}
break;
}
int target_level = 1;
if (packet_len_ms_ > 0) {
target_level += bucket_index * kBucketSizeMs / packet_len_ms_;
}
base_target_level_ = target_level;
// Sanity check. |target_level| must be strictly positive.
target_level = std::max(target_level, 1);
@ -353,14 +311,8 @@ int DelayManager::SetPacketAudioLength(int length_ms) {
RTC_LOG_F(LS_ERROR) << "length_ms = " << length_ms;
return -1;
}
if (histogram_mode_ == INTER_ARRIVAL_TIME &&
frame_length_change_experiment_ && packet_len_ms_ != length_ms &&
packet_len_ms_ > 0) {
histogram_->Scale(packet_len_ms_, length_ms);
}
packet_len_ms_ = length_ms;
peak_detector_.SetPacketAudioLength(packet_len_ms_);
packet_iat_stopwatch_ = tick_timer_->GetNewStopwatch();
last_pack_cng_or_dtmf_ = 1; // TODO(hlundin): Legacy. Remove?
return 0;
@ -368,7 +320,6 @@ int DelayManager::SetPacketAudioLength(int length_ms) {
void DelayManager::Reset() {
packet_len_ms_ = 0; // Packet size unknown.
peak_detector_.Reset();
histogram_->Reset();
delay_history_.clear();
base_target_level_ = 4;
@ -377,10 +328,6 @@ void DelayManager::Reset() {
last_pack_cng_or_dtmf_ = 1;
}
bool DelayManager::PeakFound() const {
return peak_detector_.peak_found();
}
void DelayManager::ResetPacketIatCount() {
packet_iat_stopwatch_ = tick_timer_->GetNewStopwatch();
}

View File

@ -23,22 +23,12 @@
namespace webrtc {
// Forward declaration.
class DelayPeakDetector;
class DelayManager {
public:
enum HistogramMode {
INTER_ARRIVAL_TIME,
RELATIVE_ARRIVAL_DELAY,
};
DelayManager(size_t max_packets_in_buffer,
int base_minimum_delay_ms,
int histogram_quantile,
HistogramMode histogram_mode,
bool enable_rtx_handling,
DelayPeakDetector* peak_detector,
const TickTimer* tick_timer,
std::unique_ptr<Histogram> histogram);
@ -50,7 +40,6 @@ class DelayManager {
static std::unique_ptr<DelayManager> Create(size_t max_packets_in_buffer,
int base_minimum_delay_ms,
bool enable_rtx_handling,
DelayPeakDetector* peak_detector,
const TickTimer* tick_timer);
virtual ~DelayManager();
@ -68,7 +57,7 @@ class DelayManager {
// Sets target_level_ (in Q8) and returns the same value. Also calculates
// and updates base_target_level_, which is the target buffer level before
// taking delay peaks into account.
virtual int CalculateTargetLevel(int iat_packets, bool reordered);
virtual int CalculateTargetLevel();
// Notifies the DelayManager of how much audio data is carried in each packet.
// The method updates the DelayPeakDetector too, and resets the inter-arrival
@ -78,11 +67,6 @@ class DelayManager {
// Resets the DelayManager and the associated DelayPeakDetector.
virtual void Reset();
// Returns true if peak-mode is active. That is, delay peaks were observed
// recently. This method simply asks for the same information from the
// DelayPeakDetector object.
virtual bool PeakFound() const;
// Reset the inter-arrival time counter to 0.
virtual void ResetPacketIatCount();
@ -122,7 +106,6 @@ class DelayManager {
}
// These accessors are only intended for testing purposes.
HistogramMode histogram_mode() const { return histogram_mode_; }
int histogram_quantile() const { return histogram_quantile_; }
Histogram* histogram() const { return histogram_.get(); }
@ -163,7 +146,6 @@ class DelayManager {
const size_t max_packets_in_buffer_; // Capacity of the packet buffer.
std::unique_ptr<Histogram> histogram_;
const int histogram_quantile_;
const HistogramMode histogram_mode_;
const TickTimer* tick_timer_;
int base_minimum_delay_ms_;
// Provides delay which is used by LimitTargetLevel as lower bound on target
@ -183,9 +165,7 @@ class DelayManager {
uint32_t last_timestamp_; // Timestamp for the last received packet.
int minimum_delay_ms_; // Externally set minimum delay.
int maximum_delay_ms_; // Externally set maximum allowed delay.
DelayPeakDetector& peak_detector_;
int last_pack_cng_or_dtmf_;
const bool frame_length_change_experiment_;
const bool enable_rtx_handling_;
int num_reordered_packets_ = 0; // Number of consecutive reordered packets.

View File

@ -17,7 +17,6 @@
#include <memory>
#include "modules/audio_coding/neteq/histogram.h"
#include "modules/audio_coding/neteq/mock/mock_delay_peak_detector.h"
#include "modules/audio_coding/neteq/mock/mock_histogram.h"
#include "modules/audio_coding/neteq/mock/mock_statistics_calculator.h"
#include "rtc_base/checks.h"
@ -47,7 +46,6 @@ class DelayManagerTest : public ::testing::Test {
protected:
DelayManagerTest();
virtual void SetUp();
virtual void TearDown();
void RecreateDelayManager();
void SetPacketAudioLength(int lengt_ms);
absl::optional<int> InsertNextPacket();
@ -56,19 +54,15 @@ class DelayManagerTest : public ::testing::Test {
std::unique_ptr<DelayManager> dm_;
TickTimer tick_timer_;
MockStatisticsCalculator stats_;
MockDelayPeakDetector detector_;
MockHistogram* mock_histogram_;
uint16_t seq_no_;
uint32_t ts_;
bool enable_rtx_handling_ = false;
bool use_mock_histogram_ = false;
DelayManager::HistogramMode histogram_mode_ =
DelayManager::HistogramMode::RELATIVE_ARRIVAL_DELAY;
};
DelayManagerTest::DelayManagerTest()
: dm_(nullptr),
detector_(&tick_timer_, false),
seq_no_(0x1234),
ts_(0x12345678) {}
@ -77,22 +71,19 @@ void DelayManagerTest::SetUp() {
}
void DelayManagerTest::RecreateDelayManager() {
EXPECT_CALL(detector_, Reset()).Times(1);
if (use_mock_histogram_) {
mock_histogram_ = new MockHistogram(kMaxIat, kForgetFactor);
std::unique_ptr<Histogram> histogram(mock_histogram_);
dm_ = std::make_unique<DelayManager>(
kMaxNumberOfPackets, kMinDelayMs, kDefaultHistogramQuantile,
histogram_mode_, enable_rtx_handling_, &detector_, &tick_timer_,
std::move(histogram));
enable_rtx_handling_, &tick_timer_, std::move(histogram));
} else {
dm_ = DelayManager::Create(kMaxNumberOfPackets, kMinDelayMs,
enable_rtx_handling_, &detector_, &tick_timer_);
enable_rtx_handling_, &tick_timer_);
}
}
void DelayManagerTest::SetPacketAudioLength(int lengt_ms) {
EXPECT_CALL(detector_, SetPacketAudioLength(lengt_ms));
dm_->SetPacketAudioLength(lengt_ms);
}
@ -109,10 +100,6 @@ void DelayManagerTest::IncreaseTime(int inc_ms) {
}
}
void DelayManagerTest::TearDown() {
EXPECT_CALL(detector_, Die());
}
TEST_F(DelayManagerTest, CreateAndDestroy) {
// Nothing to do here. The test fixture creates and destroys the DelayManager
// object.
@ -120,23 +107,10 @@ TEST_F(DelayManagerTest, CreateAndDestroy) {
TEST_F(DelayManagerTest, SetPacketAudioLength) {
const int kLengthMs = 30;
// Expect DelayManager to pass on the new length to the detector object.
EXPECT_CALL(detector_, SetPacketAudioLength(kLengthMs)).Times(1);
EXPECT_EQ(0, dm_->SetPacketAudioLength(kLengthMs));
EXPECT_EQ(-1, dm_->SetPacketAudioLength(-1)); // Illegal parameter value.
}
TEST_F(DelayManagerTest, PeakFound) {
// Expect DelayManager to pass on the question to the detector.
// Call twice, and let the detector return true the first time and false the
// second time.
EXPECT_CALL(detector_, peak_found())
.WillOnce(Return(true))
.WillOnce(Return(false));
EXPECT_TRUE(dm_->PeakFound());
EXPECT_FALSE(dm_->PeakFound());
}
TEST_F(DelayManagerTest, UpdateNormal) {
SetPacketAudioLength(kFrameSizeMs);
// First packet arrival.
@ -495,8 +469,6 @@ TEST_F(DelayManagerTest, DelayHistogramFieldTrial) {
test::ScopedFieldTrials field_trial(
"WebRTC-Audio-NetEqDelayHistogram/Enabled-96-0.998/");
RecreateDelayManager();
EXPECT_EQ(DelayManager::HistogramMode::RELATIVE_ARRIVAL_DELAY,
dm_->histogram_mode());
EXPECT_EQ(1030792151, dm_->histogram_quantile()); // 0.96 in Q30.
EXPECT_EQ(
32702,
@ -507,8 +479,6 @@ TEST_F(DelayManagerTest, DelayHistogramFieldTrial) {
test::ScopedFieldTrials field_trial(
"WebRTC-Audio-NetEqDelayHistogram/Enabled-97.5-0.998/");
RecreateDelayManager();
EXPECT_EQ(DelayManager::HistogramMode::RELATIVE_ARRIVAL_DELAY,
dm_->histogram_mode());
EXPECT_EQ(1046898278, dm_->histogram_quantile()); // 0.975 in Q30.
EXPECT_EQ(
32702,
@ -536,8 +506,7 @@ TEST_F(DelayManagerTest, DelayHistogramFieldTrial) {
}
}
TEST_F(DelayManagerTest, RelativeArrivalDelayMode) {
histogram_mode_ = DelayManager::HistogramMode::RELATIVE_ARRIVAL_DELAY;
TEST_F(DelayManagerTest, RelativeArrivalDelay) {
use_mock_histogram_ = true;
RecreateDelayManager();
@ -561,7 +530,6 @@ TEST_F(DelayManagerTest, RelativeArrivalDelayMode) {
}
TEST_F(DelayManagerTest, MaxDelayHistory) {
histogram_mode_ = DelayManager::HistogramMode::RELATIVE_ARRIVAL_DELAY;
use_mock_histogram_ = true;
RecreateDelayManager();

View File

@ -1,134 +0,0 @@
/*
* 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

View File

@ -1,78 +0,0 @@
/*
* 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.
*/
#ifndef MODULES_AUDIO_CODING_NETEQ_DELAY_PEAK_DETECTOR_H_
#define MODULES_AUDIO_CODING_NETEQ_DELAY_PEAK_DETECTOR_H_
#include <stdint.h>
#include <string.h>
#include <list>
#include <memory>
#include "api/neteq/tick_timer.h"
#include "rtc_base/constructor_magic.h"
namespace webrtc {
class DelayPeakDetector {
public:
DelayPeakDetector(const TickTimer* tick_timer, bool ignore_reordered_packets);
virtual ~DelayPeakDetector();
virtual void Reset();
// Notifies the DelayPeakDetector of how much audio data is carried in each
// packet.
virtual void SetPacketAudioLength(int length_ms);
// Returns true if peak-mode is active. That is, delay peaks were observed
// recently.
virtual bool peak_found();
// Calculates and returns the maximum delay peak height. Returns -1 if no
// delay peaks have been observed recently. The unit is number of packets.
virtual int MaxPeakHeight() const;
// Calculates and returns the maximum delay peak distance in ms (strictly
// larger than 0), or 0 if no delay peaks have been observed recently.
virtual uint64_t MaxPeakPeriod() const;
// Updates the DelayPeakDetector with a new inter-arrival time (in packets),
// the current target buffer level (needed to decide if a peak is observed or
// not) and if the new inter-arrival time includes a compensation for
// reordering. Returns true if peak-mode is active, false if not.
virtual bool Update(int inter_arrival_time, bool reordered, int target_level);
private:
static const size_t kMaxNumPeaks = 8;
static const size_t kMinPeaksToTrigger = 2;
static const int kPeakHeightMs = 78;
static const int kMaxPeakPeriodMs = 10000;
typedef struct {
uint64_t period_ms;
int peak_height_packets;
} Peak;
bool CheckPeakConditions();
std::list<Peak> peak_history_;
bool peak_found_;
int peak_detection_threshold_;
const TickTimer* tick_timer_;
std::unique_ptr<TickTimer::Stopwatch> peak_period_stopwatch_;
const bool ignore_reordered_packets_;
const bool frame_length_change_experiment_;
RTC_DISALLOW_COPY_AND_ASSIGN(DelayPeakDetector);
};
} // namespace webrtc
#endif // MODULES_AUDIO_CODING_NETEQ_DELAY_PEAK_DETECTOR_H_

View File

@ -1,161 +0,0 @@
/*
* 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.
*/
// Unit tests for DelayPeakDetector class.
#include "modules/audio_coding/neteq/delay_peak_detector.h"
#include "test/gtest.h"
namespace webrtc {
TEST(DelayPeakDetector, CreateAndDestroy) {
TickTimer tick_timer;
DelayPeakDetector* detector = new DelayPeakDetector(&tick_timer, false);
EXPECT_FALSE(detector->peak_found());
delete detector;
}
TEST(DelayPeakDetector, EmptyHistory) {
TickTimer tick_timer;
DelayPeakDetector detector(&tick_timer, false);
EXPECT_EQ(-1, detector.MaxPeakHeight());
EXPECT_EQ(0u, detector.MaxPeakPeriod());
}
// Inject a series of packet arrivals into the detector. Three of the packets
// have suffered delays. After the third delay peak, peak-mode is expected to
// start. This should then continue until it is disengaged due to lack of peaks.
TEST(DelayPeakDetector, TriggerPeakMode) {
TickTimer tick_timer;
DelayPeakDetector detector(&tick_timer, false);
const int kPacketSizeMs = 30;
detector.SetPacketAudioLength(kPacketSizeMs);
// Load up normal arrival times; 0 ms, 30 ms, 60 ms, 90 ms, ...
const int kNumPackets = 1000;
int arrival_times_ms[kNumPackets];
for (int i = 0; i < kNumPackets; ++i) {
arrival_times_ms[i] = i * kPacketSizeMs;
}
// Delay three packets.
const int kPeakDelayMs = 100;
// First delay peak.
arrival_times_ms[100] += kPeakDelayMs;
// Second delay peak.
arrival_times_ms[200] += kPeakDelayMs;
// Third delay peak. Trigger peak-mode after this packet.
arrival_times_ms[400] += kPeakDelayMs;
// The second peak period is the longest, 200 packets.
const uint64_t kWorstPeakPeriod = 200 * kPacketSizeMs;
int peak_mode_start_ms = arrival_times_ms[400];
// Expect to disengage after no peaks are observed for two period times.
int peak_mode_end_ms = peak_mode_start_ms + 2 * kWorstPeakPeriod;
// Load into detector.
int time = 0;
int next = 1; // Start with the second packet to get a proper IAT.
while (next < kNumPackets) {
while (next < kNumPackets && arrival_times_ms[next] <= time) {
int iat_packets =
(arrival_times_ms[next] - arrival_times_ms[next - 1]) / kPacketSizeMs;
const int kTargetBufferLevel = 1; // Define peaks to be iat > 2.
if (time < peak_mode_start_ms || time > peak_mode_end_ms) {
EXPECT_FALSE(detector.Update(iat_packets, false, kTargetBufferLevel));
} else {
EXPECT_TRUE(detector.Update(iat_packets, false, kTargetBufferLevel));
EXPECT_EQ(kWorstPeakPeriod, detector.MaxPeakPeriod());
EXPECT_EQ(kPeakDelayMs / kPacketSizeMs + 1, detector.MaxPeakHeight());
}
++next;
}
tick_timer.Increment();
time += 10; // Increase time 10 ms.
}
}
// Same test as TriggerPeakMode, but with base target buffer level increased to
// 2, in order to raise the bar for delay peaks to inter-arrival times > 4.
// The delay pattern has peaks with delay = 3, thus should not trigger.
TEST(DelayPeakDetector, DoNotTriggerPeakMode) {
TickTimer tick_timer;
DelayPeakDetector detector(&tick_timer, false);
const int kPacketSizeMs = 30;
detector.SetPacketAudioLength(kPacketSizeMs);
// Load up normal arrival times; 0 ms, 30 ms, 60 ms, 90 ms, ...
const int kNumPackets = 1000;
int arrival_times_ms[kNumPackets];
for (int i = 0; i < kNumPackets; ++i) {
arrival_times_ms[i] = i * kPacketSizeMs;
}
// Delay three packets.
const int kPeakDelayMs = 100;
// First delay peak.
arrival_times_ms[100] += kPeakDelayMs;
// Second delay peak.
arrival_times_ms[200] += kPeakDelayMs;
// Third delay peak.
arrival_times_ms[400] += kPeakDelayMs;
// Load into detector.
int time = 0;
int next = 1; // Start with the second packet to get a proper IAT.
while (next < kNumPackets) {
while (next < kNumPackets && arrival_times_ms[next] <= time) {
int iat_packets =
(arrival_times_ms[next] - arrival_times_ms[next - 1]) / kPacketSizeMs;
const int kTargetBufferLevel = 2; // Define peaks to be iat > 4.
EXPECT_FALSE(detector.Update(iat_packets, false, kTargetBufferLevel));
++next;
}
tick_timer.Increment();
time += 10; // Increase time 10 ms.
}
}
// In situations with reordered packets, the DelayPeakDetector may be updated
// back-to-back (i.e., without the tick_timer moving) but still with non-zero
// inter-arrival time. This test is to make sure that this does not cause
// problems.
TEST(DelayPeakDetector, ZeroDistancePeaks) {
TickTimer tick_timer;
DelayPeakDetector detector(&tick_timer, false);
const int kPacketSizeMs = 30;
detector.SetPacketAudioLength(kPacketSizeMs);
const int kTargetBufferLevel = 2; // Define peaks to be iat > 4.
const int kInterArrivalTime =
3 * kTargetBufferLevel; // Above peak threshold.
EXPECT_FALSE(detector.Update(kInterArrivalTime, false, kTargetBufferLevel));
tick_timer.Increment();
EXPECT_FALSE(detector.Update(kInterArrivalTime, false, kTargetBufferLevel));
// The following would fail if there were non-zero time between the updates.
EXPECT_FALSE(detector.Update(kInterArrivalTime, false, kTargetBufferLevel));
}
TEST(DelayPeakDetector, IgnoreReorderedPacket) {
TickTimer tick_timer;
DelayPeakDetector detector(&tick_timer, true);
const int kTargetBufferLevel = 2; // Define peaks to be iat > 4.
const int kInterArrivalTime =
3 * kTargetBufferLevel; // Above peak threshold.
EXPECT_FALSE(detector.Update(kInterArrivalTime, false, kTargetBufferLevel));
tick_timer.Increment();
EXPECT_FALSE(detector.Update(kInterArrivalTime, false, kTargetBufferLevel));
tick_timer.Increment();
// The following would fail if the packet was not reordered.
EXPECT_FALSE(detector.Update(kInterArrivalTime, true, kTargetBufferLevel));
}
} // namespace webrtc

View File

@ -146,58 +146,4 @@ int Histogram::NumBuckets() const {
return buckets_.size();
}
void Histogram::Scale(int old_bucket_width, int new_bucket_width) {
buckets_ = ScaleBuckets(buckets_, old_bucket_width, new_bucket_width);
}
std::vector<int> Histogram::ScaleBuckets(const std::vector<int>& buckets,
int old_bucket_width,
int new_bucket_width) {
RTC_DCHECK_GT(old_bucket_width, 0);
RTC_DCHECK_GT(new_bucket_width, 0);
RTC_DCHECK_EQ(old_bucket_width % 10, 0);
RTC_DCHECK_EQ(new_bucket_width % 10, 0);
std::vector<int> new_histogram(buckets.size(), 0);
int64_t acc = 0;
int time_counter = 0;
size_t new_histogram_idx = 0;
for (size_t i = 0; i < buckets.size(); i++) {
acc += buckets[i];
time_counter += old_bucket_width;
// The bins should be scaled, to ensure the histogram still sums to one.
const int64_t scaled_acc = acc * new_bucket_width / time_counter;
int64_t actually_used_acc = 0;
while (time_counter >= new_bucket_width) {
const int64_t old_histogram_val = new_histogram[new_histogram_idx];
new_histogram[new_histogram_idx] =
rtc::saturated_cast<int>(old_histogram_val + scaled_acc);
actually_used_acc += new_histogram[new_histogram_idx] - old_histogram_val;
new_histogram_idx =
std::min(new_histogram_idx + 1, new_histogram.size() - 1);
time_counter -= new_bucket_width;
}
// Only subtract the part that was succesfully written to the new histogram.
acc -= actually_used_acc;
}
// If there is anything left in acc (due to rounding errors), add it to the
// last bin. If we cannot add everything to the last bin we need to add as
// much as possible to the bins after the last bin (this is only possible
// when compressing a histogram).
while (acc > 0 && new_histogram_idx < new_histogram.size()) {
const int64_t old_histogram_val = new_histogram[new_histogram_idx];
new_histogram[new_histogram_idx] =
rtc::saturated_cast<int>(old_histogram_val + acc);
acc -= new_histogram[new_histogram_idx] - old_histogram_val;
new_histogram_idx++;
}
RTC_DCHECK_EQ(buckets.size(), new_histogram.size());
if (acc == 0) {
// If acc is non-zero, we were not able to add everything to the new
// histogram, so this check will not hold.
RTC_DCHECK_EQ(accumulate(buckets.begin(), buckets.end(), 0ll),
accumulate(new_histogram.begin(), new_histogram.end(), 0ll));
}
return new_histogram;
}
} // namespace webrtc

View File

@ -38,20 +38,12 @@ class Histogram {
// distribution.
virtual int Quantile(int probability);
// Apply compression or stretching to the histogram.
virtual void Scale(int old_bucket_width, int new_bucket_width);
// Returns the number of buckets in the histogram.
virtual int NumBuckets() const;
// Returns the probability for each bucket in Q30.
std::vector<int> buckets() const { return buckets_; }
// Made public for testing.
static std::vector<int> ScaleBuckets(const std::vector<int>& buckets,
int old_bucket_width,
int new_bucket_width);
// Accessors only intended for testing purposes.
int base_forget_factor_for_testing() const { return base_forget_factor_; }
int forget_factor_for_testing() const { return forget_factor_; }

View File

@ -59,116 +59,6 @@ TEST(HistogramTest, ForgetFactor) {
}
}
// Test if the histogram is scaled correctly if the bucket width is decreased.
TEST(HistogramTest, DownScale) {
// Test a straightforward 60 to 20 change.
std::vector<int> buckets = {12, 0, 0, 0, 0, 0};
std::vector<int> expected_result = {4, 4, 4, 0, 0, 0};
std::vector<int> stretched_buckets = Histogram::ScaleBuckets(buckets, 60, 20);
EXPECT_EQ(stretched_buckets, expected_result);
// Test an example where the last bin in the stretched histogram should
// contain the sum of the elements that don't fit into the new histogram.
buckets = {18, 15, 12, 9, 6, 3, 0};
expected_result = {6, 6, 6, 5, 5, 5, 30};
stretched_buckets = Histogram::ScaleBuckets(buckets, 60, 20);
EXPECT_EQ(stretched_buckets, expected_result);
// Test a 120 to 60 change.
buckets = {18, 16, 14, 4, 0};
expected_result = {9, 9, 8, 8, 18};
stretched_buckets = Histogram::ScaleBuckets(buckets, 120, 60);
EXPECT_EQ(stretched_buckets, expected_result);
// Test a 120 to 20 change.
buckets = {19, 12, 0, 0, 0, 0, 0, 0};
expected_result = {3, 3, 3, 3, 3, 3, 2, 11};
stretched_buckets = Histogram::ScaleBuckets(buckets, 120, 20);
EXPECT_EQ(stretched_buckets, expected_result);
// Test a 70 to 40 change.
buckets = {13, 7, 5, 3, 1, 5, 12, 11, 3, 0, 0, 0};
expected_result = {7, 5, 5, 3, 3, 2, 2, 1, 2, 2, 6, 22};
stretched_buckets = Histogram::ScaleBuckets(buckets, 70, 40);
EXPECT_EQ(stretched_buckets, expected_result);
// Test a 30 to 20 change.
buckets = {13, 7, 5, 3, 1, 5, 12, 11, 3, 0, 0, 0};
expected_result = {8, 6, 6, 3, 2, 2, 1, 3, 3, 8, 7, 11};
stretched_buckets = Histogram::ScaleBuckets(buckets, 30, 20);
EXPECT_EQ(stretched_buckets, expected_result);
}
// Test if the histogram is scaled correctly if the bucket width is increased.
TEST(HistogramTest, UpScale) {
// Test a 20 to 60 change.
std::vector<int> buckets = {12, 11, 10, 3, 2, 1};
std::vector<int> expected_result = {33, 6, 0, 0, 0, 0};
std::vector<int> compressed_buckets =
Histogram::ScaleBuckets(buckets, 20, 60);
EXPECT_EQ(compressed_buckets, expected_result);
// Test a 60 to 120 change.
buckets = {18, 16, 14, 4, 1};
expected_result = {34, 18, 1, 0, 0};
compressed_buckets = Histogram::ScaleBuckets(buckets, 60, 120);
EXPECT_EQ(compressed_buckets, expected_result);
// Test a 20 to 120 change.
buckets = {18, 12, 5, 4, 4, 3, 5, 1};
expected_result = {46, 6, 0, 0, 0, 0, 0, 0};
compressed_buckets = Histogram::ScaleBuckets(buckets, 20, 120);
EXPECT_EQ(compressed_buckets, expected_result);
// Test a 70 to 80 change.
buckets = {13, 7, 5, 3, 1, 5, 12, 11, 3};
expected_result = {11, 8, 6, 2, 5, 12, 13, 3, 0};
compressed_buckets = Histogram::ScaleBuckets(buckets, 70, 80);
EXPECT_EQ(compressed_buckets, expected_result);
// Test a 50 to 110 change.
buckets = {13, 7, 5, 3, 1, 5, 12, 11, 3};
expected_result = {18, 8, 16, 16, 2, 0, 0, 0, 0};
compressed_buckets = Histogram::ScaleBuckets(buckets, 50, 110);
EXPECT_EQ(compressed_buckets, expected_result);
}
// Test if the histogram scaling function handles overflows correctly.
TEST(HistogramTest, OverflowTest) {
// Test a upscale operation that can cause overflow.
std::vector<int> buckets = {733544448, 0, 0, 0, 0, 0, 0,
340197376, 0, 0, 0, 0, 0, 0};
std::vector<int> expected_result = {733544448, 340197376, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0};
std::vector<int> scaled_buckets = Histogram::ScaleBuckets(buckets, 10, 60);
EXPECT_EQ(scaled_buckets, expected_result);
buckets = {655591163, 39962288, 360736736, 1930514, 4003853, 1782764,
114119, 2072996, 0, 2149354, 0};
expected_result = {1056290187, 7717131, 2187115, 2149354, 0, 0,
0, 0, 0, 0, 0};
scaled_buckets = Histogram::ScaleBuckets(buckets, 20, 60);
EXPECT_EQ(scaled_buckets, expected_result);
// In this test case we will not be able to add everything to the final bin in
// the scaled histogram. Check that the last bin doesn't overflow.
buckets = {2000000000, 2000000000, 2000000000,
2000000000, 2000000000, 2000000000};
expected_result = {666666666, 666666666, 666666666,
666666667, 666666667, 2147483647};
scaled_buckets = Histogram::ScaleBuckets(buckets, 60, 20);
EXPECT_EQ(scaled_buckets, expected_result);
// In this test case we will not be able to add enough to each of the bins,
// so the values should be smeared out past the end of the normal range.
buckets = {2000000000, 2000000000, 2000000000,
2000000000, 2000000000, 2000000000};
expected_result = {2147483647, 2147483647, 2147483647,
2147483647, 2147483647, 1262581765};
scaled_buckets = Histogram::ScaleBuckets(buckets, 20, 60);
EXPECT_EQ(scaled_buckets, expected_result);
}
TEST(HistogramTest, ReachSteadyStateForgetFactor) {
static constexpr int kSteadyStateForgetFactor = (1 << 15) * 0.9993;
Histogram histogram(100, kSteadyStateForgetFactor, 1.0);

View File

@ -1,37 +0,0 @@
/*
* 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.
*/
#ifndef MODULES_AUDIO_CODING_NETEQ_MOCK_MOCK_DELAY_PEAK_DETECTOR_H_
#define MODULES_AUDIO_CODING_NETEQ_MOCK_MOCK_DELAY_PEAK_DETECTOR_H_
#include "modules/audio_coding/neteq/delay_peak_detector.h"
#include "test/gmock.h"
namespace webrtc {
class MockDelayPeakDetector : public DelayPeakDetector {
public:
MockDelayPeakDetector(const TickTimer* tick_timer,
bool ignore_reordered_packets)
: DelayPeakDetector(tick_timer, ignore_reordered_packets) {}
virtual ~MockDelayPeakDetector() { Die(); }
MOCK_METHOD0(Die, void());
MOCK_METHOD0(Reset, void());
MOCK_METHOD1(SetPacketAudioLength, void(int length_ms));
MOCK_METHOD0(peak_found, bool());
MOCK_CONST_METHOD0(MaxPeakHeight, int());
MOCK_CONST_METHOD0(MaxPeakPeriod, uint64_t());
MOCK_METHOD3(Update,
bool(int inter_arrival_time, bool reordered, int target_level));
};
} // namespace webrtc
#endif // MODULES_AUDIO_CODING_NETEQ_MOCK_MOCK_DELAY_PEAK_DETECTOR_H_