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();