NetEq: Introduce TickTimer in DelayPeakDetector
Specifically, this change replaces peak_period_counter_ms_ with
peak_period_stopwatch_ which obtains a Stopwatch object from
TickTimer. Necessary plumbing to get the TickTimer through to the
DelayPeakDetector is also included.
BUG=webrtc:5608
NOTRY=True
Review-Url: https://codereview.webrtc.org/1921163003
Cr-Commit-Position: refs/heads/master@{#12542}
diff --git a/webrtc/modules/audio_coding/neteq/decision_logic_unittest.cc b/webrtc/modules/audio_coding/neteq/decision_logic_unittest.cc
index ff8a0c4..350821c 100644
--- a/webrtc/modules/audio_coding/neteq/decision_logic_unittest.cc
+++ b/webrtc/modules/audio_coding/neteq/decision_logic_unittest.cc
@@ -27,7 +27,7 @@
DecoderDatabase decoder_database;
TickTimer tick_timer;
PacketBuffer packet_buffer(10, &tick_timer);
- DelayPeakDetector delay_peak_detector;
+ DelayPeakDetector delay_peak_detector(&tick_timer);
DelayManager delay_manager(240, &delay_peak_detector);
BufferLevelFilter buffer_level_filter;
DecisionLogic* logic = DecisionLogic::Create(fs_hz, output_size_samples,
diff --git a/webrtc/modules/audio_coding/neteq/delay_manager.cc b/webrtc/modules/audio_coding/neteq/delay_manager.cc
index af49f00..e955f17 100644
--- a/webrtc/modules/audio_coding/neteq/delay_manager.cc
+++ b/webrtc/modules/audio_coding/neteq/delay_manager.cc
@@ -342,7 +342,6 @@
void DelayManager::UpdateCounters(int elapsed_time_ms) {
packet_iat_count_ms_ += elapsed_time_ms;
- peak_detector_.IncrementCounter(elapsed_time_ms);
max_timer_ms_ += elapsed_time_ms;
}
diff --git a/webrtc/modules/audio_coding/neteq/delay_manager_unittest.cc b/webrtc/modules/audio_coding/neteq/delay_manager_unittest.cc
index f231c3d..05d6f3e 100644
--- a/webrtc/modules/audio_coding/neteq/delay_manager_unittest.cc
+++ b/webrtc/modules/audio_coding/neteq/delay_manager_unittest.cc
@@ -39,16 +39,14 @@
void IncreaseTime(int inc_ms);
DelayManager* dm_;
+ TickTimer tick_timer_;
MockDelayPeakDetector detector_;
uint16_t seq_no_;
uint32_t ts_;
};
DelayManagerTest::DelayManagerTest()
- : dm_(NULL),
- seq_no_(0x1234),
- ts_(0x12345678) {
-}
+ : dm_(NULL), detector_(&tick_timer_), seq_no_(0x1234), ts_(0x12345678) {}
void DelayManagerTest::SetUp() {
EXPECT_CALL(detector_, Reset())
@@ -69,9 +67,8 @@
void DelayManagerTest::IncreaseTime(int inc_ms) {
for (int t = 0; t < inc_ms; t += kTimeStepMs) {
- EXPECT_CALL(detector_, IncrementCounter(kTimeStepMs))
- .Times(1);
dm_->UpdateCounters(kTimeStepMs);
+ tick_timer_.Increment();
}
}
void DelayManagerTest::TearDown() {
@@ -115,13 +112,6 @@
EXPECT_FALSE(dm_->PeakFound());
}
-TEST_F(DelayManagerTest, UpdateCounters) {
- // Expect DelayManager to pass on the counter update to the detector.
- EXPECT_CALL(detector_, IncrementCounter(kTimeStepMs))
- .Times(1);
- dm_->UpdateCounters(kTimeStepMs);
-}
-
TEST_F(DelayManagerTest, UpdateNormal) {
SetPacketAudioLength(kFrameSizeMs);
// First packet arrival.
diff --git a/webrtc/modules/audio_coding/neteq/delay_peak_detector.cc b/webrtc/modules/audio_coding/neteq/delay_peak_detector.cc
index 712c778..ce9133b 100644
--- a/webrtc/modules/audio_coding/neteq/delay_peak_detector.cc
+++ b/webrtc/modules/audio_coding/neteq/delay_peak_detector.cc
@@ -12,6 +12,9 @@
#include <algorithm> // max
+#include "webrtc/base/checks.h"
+#include "webrtc/base/safe_conversions.h"
+
namespace webrtc {
// The DelayPeakDetector keeps track of severe inter-arrival times, called
@@ -23,14 +26,15 @@
DelayPeakDetector::~DelayPeakDetector() = default;
-DelayPeakDetector::DelayPeakDetector()
- : peak_found_(false),
- peak_detection_threshold_(0),
- peak_period_counter_ms_(-1) {
+DelayPeakDetector::DelayPeakDetector(const TickTimer* tick_timer)
+ : peak_found_(false),
+ peak_detection_threshold_(0),
+ tick_timer_(tick_timer) {
+ RTC_DCHECK(!peak_period_stopwatch_);
}
void DelayPeakDetector::Reset() {
- peak_period_counter_ms_ = -1; // Indicate that next peak is the first.
+ peak_period_stopwatch_.reset();
peak_found_ = false;
peak_history_.clear();
}
@@ -55,38 +59,40 @@
return max_height;
}
-int DelayPeakDetector::MaxPeakPeriod() const {
- int max_period = -1; // Returns -1 for an empty history.
- std::list<Peak>::const_iterator it;
- for (it = peak_history_.begin(); it != peak_history_.end(); ++it) {
- max_period = std::max(max_period, it->period_ms);
+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.
}
- return max_period;
+ RTC_DCHECK_GT(max_period_element->period_ms, 0u);
+ return max_period_element->period_ms;
}
bool DelayPeakDetector::Update(int inter_arrival_time, int target_level) {
if (inter_arrival_time > target_level + peak_detection_threshold_ ||
inter_arrival_time > 2 * target_level) {
// A delay peak is observed.
- if (peak_period_counter_ms_ == -1) {
+ if (!peak_period_stopwatch_) {
// This is the first peak. Reset the period counter.
- peak_period_counter_ms_ = 0;
- } else if (peak_period_counter_ms_ <= kMaxPeakPeriodMs) {
+ peak_period_stopwatch_ = tick_timer_->GetNewStopwatch();
+ } else 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_counter_ms_;
+ 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_counter_ms_ = 0;
- } else if (peak_period_counter_ms_ <= 2 * kMaxPeakPeriodMs) {
+ 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_counter_ms_ = 0;
+ 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.
@@ -97,16 +103,10 @@
return CheckPeakConditions();
}
-void DelayPeakDetector::IncrementCounter(int inc_ms) {
- if (peak_period_counter_ms_ >= 0) {
- peak_period_counter_ms_ += inc_ms;
- }
-}
-
bool DelayPeakDetector::CheckPeakConditions() {
size_t s = peak_history_.size();
if (s >= kMinPeaksToTrigger &&
- peak_period_counter_ms_ <= 2 * MaxPeakPeriod()) {
+ peak_period_stopwatch_->ElapsedMs() <= 2 * MaxPeakPeriod()) {
peak_found_ = true;
} else {
peak_found_ = false;
diff --git a/webrtc/modules/audio_coding/neteq/delay_peak_detector.h b/webrtc/modules/audio_coding/neteq/delay_peak_detector.h
index 69433b4..060e2e1 100644
--- a/webrtc/modules/audio_coding/neteq/delay_peak_detector.h
+++ b/webrtc/modules/audio_coding/neteq/delay_peak_detector.h
@@ -16,12 +16,13 @@
#include <list>
#include "webrtc/base/constructormagic.h"
+#include "webrtc/modules/audio_coding/neteq/tick_timer.h"
namespace webrtc {
class DelayPeakDetector {
public:
- DelayPeakDetector();
+ DelayPeakDetector(const TickTimer* tick_timer);
virtual ~DelayPeakDetector();
virtual void Reset();
@@ -37,20 +38,15 @@
// 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.
- // Returns -1 if no delay peaks have been observed recently.
- virtual int MaxPeakPeriod() 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)
// and the current target buffer level (needed to decide if a peak is observed
// or not). Returns true if peak-mode is active, false if not.
virtual bool Update(int inter_arrival_time, int target_level);
- // Increments the |peak_period_counter_ms_| with |inc_ms|. Only increments
- // the counter if it is non-negative. A negative denotes that no peak has
- // been observed.
- virtual void IncrementCounter(int inc_ms);
-
private:
static const size_t kMaxNumPeaks = 8;
static const size_t kMinPeaksToTrigger = 2;
@@ -58,7 +54,7 @@
static const int kMaxPeakPeriodMs = 10000;
typedef struct {
- int period_ms;
+ uint64_t period_ms;
int peak_height_packets;
} Peak;
@@ -67,7 +63,8 @@
std::list<Peak> peak_history_;
bool peak_found_;
int peak_detection_threshold_;
- int peak_period_counter_ms_;
+ const TickTimer* tick_timer_;
+ std::unique_ptr<TickTimer::Stopwatch> peak_period_stopwatch_;
RTC_DISALLOW_COPY_AND_ASSIGN(DelayPeakDetector);
};
diff --git a/webrtc/modules/audio_coding/neteq/delay_peak_detector_unittest.cc b/webrtc/modules/audio_coding/neteq/delay_peak_detector_unittest.cc
index c40f399..32b36b2 100644
--- a/webrtc/modules/audio_coding/neteq/delay_peak_detector_unittest.cc
+++ b/webrtc/modules/audio_coding/neteq/delay_peak_detector_unittest.cc
@@ -17,22 +17,25 @@
namespace webrtc {
TEST(DelayPeakDetector, CreateAndDestroy) {
- DelayPeakDetector* detector = new DelayPeakDetector();
+ TickTimer tick_timer;
+ DelayPeakDetector* detector = new DelayPeakDetector(&tick_timer);
EXPECT_FALSE(detector->peak_found());
delete detector;
}
TEST(DelayPeakDetector, EmptyHistory) {
- DelayPeakDetector detector;
+ TickTimer tick_timer;
+ DelayPeakDetector detector(&tick_timer);
EXPECT_EQ(-1, detector.MaxPeakHeight());
- EXPECT_EQ(-1, detector.MaxPeakPeriod());
+ 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) {
- DelayPeakDetector detector;
+ TickTimer tick_timer;
+ DelayPeakDetector detector(&tick_timer);
const int kPacketSizeMs = 30;
detector.SetPacketAudioLength(kPacketSizeMs);
@@ -52,7 +55,7 @@
// Third delay peak. Trigger peak-mode after this packet.
arrival_times_ms[400] += kPeakDelayMs;
// The second peak period is the longest, 200 packets.
- const int kWorstPeakPeriod = 200 * kPacketSizeMs;
+ 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;
@@ -74,7 +77,7 @@
}
++next;
}
- detector.IncrementCounter(10);
+ tick_timer.Increment();
time += 10; // Increase time 10 ms.
}
}
@@ -83,7 +86,8 @@
// 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) {
- DelayPeakDetector detector;
+ TickTimer tick_timer;
+ DelayPeakDetector detector(&tick_timer);
const int kPacketSizeMs = 30;
detector.SetPacketAudioLength(kPacketSizeMs);
@@ -114,7 +118,7 @@
EXPECT_FALSE(detector.Update(iat_packets, kTargetBufferLevel));
++next;
}
- detector.IncrementCounter(10);
+ tick_timer.Increment();
time += 10; // Increase time 10 ms.
}
}
diff --git a/webrtc/modules/audio_coding/neteq/mock/mock_delay_peak_detector.h b/webrtc/modules/audio_coding/neteq/mock/mock_delay_peak_detector.h
index fa5cd7e..5564fba 100644
--- a/webrtc/modules/audio_coding/neteq/mock/mock_delay_peak_detector.h
+++ b/webrtc/modules/audio_coding/neteq/mock/mock_delay_peak_detector.h
@@ -19,15 +19,16 @@
class MockDelayPeakDetector : public DelayPeakDetector {
public:
+ MockDelayPeakDetector(const TickTimer* tick_timer)
+ : DelayPeakDetector(tick_timer) {}
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, int());
+ MOCK_CONST_METHOD0(MaxPeakPeriod, uint64_t());
MOCK_METHOD2(Update, bool(int inter_arrival_time, int target_level));
- MOCK_METHOD1(IncrementCounter, void(int inc_ms));
};
} // namespace webrtc
diff --git a/webrtc/modules/audio_coding/neteq/neteq_impl.cc b/webrtc/modules/audio_coding/neteq/neteq_impl.cc
index 01325e3..7bdb23c 100644
--- a/webrtc/modules/audio_coding/neteq/neteq_impl.cc
+++ b/webrtc/modules/audio_coding/neteq/neteq_impl.cc
@@ -58,7 +58,7 @@
: tick_timer(new TickTimer),
buffer_level_filter(new BufferLevelFilter),
decoder_database(new DecoderDatabase),
- delay_peak_detector(new DelayPeakDetector),
+ delay_peak_detector(new DelayPeakDetector(tick_timer.get())),
delay_manager(new DelayManager(config.max_packets_in_buffer,
delay_peak_detector.get())),
dtmf_buffer(new DtmfBuffer(config.sample_rate_hz)),
diff --git a/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc b/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc
index 5cb9762..ed6dc20 100644
--- a/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc
+++ b/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc
@@ -81,7 +81,8 @@
decoder_database_ = deps.decoder_database.get();
if (use_mock_delay_peak_detector_) {
- std::unique_ptr<MockDelayPeakDetector> mock(new MockDelayPeakDetector);
+ std::unique_ptr<MockDelayPeakDetector> mock(
+ new MockDelayPeakDetector(tick_timer_));
mock_delay_peak_detector_ = mock.get();
EXPECT_CALL(*mock_delay_peak_detector_, Reset()).Times(1);
deps.delay_peak_detector = std::move(mock);