From edbea46295b8ee474a7807400d38d1cc6b7b5018 Mon Sep 17 00:00:00 2001 From: Ruslan Burakov Date: Mon, 4 Feb 2019 16:17:31 +0100 Subject: [PATCH] Allow to change base minimum delay on NetEq. This is first step to allow to set latency from client code in Chromium. Existing minimum latency hasn't been used because it can clash with video syncronization code. Bug: webrtc:10287 Change-Id: Ia38906506069a1abfa01698dc62df283fc15cfbc Reviewed-on: https://webrtc-review.googlesource.com/c/121423 Reviewed-by: Ivo Creusen Commit-Queue: Ruslan Burakov Cr-Commit-Position: refs/heads/master@{#26536} --- modules/audio_coding/neteq/delay_manager.cc | 32 +++++++++++--- modules/audio_coding/neteq/delay_manager.h | 11 ++++- .../neteq/delay_manager_unittest.cc | 44 +++++++++++++++++++ 3 files changed, 78 insertions(+), 9 deletions(-) diff --git a/modules/audio_coding/neteq/delay_manager.cc b/modules/audio_coding/neteq/delay_manager.cc index cbf3da1a68..4ca545d176 100644 --- a/modules/audio_coding/neteq/delay_manager.cc +++ b/modules/audio_coding/neteq/delay_manager.cc @@ -482,16 +482,19 @@ DelayManager::IATVector DelayManager::ScaleHistogram(const IATVector& histogram, return new_histogram; } +bool DelayManager::IsValidMinimumDelay(int delay_ms) { + const int q75 = + rtc::dchecked_cast(3 * max_packets_in_buffer_ * packet_len_ms_ / 4); + return delay_ms >= 0 && + (maximum_delay_ms_ <= 0 || delay_ms <= maximum_delay_ms_) && + (packet_len_ms_ <= 0 || delay_ms <= q75); +} + bool DelayManager::SetMinimumDelay(int delay_ms) { - // Minimum delay shouldn't be more than maximum delay, if any maximum is set. - // Also, if possible check |delay| to less than 75% of - // |max_packets_in_buffer_|. - if ((maximum_delay_ms_ > 0 && delay_ms > maximum_delay_ms_) || - (packet_len_ms_ > 0 && - delay_ms > - static_cast(3 * max_packets_in_buffer_ * packet_len_ms_ / 4))) { + if (!IsValidMinimumDelay(delay_ms)) { return false; } + // Ensure that minimum_delay_ms is no bigger than base_min_target_delay_ms_ minimum_delay_ms_ = std::max(delay_ms, base_min_target_delay_ms_); return true; } @@ -509,6 +512,21 @@ bool DelayManager::SetMaximumDelay(int delay_ms) { return true; } +bool DelayManager::SetBaseMinimumDelay(int delay_ms) { + if (!IsValidMinimumDelay(delay_ms)) { + return false; + } + + base_min_target_delay_ms_ = delay_ms; + // Ensure that minimum_delay_ms is no bigger than base_min_target_delay_ms_ + minimum_delay_ms_ = std::max(delay_ms, base_min_target_delay_ms_); + return true; +} + +int DelayManager::GetBaseMinimumDelay() const { + return base_min_target_delay_ms_; +} + int DelayManager::base_target_level() const { return base_target_level_; } diff --git a/modules/audio_coding/neteq/delay_manager.h b/modules/audio_coding/neteq/delay_manager.h index 25eaba38dc..8eee49c5fc 100644 --- a/modules/audio_coding/neteq/delay_manager.h +++ b/modules/audio_coding/neteq/delay_manager.h @@ -112,6 +112,8 @@ class DelayManager { // Assuming |delay| is in valid range. virtual bool SetMinimumDelay(int delay_ms); virtual bool SetMaximumDelay(int delay_ms); + virtual bool SetBaseMinimumDelay(int delay_ms); + virtual int GetBaseMinimumDelay() const; virtual int base_target_level() const; virtual void set_streaming_mode(bool value); virtual int last_pack_cng_or_dtmf() const; @@ -141,13 +143,18 @@ class DelayManager { // called by Update(). void LimitTargetLevel(); + // Makes sure that |delay_ms| is less than maximum delay, if any maximum + // is set. Also, if possible check |delay_ms| to be less than 75% of + // |max_packets_in_buffer_|. + bool IsValidMinimumDelay(int delay_ms); + bool first_packet_received_; const size_t max_packets_in_buffer_; // Capacity of the packet buffer. IATVector iat_vector_; // Histogram of inter-arrival times. int iat_factor_; // Forgetting factor for updating the IAT histogram (Q15). const TickTimer* tick_timer_; - const int base_min_target_delay_ms_; // Lower bound for target_level_ and - // minimum_delay_ms_. + int base_min_target_delay_ms_; // Lower bound for target_level_ and + // minimum_delay_ms_. // Time elapsed since last packet. std::unique_ptr packet_iat_stopwatch_; int base_target_level_; // Currently preferred buffer level before peak diff --git a/modules/audio_coding/neteq/delay_manager_unittest.cc b/modules/audio_coding/neteq/delay_manager_unittest.cc index e1cca89ffc..b0e23a979c 100644 --- a/modules/audio_coding/neteq/delay_manager_unittest.cc +++ b/modules/audio_coding/neteq/delay_manager_unittest.cc @@ -267,6 +267,50 @@ TEST_F(DelayManagerTest, MinDelay) { EXPECT_EQ(kMinDelayPackets << 8, dm_->TargetLevel()); } +TEST_F(DelayManagerTest, BaseMinDelay) { + const int kExpectedTarget = 5; + const int kTimeIncrement = kExpectedTarget * kFrameSizeMs; + SetPacketAudioLength(kFrameSizeMs); + // First packet arrival. + InsertNextPacket(); + // Second packet arrival. + // Expect detector update method to be called once with inter-arrival time + // equal to |kExpectedTarget| packet. Return true to indicate peaks found. + EXPECT_CALL(detector_, Update(kExpectedTarget, false, _)) + .WillRepeatedly(Return(true)); + EXPECT_CALL(detector_, MaxPeakHeight()) + .WillRepeatedly(Return(kExpectedTarget)); + IncreaseTime(kTimeIncrement); + InsertNextPacket(); + + // No limit is applied. + EXPECT_EQ(kExpectedTarget << 8, dm_->TargetLevel()); + + int kBaseMinDelayPackets = kExpectedTarget + 2; + int kBaseMinDelayMs = kBaseMinDelayPackets * kFrameSizeMs; + EXPECT_TRUE(dm_->SetBaseMinimumDelay(kBaseMinDelayMs)); + EXPECT_EQ(dm_->GetBaseMinimumDelay(), kBaseMinDelayMs); + + IncreaseTime(kTimeIncrement); + InsertNextPacket(); + EXPECT_EQ(dm_->GetBaseMinimumDelay(), kBaseMinDelayMs); + EXPECT_EQ(kBaseMinDelayPackets << 8, dm_->TargetLevel()); +} + +TEST_F(DelayManagerTest, BaseMinDelayGreaterThanMaxDelayIsInvalid) { + int kMaxDelayMs = 2 * kFrameSizeMs; + int kBaseMinDelayMs = 4 * kFrameSizeMs; + EXPECT_TRUE(dm_->SetMaximumDelay(kMaxDelayMs)); + EXPECT_FALSE(dm_->SetBaseMinimumDelay(kBaseMinDelayMs)); +} + +TEST_F(DelayManagerTest, BaseMinDelayGreaterThanQ75MaxPacketsIsInvalid) { + // .75 of |max_packets_in_buffer|, + 1 to ensure that |kBaseMinDelayMs| is + // greater. + int kBaseMinDelayMs = (3 * kMaxNumberOfPackets * kFrameSizeMs / 4) + 1; + EXPECT_FALSE(dm_->SetBaseMinimumDelay(kBaseMinDelayMs)); +} + TEST_F(DelayManagerTest, UpdateReorderedPacket) { SetPacketAudioLength(kFrameSizeMs); InsertNextPacket();