From d3fc161c169dfe8816a5549c251481790d2cd543 Mon Sep 17 00:00:00 2001 From: Jakob Ivarsson Date: Tue, 25 Jun 2019 12:32:48 +0000 Subject: [PATCH] Revert "Change buffer level filter to store current level in number of samples." This reverts commit 87977dd06e702ed517f26235c12e37bd927527c7. Reason for revert: Breaks downstream project Original change's description: > Change buffer level filter to store current level in number of samples. > > The buffer level should not be converted back and forth between samples and packets in case of variable packet lengths. > > Bug: webrtc:10736 > Change-Id: Ia08dcfac3d8104dc79fbad0704a5f6f12a050a01 > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/142178 > Reviewed-by: Minyue Li > Commit-Queue: Jakob Ivarsson > Cr-Commit-Position: refs/heads/master@{#28368} TBR=henrik.lundin@webrtc.org,minyue@webrtc.org,jakobi@webrtc.org Change-Id: I3900c9f6071fce51d13fb3b7c886157304d7a5c3 No-Presubmit: true No-Tree-Checks: true No-Try: true Bug: webrtc:10736 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/143786 Reviewed-by: Jakob Ivarsson Commit-Queue: Jakob Ivarsson Cr-Commit-Position: refs/heads/master@{#28369} --- .../acm2/audio_coding_module_unittest.cc | 50 ++++----- .../audio_coding/neteq/buffer_level_filter.cc | 61 ++++++---- .../audio_coding/neteq/buffer_level_filter.h | 24 ++-- .../neteq/buffer_level_filter_unittest.cc | 105 +++++++++++++----- modules/audio_coding/neteq/decision_logic.cc | 51 ++++----- modules/audio_coding/neteq/decision_logic.h | 4 +- .../neteq/mock/mock_buffer_level_filter.h | 6 +- modules/audio_coding/neteq/neteq_impl.cc | 14 ++- modules/audio_coding/neteq/neteq_unittest.cc | 34 +++--- 9 files changed, 213 insertions(+), 136 deletions(-) diff --git a/modules/audio_coding/acm2/audio_coding_module_unittest.cc b/modules/audio_coding/acm2/audio_coding_module_unittest.cc index f9488a34b7..c95091f1c3 100644 --- a/modules/audio_coding/acm2/audio_coding_module_unittest.cc +++ b/modules/audio_coding/acm2/audio_coding_module_unittest.cc @@ -994,35 +994,35 @@ class AcmReceiverBitExactnessOldApi : public ::testing::Test { #if (defined(WEBRTC_CODEC_ISAC) || defined(WEBRTC_CODEC_ISACFX)) && \ defined(WEBRTC_CODEC_ILBC) TEST_F(AcmReceiverBitExactnessOldApi, 8kHzOutput) { - Run(8000, PlatformChecksum("bc5cc2391174c865f02d9b2ae568020a", - "06621315b131e5ece54aff186ec7b9e4", - "2d05bd35f4dd9798e4189d7da6e6ba10", + Run(8000, PlatformChecksum("bcfbe2e89b4317b22e29557168edf187", + "af15addb648cf7f032d6415672365fb3", + "54a0008eb79537dee1d8fdaa5bc29f4b", "4598140b5e4f7ee66c5adad609e65a3e", - "c0c14f9d8d4151510cafdaf78e2ebd20")); + "3155d7f2593a3276986f36221a61783c")); } TEST_F(AcmReceiverBitExactnessOldApi, 16kHzOutput) { - Run(16000, PlatformChecksum("9e3893aeb5dda4f9cea6adec21d21ad8", - "70d26c18385e05a35162460a2ef6a0e4", - "b1ef73d7dde40033e30a76a1cc6a1ab6", + Run(16000, PlatformChecksum("1737deef193e6c90e139ce82b7361ae4", + "9e2a9f7728c71d6559ce3a32d2b10a5d", + "114958862099142ac78b12100c21cb8d", "f2aad418af974a3b1694d5ae5cc2c3c7", - "25ae85ea1d2d629956cec7ea0b94f51c")); + "af2889a5ca84fb40c9aa209b9318ee7a")); } TEST_F(AcmReceiverBitExactnessOldApi, 32kHzOutput) { - Run(32000, PlatformChecksum("4be3e35ebfdce55157491945610ef663", - "424fcd896d2050530648de083567aff7", - "ab50b8546f56c359c8e4c7d74e49aae4", + Run(32000, PlatformChecksum("1bf40ff024c6aa5b832d1d242c29cb3b", + "3c9690cd136e9ecd1b26a22f70fe1d5c", + "a1a3a01d8e25fcd11f1cedcd02e968b8", "100869c8dcde51346c2073e52a272d98", - "87731746b160e4ae8313fa8af92bba12")); + "33695077e9ec6bca80819ce2ba263a78")); } TEST_F(AcmReceiverBitExactnessOldApi, 48kHzOutput) { - Run(48000, PlatformChecksum("1df82e2f5c1c96d94ad0edc55c723d01", - "a623e44f7e41263245361e2b8c6cedd2", - "22d0e9c2b62f367fb2d2052569c70e55", + Run(48000, PlatformChecksum("bf92db1e502deff5adf6fd2e6ab9a2e5", + "c37b110ab50d87620972daee5d1eaf31", + "5d55b68be7bcf39b60fcc74519363fb4", "bd44bf97e7899186532f91235cef444d", - "c3188d9fdaa8057a98815c9b7ecc48f1")); + "32eec738698ffe62b9777d6a349cd596")); } TEST_F(AcmReceiverBitExactnessOldApi, 48kHzOutputExternalDecoder) { @@ -1105,11 +1105,11 @@ TEST_F(AcmReceiverBitExactnessOldApi, 48kHzOutputExternalDecoder) { rtc::scoped_refptr> factory( new rtc::RefCountedObject); Run(48000, - PlatformChecksum("1df82e2f5c1c96d94ad0edc55c723d01", - "a623e44f7e41263245361e2b8c6cedd2", - "22d0e9c2b62f367fb2d2052569c70e55", + PlatformChecksum("bf92db1e502deff5adf6fd2e6ab9a2e5", + "c37b110ab50d87620972daee5d1eaf31", + "5d55b68be7bcf39b60fcc74519363fb4", "bd44bf97e7899186532f91235cef444d", - "c3188d9fdaa8057a98815c9b7ecc48f1"), + "32eec738698ffe62b9777d6a349cd596"), factory, [](AudioCodingModule* acm) { acm->SetReceiveCodecs({{0, {"MockPCMu", 8000, 1}}, {103, {"ISAC", 16000, 1}}, @@ -1328,7 +1328,7 @@ TEST_F(AcmSenderBitExactnessOldApi, IsacWb30ms) { Run(AcmReceiverBitExactnessOldApi::PlatformChecksum( "2c9cb15d4ed55b5a0cadd04883bc73b0", "9336a9b993cbd8a751f0e8958e66c89c", - "5c2eb46199994506236f68b2c8e51b0d", + "bd4682225f7c4ad5f2049f6769713ac2", "343f1f42be0607c61e6516aece424609", "2c9cb15d4ed55b5a0cadd04883bc73b0"), AcmReceiverBitExactnessOldApi::PlatformChecksum( @@ -1343,11 +1343,11 @@ TEST_F(AcmSenderBitExactnessOldApi, IsacWb30ms) { TEST_F(AcmSenderBitExactnessOldApi, IsacWb60ms) { ASSERT_NO_FATAL_FAILURE(SetUpTest("ISAC", 16000, 1, 103, 960, 960)); Run(AcmReceiverBitExactnessOldApi::PlatformChecksum( - "f59760fa000991ee5fa81f2e607db254", - "986aa16d7097a26e32e212e39ec58517", - "9a81e467eb1485f84aca796f8ea65011", + "1ad29139a04782a33daad8c2b9b35875", + "14d63c5f08127d280e722e3191b73bdd", + "edcf26694c289e3d9691faf79b74f09f", "ef75e900e6f375e3061163c53fd09a63", - "f59760fa000991ee5fa81f2e607db254"), + "1ad29139a04782a33daad8c2b9b35875"), AcmReceiverBitExactnessOldApi::PlatformChecksum( "9e0a0ab743ad987b55b8e14802769c56", "ebe04a819d3a9d83a83a17f271e1139a", diff --git a/modules/audio_coding/neteq/buffer_level_filter.cc b/modules/audio_coding/neteq/buffer_level_filter.cc index 675091d371..2f96618536 100644 --- a/modules/audio_coding/neteq/buffer_level_filter.cc +++ b/modules/audio_coding/neteq/buffer_level_filter.cc @@ -22,31 +22,52 @@ BufferLevelFilter::BufferLevelFilter() { } void BufferLevelFilter::Reset() { - filtered_current_level_ = 0.0; - level_factor_ = 0.988; + filtered_current_level_ = 0; + level_factor_ = 253; } -void BufferLevelFilter::Update(size_t buffer_size_samples, - int time_stretched_samples) { - filtered_current_level_ = level_factor_ * filtered_current_level_ + - (1 - level_factor_) * buffer_size_samples; - - // Account for time-scale operations (accelerate and pre-emptive expand) and - // make sure that the filtered value remains non-negative. +void BufferLevelFilter::Update(size_t buffer_size_packets, + int time_stretched_samples, + size_t packet_len_samples) { + // Filter: + // |filtered_current_level_| = |level_factor_| * |filtered_current_level_| + + // (1 - |level_factor_|) * |buffer_size_packets| + // |level_factor_| and |filtered_current_level_| are in Q8. + // |buffer_size_packets| is in Q0. filtered_current_level_ = - std::max(0.0, filtered_current_level_ - time_stretched_samples); -} + ((level_factor_ * filtered_current_level_) >> 8) + + ((256 - level_factor_) * rtc::dchecked_cast(buffer_size_packets)); -void BufferLevelFilter::SetTargetBufferLevel(int target_buffer_level_packets) { - if (target_buffer_level_packets <= 1) { - level_factor_ = 0.980; - } else if (target_buffer_level_packets <= 3) { - level_factor_ = 0.984; - } else if (target_buffer_level_packets <= 7) { - level_factor_ = 0.988; - } else { - level_factor_ = 0.992; + // Account for time-scale operations (accelerate and pre-emptive expand). + if (time_stretched_samples && packet_len_samples > 0) { + // Time-scaling has been performed since last filter update. Subtract the + // value of |time_stretched_samples| from |filtered_current_level_| after + // converting |time_stretched_samples| from samples to packets in Q8. + // Make sure that the filtered value remains non-negative. + + int64_t time_stretched_packets = + (int64_t{time_stretched_samples} * (1 << 8)) / + rtc::dchecked_cast(packet_len_samples); + + filtered_current_level_ = rtc::saturated_cast( + std::max(0, filtered_current_level_ - time_stretched_packets)); } } +void BufferLevelFilter::SetTargetBufferLevel(int target_buffer_level) { + if (target_buffer_level <= 1) { + level_factor_ = 251; + } else if (target_buffer_level <= 3) { + level_factor_ = 252; + } else if (target_buffer_level <= 7) { + level_factor_ = 253; + } else { + level_factor_ = 254; + } +} + +int BufferLevelFilter::filtered_current_level() const { + return filtered_current_level_; +} + } // namespace webrtc diff --git a/modules/audio_coding/neteq/buffer_level_filter.h b/modules/audio_coding/neteq/buffer_level_filter.h index 18b43a3806..83388fb4f5 100644 --- a/modules/audio_coding/neteq/buffer_level_filter.h +++ b/modules/audio_coding/neteq/buffer_level_filter.h @@ -24,24 +24,24 @@ class BufferLevelFilter { virtual void Reset(); // Updates the filter. Current buffer size is |buffer_size_packets| (Q0). - // |time_stretched_samples| is subtracted from the filtered value (thus - // bypassing the filter operation). - virtual void Update(size_t buffer_size_samples, int time_stretched_samples); + // If |time_stretched_samples| is non-zero, the value is converted to the + // corresponding number of packets, and is subtracted from the filtered + // value (thus bypassing the filter operation). |packet_len_samples| is the + // number of audio samples carried in each incoming packet. + virtual void Update(size_t buffer_size_packets, + int time_stretched_samples, + size_t packet_len_samples); - // Set the current target buffer level in number of packets (obtained from + // Set the current target buffer level (obtained from // DelayManager::base_target_level()). Used to select the appropriate // filter coefficient. - virtual void SetTargetBufferLevel(int target_buffer_level_packets); + virtual void SetTargetBufferLevel(int target_buffer_level); - // Returns filtered current level in number of samples. - virtual int filtered_current_level() const { - // Round to nearest whole sample. - return static_cast(filtered_current_level_ + 0.5); - } + virtual int filtered_current_level() const; private: - double level_factor_; // Filter factor for the buffer level filter. - double filtered_current_level_; + int level_factor_; // Filter factor for the buffer level filter in Q8. + int filtered_current_level_; // Filtered current buffer level in Q8. RTC_DISALLOW_COPY_AND_ASSIGN(BufferLevelFilter); }; diff --git a/modules/audio_coding/neteq/buffer_level_filter_unittest.cc b/modules/audio_coding/neteq/buffer_level_filter_unittest.cc index 0d4a0f29aa..1f12e73d10 100644 --- a/modules/audio_coding/neteq/buffer_level_filter_unittest.cc +++ b/modules/audio_coding/neteq/buffer_level_filter_unittest.cc @@ -30,22 +30,23 @@ TEST(BufferLevelFilter, ConvergenceTest) { for (int times = 10; times <= 50; times += 10) { for (int value = 100; value <= 200; value += 10) { filter.Reset(); - filter.SetTargetBufferLevel(1); // Makes filter coefficient 0.98. + filter.SetTargetBufferLevel(1); // Makes filter coefficient 251/256. rtc::StringBuilder ss; ss << "times = " << times << ", value = " << value; SCOPED_TRACE(ss.str()); // Print out the parameter values on failure. for (int i = 0; i < times; ++i) { - filter.Update(value, 0 /* time_stretched_samples */); + filter.Update(value, 0 /* time_stretched_samples */, + 160 /* packet_len_samples */); } // Expect the filtered value to be (theoretically) - // (1 - 0.980 ^ |times|) * |value|. - double expected_value_double = (1 - pow(0.98, times)) * value; + // (1 - (251/256) ^ |times|) * |value|. + double expected_value_double = (1 - pow(251.0 / 256.0, times)) * value; int expected_value = static_cast(expected_value_double); // filtered_current_level() returns the value in Q8. // The actual value may differ slightly from the expected value due to // intermediate-stage rounding errors in the filter implementation. // This is why we have to use EXPECT_NEAR with a tolerance of +/-1. - EXPECT_NEAR(expected_value, filter.filtered_current_level(), 1); + EXPECT_NEAR(expected_value, filter.filtered_current_level() >> 8, 1); } } } @@ -57,60 +58,104 @@ TEST(BufferLevelFilter, FilterFactor) { const int kTimes = 10; const int kValue = 100; - filter.SetTargetBufferLevel(3); // Makes filter coefficient 0.984. + filter.SetTargetBufferLevel(3); // Makes filter coefficient 252/256. for (int i = 0; i < kTimes; ++i) { - filter.Update(kValue, 0 /* time_stretched_samples */); + filter.Update(kValue, 0 /* time_stretched_samples */, + 160 /* packet_len_samples */); } // Expect the filtered value to be - // (1 - 0.984 ^ |kTimes|) * |kValue|. - int expected_value = 15; - EXPECT_EQ(expected_value, filter.filtered_current_level()); + // (1 - (252/256) ^ |kTimes|) * |kValue|. + int expected_value = 14; + // filtered_current_level() returns the value in Q8. + EXPECT_EQ(expected_value, filter.filtered_current_level() >> 8); filter.Reset(); - filter.SetTargetBufferLevel(7); // Makes filter coefficient 0.988. + filter.SetTargetBufferLevel(7); // Makes filter coefficient 253/256. for (int i = 0; i < kTimes; ++i) { - filter.Update(kValue, 0 /* time_stretched_samples */); + filter.Update(kValue, 0 /* time_stretched_samples */, + 160 /* packet_len_samples */); } // Expect the filtered value to be - // (1 - 0.988 ^ |kTimes|) * |kValue|. + // (1 - (253/256) ^ |kTimes|) * |kValue|. expected_value = 11; - EXPECT_EQ(expected_value, filter.filtered_current_level()); + // filtered_current_level() returns the value in Q8. + EXPECT_EQ(expected_value, filter.filtered_current_level() >> 8); filter.Reset(); - filter.SetTargetBufferLevel(8); // Makes filter coefficient 0.992. + filter.SetTargetBufferLevel(8); // Makes filter coefficient 254/256. for (int i = 0; i < kTimes; ++i) { - filter.Update(kValue, 0 /* time_stretched_samples */); + filter.Update(kValue, 0 /* time_stretched_samples */, + 160 /* packet_len_samples */); } // Expect the filtered value to be - // (1 - 0.992 ^ |kTimes|) * |kValue|. - expected_value = 8; - EXPECT_EQ(expected_value, filter.filtered_current_level()); + // (1 - (254/256) ^ |kTimes|) * |kValue|. + expected_value = 7; + // filtered_current_level() returns the value in Q8. + EXPECT_EQ(expected_value, filter.filtered_current_level() >> 8); } TEST(BufferLevelFilter, TimeStretchedSamples) { BufferLevelFilter filter; - filter.SetTargetBufferLevel(1); // Makes filter coefficient 0.98. + filter.SetTargetBufferLevel(1); // Makes filter coefficient 251/256. // Update 10 times with value 100. const int kTimes = 10; const int kValue = 100; - const int kTimeStretchedSamples = 3; + const int kPacketSizeSamples = 160; + const int kNumPacketsStretched = 2; + const int kTimeStretchedSamples = kNumPacketsStretched * kPacketSizeSamples; for (int i = 0; i < kTimes; ++i) { - filter.Update(kValue, 0); + // Packet size set to 0. Do not expect the parameter + // |kTimeStretchedSamples| to have any effect. + filter.Update(kValue, kTimeStretchedSamples, 0 /* packet_len_samples */); } // Expect the filtered value to be - // (1 - 0.98 ^ |kTimes|) * |kValue|. - const int kExpectedValue = 18; - EXPECT_EQ(kExpectedValue, filter.filtered_current_level()); + // (1 - (251/256) ^ |kTimes|) * |kValue|. + const int kExpectedValue = 17; + // filtered_current_level() returns the value in Q8. + EXPECT_EQ(kExpectedValue, filter.filtered_current_level() >> 8); // Update filter again, now with non-zero value for packet length. // Set the current filtered value to be the input, in order to isolate the // impact of |kTimeStretchedSamples|. - filter.Update(filter.filtered_current_level(), kTimeStretchedSamples); - EXPECT_EQ(kExpectedValue - kTimeStretchedSamples, - filter.filtered_current_level()); + filter.Update(filter.filtered_current_level() >> 8, kTimeStretchedSamples, + kPacketSizeSamples); + EXPECT_EQ(kExpectedValue - kNumPacketsStretched, + filter.filtered_current_level() >> 8); // Try negative value and verify that we come back to the previous result. - filter.Update(filter.filtered_current_level(), -kTimeStretchedSamples); - EXPECT_EQ(kExpectedValue, filter.filtered_current_level()); + filter.Update(filter.filtered_current_level() >> 8, -kTimeStretchedSamples, + kPacketSizeSamples); + EXPECT_EQ(kExpectedValue, filter.filtered_current_level() >> 8); +} + +TEST(BufferLevelFilter, TimeStretchedSamplesNegativeUnevenFrames) { + BufferLevelFilter filter; + filter.SetTargetBufferLevel(1); // Makes filter coefficient 251/256. + // Update 10 times with value 100. + const int kTimes = 10; + const int kValue = 100; + const int kPacketSizeSamples = 160; + const int kTimeStretchedSamples = -3.1415 * kPacketSizeSamples; + for (int i = 0; i < kTimes; ++i) { + // Packet size set to 0. Do not expect the parameter + // |kTimeStretchedSamples| to have any effect. + filter.Update(kValue, kTimeStretchedSamples, 0 /* packet_len_samples */); + } + // Expect the filtered value to be + // (1 - (251/256) ^ |kTimes|) * |kValue|. + const int kExpectedValue = 17; + // filtered_current_level() returns the value in Q8. + EXPECT_EQ(kExpectedValue, filter.filtered_current_level() >> 8); + + // Update filter again, now with non-zero value for packet length. + // Set the current filtered value to be the input, in order to isolate the + // impact of |kTimeStretchedSamples|. + filter.Update(filter.filtered_current_level() >> 8, kTimeStretchedSamples, + kPacketSizeSamples); + EXPECT_EQ(21, filter.filtered_current_level() >> 8); + // Try negative value and verify that we come back to the previous result. + filter.Update(filter.filtered_current_level() >> 8, -kTimeStretchedSamples, + kPacketSizeSamples); + EXPECT_EQ(kExpectedValue, filter.filtered_current_level() >> 8); } } // namespace webrtc diff --git a/modules/audio_coding/neteq/decision_logic.cc b/modules/audio_coding/neteq/decision_logic.cc index f9f420af0e..40e421d672 100644 --- a/modules/audio_coding/neteq/decision_logic.cc +++ b/modules/audio_coding/neteq/decision_logic.cc @@ -113,9 +113,11 @@ Operations DecisionLogic::GetDecision(const SyncBuffer& sync_buffer, cng_state_ = kCngInternalOn; } + const size_t samples_left = + sync_buffer.FutureLength() - expand.overlap_length(); // TODO(jakobi): Use buffer span instead of num samples. const size_t cur_size_samples = - packet_buffer_.NumSamplesInBuffer(decoder_frame_length); + samples_left + packet_buffer_.NumSamplesInBuffer(decoder_frame_length); prev_time_scale_ = prev_time_scale_ && (prev_mode == kModeAccelerateSuccess || @@ -173,7 +175,8 @@ Operations DecisionLogic::GetDecision(const SyncBuffer& sync_buffer, // if the mute factor is low enough (otherwise the expansion was short enough // to not be noticable). // Note that the MuteFactor is in Q14, so a value of 16384 corresponds to 1. - size_t current_span = packet_buffer_.GetSpanSamples(decoder_frame_length); + size_t current_span = + samples_left + packet_buffer_.GetSpanSamples(decoder_frame_length); if ((prev_mode == kModeExpand || prev_mode == kModeCodecPlc) && expand.MuteFactor(0) < 16384 / 2 && current_span < static_cast(delay_manager_->TargetLevel() * @@ -190,9 +193,9 @@ Operations DecisionLogic::GetDecision(const SyncBuffer& sync_buffer, return ExpectedPacketAvailable(prev_mode, play_dtmf); } else if (!PacketBuffer::IsObsoleteTimestamp( available_timestamp, target_timestamp, five_seconds_samples)) { - return FuturePacketAvailable(decoder_frame_length, prev_mode, - target_timestamp, available_timestamp, - play_dtmf, generated_noise_samples); + return FuturePacketAvailable( + sync_buffer, expand, decoder_frame_length, prev_mode, target_timestamp, + available_timestamp, play_dtmf, generated_noise_samples); } else { // This implies that available_timestamp < target_timestamp, which can // happen when a new stream or codec is received. Signal for a reset. @@ -212,13 +215,19 @@ void DecisionLogic::FilterBufferLevel(size_t buffer_size_samples) { buffer_level_filter_->SetTargetBufferLevel( delay_manager_->base_target_level()); + size_t buffer_size_packets = 0; + if (packet_length_samples_ > 0) { + // Calculate size in packets. + buffer_size_packets = buffer_size_samples / packet_length_samples_; + } int sample_memory_local = 0; if (prev_time_scale_) { sample_memory_local = sample_memory_; timescale_countdown_ = tick_timer_->GetNewCountdown(kMinTimescaleInterval); } - buffer_level_filter_->Update(buffer_size_samples, sample_memory_local); + buffer_level_filter_->Update(buffer_size_packets, sample_memory_local, + packet_length_samples_); prev_time_scale_ = false; } @@ -274,22 +283,15 @@ Operations DecisionLogic::NoPacket(bool play_dtmf) { Operations DecisionLogic::ExpectedPacketAvailable(Modes prev_mode, bool play_dtmf) { if (!disallow_time_stretching_ && prev_mode != kModeExpand && !play_dtmf) { - // Check criterion for time-stretching. The values are in number of packets - // in Q8. + // Check criterion for time-stretching. int low_limit, high_limit; delay_manager_->BufferLimits(&low_limit, &high_limit); - int buffer_level_packets = 0; - if (packet_length_samples_ > 0) { - buffer_level_packets = - ((1 << 8) * buffer_level_filter_->filtered_current_level()) / - packet_length_samples_; - } - if (buffer_level_packets >= high_limit << 2) + if (buffer_level_filter_->filtered_current_level() >= high_limit << 2) return kFastAccelerate; if (TimescaleAllowed()) { - if (buffer_level_packets >= high_limit) + if (buffer_level_filter_->filtered_current_level() >= high_limit) return kAccelerate; - if (buffer_level_packets < low_limit) + if (buffer_level_filter_->filtered_current_level() < low_limit) return kPreemptiveExpand; } } @@ -297,6 +299,8 @@ Operations DecisionLogic::ExpectedPacketAvailable(Modes prev_mode, } Operations DecisionLogic::FuturePacketAvailable( + const SyncBuffer& sync_buffer, + const Expand& expand, size_t decoder_frame_length, Modes prev_mode, uint32_t target_timestamp, @@ -323,8 +327,10 @@ Operations DecisionLogic::FuturePacketAvailable( return kNormal; } + const size_t samples_left = + sync_buffer.FutureLength() - expand.overlap_length(); const size_t cur_size_samples = - packet_buffer_.NumPacketsInBuffer() * decoder_frame_length; + samples_left + packet_buffer_.NumPacketsInBuffer() * decoder_frame_length; // If previous was comfort noise, then no merge is needed. if (prev_mode == kModeRfc3389Cng || prev_mode == kModeCodecInternalCng) { @@ -359,13 +365,8 @@ Operations DecisionLogic::FuturePacketAvailable( } bool DecisionLogic::UnderTargetLevel() const { - int buffer_level_packets = 0; - if (packet_length_samples_ > 0) { - buffer_level_packets = - ((1 << 8) * buffer_level_filter_->filtered_current_level()) / - packet_length_samples_; - } - return buffer_level_packets <= delay_manager_->TargetLevel(); + return buffer_level_filter_->filtered_current_level() <= + delay_manager_->TargetLevel(); } bool DecisionLogic::ReinitAfterExpands(uint32_t timestamp_leap) const { diff --git a/modules/audio_coding/neteq/decision_logic.h b/modules/audio_coding/neteq/decision_logic.h index 49020b0aab..2414e8cc25 100644 --- a/modules/audio_coding/neteq/decision_logic.h +++ b/modules/audio_coding/neteq/decision_logic.h @@ -134,7 +134,9 @@ class DecisionLogic final { // Returns the operation to do given that the expected packet is not // available, but a packet further into the future is at hand. - Operations FuturePacketAvailable(size_t decoder_frame_length, + Operations FuturePacketAvailable(const SyncBuffer& sync_buffer, + const Expand& expand, + size_t decoder_frame_length, Modes prev_mode, uint32_t target_timestamp, uint32_t available_timestamp, diff --git a/modules/audio_coding/neteq/mock/mock_buffer_level_filter.h b/modules/audio_coding/neteq/mock/mock_buffer_level_filter.h index 031195cd0f..bf9fd59c9a 100644 --- a/modules/audio_coding/neteq/mock/mock_buffer_level_filter.h +++ b/modules/audio_coding/neteq/mock/mock_buffer_level_filter.h @@ -22,8 +22,10 @@ class MockBufferLevelFilter : public BufferLevelFilter { virtual ~MockBufferLevelFilter() { Die(); } MOCK_METHOD0(Die, void()); MOCK_METHOD0(Reset, void()); - MOCK_METHOD2(Update, - void(size_t buffer_size_samples, int time_stretched_samples)); + MOCK_METHOD3(Update, + void(size_t buffer_size_packets, + int time_stretched_samples, + size_t packet_len_samples)); MOCK_METHOD1(SetTargetBufferLevel, void(int target_buffer_level)); MOCK_CONST_METHOD0(filtered_current_level, int()); }; diff --git a/modules/audio_coding/neteq/neteq_impl.cc b/modules/audio_coding/neteq/neteq_impl.cc index 82ec18db17..ad6becc90e 100644 --- a/modules/audio_coding/neteq/neteq_impl.cc +++ b/modules/audio_coding/neteq/neteq_impl.cc @@ -310,12 +310,18 @@ int NetEqImpl::TargetDelayMs() const { int NetEqImpl::FilteredCurrentDelayMs() const { rtc::CritScope lock(&crit_sect_); + // Calculate the filtered packet buffer level in samples. The value from + // |buffer_level_filter_| is in number of packets, represented in Q8. + const size_t packet_buffer_samples = + (buffer_level_filter_->filtered_current_level() * + decoder_frame_length_) >> + 8; // Sum up the filtered packet buffer level with the future length of the sync - // buffer. - const int delay_samples = buffer_level_filter_->filtered_current_level() + - sync_buffer_->FutureLength(); + // buffer, and divide the sum by the sample rate. + const size_t delay_samples = + packet_buffer_samples + sync_buffer_->FutureLength(); // The division below will truncate. The return value is in ms. - return delay_samples / rtc::CheckedDivExact(fs_hz_, 1000); + return static_cast(delay_samples) / rtc::CheckedDivExact(fs_hz_, 1000); } int NetEqImpl::NetworkStatistics(NetEqNetworkStatistics* stats) { diff --git a/modules/audio_coding/neteq/neteq_unittest.cc b/modules/audio_coding/neteq/neteq_unittest.cc index a8649853e7..6c67ca8ea0 100644 --- a/modules/audio_coding/neteq/neteq_unittest.cc +++ b/modules/audio_coding/neteq/neteq_unittest.cc @@ -458,16 +458,16 @@ TEST_F(NetEqDecodingTest, MAYBE_TestBitExactness) { webrtc::test::ResourcePath("audio_coding/neteq_universal_new", "rtp"); const std::string output_checksum = - PlatformChecksum("415cc2366810676aad27a92b7a9068e79b7e4093", - "52411c46e946e1d50fa777bbfb4686e7161f9cc7", "not used", - "415cc2366810676aad27a92b7a9068e79b7e4093", - "3e02f268f3b4f3acfcc1c397214ea13d09c212fd"); + PlatformChecksum("9652cee1d6771a9cbfda821ae1bbdb41b0dd4dee", + "54a7e32f163663c0af35bf70bf45cefc24ad62ef", "not used", + "9652cee1d6771a9cbfda821ae1bbdb41b0dd4dee", + "79496b0a1ef0a3824f3ee04789748a461bed643f"); const std::string network_stats_checksum = - PlatformChecksum("6c8726e8699cc61535e65ef9406d339954a05cf8", - "b9f2c862328ddb8d3ec9e79f61cc1d937ee56df6", "not used", - "6c8726e8699cc61535e65ef9406d339954a05cf8", - "6c8726e8699cc61535e65ef9406d339954a05cf8"); + PlatformChecksum("c59b1f9f282b6d8733cdff975e3c150ca4a47d51", + "bca95e565996a4ffd6e2ac15736e08843bdca93b", "not used", + "c59b1f9f282b6d8733cdff975e3c150ca4a47d51", + "c59b1f9f282b6d8733cdff975e3c150ca4a47d51"); DecodeAndCompare(input_rtp_file, output_checksum, network_stats_checksum, FLAG_gen_ref); @@ -486,17 +486,17 @@ TEST_F(NetEqDecodingTest, MAYBE_TestOpusBitExactness) { // Checksum depends on libopus being compiled with or without SSE. const std::string maybe_sse = "14a63b3c7b925c82296be4bafc71bec85f2915c2|" - "8884ffe98700454875a88d1c3ea9b55e829a2016"; + "2c05677daa968d6c68b92adf4affb7cd9bb4d363"; const std::string output_checksum = PlatformChecksum( - maybe_sse, "1f76c884d16812704dec85f2b98db697108d2d9b", - "f888efef2d0710f202f19ba167ed509609146929", maybe_sse, maybe_sse); + maybe_sse, "b7b7ed802b0e18ee416973bf3b9ae98599b0181d", + "5876e52dda90d5ca433c3726555b907b97c86374", maybe_sse, maybe_sse); const std::string network_stats_checksum = - PlatformChecksum("bb8d91f71873df562224fe0dc5822b5dfb030090", - "9f858290a675c4ceabf575feb6a59bef76d62eaf", - "12963c965d9d102ebbc1f619508e2960a1f7dbee", - "bb8d91f71873df562224fe0dc5822b5dfb030090", - "bb8d91f71873df562224fe0dc5822b5dfb030090"); + PlatformChecksum("adb3272498e436d1c019cbfd71610e9510c54497", + "fa935a91abc7291db47428a2d7c5361b98713a92", + "42106aa5267300f709f63737707ef07afd9dac61", + "adb3272498e436d1c019cbfd71610e9510c54497", + "adb3272498e436d1c019cbfd71610e9510c54497"); DecodeAndCompare(input_rtp_file, output_checksum, network_stats_checksum, FLAG_gen_ref); @@ -796,7 +796,7 @@ TEST_F(NetEqDecodingTest, LongCngWithNegativeClockDriftNetworkFreeze) { const double kDriftFactor = 1000.0 / (1000.0 + 25.0); const double kNetworkFreezeTimeMs = 5000.0; const bool kGetAudioDuringFreezeRecovery = false; - const int kDelayToleranceMs = 60; + const int kDelayToleranceMs = 50; const int kMaxTimeToSpeechMs = 200; LongCngWithClockDrift(kDriftFactor, kNetworkFreezeTimeMs, kGetAudioDuringFreezeRecovery, kDelayToleranceMs,