Refactor NetEq delay manager logic.

- Removes dependence on sequence number for calculating target delay.
- Changes target delay unit to milliseconds instead of number of
  packets.
- Moves acceleration/preemptive expand thresholds to decision logic.
  Tests for this will be added in a follow up cl.

Bug: webrtc:10333
Change-Id: If690aae4abf41ef1d9353f0ff01fb7d121cf8a26
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/186265
Commit-Queue: Jakob Ivarsson <jakobi@webrtc.org>
Reviewed-by: Ivo Creusen <ivoc@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#32326}
This commit is contained in:
Jakob Ivarsson
2020-10-06 14:36:54 +02:00
committed by Commit Bot
parent 76d3e7a8d1
commit f8e62fcb14
12 changed files with 251 additions and 625 deletions

View File

@ -939,58 +939,58 @@ class AcmReceiverBitExactnessOldApi : public ::testing::Test {
defined(WEBRTC_CODEC_ILBC) defined(WEBRTC_CODEC_ILBC)
TEST_F(AcmReceiverBitExactnessOldApi, 8kHzOutput) { TEST_F(AcmReceiverBitExactnessOldApi, 8kHzOutput) {
std::string others_checksum_reference = std::string others_checksum_reference =
GetCPUInfo(kAVX2) != 0 ? "6edbfe69b965a8687b8744ed1b8eb5a7" GetCPUInfo(kAVX2) != 0 ? "1d7b784031599e2c01a3f575f8439f2f"
: "6c204b289486b0695b08a9e94fab1948"; : "c119fda4ea2c119ff2a720fd0c289071";
std::string win64_checksum_reference = std::string win64_checksum_reference =
GetCPUInfo(kAVX2) != 0 ? "405a50f0bcb8827e20aa944299fc59f6" GetCPUInfo(kAVX2) != 0 ? "405a50f0bcb8827e20aa944299fc59f6"
: "ff5ffee2ee92f8fe61d9f2010b8a68a3"; : "38e70d4e186f8e1a56b929fafcb7c379";
Run(8000, Run(8000,
PlatformChecksum(others_checksum_reference, win64_checksum_reference, PlatformChecksum(others_checksum_reference, win64_checksum_reference,
"53494a96f3db4a5b07d723e0cbac0ad7", "3b03e41731e1cef5ae2b9f9618660b42",
"4598140b5e4f7ee66c5adad609e65a3e", "4598140b5e4f7ee66c5adad609e65a3e",
"516c2859126ea4913f30d51af4a4f3dc")); "da7e76687c8c0a9509cd1d57ee1aba3b"));
} }
TEST_F(AcmReceiverBitExactnessOldApi, 16kHzOutput) { TEST_F(AcmReceiverBitExactnessOldApi, 16kHzOutput) {
std::string others_checksum_reference = std::string others_checksum_reference =
GetCPUInfo(kAVX2) != 0 ? "295f031e051f1770b4ab4107dba768b5" GetCPUInfo(kAVX2) != 0 ? "8884d910e443c244d8593c2e3cef5e63"
: "226dbdbce2354399c6df05371042cda3"; : "36dc8c0532ba0efa099e2b6a689cde40";
std::string win64_checksum_reference = std::string win64_checksum_reference =
GetCPUInfo(kAVX2) != 0 ? "58fd62a5c49ee513f9fa6fe7dbf62c97" GetCPUInfo(kAVX2) != 0 ? "58fd62a5c49ee513f9fa6fe7dbf62c97"
: "9c80bf5ec496c41ce8112e1523bf8c83"; : "07e4b388168e273fa19da0a167aff782";
Run(16000, Run(16000,
PlatformChecksum(others_checksum_reference, win64_checksum_reference, PlatformChecksum(others_checksum_reference, win64_checksum_reference,
"11a6f170fdaffa81a2948af121f370af", "06b08d14a72f6e7c72840b1cc9ad204d",
"f2aad418af974a3b1694d5ae5cc2c3c7", "f2aad418af974a3b1694d5ae5cc2c3c7",
"6133301a18be95c416984182816d859f")); "1d5f9a93f3975e7e491373b81eb5fd14"));
} }
TEST_F(AcmReceiverBitExactnessOldApi, 32kHzOutput) { TEST_F(AcmReceiverBitExactnessOldApi, 32kHzOutput) {
std::string others_checksum_reference = std::string others_checksum_reference =
GetCPUInfo(kAVX2) != 0 ? "2895e5ab3146eaa78fa6843ed60e7e37" GetCPUInfo(kAVX2) != 0 ? "73f4fe21996c0af495e2c47e3708e519"
: "f94665cc0e904d5d5cf0394e30ee4edd"; : "c848ce9002d3825056a1eac2a067c0d3";
std::string win64_checksum_reference = std::string win64_checksum_reference =
GetCPUInfo(kAVX2) != 0 ? "04ce6a1dac5ffdd8438d804623d0132f" GetCPUInfo(kAVX2) != 0 ? "04ce6a1dac5ffdd8438d804623d0132f"
: "697934bcf0849f80d76ce20854161220"; : "0e705f6844c75fd57a84734f7c30af87";
Run(32000, Run(32000,
PlatformChecksum(others_checksum_reference, win64_checksum_reference, PlatformChecksum(others_checksum_reference, win64_checksum_reference,
"3609aa5288c1d512e8e652ceabecb495", "c18e98e5701ec91bba5c026b720d1790",
"100869c8dcde51346c2073e52a272d98", "100869c8dcde51346c2073e52a272d98",
"55363bc9cdda6464a58044919157827b")); "e35df943bfa3ca32e86b26bf1e37ed8f"));
} }
TEST_F(AcmReceiverBitExactnessOldApi, 48kHzOutput) { TEST_F(AcmReceiverBitExactnessOldApi, 48kHzOutput) {
std::string others_checksum_reference = std::string others_checksum_reference =
GetCPUInfo(kAVX2) != 0 ? "640bca210e1b8dd229224d2a0c79ff1f" GetCPUInfo(kAVX2) != 0 ? "884243f7e1476931e93eda5de88d1326"
: "2955d0b83602541fd92d9b820ebce68d"; : "ba0f66d538487bba377e721cfac62d1e";
std::string win64_checksum_reference = std::string win64_checksum_reference =
GetCPUInfo(kAVX2) != 0 ? "f59833d9b0924f4b0704707dd3589f80" GetCPUInfo(kAVX2) != 0 ? "f59833d9b0924f4b0704707dd3589f80"
: "f4a8386a6a49439ced60ed9a7c7f75fd"; : "6a480541fb86faa95c7563b9de08104d";
Run(48000, Run(48000,
PlatformChecksum(others_checksum_reference, win64_checksum_reference, PlatformChecksum(others_checksum_reference, win64_checksum_reference,
"d8169dfeba708b5212bdc365e08aee9d", "30e617e4b3c9ba1979d1b2e8eba3519b",
"bd44bf97e7899186532f91235cef444d", "bd44bf97e7899186532f91235cef444d",
"47594deaab5d9166cfbf577203b2563e")); "90158462a1853b1de50873eebd68dba7"));
} }
TEST_F(AcmReceiverBitExactnessOldApi, 48kHzOutputExternalDecoder) { TEST_F(AcmReceiverBitExactnessOldApi, 48kHzOutputExternalDecoder) {
@ -1069,16 +1069,16 @@ TEST_F(AcmReceiverBitExactnessOldApi, 48kHzOutputExternalDecoder) {
rtc::scoped_refptr<rtc::RefCountedObject<ADFactory>> factory( rtc::scoped_refptr<rtc::RefCountedObject<ADFactory>> factory(
new rtc::RefCountedObject<ADFactory>); new rtc::RefCountedObject<ADFactory>);
std::string others_checksum_reference = std::string others_checksum_reference =
GetCPUInfo(kAVX2) != 0 ? "640bca210e1b8dd229224d2a0c79ff1f" GetCPUInfo(kAVX2) != 0 ? "884243f7e1476931e93eda5de88d1326"
: "2955d0b83602541fd92d9b820ebce68d"; : "ba0f66d538487bba377e721cfac62d1e";
std::string win64_checksum_reference = std::string win64_checksum_reference =
GetCPUInfo(kAVX2) != 0 ? "f59833d9b0924f4b0704707dd3589f80" GetCPUInfo(kAVX2) != 0 ? "f59833d9b0924f4b0704707dd3589f80"
: "f4a8386a6a49439ced60ed9a7c7f75fd"; : "6a480541fb86faa95c7563b9de08104d";
Run(48000, Run(48000,
PlatformChecksum(others_checksum_reference, win64_checksum_reference, PlatformChecksum(others_checksum_reference, win64_checksum_reference,
"d8169dfeba708b5212bdc365e08aee9d", "30e617e4b3c9ba1979d1b2e8eba3519b",
"bd44bf97e7899186532f91235cef444d", "bd44bf97e7899186532f91235cef444d",
"47594deaab5d9166cfbf577203b2563e"), "90158462a1853b1de50873eebd68dba7"),
factory, [](AudioCodingModule* acm) { factory, [](AudioCodingModule* acm) {
acm->SetReceiveCodecs({{0, {"MockPCMu", 8000, 1}}, acm->SetReceiveCodecs({{0, {"MockPCMu", 8000, 1}},
{103, {"ISAC", 16000, 1}}, {103, {"ISAC", 16000, 1}},
@ -1312,11 +1312,11 @@ TEST_F(AcmSenderBitExactnessOldApi, IsacWb30ms) {
TEST_F(AcmSenderBitExactnessOldApi, IsacWb60ms) { TEST_F(AcmSenderBitExactnessOldApi, IsacWb60ms) {
ASSERT_NO_FATAL_FAILURE(SetUpTest("ISAC", 16000, 1, 103, 960, 960)); ASSERT_NO_FATAL_FAILURE(SetUpTest("ISAC", 16000, 1, 103, 960, 960));
Run(AcmReceiverBitExactnessOldApi::PlatformChecksum( Run(AcmReceiverBitExactnessOldApi::PlatformChecksum(
"f59760fa000991ee5fa81f2e607db254", "1ad29139a04782a33daad8c2b9b35875",
"986aa16d7097a26e32e212e39ec58517", "14d63c5f08127d280e722e3191b73bdd",
"9a81e467eb1485f84aca796f8ea65011", "9a81e467eb1485f84aca796f8ea65011",
"ef75e900e6f375e3061163c53fd09a63", "ef75e900e6f375e3061163c53fd09a63",
"f59760fa000991ee5fa81f2e607db254"), "1ad29139a04782a33daad8c2b9b35875"),
AcmReceiverBitExactnessOldApi::PlatformChecksum( AcmReceiverBitExactnessOldApi::PlatformChecksum(
"9e0a0ab743ad987b55b8e14802769c56", "9e0a0ab743ad987b55b8e14802769c56",
"ebe04a819d3a9d83a83a17f271e1139a", "ebe04a819d3a9d83a83a17f271e1139a",
@ -1349,37 +1349,37 @@ TEST_F(AcmSenderBitExactnessOldApi, MAYBE_IsacSwb30ms) {
TEST_F(AcmSenderBitExactnessOldApi, Pcm16_8000khz_10ms) { TEST_F(AcmSenderBitExactnessOldApi, Pcm16_8000khz_10ms) {
ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 8000, 1, 107, 80, 80)); ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 8000, 1, 107, 80, 80));
Run("de4a98e1406f8b798d99cd0704e862e2", "c1edd36339ce0326cc4550041ad719a0", Run("15396f66b5b0ab6842e151c807395e4c", "c1edd36339ce0326cc4550041ad719a0",
100, test::AcmReceiveTestOldApi::kMonoOutput); 100, test::AcmReceiveTestOldApi::kMonoOutput);
} }
TEST_F(AcmSenderBitExactnessOldApi, Pcm16_16000khz_10ms) { TEST_F(AcmSenderBitExactnessOldApi, Pcm16_16000khz_10ms) {
ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 16000, 1, 108, 160, 160)); ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 16000, 1, 108, 160, 160));
Run("ae646d7b68384a1269cc080dd4501916", "ad786526383178b08d80d6eee06e9bad", Run("54ae004529874c2b362c7f0ccd19cb99", "ad786526383178b08d80d6eee06e9bad",
100, test::AcmReceiveTestOldApi::kMonoOutput); 100, test::AcmReceiveTestOldApi::kMonoOutput);
} }
TEST_F(AcmSenderBitExactnessOldApi, Pcm16_32000khz_10ms) { TEST_F(AcmSenderBitExactnessOldApi, Pcm16_32000khz_10ms) {
ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 32000, 1, 109, 320, 320)); ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 32000, 1, 109, 320, 320));
Run("7fe325e8fbaf755e3c5df0b11a4774fb", "5ef82ea885e922263606c6fdbc49f651", Run("d6a4a68b8c838dcc1e7ae7136467cdf0", "5ef82ea885e922263606c6fdbc49f651",
100, test::AcmReceiveTestOldApi::kMonoOutput); 100, test::AcmReceiveTestOldApi::kMonoOutput);
} }
TEST_F(AcmSenderBitExactnessOldApi, Pcm16_stereo_8000khz_10ms) { TEST_F(AcmSenderBitExactnessOldApi, Pcm16_stereo_8000khz_10ms) {
ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 8000, 2, 111, 80, 80)); ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 8000, 2, 111, 80, 80));
Run("fb263b74e7ac3de915474d77e4744ceb", "62ce5adb0d4965d0a52ec98ae7f98974", Run("6b011dab43e3a8a46ccff7e4412ed8a2", "62ce5adb0d4965d0a52ec98ae7f98974",
100, test::AcmReceiveTestOldApi::kStereoOutput); 100, test::AcmReceiveTestOldApi::kStereoOutput);
} }
TEST_F(AcmSenderBitExactnessOldApi, Pcm16_stereo_16000khz_10ms) { TEST_F(AcmSenderBitExactnessOldApi, Pcm16_stereo_16000khz_10ms) {
ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 16000, 2, 112, 160, 160)); ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 16000, 2, 112, 160, 160));
Run("d09e9239553649d7ac93e19d304281fd", "41ca8edac4b8c71cd54fd9f25ec14870", Run("17fc9854358bfe0419408290664bd78e", "41ca8edac4b8c71cd54fd9f25ec14870",
100, test::AcmReceiveTestOldApi::kStereoOutput); 100, test::AcmReceiveTestOldApi::kStereoOutput);
} }
TEST_F(AcmSenderBitExactnessOldApi, Pcm16_stereo_32000khz_10ms) { TEST_F(AcmSenderBitExactnessOldApi, Pcm16_stereo_32000khz_10ms) {
ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 32000, 2, 113, 320, 320)); ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 32000, 2, 113, 320, 320));
Run("5f025d4f390982cc26b3d92fe02e3044", "50e58502fb04421bf5b857dda4c96879", Run("9ac9a1f64d55da2fc9f3167181cc511d", "50e58502fb04421bf5b857dda4c96879",
100, test::AcmReceiveTestOldApi::kStereoOutput); 100, test::AcmReceiveTestOldApi::kStereoOutput);
} }

View File

@ -45,12 +45,12 @@ void BufferLevelFilter::Update(size_t buffer_size_samples,
filtered_current_level - (int64_t{time_stretched_samples} * (1 << 8)))); filtered_current_level - (int64_t{time_stretched_samples} * (1 << 8))));
} }
void BufferLevelFilter::SetTargetBufferLevel(int target_buffer_level) { void BufferLevelFilter::SetTargetBufferLevel(int target_buffer_level_ms) {
if (target_buffer_level <= 1) { if (target_buffer_level_ms <= 20) {
level_factor_ = 251; level_factor_ = 251;
} else if (target_buffer_level <= 3) { } else if (target_buffer_level_ms <= 60) {
level_factor_ = 252; level_factor_ = 252;
} else if (target_buffer_level <= 7) { } else if (target_buffer_level_ms <= 140) {
level_factor_ = 253; level_factor_ = 253;
} else { } else {
level_factor_ = 254; level_factor_ = 254;

View File

@ -23,15 +23,13 @@ class BufferLevelFilter {
virtual ~BufferLevelFilter() {} virtual ~BufferLevelFilter() {}
virtual void Reset(); virtual void Reset();
// Updates the filter. Current buffer size is |buffer_size_packets| (Q0). // Updates the filter. Current buffer size is |buffer_size_samples|.
// |time_stretched_samples| is subtracted from the filtered value (thus // |time_stretched_samples| is subtracted from the filtered value (thus
// bypassing the filter operation). // bypassing the filter operation).
virtual void Update(size_t buffer_size_samples, int time_stretched_samples); virtual void Update(size_t buffer_size_samples, int time_stretched_samples);
// Set the current target buffer level in number of packets (obtained from // The target level is used to select the appropriate filter coefficient.
// DelayManager::base_target_level()). Used to select the appropriate virtual void SetTargetBufferLevel(int target_buffer_level_ms);
// filter coefficient.
virtual void SetTargetBufferLevel(int target_buffer_level_packets);
// Returns filtered current level in number of samples. // Returns filtered current level in number of samples.
virtual int filtered_current_level() const { virtual int filtered_current_level() const {

View File

@ -30,7 +30,7 @@ TEST(BufferLevelFilter, ConvergenceTest) {
for (int times = 10; times <= 50; times += 10) { for (int times = 10; times <= 50; times += 10) {
for (int value = 100; value <= 200; value += 10) { for (int value = 100; value <= 200; value += 10) {
filter.Reset(); filter.Reset();
filter.SetTargetBufferLevel(1); // Makes filter coefficient 251/256. filter.SetTargetBufferLevel(20); // Makes filter coefficient 251/256.
rtc::StringBuilder ss; rtc::StringBuilder ss;
ss << "times = " << times << ", value = " << value; ss << "times = " << times << ", value = " << value;
SCOPED_TRACE(ss.str()); // Print out the parameter values on failure. SCOPED_TRACE(ss.str()); // Print out the parameter values on failure.
@ -57,7 +57,7 @@ TEST(BufferLevelFilter, FilterFactor) {
const int kTimes = 10; const int kTimes = 10;
const int kValue = 100; const int kValue = 100;
filter.SetTargetBufferLevel(3); // Makes filter coefficient 252/256. filter.SetTargetBufferLevel(60); // Makes filter coefficient 252/256.
for (int i = 0; i < kTimes; ++i) { for (int i = 0; i < kTimes; ++i) {
filter.Update(kValue, 0 /* time_stretched_samples */); filter.Update(kValue, 0 /* time_stretched_samples */);
} }
@ -67,7 +67,7 @@ TEST(BufferLevelFilter, FilterFactor) {
EXPECT_EQ(expected_value, filter.filtered_current_level()); EXPECT_EQ(expected_value, filter.filtered_current_level());
filter.Reset(); filter.Reset();
filter.SetTargetBufferLevel(7); // Makes filter coefficient 253/256. filter.SetTargetBufferLevel(140); // Makes filter coefficient 253/256.
for (int i = 0; i < kTimes; ++i) { for (int i = 0; i < kTimes; ++i) {
filter.Update(kValue, 0 /* time_stretched_samples */); filter.Update(kValue, 0 /* time_stretched_samples */);
} }
@ -77,7 +77,7 @@ TEST(BufferLevelFilter, FilterFactor) {
EXPECT_EQ(expected_value, filter.filtered_current_level()); EXPECT_EQ(expected_value, filter.filtered_current_level());
filter.Reset(); filter.Reset();
filter.SetTargetBufferLevel(8); // Makes filter coefficient 254/256. filter.SetTargetBufferLevel(160); // Makes filter coefficient 254/256.
for (int i = 0; i < kTimes; ++i) { for (int i = 0; i < kTimes; ++i) {
filter.Update(kValue, 0 /* time_stretched_samples */); filter.Update(kValue, 0 /* time_stretched_samples */);
} }
@ -89,7 +89,7 @@ TEST(BufferLevelFilter, FilterFactor) {
TEST(BufferLevelFilter, TimeStretchedSamples) { TEST(BufferLevelFilter, TimeStretchedSamples) {
BufferLevelFilter filter; BufferLevelFilter filter;
filter.SetTargetBufferLevel(1); // Makes filter coefficient 251/256. filter.SetTargetBufferLevel(20); // Makes filter coefficient 251/256.
// Update 10 times with value 100. // Update 10 times with value 100.
const int kTimes = 10; const int kTimes = 10;
const int kValue = 100; const int kValue = 100;

View File

@ -27,6 +27,7 @@ namespace {
constexpr int kPostponeDecodingLevel = 50; constexpr int kPostponeDecodingLevel = 50;
constexpr int kDefaultTargetLevelWindowMs = 100; constexpr int kDefaultTargetLevelWindowMs = 100;
constexpr int kDecelerationTargetLevelOffsetMs = 85;
} // namespace } // namespace
@ -35,7 +36,6 @@ namespace webrtc {
DecisionLogic::DecisionLogic(NetEqController::Config config) DecisionLogic::DecisionLogic(NetEqController::Config config)
: delay_manager_(DelayManager::Create(config.max_packets_in_buffer, : delay_manager_(DelayManager::Create(config.max_packets_in_buffer,
config.base_min_delay_ms, config.base_min_delay_ms,
config.enable_rtx_handling,
config.tick_timer)), config.tick_timer)),
tick_timer_(config.tick_timer), tick_timer_(config.tick_timer),
disallow_time_stretching_(!config.allow_time_stretching), disallow_time_stretching_(!config.allow_time_stretching),
@ -67,6 +67,7 @@ void DecisionLogic::Reset() {
packet_length_samples_ = 0; packet_length_samples_ = 0;
sample_memory_ = 0; sample_memory_ = 0;
prev_time_scale_ = false; prev_time_scale_ = false;
last_pack_cng_or_dtmf_ = true;
timescale_countdown_.reset(); timescale_countdown_.reset();
num_consecutive_expands_ = 0; num_consecutive_expands_ = 0;
time_stretched_cn_samples_ = 0; time_stretched_cn_samples_ = 0;
@ -76,6 +77,7 @@ void DecisionLogic::SoftReset() {
packet_length_samples_ = 0; packet_length_samples_ = 0;
sample_memory_ = 0; sample_memory_ = 0;
prev_time_scale_ = false; prev_time_scale_ = false;
last_pack_cng_or_dtmf_ = true;
timescale_countdown_ = timescale_countdown_ =
tick_timer_->GetNewCountdown(kMinTimescaleInterval + 1); tick_timer_->GetNewCountdown(kMinTimescaleInterval + 1);
time_stretched_cn_samples_ = 0; time_stretched_cn_samples_ = 0;
@ -158,12 +160,13 @@ NetEq::Operation DecisionLogic::GetDecision(const NetEqStatus& status,
const size_t current_span = const size_t current_span =
estimate_dtx_delay_ ? status.packet_buffer_info.span_samples estimate_dtx_delay_ ? status.packet_buffer_info.span_samples
: status.packet_buffer_info.span_samples_no_dtx; : status.packet_buffer_info.span_samples_no_dtx;
const int target_level_samples =
delay_manager_->TargetDelayMs() * sample_rate_ / 1000;
if ((status.last_mode == NetEq::Mode::kExpand || if ((status.last_mode == NetEq::Mode::kExpand ||
status.last_mode == NetEq::Mode::kCodecPlc) && status.last_mode == NetEq::Mode::kCodecPlc) &&
status.expand_mutefactor < 16384 / 2 && status.expand_mutefactor < 16384 / 2 &&
current_span<static_cast<size_t>(delay_manager_->TargetLevel() * current_span < static_cast<size_t>(target_level_samples *
packet_length_samples_ * kPostponeDecodingLevel / 100) &&
kPostponeDecodingLevel / 100)>> 8 &&
!status.packet_buffer_info.dtx_or_cng) { !status.packet_buffer_info.dtx_or_cng) {
return NetEq::Operation::kExpand; return NetEq::Operation::kExpand;
} }
@ -195,41 +198,32 @@ void DecisionLogic::ExpandDecision(NetEq::Operation operation) {
} }
} }
absl::optional<int> DecisionLogic::PacketArrived(bool last_cng_or_dtmf, absl::optional<int> DecisionLogic::PacketArrived(bool is_cng_or_dtmf,
size_t packet_length_samples, size_t packet_length_samples,
bool should_update_stats, bool should_update_stats,
uint16_t main_sequence_number, uint16_t main_sequence_number,
uint32_t main_timestamp, uint32_t main_timestamp,
int fs_hz) { int fs_hz) {
delay_manager_->LastDecodedWasCngOrDtmf(last_cng_or_dtmf); if (is_cng_or_dtmf) {
absl::optional<int> relative_delay; last_pack_cng_or_dtmf_ = true;
if (delay_manager_->last_pack_cng_or_dtmf() == 0) { return absl::nullopt;
// Calculate the total speech length carried in each packet.
if (packet_length_samples > 0 &&
packet_length_samples != packet_length_samples_) {
packet_length_samples_ = packet_length_samples;
delay_manager_->SetPacketAudioLength(
rtc::dchecked_cast<int>((1000 * packet_length_samples) / fs_hz));
}
// Update statistics.
if (should_update_stats) {
relative_delay =
delay_manager_->Update(main_sequence_number, main_timestamp, fs_hz);
}
} else if (delay_manager_->last_pack_cng_or_dtmf() == -1) {
// This is first "normal" packet after CNG or DTMF.
// Reset packet time counter and measure time until next packet,
// but don't update statistics.
delay_manager_->set_last_pack_cng_or_dtmf(0);
delay_manager_->ResetPacketIatCount();
} }
if (!should_update_stats) {
return absl::nullopt;
}
if (packet_length_samples > 0 && fs_hz > 0 &&
packet_length_samples != packet_length_samples_) {
packet_length_samples_ = packet_length_samples;
delay_manager_->SetPacketAudioLength(packet_length_samples_ * 1000 / fs_hz);
}
auto relative_delay = delay_manager_->Update(
main_timestamp, fs_hz, /*reset=*/last_pack_cng_or_dtmf_);
last_pack_cng_or_dtmf_ = false;
return relative_delay; return relative_delay;
} }
void DecisionLogic::FilterBufferLevel(size_t buffer_size_samples) { void DecisionLogic::FilterBufferLevel(size_t buffer_size_samples) {
buffer_level_filter_.SetTargetBufferLevel( buffer_level_filter_.SetTargetBufferLevel(delay_manager_->TargetDelayMs());
delay_manager_->base_target_level());
int time_stretched_samples = time_stretched_cn_samples_; int time_stretched_samples = time_stretched_cn_samples_;
if (prev_time_scale_) { if (prev_time_scale_) {
@ -250,8 +244,8 @@ NetEq::Operation DecisionLogic::CngOperation(NetEq::Mode prev_mode,
int32_t timestamp_diff = static_cast<int32_t>( int32_t timestamp_diff = static_cast<int32_t>(
static_cast<uint32_t>(generated_noise_samples + target_timestamp) - static_cast<uint32_t>(generated_noise_samples + target_timestamp) -
available_timestamp); available_timestamp);
int32_t optimal_level_samp = static_cast<int32_t>( int optimal_level_samp =
(delay_manager_->TargetLevel() * packet_length_samples_) >> 8); delay_manager_->TargetDelayMs() * sample_rate_ / 1000;
const int64_t excess_waiting_time_samp = const int64_t excess_waiting_time_samp =
-static_cast<int64_t>(timestamp_diff) - optimal_level_samp; -static_cast<int64_t>(timestamp_diff) - optimal_level_samp;
@ -295,22 +289,26 @@ NetEq::Operation DecisionLogic::ExpectedPacketAvailable(NetEq::Mode prev_mode,
bool play_dtmf) { bool play_dtmf) {
if (!disallow_time_stretching_ && prev_mode != NetEq::Mode::kExpand && if (!disallow_time_stretching_ && prev_mode != NetEq::Mode::kExpand &&
!play_dtmf) { !play_dtmf) {
// Check criterion for time-stretching. The values are in number of packets const int samples_per_ms = sample_rate_ / 1000;
// in Q8. const int target_level_samples =
int low_limit, high_limit; delay_manager_->TargetDelayMs() * samples_per_ms;
delay_manager_->BufferLimits(&low_limit, &high_limit); const int low_limit =
int buffer_level_packets = 0; std::max(target_level_samples * 3 / 4,
if (packet_length_samples_ > 0) { target_level_samples -
buffer_level_packets = kDecelerationTargetLevelOffsetMs * samples_per_ms);
((1 << 8) * buffer_level_filter_.filtered_current_level()) / // |higher_limit| is equal to |target_level|, but should at
packet_length_samples_; // least be 20 ms higher than |lower_limit|.
} const int high_limit =
if (buffer_level_packets >= high_limit << 2) std::max(target_level_samples, low_limit + 20 * samples_per_ms);
const int buffer_level_samples =
buffer_level_filter_.filtered_current_level();
if (buffer_level_samples >= high_limit << 2)
return NetEq::Operation::kFastAccelerate; return NetEq::Operation::kFastAccelerate;
if (TimescaleAllowed()) { if (TimescaleAllowed()) {
if (buffer_level_packets >= high_limit) if (buffer_level_samples >= high_limit)
return NetEq::Operation::kAccelerate; return NetEq::Operation::kAccelerate;
if (buffer_level_packets < low_limit) if (buffer_level_samples < low_limit)
return NetEq::Operation::kPreemptiveExpand; return NetEq::Operation::kPreemptiveExpand;
} }
} }
@ -352,11 +350,11 @@ NetEq::Operation DecisionLogic::FuturePacketAvailable(
prev_mode == NetEq::Mode::kCodecInternalCng) { prev_mode == NetEq::Mode::kCodecInternalCng) {
size_t cur_size_samples = size_t cur_size_samples =
estimate_dtx_delay_ estimate_dtx_delay_
? cur_size_samples = span_samples_in_packet_buffer ? span_samples_in_packet_buffer
: num_packets_in_packet_buffer * decoder_frame_length; : num_packets_in_packet_buffer * decoder_frame_length;
// Target level is in number of packets in Q8. // Target level is in number of packets in Q8.
const size_t target_level_samples = const size_t target_level_samples =
(delay_manager_->TargetLevel() * packet_length_samples_) >> 8; delay_manager_->TargetDelayMs() * sample_rate_ / 1000;
const bool generated_enough_noise = const bool generated_enough_noise =
static_cast<uint32_t>(generated_noise_samples + target_timestamp) >= static_cast<uint32_t>(generated_noise_samples + target_timestamp) >=
available_timestamp; available_timestamp;
@ -406,13 +404,8 @@ NetEq::Operation DecisionLogic::FuturePacketAvailable(
} }
bool DecisionLogic::UnderTargetLevel() const { bool DecisionLogic::UnderTargetLevel() const {
int buffer_level_packets = 0; return buffer_level_filter_.filtered_current_level() <
if (packet_length_samples_ > 0) { delay_manager_->TargetDelayMs() * sample_rate_ / 1000;
buffer_level_packets =
((1 << 8) * buffer_level_filter_.filtered_current_level()) /
packet_length_samples_;
}
return buffer_level_packets <= delay_manager_->TargetLevel();
} }
bool DecisionLogic::ReinitAfterExpands(uint32_t timestamp_leap) const { bool DecisionLogic::ReinitAfterExpands(uint32_t timestamp_leap) const {

View File

@ -70,19 +70,16 @@ class DecisionLogic : public NetEqController {
// Adds |value| to |sample_memory_|. // Adds |value| to |sample_memory_|.
void AddSampleMemory(int32_t value) override { sample_memory_ += value; } void AddSampleMemory(int32_t value) override { sample_memory_ += value; }
int TargetLevelMs() const override { int TargetLevelMs() const override { return delay_manager_->TargetDelayMs(); }
return ((delay_manager_->TargetLevel() * packet_length_samples_) >> 8) /
rtc::CheckedDivExact(sample_rate_, 1000);
}
absl::optional<int> PacketArrived(bool last_cng_or_dtmf, absl::optional<int> PacketArrived(bool is_cng_or_dtmf,
size_t packet_length_samples, size_t packet_length_samples,
bool should_update_stats, bool should_update_stats,
uint16_t main_sequence_number, uint16_t main_sequence_number,
uint32_t main_timestamp, uint32_t main_timestamp,
int fs_hz) override; int fs_hz) override;
void RegisterEmptyPacket() override { delay_manager_->RegisterEmptyPacket(); } void RegisterEmptyPacket() override {}
bool SetMaximumDelay(int delay_ms) override { bool SetMaximumDelay(int delay_ms) override {
return delay_manager_->SetMaximumDelay(delay_ms); return delay_manager_->SetMaximumDelay(delay_ms);
@ -120,8 +117,8 @@ class DecisionLogic : public NetEqController {
enum CngState { kCngOff, kCngRfc3389On, kCngInternalOn }; enum CngState { kCngOff, kCngRfc3389On, kCngInternalOn };
// Updates the |buffer_level_filter_| with the current buffer level // Updates the |buffer_level_filter_| with the current buffer level
// |buffer_size_packets|. // |buffer_size_samples|.
void FilterBufferLevel(size_t buffer_size_packets); void FilterBufferLevel(size_t buffer_size_samples);
// Returns the operation given that the next available packet is a comfort // Returns the operation given that the next available packet is a comfort
// noise payload (RFC 3389 only, not codec-internal). // noise payload (RFC 3389 only, not codec-internal).
@ -186,6 +183,7 @@ class DecisionLogic : public NetEqController {
std::unique_ptr<TickTimer::Countdown> timescale_countdown_; std::unique_ptr<TickTimer::Countdown> timescale_countdown_;
int num_consecutive_expands_ = 0; int num_consecutive_expands_ = 0;
int time_stretched_cn_samples_ = 0; int time_stretched_cn_samples_ = 0;
bool last_pack_cng_or_dtmf_ = true;
FieldTrialParameter<bool> estimate_dtx_delay_; FieldTrialParameter<bool> estimate_dtx_delay_;
FieldTrialParameter<bool> time_stretch_cn_; FieldTrialParameter<bool> time_stretch_cn_;
FieldTrialConstrained<int> target_level_window_ms_; FieldTrialConstrained<int> target_level_window_ms_;

View File

@ -43,6 +43,6 @@ TEST(DecisionLogic, CreateAndDestroy) {
logic->SetSampleRate(fs_hz, output_size_samples); logic->SetSampleRate(fs_hz, output_size_samples);
} }
// TODO(hlundin): Write more tests. // TODO(jakobi): Write more tests.
} // namespace webrtc } // namespace webrtc

View File

@ -27,17 +27,16 @@
#include "rtc_base/numerics/safe_minmax.h" #include "rtc_base/numerics/safe_minmax.h"
#include "system_wrappers/include/field_trial.h" #include "system_wrappers/include/field_trial.h"
namespace webrtc {
namespace { namespace {
constexpr int kMinBaseMinimumDelayMs = 0; constexpr int kMinBaseMinimumDelayMs = 0;
constexpr int kMaxBaseMinimumDelayMs = 10000; constexpr int kMaxBaseMinimumDelayMs = 10000;
constexpr int kMaxReorderedPackets =
10; // Max number of consecutive reordered packets.
constexpr int kMaxHistoryMs = 2000; // Oldest packet to include in history to constexpr int kMaxHistoryMs = 2000; // Oldest packet to include in history to
// calculate relative packet arrival delay. // calculate relative packet arrival delay.
constexpr int kDelayBuckets = 100; constexpr int kDelayBuckets = 100;
constexpr int kBucketSizeMs = 20; constexpr int kBucketSizeMs = 20;
constexpr int kDecelerationTargetLevelOffsetMs = 85 << 8; // In Q8. constexpr int kStartDelayMs = 80;
int PercentileToQuantile(double percentile) { int PercentileToQuantile(double percentile) {
return static_cast<int>((1 << 30) * percentile / 100.0 + 0.5); return static_cast<int>((1 << 30) * percentile / 100.0 + 0.5);
@ -49,6 +48,7 @@ struct DelayHistogramConfig {
absl::optional<double> start_forget_weight = 2; absl::optional<double> start_forget_weight = 2;
}; };
// TODO(jakobi): Remove legacy field trial.
DelayHistogramConfig GetDelayHistogramConfig() { DelayHistogramConfig GetDelayHistogramConfig() {
constexpr char kDelayHistogramFieldTrial[] = constexpr char kDelayHistogramFieldTrial[] =
"WebRTC-Audio-NetEqDelayHistogram"; "WebRTC-Audio-NetEqDelayHistogram";
@ -81,12 +81,9 @@ DelayHistogramConfig GetDelayHistogramConfig() {
} // namespace } // namespace
namespace webrtc { DelayManager::DelayManager(int max_packets_in_buffer,
DelayManager::DelayManager(size_t max_packets_in_buffer,
int base_minimum_delay_ms, int base_minimum_delay_ms,
int histogram_quantile, int histogram_quantile,
bool enable_rtx_handling,
const TickTimer* tick_timer, const TickTimer* tick_timer,
std::unique_ptr<Histogram> histogram) std::unique_ptr<Histogram> histogram)
: first_packet_received_(false), : first_packet_received_(false),
@ -96,15 +93,10 @@ DelayManager::DelayManager(size_t max_packets_in_buffer,
tick_timer_(tick_timer), tick_timer_(tick_timer),
base_minimum_delay_ms_(base_minimum_delay_ms), base_minimum_delay_ms_(base_minimum_delay_ms),
effective_minimum_delay_ms_(base_minimum_delay_ms), effective_minimum_delay_ms_(base_minimum_delay_ms),
base_target_level_(4), // In Q0 domain.
target_level_(base_target_level_ << 8), // In Q8 domain.
packet_len_ms_(0),
last_seq_no_(0),
last_timestamp_(0),
minimum_delay_ms_(0), minimum_delay_ms_(0),
maximum_delay_ms_(0), maximum_delay_ms_(0),
last_pack_cng_or_dtmf_(1), target_level_ms_(kStartDelayMs),
enable_rtx_handling_(enable_rtx_handling) { last_timestamp_(0) {
RTC_CHECK(histogram_); RTC_CHECK(histogram_);
RTC_DCHECK_GE(base_minimum_delay_ms_, 0); RTC_DCHECK_GE(base_minimum_delay_ms_, 0);
@ -112,102 +104,70 @@ DelayManager::DelayManager(size_t max_packets_in_buffer,
} }
std::unique_ptr<DelayManager> DelayManager::Create( std::unique_ptr<DelayManager> DelayManager::Create(
size_t max_packets_in_buffer, int max_packets_in_buffer,
int base_minimum_delay_ms, int base_minimum_delay_ms,
bool enable_rtx_handling,
const TickTimer* tick_timer) { const TickTimer* tick_timer) {
DelayHistogramConfig config = GetDelayHistogramConfig(); auto config = GetDelayHistogramConfig();
const int quantile = config.quantile;
std::unique_ptr<Histogram> histogram = std::make_unique<Histogram>( std::unique_ptr<Histogram> histogram = std::make_unique<Histogram>(
kDelayBuckets, config.forget_factor, config.start_forget_weight); kDelayBuckets, config.forget_factor, config.start_forget_weight);
return std::make_unique<DelayManager>( return std::make_unique<DelayManager>(max_packets_in_buffer,
max_packets_in_buffer, base_minimum_delay_ms, quantile, base_minimum_delay_ms, config.quantile,
enable_rtx_handling, tick_timer, std::move(histogram)); tick_timer, std::move(histogram));
} }
DelayManager::~DelayManager() {} DelayManager::~DelayManager() {}
absl::optional<int> DelayManager::Update(uint16_t sequence_number, absl::optional<int> DelayManager::Update(uint32_t timestamp,
uint32_t timestamp, int sample_rate_hz,
int sample_rate_hz) { bool reset) {
if (sample_rate_hz <= 0) { if (sample_rate_hz <= 0) {
return absl::nullopt; return absl::nullopt;
} }
if (!first_packet_received_) { if (!first_packet_received_ || reset) {
// Prepare for next packet arrival. // Restart relative delay esimation from this packet.
delay_history_.clear();
packet_iat_stopwatch_ = tick_timer_->GetNewStopwatch(); packet_iat_stopwatch_ = tick_timer_->GetNewStopwatch();
last_seq_no_ = sequence_number;
last_timestamp_ = timestamp; last_timestamp_ = timestamp;
first_packet_received_ = true; first_packet_received_ = true;
return absl::nullopt; return absl::nullopt;
} }
// Try calculating packet length from current and previous timestamps. const int expected_iat_ms =
int packet_len_ms; 1000 * static_cast<int32_t>(timestamp - last_timestamp_) / sample_rate_hz;
if (!IsNewerTimestamp(timestamp, last_timestamp_) || const int iat_ms = packet_iat_stopwatch_->ElapsedMs();
!IsNewerSequenceNumber(sequence_number, last_seq_no_)) { const int iat_delay_ms = iat_ms - expected_iat_ms;
// Wrong timestamp or sequence order; use stored value.
packet_len_ms = packet_len_ms_;
} else {
// Calculate timestamps per packet and derive packet length in ms.
int64_t packet_len_samp =
static_cast<uint32_t>(timestamp - last_timestamp_) /
static_cast<uint16_t>(sequence_number - last_seq_no_);
packet_len_ms =
rtc::saturated_cast<int>(1000 * packet_len_samp / sample_rate_hz);
}
bool reordered = false;
absl::optional<int> relative_delay; absl::optional<int> relative_delay;
if (packet_len_ms > 0) { if (!IsNewerTimestamp(timestamp, last_timestamp_)) {
// Cannot update statistics unless |packet_len_ms| is valid. relative_delay = std::max(iat_delay_ms, 0);
// Reset the history and restart delay estimation from this packet.
// Inter-arrival time (IAT) in integer "packet times" (rounding down). This delay_history_.clear();
// is the value added to the inter-arrival time histogram. } else {
int iat_ms = packet_iat_stopwatch_->ElapsedMs(); UpdateDelayHistory(iat_delay_ms, timestamp, sample_rate_hz);
// Check for discontinuous packet sequence and re-ordering. relative_delay = CalculateRelativePacketArrivalDelay();
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_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_ms += packet_offset * packet_len_ms;
reordered = true;
}
int iat_delay = iat_ms - packet_len_ms;
if (reordered) {
relative_delay = std::max(iat_delay, 0);
} else {
UpdateDelayHistory(iat_delay, timestamp, sample_rate_hz);
relative_delay = CalculateRelativePacketArrivalDelay();
}
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();
LimitTargetLevel();
} // End if (packet_len_ms > 0).
if (enable_rtx_handling_ && reordered &&
num_reordered_packets_ < kMaxReorderedPackets) {
++num_reordered_packets_;
return relative_delay;
} }
num_reordered_packets_ = 0; 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_ms_| based on updated statistics.
int bucket_index = histogram_->Quantile(histogram_quantile_);
target_level_ms_ = (1 + bucket_index) * kBucketSizeMs;
target_level_ms_ = std::max(target_level_ms_, effective_minimum_delay_ms_);
if (maximum_delay_ms_ > 0) {
target_level_ms_ = std::min(target_level_ms_, maximum_delay_ms_);
}
if (packet_len_ms_ > 0) {
// Target level should be at least one packet.
target_level_ms_ = std::max(target_level_ms_, packet_len_ms_);
// Limit to 75% of maximum buffer size.
target_level_ms_ = std::min(
target_level_ms_, 3 * max_packets_in_buffer_ * packet_len_ms_ / 4);
}
// Prepare for next packet arrival. // Prepare for next packet arrival.
packet_iat_stopwatch_ = tick_timer_->GetNewStopwatch(); packet_iat_stopwatch_ = tick_timer_->GetNewStopwatch();
last_seq_no_ = sequence_number;
last_timestamp_ = timestamp; last_timestamp_ = timestamp;
return relative_delay; return relative_delay;
} }
@ -238,128 +198,26 @@ int DelayManager::CalculateRelativePacketArrivalDelay() const {
return relative_delay; return relative_delay;
} }
// Enforces upper and lower limits for |target_level_|. The upper limit is
// chosen to be minimum of i) 75% of |max_packets_in_buffer_|, to leave some
// headroom for natural fluctuations around the target, and ii) equivalent of
// |maximum_delay_ms_| in packets. Note that in practice, if no
// |maximum_delay_ms_| is specified, this does not have any impact, since the
// target level is far below the buffer capacity in all reasonable cases.
// The lower limit is equivalent of |effective_minimum_delay_ms_| in packets.
// We update |least_required_level_| while the above limits are applied.
// TODO(hlundin): Move this check to the buffer logistics class.
void DelayManager::LimitTargetLevel() {
if (packet_len_ms_ > 0 && effective_minimum_delay_ms_ > 0) {
int minimum_delay_packet_q8 =
(effective_minimum_delay_ms_ << 8) / packet_len_ms_;
target_level_ = std::max(target_level_, minimum_delay_packet_q8);
}
if (maximum_delay_ms_ > 0 && packet_len_ms_ > 0) {
int maximum_delay_packet_q8 = (maximum_delay_ms_ << 8) / packet_len_ms_;
target_level_ = std::min(target_level_, maximum_delay_packet_q8);
}
// Shift to Q8, then 75%.;
int max_buffer_packets_q8 =
static_cast<int>((3 * (max_packets_in_buffer_ << 8)) / 4);
target_level_ = std::min(target_level_, max_buffer_packets_q8);
// Sanity check, at least 1 packet (in Q8).
target_level_ = std::max(target_level_, 1 << 8);
}
int DelayManager::CalculateTargetLevel() {
int limit_probability = histogram_quantile_;
int bucket_index = histogram_->Quantile(limit_probability);
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);
// Scale to Q8 and assign to member variable.
target_level_ = target_level << 8;
return target_level_;
}
int DelayManager::SetPacketAudioLength(int length_ms) { int DelayManager::SetPacketAudioLength(int length_ms) {
if (length_ms <= 0) { if (length_ms <= 0) {
RTC_LOG_F(LS_ERROR) << "length_ms = " << length_ms; RTC_LOG_F(LS_ERROR) << "length_ms = " << length_ms;
return -1; return -1;
} }
packet_len_ms_ = length_ms; packet_len_ms_ = length_ms;
packet_iat_stopwatch_ = tick_timer_->GetNewStopwatch();
last_pack_cng_or_dtmf_ = 1; // TODO(hlundin): Legacy. Remove?
return 0; return 0;
} }
void DelayManager::Reset() { void DelayManager::Reset() {
packet_len_ms_ = 0; // Packet size unknown. packet_len_ms_ = 0;
histogram_->Reset(); histogram_->Reset();
delay_history_.clear(); delay_history_.clear();
base_target_level_ = 4; target_level_ms_ = kStartDelayMs;
target_level_ = base_target_level_ << 8;
packet_iat_stopwatch_ = tick_timer_->GetNewStopwatch(); packet_iat_stopwatch_ = tick_timer_->GetNewStopwatch();
last_pack_cng_or_dtmf_ = 1; first_packet_received_ = false;
} }
void DelayManager::ResetPacketIatCount() { int DelayManager::TargetDelayMs() const {
packet_iat_stopwatch_ = tick_timer_->GetNewStopwatch(); return target_level_ms_;
}
void DelayManager::BufferLimits(int* lower_limit, int* higher_limit) const {
BufferLimits(target_level_, lower_limit, higher_limit);
}
// Note that |low_limit| and |higher_limit| are not assigned to
// |minimum_delay_ms_| and |maximum_delay_ms_| defined by the client of this
// class. They are computed from |target_level| in Q8 and used for decision
// making.
void DelayManager::BufferLimits(int target_level,
int* lower_limit,
int* higher_limit) const {
if (!lower_limit || !higher_limit) {
RTC_LOG_F(LS_ERROR) << "NULL pointers supplied as input";
assert(false);
return;
}
// |target_level| is in Q8 already.
*lower_limit = (target_level * 3) / 4;
if (packet_len_ms_ > 0) {
*lower_limit =
std::max(*lower_limit, target_level - kDecelerationTargetLevelOffsetMs /
packet_len_ms_);
}
int window_20ms = 0x7FFF; // Default large value for legacy bit-exactness.
if (packet_len_ms_ > 0) {
window_20ms = (20 << 8) / packet_len_ms_;
}
// |higher_limit| is equal to |target_level|, but should at
// least be 20 ms higher than |lower_limit|.
*higher_limit = std::max(target_level, *lower_limit + window_20ms);
}
int DelayManager::TargetLevel() const {
return target_level_;
}
void DelayManager::LastDecodedWasCngOrDtmf(bool it_was) {
if (it_was) {
last_pack_cng_or_dtmf_ = 1;
} else if (last_pack_cng_or_dtmf_ != 0) {
last_pack_cng_or_dtmf_ = -1;
}
}
void DelayManager::RegisterEmptyPacket() {
++last_seq_no_;
} }
bool DelayManager::IsValidMinimumDelay(int delay_ms) const { bool DelayManager::IsValidMinimumDelay(int delay_ms) const {
@ -409,17 +267,6 @@ int DelayManager::GetBaseMinimumDelay() const {
return base_minimum_delay_ms_; return base_minimum_delay_ms_;
} }
int DelayManager::base_target_level() const {
return base_target_level_;
}
int DelayManager::last_pack_cng_or_dtmf() const {
return last_pack_cng_or_dtmf_;
}
void DelayManager::set_last_pack_cng_or_dtmf(int value) {
last_pack_cng_or_dtmf_ = value;
}
void DelayManager::UpdateEffectiveMinimumDelay() { void DelayManager::UpdateEffectiveMinimumDelay() {
// Clamp |base_minimum_delay_ms_| into the range which can be effectively // Clamp |base_minimum_delay_ms_| into the range which can be effectively
// used. // used.
@ -432,16 +279,11 @@ void DelayManager::UpdateEffectiveMinimumDelay() {
int DelayManager::MinimumDelayUpperBound() const { int DelayManager::MinimumDelayUpperBound() const {
// Choose the lowest possible bound discarding 0 cases which mean the value // Choose the lowest possible bound discarding 0 cases which mean the value
// is not set and unconstrained. // is not set and unconstrained.
int q75 = MaxBufferTimeQ75(); int q75 = max_packets_in_buffer_ * packet_len_ms_ * 3 / 4;
q75 = q75 > 0 ? q75 : kMaxBaseMinimumDelayMs; q75 = q75 > 0 ? q75 : kMaxBaseMinimumDelayMs;
const int maximum_delay_ms = const int maximum_delay_ms =
maximum_delay_ms_ > 0 ? maximum_delay_ms_ : kMaxBaseMinimumDelayMs; maximum_delay_ms_ > 0 ? maximum_delay_ms_ : kMaxBaseMinimumDelayMs;
return std::min(maximum_delay_ms, q75); return std::min(maximum_delay_ms, q75);
} }
int DelayManager::MaxBufferTimeQ75() const {
const int max_buffer_time = max_packets_in_buffer_ * packet_len_ms_;
return rtc::dchecked_cast<int>(3 * max_buffer_time / 4);
}
} // namespace webrtc } // namespace webrtc

View File

@ -25,10 +25,9 @@ namespace webrtc {
class DelayManager { class DelayManager {
public: public:
DelayManager(size_t max_packets_in_buffer, DelayManager(int max_packets_in_buffer,
int base_minimum_delay_ms, int base_minimum_delay_ms,
int histogram_quantile, int histogram_quantile,
bool enable_rtx_handling,
const TickTimer* tick_timer, const TickTimer* tick_timer,
std::unique_ptr<Histogram> histogram); std::unique_ptr<Histogram> histogram);
@ -37,58 +36,29 @@ class DelayManager {
// is the number of packet slots in the buffer) and that the target delay // is the number of packet slots in the buffer) and that the target delay
// should be greater than or equal to |base_minimum_delay_ms|. Supply a // should be greater than or equal to |base_minimum_delay_ms|. Supply a
// PeakDetector object to the DelayManager. // PeakDetector object to the DelayManager.
static std::unique_ptr<DelayManager> Create(size_t max_packets_in_buffer, static std::unique_ptr<DelayManager> Create(int max_packets_in_buffer,
int base_minimum_delay_ms, int base_minimum_delay_ms,
bool enable_rtx_handling,
const TickTimer* tick_timer); const TickTimer* tick_timer);
virtual ~DelayManager(); virtual ~DelayManager();
// Updates the delay manager with a new incoming packet, with // Updates the delay manager with a new incoming packet, with |timestamp| from
// |sequence_number| and |timestamp| from the RTP header. This updates the // the RTP header. This updates the statistics and a new target buffer level
// inter-arrival time histogram and other statistics, as well as the // is calculated. Returns the relative delay if it can be calculated. If
// associated DelayPeakDetector. A new target buffer level is calculated. // |reset| is true, restarts the relative arrival delay calculation from this
// Returns the relative delay if it can be calculated. // packet.
virtual absl::optional<int> Update(uint16_t sequence_number, virtual absl::optional<int> Update(uint32_t timestamp,
uint32_t timestamp, int sample_rate_hz,
int sample_rate_hz); bool reset = false);
// Calculates a new target buffer level. Called from the Update() method. // Resets all state.
// 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();
// Notifies the DelayManager of how much audio data is carried in each packet.
// The method updates the DelayPeakDetector too, and resets the inter-arrival
// time counter. Returns 0 on success, -1 on failure.
virtual int SetPacketAudioLength(int length_ms);
// Resets the DelayManager and the associated DelayPeakDetector.
virtual void Reset(); virtual void Reset();
// Reset the inter-arrival time counter to 0. // Gets the target buffer level in milliseconds.
virtual void ResetPacketIatCount(); virtual int TargetDelayMs() const;
// Writes the lower and higher limits which the buffer level should stay // Notifies the DelayManager of how much audio data is carried in each packet.
// within to the corresponding pointers. The values are in (fractions of) virtual int SetPacketAudioLength(int length_ms);
// packets in Q8.
virtual void BufferLimits(int* lower_limit, int* higher_limit) const;
virtual void BufferLimits(int target_level,
int* lower_limit,
int* higher_limit) const;
// Gets the target buffer level, in (fractions of) packets in Q8.
virtual int TargetLevel() const;
// Informs the delay manager whether or not the last decoded packet contained
// speech.
virtual void LastDecodedWasCngOrDtmf(bool it_was);
// Notify the delay manager that empty packets have been received. These are
// packets that are part of the sequence number series, so that an empty
// packet will shift the sequence numbers for the following packets.
virtual void RegisterEmptyPacket();
// Accessors and mutators. // Accessors and mutators.
// Assuming |delay| is in valid range. // Assuming |delay| is in valid range.
@ -96,16 +66,11 @@ class DelayManager {
virtual bool SetMaximumDelay(int delay_ms); virtual bool SetMaximumDelay(int delay_ms);
virtual bool SetBaseMinimumDelay(int delay_ms); virtual bool SetBaseMinimumDelay(int delay_ms);
virtual int GetBaseMinimumDelay() const; virtual int GetBaseMinimumDelay() const;
virtual int base_target_level() const;
virtual int last_pack_cng_or_dtmf() const;
virtual void set_last_pack_cng_or_dtmf(int value);
// This accessor is only intended for testing purposes. // These accessors are only intended for testing purposes.
int effective_minimum_delay_ms_for_test() const { int effective_minimum_delay_ms_for_test() const {
return effective_minimum_delay_ms_; return effective_minimum_delay_ms_;
} }
// These accessors are only intended for testing purposes.
int histogram_quantile() const { return histogram_quantile_; } int histogram_quantile() const { return histogram_quantile_; }
Histogram* histogram() const { return histogram_.get(); } Histogram* histogram() const { return histogram_.get(); }
@ -114,9 +79,6 @@ class DelayManager {
// size and given |maximum_delay_ms_|. Lower bound is a constant 0. // size and given |maximum_delay_ms_|. Lower bound is a constant 0.
int MinimumDelayUpperBound() const; int MinimumDelayUpperBound() const;
// Provides 75% of currently possible maximum buffer size in milliseconds.
int MaxBufferTimeQ75() const;
// Updates |delay_history_|. // Updates |delay_history_|.
void UpdateDelayHistory(int iat_delay_ms, void UpdateDelayHistory(int iat_delay_ms,
uint32_t timestamp, uint32_t timestamp,
@ -130,10 +92,6 @@ class DelayManager {
// and buffer size. // and buffer size.
void UpdateEffectiveMinimumDelay(); void UpdateEffectiveMinimumDelay();
// Makes sure that |target_level_| is not too large, taking
// |max_packets_in_buffer_| into account. This method is called by Update().
void LimitTargetLevel();
// Makes sure that |delay_ms| is less than maximum delay, if any maximum // 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 // is set. Also, if possible check |delay_ms| to be less than 75% of
// |max_packets_in_buffer_|. // |max_packets_in_buffer_|.
@ -142,31 +100,21 @@ class DelayManager {
bool IsValidBaseMinimumDelay(int delay_ms) const; bool IsValidBaseMinimumDelay(int delay_ms) const;
bool first_packet_received_; bool first_packet_received_;
const size_t max_packets_in_buffer_; // Capacity of the packet buffer. // TODO(jakobi): set maximum buffer delay instead of number of packets.
const int max_packets_in_buffer_;
std::unique_ptr<Histogram> histogram_; std::unique_ptr<Histogram> histogram_;
const int histogram_quantile_; const int histogram_quantile_;
const TickTimer* tick_timer_; const TickTimer* tick_timer_;
int base_minimum_delay_ms_; int base_minimum_delay_ms_;
// Provides delay which is used by LimitTargetLevel as lower bound on target int effective_minimum_delay_ms_; // Used as lower bound for target delay.
// delay. int minimum_delay_ms_; // Externally set minimum delay.
int effective_minimum_delay_ms_; int maximum_delay_ms_; // Externally set maximum allowed delay.
// Time elapsed since last packet. int packet_len_ms_ = 0;
std::unique_ptr<TickTimer::Stopwatch> packet_iat_stopwatch_; std::unique_ptr<TickTimer::Stopwatch>
int base_target_level_; // Currently preferred buffer level before peak packet_iat_stopwatch_; // Time elapsed since last packet.
// detection and streaming mode (Q0). int target_level_ms_; // Currently preferred buffer level.
// TODO(turajs) change the comment according to the implementation of uint32_t last_timestamp_; // Timestamp for the last received packet.
// minimum-delay.
int target_level_; // Currently preferred buffer level in (fractions)
// of packets (Q8), before adding any extra delay.
int packet_len_ms_; // Length of audio in each incoming packet [ms].
uint16_t last_seq_no_; // Sequence number for last received packet.
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.
int last_pack_cng_or_dtmf_;
const bool enable_rtx_handling_;
int num_reordered_packets_ = 0; // Number of consecutive reordered packets.
struct PacketDelay { struct PacketDelay {
int iat_delay_ms; int iat_delay_ms;

View File

@ -35,19 +35,15 @@ constexpr int kFrameSizeMs = 20;
constexpr int kTsIncrement = kFrameSizeMs * kFs / 1000; constexpr int kTsIncrement = kFrameSizeMs * kFs / 1000;
constexpr int kMaxBufferSizeMs = kMaxNumberOfPackets * kFrameSizeMs; constexpr int kMaxBufferSizeMs = kMaxNumberOfPackets * kFrameSizeMs;
constexpr int kDefaultHistogramQuantile = 1020054733; constexpr int kDefaultHistogramQuantile = 1020054733;
constexpr int kMaxIat = 64; constexpr int kNumBuckets = 100;
constexpr int kForgetFactor = 32745; constexpr int kForgetFactor = 32745;
} // namespace } // namespace
using ::testing::_;
using ::testing::Return;
class DelayManagerTest : public ::testing::Test { class DelayManagerTest : public ::testing::Test {
protected: protected:
DelayManagerTest(); DelayManagerTest();
virtual void SetUp(); virtual void SetUp();
void RecreateDelayManager(); void RecreateDelayManager();
void SetPacketAudioLength(int lengt_ms);
absl::optional<int> InsertNextPacket(); absl::optional<int> InsertNextPacket();
void IncreaseTime(int inc_ms); void IncreaseTime(int inc_ms);
@ -55,15 +51,12 @@ class DelayManagerTest : public ::testing::Test {
TickTimer tick_timer_; TickTimer tick_timer_;
MockStatisticsCalculator stats_; MockStatisticsCalculator stats_;
MockHistogram* mock_histogram_; MockHistogram* mock_histogram_;
uint16_t seq_no_;
uint32_t ts_; uint32_t ts_;
bool enable_rtx_handling_ = false;
bool use_mock_histogram_ = false; bool use_mock_histogram_ = false;
}; };
DelayManagerTest::DelayManagerTest() DelayManagerTest::DelayManagerTest()
: dm_(nullptr), : dm_(nullptr),
seq_no_(0x1234),
ts_(0x12345678) {} ts_(0x12345678) {}
void DelayManagerTest::SetUp() { void DelayManagerTest::SetUp() {
@ -72,24 +65,19 @@ void DelayManagerTest::SetUp() {
void DelayManagerTest::RecreateDelayManager() { void DelayManagerTest::RecreateDelayManager() {
if (use_mock_histogram_) { if (use_mock_histogram_) {
mock_histogram_ = new MockHistogram(kMaxIat, kForgetFactor); mock_histogram_ = new MockHistogram(kNumBuckets, kForgetFactor);
std::unique_ptr<Histogram> histogram(mock_histogram_); std::unique_ptr<Histogram> histogram(mock_histogram_);
dm_ = std::make_unique<DelayManager>( dm_ = std::make_unique<DelayManager>(kMaxNumberOfPackets, kMinDelayMs,
kMaxNumberOfPackets, kMinDelayMs, kDefaultHistogramQuantile, kDefaultHistogramQuantile,
enable_rtx_handling_, &tick_timer_, std::move(histogram)); &tick_timer_, std::move(histogram));
} else { } else {
dm_ = DelayManager::Create(kMaxNumberOfPackets, kMinDelayMs, dm_ = DelayManager::Create(kMaxNumberOfPackets, kMinDelayMs, &tick_timer_);
enable_rtx_handling_, &tick_timer_);
} }
} dm_->SetPacketAudioLength(kFrameSizeMs);
void DelayManagerTest::SetPacketAudioLength(int lengt_ms) {
dm_->SetPacketAudioLength(lengt_ms);
} }
absl::optional<int> DelayManagerTest::InsertNextPacket() { absl::optional<int> DelayManagerTest::InsertNextPacket() {
auto relative_delay = dm_->Update(seq_no_, ts_, kFs); auto relative_delay = dm_->Update(ts_, kFs);
seq_no_ += 1;
ts_ += kTsIncrement; ts_ += kTsIncrement;
return relative_delay; return relative_delay;
} }
@ -105,98 +93,66 @@ TEST_F(DelayManagerTest, CreateAndDestroy) {
// object. // object.
} }
TEST_F(DelayManagerTest, SetPacketAudioLength) {
const int kLengthMs = 30;
EXPECT_EQ(0, dm_->SetPacketAudioLength(kLengthMs));
EXPECT_EQ(-1, dm_->SetPacketAudioLength(-1)); // Illegal parameter value.
}
TEST_F(DelayManagerTest, UpdateNormal) { TEST_F(DelayManagerTest, UpdateNormal) {
SetPacketAudioLength(kFrameSizeMs);
// First packet arrival. // First packet arrival.
InsertNextPacket(); InsertNextPacket();
// Advance time by one frame size. // Advance time by one frame size.
IncreaseTime(kFrameSizeMs); IncreaseTime(kFrameSizeMs);
// Second packet arrival. // Second packet arrival.
InsertNextPacket(); InsertNextPacket();
EXPECT_EQ(1 << 8, dm_->TargetLevel()); // In Q8. EXPECT_EQ(20, dm_->TargetDelayMs());
EXPECT_EQ(1, dm_->base_target_level());
int lower, higher;
dm_->BufferLimits(&lower, &higher);
// Expect |lower| to be 75% of target level, and |higher| to be target level,
// but also at least 20 ms higher than |lower|, which is the limiting case
// here.
EXPECT_EQ((1 << 8) * 3 / 4, lower);
EXPECT_EQ(lower + (20 << 8) / kFrameSizeMs, higher);
} }
TEST_F(DelayManagerTest, UpdateLongInterArrivalTime) { TEST_F(DelayManagerTest, UpdateLongInterArrivalTime) {
SetPacketAudioLength(kFrameSizeMs);
// First packet arrival. // First packet arrival.
InsertNextPacket(); InsertNextPacket();
// Advance time by two frame size. // Advance time by two frame size.
IncreaseTime(2 * kFrameSizeMs); IncreaseTime(2 * kFrameSizeMs);
// Second packet arrival. // Second packet arrival.
InsertNextPacket(); InsertNextPacket();
EXPECT_EQ(2 << 8, dm_->TargetLevel()); // In Q8. EXPECT_EQ(40, dm_->TargetDelayMs());
EXPECT_EQ(2, dm_->base_target_level());
int lower, higher;
dm_->BufferLimits(&lower, &higher);
// Expect |lower| to be 75% of target level, and |higher| to be target level,
// but also at least 20 ms higher than |lower|, which is the limiting case
// here.
EXPECT_EQ((2 << 8) * 3 / 4, lower);
EXPECT_EQ(lower + (20 << 8) / kFrameSizeMs, higher);
} }
TEST_F(DelayManagerTest, MaxDelay) { TEST_F(DelayManagerTest, MaxDelay) {
const int kExpectedTarget = 5; const int kExpectedTarget = 5 * kFrameSizeMs;
const int kTimeIncrement = kExpectedTarget * kFrameSizeMs;
SetPacketAudioLength(kFrameSizeMs);
// First packet arrival. // First packet arrival.
InsertNextPacket(); InsertNextPacket();
// Second packet arrival. // Second packet arrival.
IncreaseTime(kTimeIncrement); IncreaseTime(kExpectedTarget);
InsertNextPacket(); InsertNextPacket();
// No limit is set. // No limit is set.
EXPECT_EQ(kExpectedTarget << 8, dm_->TargetLevel()); EXPECT_EQ(kExpectedTarget, dm_->TargetDelayMs());
int kMaxDelayPackets = kExpectedTarget - 2; const int kMaxDelayMs = 3 * kFrameSizeMs;
int kMaxDelayMs = kMaxDelayPackets * kFrameSizeMs;
EXPECT_TRUE(dm_->SetMaximumDelay(kMaxDelayMs)); EXPECT_TRUE(dm_->SetMaximumDelay(kMaxDelayMs));
IncreaseTime(kTimeIncrement); IncreaseTime(kFrameSizeMs);
InsertNextPacket(); InsertNextPacket();
EXPECT_EQ(kMaxDelayPackets << 8, dm_->TargetLevel()); EXPECT_EQ(kMaxDelayMs, dm_->TargetDelayMs());
// Target level at least should be one packet. // Target level at least should be one packet.
EXPECT_FALSE(dm_->SetMaximumDelay(kFrameSizeMs - 1)); EXPECT_FALSE(dm_->SetMaximumDelay(kFrameSizeMs - 1));
} }
TEST_F(DelayManagerTest, MinDelay) { TEST_F(DelayManagerTest, MinDelay) {
const int kExpectedTarget = 5; const int kExpectedTarget = 5 * kFrameSizeMs;
const int kTimeIncrement = kExpectedTarget * kFrameSizeMs;
SetPacketAudioLength(kFrameSizeMs);
// First packet arrival. // First packet arrival.
InsertNextPacket(); InsertNextPacket();
// Second packet arrival. // Second packet arrival.
IncreaseTime(kTimeIncrement); IncreaseTime(kExpectedTarget);
InsertNextPacket(); InsertNextPacket();
// No limit is applied. // No limit is applied.
EXPECT_EQ(kExpectedTarget << 8, dm_->TargetLevel()); EXPECT_EQ(kExpectedTarget, dm_->TargetDelayMs());
int kMinDelayPackets = kExpectedTarget + 2; int kMinDelayMs = 7 * kFrameSizeMs;
int kMinDelayMs = kMinDelayPackets * kFrameSizeMs;
dm_->SetMinimumDelay(kMinDelayMs); dm_->SetMinimumDelay(kMinDelayMs);
IncreaseTime(kFrameSizeMs); IncreaseTime(kFrameSizeMs);
InsertNextPacket(); InsertNextPacket();
EXPECT_EQ(kMinDelayPackets << 8, dm_->TargetLevel()); EXPECT_EQ(kMinDelayMs, dm_->TargetDelayMs());
} }
TEST_F(DelayManagerTest, BaseMinimumDelayCheckValidRange) { TEST_F(DelayManagerTest, BaseMinimumDelayCheckValidRange) {
SetPacketAudioLength(kFrameSizeMs);
// Base minimum delay should be between [0, 10000] milliseconds. // Base minimum delay should be between [0, 10000] milliseconds.
EXPECT_FALSE(dm_->SetBaseMinimumDelay(-1)); EXPECT_FALSE(dm_->SetBaseMinimumDelay(-1));
EXPECT_FALSE(dm_->SetBaseMinimumDelay(10001)); EXPECT_FALSE(dm_->SetBaseMinimumDelay(10001));
@ -207,7 +163,6 @@ TEST_F(DelayManagerTest, BaseMinimumDelayCheckValidRange) {
} }
TEST_F(DelayManagerTest, BaseMinimumDelayLowerThanMinimumDelay) { TEST_F(DelayManagerTest, BaseMinimumDelayLowerThanMinimumDelay) {
SetPacketAudioLength(kFrameSizeMs);
constexpr int kBaseMinimumDelayMs = 100; constexpr int kBaseMinimumDelayMs = 100;
constexpr int kMinimumDelayMs = 200; constexpr int kMinimumDelayMs = 200;
@ -221,7 +176,6 @@ TEST_F(DelayManagerTest, BaseMinimumDelayLowerThanMinimumDelay) {
} }
TEST_F(DelayManagerTest, BaseMinimumDelayGreaterThanMinimumDelay) { TEST_F(DelayManagerTest, BaseMinimumDelayGreaterThanMinimumDelay) {
SetPacketAudioLength(kFrameSizeMs);
constexpr int kBaseMinimumDelayMs = 70; constexpr int kBaseMinimumDelayMs = 70;
constexpr int kMinimumDelayMs = 30; constexpr int kMinimumDelayMs = 30;
@ -235,7 +189,6 @@ TEST_F(DelayManagerTest, BaseMinimumDelayGreaterThanMinimumDelay) {
} }
TEST_F(DelayManagerTest, BaseMinimumDelayGreaterThanBufferSize) { TEST_F(DelayManagerTest, BaseMinimumDelayGreaterThanBufferSize) {
SetPacketAudioLength(kFrameSizeMs);
constexpr int kBaseMinimumDelayMs = kMaxBufferSizeMs + 1; constexpr int kBaseMinimumDelayMs = kMaxBufferSizeMs + 1;
constexpr int kMinimumDelayMs = 12; constexpr int kMinimumDelayMs = 12;
constexpr int kMaximumDelayMs = 20; constexpr int kMaximumDelayMs = 20;
@ -262,7 +215,6 @@ TEST_F(DelayManagerTest, BaseMinimumDelayGreaterThanBufferSize) {
} }
TEST_F(DelayManagerTest, BaseMinimumDelayGreaterThanMaximumDelay) { TEST_F(DelayManagerTest, BaseMinimumDelayGreaterThanMaximumDelay) {
SetPacketAudioLength(kFrameSizeMs);
constexpr int kMaximumDelayMs = 400; constexpr int kMaximumDelayMs = 400;
constexpr int kBaseMinimumDelayMs = kMaximumDelayMs + 1; constexpr int kBaseMinimumDelayMs = kMaximumDelayMs + 1;
constexpr int kMinimumDelayMs = 20; constexpr int kMinimumDelayMs = 20;
@ -280,7 +232,6 @@ TEST_F(DelayManagerTest, BaseMinimumDelayGreaterThanMaximumDelay) {
} }
TEST_F(DelayManagerTest, BaseMinimumDelayLowerThanMaxSize) { TEST_F(DelayManagerTest, BaseMinimumDelayLowerThanMaxSize) {
SetPacketAudioLength(kFrameSizeMs);
constexpr int kMaximumDelayMs = 400; constexpr int kMaximumDelayMs = 400;
constexpr int kBaseMinimumDelayMs = kMaximumDelayMs - 1; constexpr int kBaseMinimumDelayMs = kMaximumDelayMs - 1;
constexpr int kMinimumDelayMs = 20; constexpr int kMinimumDelayMs = 20;
@ -301,8 +252,6 @@ TEST_F(DelayManagerTest, MinimumDelayMemorization) {
// minimum delay then minimum delay is still memorized. This allows to // minimum delay then minimum delay is still memorized. This allows to
// restore effective minimum delay to memorized minimum delay value when we // restore effective minimum delay to memorized minimum delay value when we
// decrease base minimum delay. // decrease base minimum delay.
SetPacketAudioLength(kFrameSizeMs);
constexpr int kBaseMinimumDelayMsLow = 10; constexpr int kBaseMinimumDelayMsLow = 10;
constexpr int kMinimumDelayMs = 20; constexpr int kMinimumDelayMs = 20;
constexpr int kBaseMinimumDelayMsHigh = 30; constexpr int kBaseMinimumDelayMsHigh = 30;
@ -323,33 +272,29 @@ TEST_F(DelayManagerTest, MinimumDelayMemorization) {
} }
TEST_F(DelayManagerTest, BaseMinimumDelay) { TEST_F(DelayManagerTest, BaseMinimumDelay) {
const int kExpectedTarget = 5; const int kExpectedTarget = 5 * kFrameSizeMs;
const int kTimeIncrement = kExpectedTarget * kFrameSizeMs;
SetPacketAudioLength(kFrameSizeMs);
// First packet arrival. // First packet arrival.
InsertNextPacket(); InsertNextPacket();
// Second packet arrival. // Second packet arrival.
IncreaseTime(kTimeIncrement); IncreaseTime(kExpectedTarget);
InsertNextPacket(); InsertNextPacket();
// No limit is applied. // No limit is applied.
EXPECT_EQ(kExpectedTarget << 8, dm_->TargetLevel()); EXPECT_EQ(kExpectedTarget, dm_->TargetDelayMs());
constexpr int kBaseMinimumDelayPackets = kExpectedTarget + 2; constexpr int kBaseMinimumDelayMs = 7 * kFrameSizeMs;
constexpr int kBaseMinimumDelayMs = kBaseMinimumDelayPackets * kFrameSizeMs;
EXPECT_TRUE(dm_->SetBaseMinimumDelay(kBaseMinimumDelayMs)); EXPECT_TRUE(dm_->SetBaseMinimumDelay(kBaseMinimumDelayMs));
EXPECT_EQ(dm_->GetBaseMinimumDelay(), kBaseMinimumDelayMs); EXPECT_EQ(dm_->GetBaseMinimumDelay(), kBaseMinimumDelayMs);
IncreaseTime(kFrameSizeMs); IncreaseTime(kFrameSizeMs);
InsertNextPacket(); InsertNextPacket();
EXPECT_EQ(dm_->GetBaseMinimumDelay(), kBaseMinimumDelayMs); EXPECT_EQ(dm_->GetBaseMinimumDelay(), kBaseMinimumDelayMs);
EXPECT_EQ(kBaseMinimumDelayPackets << 8, dm_->TargetLevel()); EXPECT_EQ(kBaseMinimumDelayMs, dm_->TargetDelayMs());
} }
TEST_F(DelayManagerTest, BaseMinimumDealyAffectTargetLevel) { TEST_F(DelayManagerTest, BaseMinimumDelayAffectsTargetDelay) {
const int kExpectedTarget = 5; const int kExpectedTarget = 5;
const int kTimeIncrement = kExpectedTarget * kFrameSizeMs; const int kTimeIncrement = kExpectedTarget * kFrameSizeMs;
SetPacketAudioLength(kFrameSizeMs);
// First packet arrival. // First packet arrival.
InsertNextPacket(); InsertNextPacket();
// Second packet arrival. // Second packet arrival.
@ -357,7 +302,7 @@ TEST_F(DelayManagerTest, BaseMinimumDealyAffectTargetLevel) {
InsertNextPacket(); InsertNextPacket();
// No limit is applied. // No limit is applied.
EXPECT_EQ(kExpectedTarget << 8, dm_->TargetLevel()); EXPECT_EQ(kTimeIncrement, dm_->TargetDelayMs());
// Minimum delay is lower than base minimum delay, that is why base minimum // Minimum delay is lower than base minimum delay, that is why base minimum
// delay is used to calculate target level. // delay is used to calculate target level.
@ -375,88 +320,19 @@ TEST_F(DelayManagerTest, BaseMinimumDealyAffectTargetLevel) {
IncreaseTime(kFrameSizeMs); IncreaseTime(kFrameSizeMs);
InsertNextPacket(); InsertNextPacket();
EXPECT_EQ(dm_->GetBaseMinimumDelay(), kBaseMinimumDelayMs); EXPECT_EQ(dm_->GetBaseMinimumDelay(), kBaseMinimumDelayMs);
EXPECT_EQ(kBaseMinimumDelayPackets << 8, dm_->TargetLevel()); EXPECT_EQ(kBaseMinimumDelayMs, dm_->TargetDelayMs());
}
TEST_F(DelayManagerTest, EnableRtxHandling) {
enable_rtx_handling_ = true;
use_mock_histogram_ = true;
RecreateDelayManager();
EXPECT_TRUE(mock_histogram_);
// Insert first packet.
SetPacketAudioLength(kFrameSizeMs);
InsertNextPacket();
// Insert reordered packet.
EXPECT_CALL(*mock_histogram_, Add(2));
dm_->Update(seq_no_ - 3, ts_ - 3 * kFrameSizeMs, kFs);
// Insert another reordered packet.
EXPECT_CALL(*mock_histogram_, Add(1));
dm_->Update(seq_no_ - 2, ts_ - 2 * kFrameSizeMs, kFs);
// Insert the next packet in order and verify that the inter-arrival time is
// estimated correctly.
IncreaseTime(kFrameSizeMs);
EXPECT_CALL(*mock_histogram_, Add(0));
InsertNextPacket();
}
// Tests that skipped sequence numbers (simulating empty packets) are handled
// correctly.
// TODO(jakobi): Make delay manager independent of sequence numbers.
TEST_F(DelayManagerTest, EmptyPacketsReported) {
SetPacketAudioLength(kFrameSizeMs);
// First packet arrival.
InsertNextPacket();
// Advance time by one frame size.
IncreaseTime(kFrameSizeMs);
// Advance the sequence number by 5, simulating that 5 empty packets were
// received, but never inserted.
seq_no_ += 10;
for (int j = 0; j < 10; ++j) {
dm_->RegisterEmptyPacket();
}
// Second packet arrival.
InsertNextPacket();
EXPECT_EQ(1 << 8, dm_->TargetLevel()); // In Q8.
}
// Same as above, but do not call RegisterEmptyPacket. Target level stays the
// same.
TEST_F(DelayManagerTest, EmptyPacketsNotReported) {
SetPacketAudioLength(kFrameSizeMs);
// First packet arrival.
InsertNextPacket();
// Advance time by one frame size.
IncreaseTime(kFrameSizeMs);
// Advance the sequence number by 10, simulating that 10 empty packets were
// received, but never inserted.
seq_no_ += 10;
// Second packet arrival.
InsertNextPacket();
EXPECT_EQ(1 << 8, dm_->TargetLevel()); // In Q8.
} }
TEST_F(DelayManagerTest, Failures) { TEST_F(DelayManagerTest, Failures) {
// Wrong sample rate. // Wrong sample rate.
EXPECT_EQ(absl::nullopt, dm_->Update(0, 0, -1)); EXPECT_EQ(absl::nullopt, dm_->Update(0, -1));
// Wrong packet size. // Wrong packet size.
EXPECT_EQ(-1, dm_->SetPacketAudioLength(0)); EXPECT_EQ(-1, dm_->SetPacketAudioLength(0));
EXPECT_EQ(-1, dm_->SetPacketAudioLength(-1)); EXPECT_EQ(-1, dm_->SetPacketAudioLength(-1));
// Minimum delay higher than a maximum delay is not accepted. // Minimum delay higher than a maximum delay is not accepted.
EXPECT_TRUE(dm_->SetMaximumDelay(10)); EXPECT_TRUE(dm_->SetMaximumDelay(20));
EXPECT_FALSE(dm_->SetMinimumDelay(20)); EXPECT_FALSE(dm_->SetMinimumDelay(40));
// Maximum delay less than minimum delay is not accepted. // Maximum delay less than minimum delay is not accepted.
EXPECT_TRUE(dm_->SetMaximumDelay(100)); EXPECT_TRUE(dm_->SetMaximumDelay(100));
@ -510,7 +386,6 @@ TEST_F(DelayManagerTest, RelativeArrivalDelay) {
use_mock_histogram_ = true; use_mock_histogram_ = true;
RecreateDelayManager(); RecreateDelayManager();
SetPacketAudioLength(kFrameSizeMs);
InsertNextPacket(); InsertNextPacket();
IncreaseTime(kFrameSizeMs); IncreaseTime(kFrameSizeMs);
@ -519,21 +394,20 @@ TEST_F(DelayManagerTest, RelativeArrivalDelay) {
IncreaseTime(2 * kFrameSizeMs); IncreaseTime(2 * kFrameSizeMs);
EXPECT_CALL(*mock_histogram_, Add(1)); // 20ms delayed. EXPECT_CALL(*mock_histogram_, Add(1)); // 20ms delayed.
dm_->Update(seq_no_, ts_, kFs); dm_->Update(ts_, kFs);
IncreaseTime(2 * kFrameSizeMs); IncreaseTime(2 * kFrameSizeMs);
EXPECT_CALL(*mock_histogram_, Add(2)); // 40ms delayed. EXPECT_CALL(*mock_histogram_, Add(2)); // 40ms delayed.
dm_->Update(seq_no_ + 1, ts_ + kTsIncrement, kFs); dm_->Update(ts_ + kTsIncrement, kFs);
EXPECT_CALL(*mock_histogram_, Add(1)); // Reordered, 20ms delayed. EXPECT_CALL(*mock_histogram_, Add(1)); // Reordered, 20ms delayed.
dm_->Update(seq_no_, ts_, kFs); dm_->Update(ts_, kFs);
} }
TEST_F(DelayManagerTest, MaxDelayHistory) { TEST_F(DelayManagerTest, MaxDelayHistory) {
use_mock_histogram_ = true; use_mock_histogram_ = true;
RecreateDelayManager(); RecreateDelayManager();
SetPacketAudioLength(kFrameSizeMs);
InsertNextPacket(); InsertNextPacket();
// Insert 20 ms iat delay in the delay history. // Insert 20 ms iat delay in the delay history.
@ -547,11 +421,10 @@ TEST_F(DelayManagerTest, MaxDelayHistory) {
IncreaseTime(kMaxHistoryMs + kFrameSizeMs); IncreaseTime(kMaxHistoryMs + kFrameSizeMs);
ts_ += kFs * kMaxHistoryMs / 1000; ts_ += kFs * kMaxHistoryMs / 1000;
EXPECT_CALL(*mock_histogram_, Add(0)); // Not delayed. EXPECT_CALL(*mock_histogram_, Add(0)); // Not delayed.
dm_->Update(seq_no_, ts_, kFs); dm_->Update(ts_, kFs);
} }
TEST_F(DelayManagerTest, RelativeArrivalDelayStatistic) { TEST_F(DelayManagerTest, RelativeArrivalDelayStatistic) {
SetPacketAudioLength(kFrameSizeMs);
EXPECT_EQ(absl::nullopt, InsertNextPacket()); EXPECT_EQ(absl::nullopt, InsertNextPacket());
IncreaseTime(kFrameSizeMs); IncreaseTime(kFrameSizeMs);
EXPECT_EQ(0, InsertNextPacket()); EXPECT_EQ(0, InsertNextPacket());
@ -560,38 +433,4 @@ TEST_F(DelayManagerTest, RelativeArrivalDelayStatistic) {
EXPECT_EQ(20, InsertNextPacket()); EXPECT_EQ(20, InsertNextPacket());
} }
TEST_F(DelayManagerTest, DecelerationTargetLevelOffset) {
SetPacketAudioLength(kFrameSizeMs);
// Deceleration target level offset follows the value hardcoded in
// delay_manager.cc.
constexpr int kDecelerationTargetLevelOffsetMs = 85 << 8; // In Q8.
// Border value where |x * 3/4 = target_level - x|.
constexpr int kBoarderTargetLevel = kDecelerationTargetLevelOffsetMs * 4;
{
// Test that for a low target level, default behaviour is intact.
const int target_level_ms = kBoarderTargetLevel / kFrameSizeMs - 1;
int lower, higher; // In Q8.
dm_->BufferLimits(target_level_ms, &lower, &higher);
// Default behaviour of taking 75% of target level.
EXPECT_EQ(target_level_ms * 3 / 4, lower);
EXPECT_EQ(target_level_ms, higher);
}
{
// Test that for the high target level, |lower| is below target level by
// fixed |kOffset|.
const int target_level_ms = kBoarderTargetLevel / kFrameSizeMs + 1;
int lower, higher; // In Q8.
dm_->BufferLimits(target_level_ms, &lower, &higher);
EXPECT_EQ(target_level_ms - kDecelerationTargetLevelOffsetMs / kFrameSizeMs,
lower);
EXPECT_EQ(target_level_ms, higher);
}
}
} // namespace webrtc } // namespace webrtc

View File

@ -804,8 +804,10 @@ TEST_P(NetEqImplTestSampleRateParameter,
EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted)); EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted));
} }
// Insert one more packet. // Insert a few packets to avoid postpone decoding after expand.
insert_packet(); for (size_t i = 0; i < 5; ++i) {
insert_packet();
}
// Pull audio until the newly inserted packet is decoded and the PLC ends. // Pull audio until the newly inserted packet is decoded and the PLC ends.
while (output.speech_type_ != AudioFrame::kNormalSpeech) { while (output.speech_type_ != AudioFrame::kNormalSpeech) {
@ -881,8 +883,10 @@ TEST_P(NetEqImplTestSampleRateParameter, AudioInterruptionLogged) {
EXPECT_NE(AudioFrame::kNormalSpeech, output.speech_type_); EXPECT_NE(AudioFrame::kNormalSpeech, output.speech_type_);
} }
// Insert one more packet. // Insert a few packets to avoid postpone decoding after expand.
insert_packet(); for (size_t i = 0; i < 5; ++i) {
insert_packet();
}
// Pull audio until the newly inserted packet is decoded and the PLC ends. // Pull audio until the newly inserted packet is decoded and the PLC ends.
while (output.speech_type_ != AudioFrame::kNormalSpeech) { while (output.speech_type_ != AudioFrame::kNormalSpeech) {
@ -1299,7 +1303,7 @@ TEST_F(NetEqImplTest, DecodingError) {
SdpAudioFormat("L16", 8000, 1))); SdpAudioFormat("L16", 8000, 1)));
// Insert packets. // Insert packets.
for (int i = 0; i < 6; ++i) { for (int i = 0; i < 20; ++i) {
rtp_header.sequenceNumber += 1; rtp_header.sequenceNumber += 1;
rtp_header.timestamp += kFrameLengthSamples; rtp_header.timestamp += kFrameLengthSamples;
EXPECT_EQ(NetEq::kOK, neteq_->InsertPacket(rtp_header, payload)); EXPECT_EQ(NetEq::kOK, neteq_->InsertPacket(rtp_header, payload));

View File

@ -84,16 +84,16 @@ TEST_F(NetEqDecodingTest, MAYBE_TestBitExactness) {
webrtc::test::ResourcePath("audio_coding/neteq_universal_new", "rtp"); webrtc::test::ResourcePath("audio_coding/neteq_universal_new", "rtp");
const std::string output_checksum = const std::string output_checksum =
PlatformChecksum("6ae9f643dc3e5f3452d28a772eef7e00e74158bc", PlatformChecksum("68ec266d2d152dfc0d938484e7936f6af4f803e3",
"f4374430e870d66268c1b8e22fb700eb072d567e", "not used", "1c243feb35e3e9ab37039eddf5b3c3ecfca3c60c", "not used",
"6ae9f643dc3e5f3452d28a772eef7e00e74158bc", "68ec266d2d152dfc0d938484e7936f6af4f803e3",
"8d73c98645917cdeaaa01c20cf095ccc5a10b2b5"); "f68c546a43bb25743297c9c0c9027e8424b8e10b");
const std::string network_stats_checksum = const std::string network_stats_checksum =
PlatformChecksum("8e50f528f245b7957db20ab406a72d81be60f5f4", PlatformChecksum("2a5516cdc1c6af9f1d9d3c2f95ed292f509311c7",
"4260b22ea6d2723b2d573e50d2c1476680c7fa4c", "not used", "e96a7f081ebc111f49c7373d3728274057012ae9", "not used",
"8e50f528f245b7957db20ab406a72d81be60f5f4", "2a5516cdc1c6af9f1d9d3c2f95ed292f509311c7",
"8e50f528f245b7957db20ab406a72d81be60f5f4"); "2a5516cdc1c6af9f1d9d3c2f95ed292f509311c7");
DecodeAndCompare(input_rtp_file, output_checksum, network_stats_checksum, DecodeAndCompare(input_rtp_file, output_checksum, network_stats_checksum,
absl::GetFlag(FLAGS_gen_ref)); absl::GetFlag(FLAGS_gen_ref));
@ -113,13 +113,13 @@ TEST_F(NetEqDecodingTest, MAYBE_TestOpusBitExactness) {
"554ad4133934e3920f97575579a46f674683d77c" "554ad4133934e3920f97575579a46f674683d77c"
"|de316e2bfb15192edb820fe5fb579d11ff5a524b"; "|de316e2bfb15192edb820fe5fb579d11ff5a524b";
const std::string output_checksum = PlatformChecksum( const std::string output_checksum = PlatformChecksum(
maybe_sse, "459c356a0ef245ddff381f7d82d205d426ef2002", maybe_sse, "b3fac4ad4f6ea384aff676ee1ea816bd70415490",
"625055e5eb0e6de2c9d170b4494eadc5afab08c8", maybe_sse, maybe_sse); "373ccd99c147cd3fcef0e7dcad6f87d0f8e5a1c0", maybe_sse, maybe_sse);
const std::string network_stats_checksum = const std::string network_stats_checksum =
PlatformChecksum("ec29e047b019a86ec06e2c40643143dc1975c69f", PlatformChecksum("ec29e047b019a86ec06e2c40643143dc1975c69f",
"0c24649824eb7147d4891b0767e86e732dd6ecc8", "ce6f519bc1220b003944ac5d9db077665a06834e",
"10f3e0b66c6947f78d60301454f2841033a6fcc0", "abb686d3ac6fac0001ca8d45a6ca6f5aefb2f9d6",
"ec29e047b019a86ec06e2c40643143dc1975c69f", "ec29e047b019a86ec06e2c40643143dc1975c69f",
"ec29e047b019a86ec06e2c40643143dc1975c69f"); "ec29e047b019a86ec06e2c40643143dc1975c69f");
@ -138,14 +138,14 @@ TEST_F(NetEqDecodingTest, MAYBE_TestOpusDtxBitExactness) {
webrtc::test::ResourcePath("audio_coding/neteq_opus_dtx", "rtp"); webrtc::test::ResourcePath("audio_coding/neteq_opus_dtx", "rtp");
const std::string maybe_sse = const std::string maybe_sse =
"df5d1d3019bf3764829b84f4fb315721f4adde29" "0fb0a3d6b3758ca6e108368bb777cd38d0a865af"
"|5935d2fad14a69a8b61dbc8e6f2d37c8c0814925"; "|5935d2fad14a69a8b61dbc8e6f2d37c8c0814925";
const std::string output_checksum = PlatformChecksum( const std::string output_checksum = PlatformChecksum(
maybe_sse, "551df04e8f45cd99eff28503edf0cf92974898ac", maybe_sse, "b6632690f8d7c2340c838df2821fc014f1cc8360",
"709a3f0f380393d3a67bace10e2265b90a6ebbeb", maybe_sse, maybe_sse); "f890b9eb9bc5ab8313489230726b297f6a0825af", maybe_sse, maybe_sse);
const std::string network_stats_checksum = const std::string network_stats_checksum =
"80f5283ac71b27596204210152927666c1732de4"; "18983bb67a57628c604dbdefa99574c6e0c5bb48";
DecodeAndCompare(input_rtp_file, output_checksum, network_stats_checksum, DecodeAndCompare(input_rtp_file, output_checksum, network_stats_checksum,
absl::GetFlag(FLAGS_gen_ref)); absl::GetFlag(FLAGS_gen_ref));
@ -737,8 +737,10 @@ TEST_F(NetEqDecodingTestWithMutedState, MutedStateOldPacket) {
GetAudioUntilMuted(); GetAudioUntilMuted();
EXPECT_NE(AudioFrame::kNormalSpeech, out_frame_.speech_type_); EXPECT_NE(AudioFrame::kNormalSpeech, out_frame_.speech_type_);
// Insert packet which is older than the first packet. // Insert a few packets which are older than the first packet.
InsertPacket(kSamples * (counter_ - 1000)); for (int i = 0; i < 5; ++i) {
InsertPacket(kSamples * (i - 1000));
}
EXPECT_FALSE(GetAudioReturnMuted()); EXPECT_FALSE(GetAudioReturnMuted());
EXPECT_EQ(AudioFrame::kNormalSpeech, out_frame_.speech_type_); EXPECT_EQ(AudioFrame::kNormalSpeech, out_frame_.speech_type_);
} }
@ -853,9 +855,11 @@ TEST_F(NetEqDecodingTestTwoInstances, CompareMutedStateOnOff) {
// Insert new data. Timestamp is corrected for the time elapsed since the last // Insert new data. Timestamp is corrected for the time elapsed since the last
// packet. // packet.
PopulateRtpInfo(0, kSamples * 1000, &rtp_info); for (int i = 0; i < 5; ++i) {
EXPECT_EQ(0, neteq_->InsertPacket(rtp_info, payload)); PopulateRtpInfo(0, kSamples * 1000 + kSamples * i, &rtp_info);
EXPECT_EQ(0, neteq2_->InsertPacket(rtp_info, payload)); EXPECT_EQ(0, neteq_->InsertPacket(rtp_info, payload));
EXPECT_EQ(0, neteq2_->InsertPacket(rtp_info, payload));
}
int counter = 0; int counter = 0;
while (out_frame1.speech_type_ != AudioFrame::kNormalSpeech) { while (out_frame1.speech_type_ != AudioFrame::kNormalSpeech) {
@ -1264,7 +1268,7 @@ TEST(NetEqOutputDelayTest, RunTestWithFieldTrial) {
// The base delay values are taken from the resuts of the non-delayed case in // The base delay values are taken from the resuts of the non-delayed case in
// NetEqOutputDelayTest.RunTest above. // NetEqOutputDelayTest.RunTest above.
EXPECT_EQ(10 + kExpectedDelayMs, result.target_delay_ms); EXPECT_EQ(20 + kExpectedDelayMs, result.target_delay_ms);
EXPECT_EQ(24 + kExpectedDelayMs, result.filtered_current_delay_ms); EXPECT_EQ(24 + kExpectedDelayMs, result.filtered_current_delay_ms);
} }
@ -1279,7 +1283,7 @@ TEST(NetEqOutputDelayTest, RunTestWithFieldTrialOddValue) {
// The base delay values are taken from the resuts of the non-delayed case in // The base delay values are taken from the resuts of the non-delayed case in
// NetEqOutputDelayTest.RunTest above. // NetEqOutputDelayTest.RunTest above.
EXPECT_EQ(10 + kRoundedDelayMs, result.target_delay_ms); EXPECT_EQ(20 + kRoundedDelayMs, result.target_delay_ms);
EXPECT_EQ(24 + kRoundedDelayMs, result.filtered_current_delay_ms); EXPECT_EQ(24 + kRoundedDelayMs, result.filtered_current_delay_ms);
} }