From fa68ac0c4e3016d5a85e53945ae14703da0afc98 Mon Sep 17 00:00:00 2001 From: Jakob Ivarsson Date: Tue, 9 Nov 2021 12:58:45 +0100 Subject: [PATCH] Reland "Remove legacy delay manger field trial and update default config." This is a reland of 93849d4b2a976b0a46059d6f74d9efd8f12eab92 Original change's description: > Remove legacy delay manger field trial and update default config. > > Bug: webrtc:10333 > Change-Id: I20e55d8d111d93657d1afe556fe3a325337c074c > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/232820 > Reviewed-by: Ivo Creusen > Commit-Queue: Jakob Ivarsson > Cr-Commit-Position: refs/heads/main@{#35321} Bug: webrtc:10333 Change-Id: I9b3c732309d32640d15c372a4dde37d5d44c95d1 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/237502 Reviewed-by: Ivo Creusen Commit-Queue: Jakob Ivarsson Cr-Commit-Position: refs/heads/main@{#35325} --- .../acm2/audio_coding_module_unittest.cc | 110 +++++++-------- modules/audio_coding/neteq/delay_manager.cc | 51 ++----- modules/audio_coding/neteq/delay_manager.h | 13 +- .../neteq/delay_manager_unittest.cc | 84 ++--------- modules/audio_coding/neteq/neteq_impl.cc | 2 +- .../audio_coding/neteq/neteq_impl_unittest.cc | 132 ++++++------------ .../neteq/neteq_network_stats_unittest.cc | 2 +- modules/audio_coding/neteq/neteq_unittest.cc | 37 ++--- .../neteq/relative_arrival_delay_tracker.cc | 2 +- .../neteq/test/neteq_decoding_test.cc | 12 +- .../audio_coding/neteq/underrun_optimizer.cc | 2 +- 11 files changed, 149 insertions(+), 298 deletions(-) diff --git a/modules/audio_coding/acm2/audio_coding_module_unittest.cc b/modules/audio_coding/acm2/audio_coding_module_unittest.cc index 87379c887c..f6e9e47828 100644 --- a/modules/audio_coding/acm2/audio_coding_module_unittest.cc +++ b/modules/audio_coding/acm2/audio_coding_module_unittest.cc @@ -920,62 +920,62 @@ class AcmReceiverBitExactnessOldApi : public ::testing::Test { defined(WEBRTC_CODEC_ILBC) TEST_F(AcmReceiverBitExactnessOldApi, 8kHzOutput) { std::string others_checksum_reference = - GetCPUInfo(kAVX2) != 0 ? "e0c966d7b8c36ff60167988fa35d33e0" - : "7d8f6b84abd1e57ec010a53bc2130652"; + GetCPUInfo(kAVX2) != 0 ? "d8671dd38dab43fc9ca64a45c048c218" + : "4710c99559aec2f9f02a983ba2146f2d"; std::string win64_checksum_reference = GetCPUInfo(kAVX2) != 0 ? "405a50f0bcb8827e20aa944299fc59f6" : "0ed5830930f5527a01bbec0ba11f8541"; Run(8000, PlatformChecksum( others_checksum_reference, win64_checksum_reference, - /*android_arm32=*/"b892ed69c38b21b16c132ec2ce03aa7b", + /*android_arm32=*/"4a8ffd7fd235c8bea74d0e18c022fac3", /*android_arm64=*/"4598140b5e4f7ee66c5adad609e65a3e", - /*android_arm64_clang=*/"5fec8d770778ef7969ec98c56d9eb10f", - /*mac_arm64=*/"636efe6d0a148f22c5383f356da3deac")); + /*android_arm64_clang=*/"ad2ae6c6e48b714d728a7af0d3c8dc51", + /*mac_arm64=*/"6a288942d67e82076b38b17777cdaee4")); } TEST_F(AcmReceiverBitExactnessOldApi, 16kHzOutput) { std::string others_checksum_reference = - GetCPUInfo(kAVX2) != 0 ? "a63c578e1195c8420f453962c6d8519c" - : "6bac83762c1306b932cd25a560155681"; + GetCPUInfo(kAVX2) != 0 ? "abcb31509af46545edb4f6700728a4de" + : "70b3217df49834b7093c631531068bd0"; std::string win64_checksum_reference = GetCPUInfo(kAVX2) != 0 ? "58fd62a5c49ee513f9fa6fe7dbf62c97" : "0509cf0672f543efb4b050e8cffefb1d"; Run(16000, PlatformChecksum( others_checksum_reference, win64_checksum_reference, - /*android_arm32=*/"3cea9abbeabbdea9a79719941b241af5", + /*android_arm32=*/"00d703da221363804d6fccc309a3f684", /*android_arm64=*/"f2aad418af974a3b1694d5ae5cc2c3c7", - /*android_arm64_clang=*/"9d4b92c31c00e321a4cff29ad002d6a2", - /*mac_arm64=*/"1e2d1b482fdc924f79a838503ee7ead5")); + /*android_arm64_clang=*/"2b8525c77a6e10800bb209a83160282a", + /*mac_arm64=*/"35786906e6e352ad7031e3acf1c2d1ea")); } TEST_F(AcmReceiverBitExactnessOldApi, 32kHzOutput) { std::string others_checksum_reference = - GetCPUInfo(kAVX2) != 0 ? "8775ce387f44dc5ff4a26da295d5ee7c" - : "e319222ca47733709f90fdf33c8574db"; + GetCPUInfo(kAVX2) != 0 ? "8489b7743d6cd1903807ac81e5ee493d" + : "2679e4e596e33259228c62df545eb635"; std::string win64_checksum_reference = GetCPUInfo(kAVX2) != 0 ? "04ce6a1dac5ffdd8438d804623d0132f" : "39a4a7a1c455b35baeffb9fd193d7858"; Run(32000, PlatformChecksum( others_checksum_reference, win64_checksum_reference, - /*android_arm32=*/"4df55b3b62bcbf4328786d474ae87f61", + /*android_arm32=*/"809446f684b8095a93495ad63ec19891", /*android_arm64=*/"100869c8dcde51346c2073e52a272d98", - /*android_arm64_clang=*/"ff58d3153d2780a3df6bc2068844cb2d", - /*mac_arm64=*/"51788e9784a10ae14a030f075a039205")); + /*android_arm64_clang=*/"dfe6fba596ed68d5a32d9f9eba5a39cb", + /*mac_arm64=*/"c42f05eafd86f8d3ae39e1dbe62b96ef")); } TEST_F(AcmReceiverBitExactnessOldApi, 48kHzOutput) { std::string others_checksum_reference = - GetCPUInfo(kAVX2) != 0 ? "7a55700b7ca9aa60237db58b33e55606" - : "57d1d316c88279f4f3da3511665069a9"; + GetCPUInfo(kAVX2) != 0 ? "454996a7adb3f62b259a53a09ff624cf" + : "f0148c5ef84e74e019ac7057af839102"; std::string win64_checksum_reference = GetCPUInfo(kAVX2) != 0 ? "f59833d9b0924f4b0704707dd3589f80" : "74cbe7345e2b6b45c1e455a5d1e921ca"; Run(48000, PlatformChecksum( others_checksum_reference, win64_checksum_reference, - /*android_arm32=*/"f52bc7bf0f499c9da25932fdf176c4ec", + /*android_arm32=*/"f5c1290ce96d675aaf52be0b54362bee", /*android_arm64=*/"bd44bf97e7899186532f91235cef444d", - /*android_arm64_clang=*/"364d403dae55d73cd69e6dbd6b723a4d", - /*mac_arm64=*/"71bc5c15a151400517c2119d1602ee9f")); + /*android_arm64_clang=*/"7c2e28b943baf8c8af556be203bea256", + /*mac_arm64=*/"74cadd87797f7123c1a7baec6a66663c")); } TEST_F(AcmReceiverBitExactnessOldApi, 48kHzOutputExternalDecoder) { @@ -1054,18 +1054,18 @@ TEST_F(AcmReceiverBitExactnessOldApi, 48kHzOutputExternalDecoder) { rtc::scoped_refptr> factory( new rtc::RefCountedObject); std::string others_checksum_reference = - GetCPUInfo(kAVX2) != 0 ? "7a55700b7ca9aa60237db58b33e55606" - : "57d1d316c88279f4f3da3511665069a9"; + GetCPUInfo(kAVX2) != 0 ? "454996a7adb3f62b259a53a09ff624cf" + : "f0148c5ef84e74e019ac7057af839102"; std::string win64_checksum_reference = GetCPUInfo(kAVX2) != 0 ? "f59833d9b0924f4b0704707dd3589f80" : "74cbe7345e2b6b45c1e455a5d1e921ca"; Run(48000, PlatformChecksum( others_checksum_reference, win64_checksum_reference, - /*android_arm32=*/"f52bc7bf0f499c9da25932fdf176c4ec", + /*android_arm32=*/"f5c1290ce96d675aaf52be0b54362bee", /*android_arm64=*/"bd44bf97e7899186532f91235cef444d", - /*android_arm64_clang=*/"364d403dae55d73cd69e6dbd6b723a4d", - /*mac_arm64=*/"71bc5c15a151400517c2119d1602ee9f"), + /*android_arm64_clang=*/"7c2e28b943baf8c8af556be203bea256", + /*mac_arm64=*/"74cadd87797f7123c1a7baec6a66663c"), factory, [](AudioCodingModule* acm) { acm->SetReceiveCodecs({{0, {"MockPCMu", 8000, 1}}, {103, {"ISAC", 16000, 1}}, @@ -1284,12 +1284,12 @@ class AcmSenderBitExactnessNewApi : public AcmSenderBitExactnessOldApi {}; TEST_F(AcmSenderBitExactnessOldApi, IsacWb30ms) { ASSERT_NO_FATAL_FAILURE(SetUpTest("ISAC", 16000, 1, 103, 480, 480)); Run(AcmReceiverBitExactnessOldApi::PlatformChecksum( - /*others=*/"2c9cb15d4ed55b5a0cadd04883bc73b0", + /*others=*/"a3077ac01b0137e8bbc237fb1f9816a5", /*win64=*/"9336a9b993cbd8a751f0e8958e66c89c", - /*android_arm32=*/"5c2eb46199994506236f68b2c8e51b0d", + /*android_arm32=*/"ab39f101ca76efdf6a5b2250550f10c4", /*android_arm64=*/"343f1f42be0607c61e6516aece424609", - /*android_arm64_clang=*/"2c9cb15d4ed55b5a0cadd04883bc73b0", - /*mac_arm64=*/"2c9cb15d4ed55b5a0cadd04883bc73b0"), + /*android_arm64_clang=*/"a3077ac01b0137e8bbc237fb1f9816a5", + /*mac_arm64=*/"a3077ac01b0137e8bbc237fb1f9816a5"), AcmReceiverBitExactnessOldApi::PlatformChecksum( /*others=*/"3c79f16f34218271f3dca4e2b1dfe1bb", /*win64=*/"d42cb5195463da26c8129bbfe73a22e6", @@ -1303,12 +1303,12 @@ TEST_F(AcmSenderBitExactnessOldApi, IsacWb30ms) { TEST_F(AcmSenderBitExactnessOldApi, IsacWb60ms) { ASSERT_NO_FATAL_FAILURE(SetUpTest("ISAC", 16000, 1, 103, 960, 960)); Run(AcmReceiverBitExactnessOldApi::PlatformChecksum( - /*others=*/"1ad29139a04782a33daad8c2b9b35875", + /*others=*/"76da9b7514f986fc2bb32b1c3170e8d4", /*win64=*/"14d63c5f08127d280e722e3191b73bdd", - /*android_arm32=*/"9a81e467eb1485f84aca796f8ea65011", + /*android_arm32=*/"0bd883118ff9c26b9471df7a0c664197", /*android_arm64=*/"ef75e900e6f375e3061163c53fd09a63", - /*android_arm64_clang=*/"1ad29139a04782a33daad8c2b9b35875", - /*mac_arm64=*/"1ad29139a04782a33daad8c2b9b35875"), + /*android_arm64_clang=*/"76da9b7514f986fc2bb32b1c3170e8d4", + /*mac_arm64=*/"76da9b7514f986fc2bb32b1c3170e8d4"), AcmReceiverBitExactnessOldApi::PlatformChecksum( /*others=*/"9e0a0ab743ad987b55b8e14802769c56", /*win64=*/"ebe04a819d3a9d83a83a17f271e1139a", @@ -1330,10 +1330,10 @@ TEST_F(AcmSenderBitExactnessOldApi, IsacWb60ms) { TEST_F(AcmSenderBitExactnessOldApi, MAYBE_IsacSwb30ms) { ASSERT_NO_FATAL_FAILURE(SetUpTest("ISAC", 32000, 1, 104, 960, 960)); Run(AcmReceiverBitExactnessOldApi::PlatformChecksum( - /*others=*/"5683b58da0fbf2063c7adc2e6bfb3fb8", + /*others=*/"f4cf577f28a0dcbac33358b757518e0c", /*win64=*/"2b3c387d06f00b7b7aad4c9be56fb83d", "android_arm32_audio", "android_arm64_audio", "android_arm64_clang_audio", - /*mac_arm64=*/"5683b58da0fbf2063c7adc2e6bfb3fb8"), + /*mac_arm64=*/"f4cf577f28a0dcbac33358b757518e0c"), AcmReceiverBitExactnessOldApi::PlatformChecksum( /*others=*/"ce86106a93419aefb063097108ec94ab", /*win64=*/"bcc2041e7744c7ebd9f701866856849c", "android_arm32_payload", @@ -1345,61 +1345,61 @@ TEST_F(AcmSenderBitExactnessOldApi, MAYBE_IsacSwb30ms) { TEST_F(AcmSenderBitExactnessOldApi, Pcm16_8000khz_10ms) { ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 8000, 1, 107, 80, 80)); - Run("15396f66b5b0ab6842e151c807395e4c", "c1edd36339ce0326cc4550041ad719a0", + Run("69118ed438ac76252d023e0463819471", "c1edd36339ce0326cc4550041ad719a0", 100, test::AcmReceiveTestOldApi::kMonoOutput); } TEST_F(AcmSenderBitExactnessOldApi, Pcm16_16000khz_10ms) { ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 16000, 1, 108, 160, 160)); - Run("54ae004529874c2b362c7f0ccd19cb99", "ad786526383178b08d80d6eee06e9bad", + Run("bc6ab94d12a464921763d7544fdbd07e", "ad786526383178b08d80d6eee06e9bad", 100, test::AcmReceiveTestOldApi::kMonoOutput); } TEST_F(AcmSenderBitExactnessOldApi, Pcm16_32000khz_10ms) { ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 32000, 1, 109, 320, 320)); - Run("d6a4a68b8c838dcc1e7ae7136467cdf0", "5ef82ea885e922263606c6fdbc49f651", + Run("c50244419c5c3a2f04cc69a022c266a2", "5ef82ea885e922263606c6fdbc49f651", 100, test::AcmReceiveTestOldApi::kMonoOutput); } TEST_F(AcmSenderBitExactnessOldApi, Pcm16_stereo_8000khz_10ms) { ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 8000, 2, 111, 80, 80)); - Run("6b011dab43e3a8a46ccff7e4412ed8a2", "62ce5adb0d4965d0a52ec98ae7f98974", + Run("4fccf4cc96f1e8e8de4b9fadf62ded9e", "62ce5adb0d4965d0a52ec98ae7f98974", 100, test::AcmReceiveTestOldApi::kStereoOutput); } TEST_F(AcmSenderBitExactnessOldApi, Pcm16_stereo_16000khz_10ms) { ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 16000, 2, 112, 160, 160)); - Run("17fc9854358bfe0419408290664bd78e", "41ca8edac4b8c71cd54fd9f25ec14870", + Run("e15e388d9d4af8c02a59fe1552fedee3", "41ca8edac4b8c71cd54fd9f25ec14870", 100, test::AcmReceiveTestOldApi::kStereoOutput); } TEST_F(AcmSenderBitExactnessOldApi, Pcm16_stereo_32000khz_10ms) { ASSERT_NO_FATAL_FAILURE(SetUpTest("L16", 32000, 2, 113, 320, 320)); - Run("9ac9a1f64d55da2fc9f3167181cc511d", "50e58502fb04421bf5b857dda4c96879", + Run("b240520c0d05003fde7a174ae5957286", "50e58502fb04421bf5b857dda4c96879", 100, test::AcmReceiveTestOldApi::kStereoOutput); } TEST_F(AcmSenderBitExactnessOldApi, Pcmu_20ms) { ASSERT_NO_FATAL_FAILURE(SetUpTest("PCMU", 8000, 1, 0, 160, 160)); - Run("81a9d4c0bb72e9becc43aef124c981e9", "8f9b8750bd80fe26b6cbf6659b89f0f9", + Run("c8d1fc677f33c2022ec5f83c7f302280", "8f9b8750bd80fe26b6cbf6659b89f0f9", 50, test::AcmReceiveTestOldApi::kMonoOutput); } TEST_F(AcmSenderBitExactnessOldApi, Pcma_20ms) { ASSERT_NO_FATAL_FAILURE(SetUpTest("PCMA", 8000, 1, 8, 160, 160)); - Run("39611f798969053925a49dc06d08de29", "6ad745e55aa48981bfc790d0eeef2dd1", + Run("47eb60e855eb12d1b0e6da9c975754a4", "6ad745e55aa48981bfc790d0eeef2dd1", 50, test::AcmReceiveTestOldApi::kMonoOutput); } TEST_F(AcmSenderBitExactnessOldApi, Pcmu_stereo_20ms) { ASSERT_NO_FATAL_FAILURE(SetUpTest("PCMU", 8000, 2, 110, 160, 160)); - Run("437bec032fdc5cbaa0d5175430af7b18", "60b6f25e8d1e74cb679cfe756dd9bca5", + Run("6ef2f57d4934714787fd0a834e3ea18e", "60b6f25e8d1e74cb679cfe756dd9bca5", 50, test::AcmReceiveTestOldApi::kStereoOutput); } TEST_F(AcmSenderBitExactnessOldApi, Pcma_stereo_20ms) { ASSERT_NO_FATAL_FAILURE(SetUpTest("PCMA", 8000, 2, 118, 160, 160)); - Run("a5c6d83c5b7cedbeff734238220a4b0c", "92b282c83efd20e7eeef52ba40842cf7", + Run("a84d75e098d87ab6b260687eb4b612a2", "92b282c83efd20e7eeef52ba40842cf7", 50, test::AcmReceiveTestOldApi::kStereoOutput); } @@ -1412,10 +1412,10 @@ TEST_F(AcmSenderBitExactnessOldApi, Pcma_stereo_20ms) { TEST_F(AcmSenderBitExactnessOldApi, MAYBE_Ilbc_30ms) { ASSERT_NO_FATAL_FAILURE(SetUpTest("ILBC", 8000, 1, 102, 240, 240)); Run(AcmReceiverBitExactnessOldApi::PlatformChecksum( - /*others=*/"7b6ec10910debd9af08011d3ed5249f7", - /*win64=*/"7b6ec10910debd9af08011d3ed5249f7", "android_arm32_audio", + /*others=*/"b14dba0de36efa5ec88a32c0b320b70f", + /*win64=*/"b14dba0de36efa5ec88a32c0b320b70f", "android_arm32_audio", "android_arm64_audio", "android_arm64_clang_audio", - /*mac_arm64=*/"7b6ec10910debd9af08011d3ed5249f7"), + /*mac_arm64=*/"b14dba0de36efa5ec88a32c0b320b70f"), AcmReceiverBitExactnessOldApi::PlatformChecksum( /*others=*/"cfae2e9f6aba96e145f2bcdd5050ce78", /*win64=*/"cfae2e9f6aba96e145f2bcdd5050ce78", "android_arm32_payload", @@ -1433,10 +1433,10 @@ TEST_F(AcmSenderBitExactnessOldApi, MAYBE_Ilbc_30ms) { TEST_F(AcmSenderBitExactnessOldApi, MAYBE_G722_20ms) { ASSERT_NO_FATAL_FAILURE(SetUpTest("G722", 16000, 1, 9, 320, 160)); Run(AcmReceiverBitExactnessOldApi::PlatformChecksum( - /*others=*/"e99c89be49a46325d03c0d990c292d68", - /*win64=*/"e99c89be49a46325d03c0d990c292d68", "android_arm32_audio", + /*others=*/"a87a91ec0124510a64967f5d768554ff", + /*win64=*/"a87a91ec0124510a64967f5d768554ff", "android_arm32_audio", "android_arm64_audio", "android_arm64_clang_audio", - /*mac_arm64=*/"e99c89be49a46325d03c0d990c292d68"), + /*mac_arm64=*/"a87a91ec0124510a64967f5d768554ff"), AcmReceiverBitExactnessOldApi::PlatformChecksum( /*others=*/"fc68a87e1380614e658087cb35d5ca10", /*win64=*/"fc68a87e1380614e658087cb35d5ca10", "android_arm32_payload", @@ -1453,10 +1453,10 @@ TEST_F(AcmSenderBitExactnessOldApi, MAYBE_G722_20ms) { TEST_F(AcmSenderBitExactnessOldApi, MAYBE_G722_stereo_20ms) { ASSERT_NO_FATAL_FAILURE(SetUpTest("G722", 16000, 2, 119, 320, 160)); Run(AcmReceiverBitExactnessOldApi::PlatformChecksum( - /*others=*/"e280aed283e499d37091b481ca094807", - /*win64=*/"e280aed283e499d37091b481ca094807", "android_arm32_audio", + /*others=*/"be0b8528ff9db3a2219f55ddd36faf7f", + /*win64=*/"be0b8528ff9db3a2219f55ddd36faf7f", "android_arm32_audio", "android_arm64_audio", "android_arm64_clang_audio", - /*mac_arm64=*/"e280aed283e499d37091b481ca094807"), + /*mac_arm64=*/"be0b8528ff9db3a2219f55ddd36faf7f"), AcmReceiverBitExactnessOldApi::PlatformChecksum( /*others=*/"66516152eeaa1e650ad94ff85f668dac", /*win64=*/"66516152eeaa1e650ad94ff85f668dac", "android_arm32_payload", @@ -1831,7 +1831,7 @@ TEST_F(AcmSenderBitExactnessOldApi, External_Pcmu_20ms) { ASSERT_TRUE(SetUpSender(kTestFileMono32kHz, 32000)); ASSERT_NO_FATAL_FAILURE( SetUpTestExternalEncoder(std::move(mock_encoder), config.payload_type)); - Run("81a9d4c0bb72e9becc43aef124c981e9", "8f9b8750bd80fe26b6cbf6659b89f0f9", + Run("c8d1fc677f33c2022ec5f83c7f302280", "8f9b8750bd80fe26b6cbf6659b89f0f9", 50, test::AcmReceiveTestOldApi::kMonoOutput); } diff --git a/modules/audio_coding/neteq/delay_manager.cc b/modules/audio_coding/neteq/delay_manager.cc index 97d1d2eaad..9f6b269b03 100644 --- a/modules/audio_coding/neteq/delay_manager.cc +++ b/modules/audio_coding/neteq/delay_manager.cc @@ -20,6 +20,7 @@ #include "modules/include/module_common_types_public.h" #include "rtc_base/checks.h" +#include "rtc_base/experiments/struct_parameters_parser.h" #include "rtc_base/logging.h" #include "rtc_base/numerics/safe_conversions.h" #include "rtc_base/numerics/safe_minmax.h" @@ -45,9 +46,17 @@ std::unique_ptr MaybeCreateReorderOptimizer( } // namespace DelayManager::Config::Config() { - Parser()->Parse(webrtc::field_trial::FindFullName( - "WebRTC-Audio-NetEqDelayManagerConfig")); - MaybeUpdateFromLegacyFieldTrial(); + StructParametersParser::Create( // + "quantile", &quantile, // + "forget_factor", &forget_factor, // + "start_forget_weight", &start_forget_weight, // + "resample_interval_ms", &resample_interval_ms, // + "max_history_ms", &max_history_ms, // + "use_reorder_optimizer", &use_reorder_optimizer, // + "reorder_forget_factor", &reorder_forget_factor, // + "ms_per_loss_percent", &ms_per_loss_percent) + ->Parse(webrtc::field_trial::FindFullName( + "WebRTC-Audio-NetEqDelayManagerConfig")); } void DelayManager::Config::Log() { @@ -63,42 +72,6 @@ void DelayManager::Config::Log() { << " ms_per_loss_percent=" << ms_per_loss_percent; } -std::unique_ptr DelayManager::Config::Parser() { - return StructParametersParser::Create( // - "quantile", &quantile, // - "forget_factor", &forget_factor, // - "start_forget_weight", &start_forget_weight, // - "resample_interval_ms", &resample_interval_ms, // - "max_history_ms", &max_history_ms, // - "use_reorder_optimizer", &use_reorder_optimizer, // - "reorder_forget_factor", &reorder_forget_factor, // - "ms_per_loss_percent", &ms_per_loss_percent); -} - -// TODO(jakobi): remove legacy field trial. -void DelayManager::Config::MaybeUpdateFromLegacyFieldTrial() { - constexpr char kDelayHistogramFieldTrial[] = - "WebRTC-Audio-NetEqDelayHistogram"; - if (!webrtc::field_trial::IsEnabled(kDelayHistogramFieldTrial)) { - return; - } - const auto field_trial_string = - webrtc::field_trial::FindFullName(kDelayHistogramFieldTrial); - double percentile = -1.0; - double forget_factor = -1.0; - double start_forget_weight = -1.0; - if (sscanf(field_trial_string.c_str(), "Enabled-%lf-%lf-%lf", &percentile, - &forget_factor, &start_forget_weight) >= 2 && - percentile >= 0.0 && percentile <= 100.0 && forget_factor >= 0.0 && - forget_factor <= 1.0) { - this->quantile = percentile / 100; - this->forget_factor = forget_factor; - this->start_forget_weight = start_forget_weight >= 1 - ? absl::make_optional(start_forget_weight) - : absl::nullopt; - } -} - DelayManager::DelayManager(const Config& config, const TickTimer* tick_timer) : max_packets_in_buffer_(config.max_packets_in_buffer), underrun_optimizer_(tick_timer, diff --git a/modules/audio_coding/neteq/delay_manager.h b/modules/audio_coding/neteq/delay_manager.h index 277b80de74..410aa94b61 100644 --- a/modules/audio_coding/neteq/delay_manager.h +++ b/modules/audio_coding/neteq/delay_manager.h @@ -23,7 +23,6 @@ #include "modules/audio_coding/neteq/reorder_optimizer.h" #include "modules/audio_coding/neteq/underrun_optimizer.h" #include "rtc_base/constructor_magic.h" -#include "rtc_base/experiments/struct_parameters_parser.h" namespace webrtc { @@ -34,10 +33,10 @@ class DelayManager { void Log(); // Options that can be configured via field trial. - double quantile = 0.97; - double forget_factor = 0.9993; + double quantile = 0.95; + double forget_factor = 0.983; absl::optional start_forget_weight = 2; - absl::optional resample_interval_ms; + absl::optional resample_interval_ms = 500; int max_history_ms = 2000; bool use_reorder_optimizer = true; @@ -47,12 +46,6 @@ class DelayManager { // Options that are externally populated. int max_packets_in_buffer = 200; int base_minimum_delay_ms = 0; - - private: - std::unique_ptr Parser(); - - // TODO(jakobi): remove legacy field trial. - void MaybeUpdateFromLegacyFieldTrial(); }; DelayManager(const Config& config, const TickTimer* tick_timer); diff --git a/modules/audio_coding/neteq/delay_manager_unittest.cc b/modules/audio_coding/neteq/delay_manager_unittest.cc index fc4e0cb4cd..ee353065ea 100644 --- a/modules/audio_coding/neteq/delay_manager_unittest.cc +++ b/modules/audio_coding/neteq/delay_manager_unittest.cc @@ -44,8 +44,8 @@ class DelayManagerTest : public ::testing::Test { absl::optional InsertNextPacket(); void IncreaseTime(int inc_ms); - DelayManager dm_; TickTimer tick_timer_; + DelayManager dm_; uint32_t ts_; }; @@ -74,39 +74,18 @@ TEST_F(DelayManagerTest, CreateAndDestroy) { } TEST_F(DelayManagerTest, UpdateNormal) { - // First packet arrival. - InsertNextPacket(); - // Advance time by one frame size. - IncreaseTime(kFrameSizeMs); - // Second packet arrival. - InsertNextPacket(); + for (int i = 0; i < 50; ++i) { + InsertNextPacket(); + IncreaseTime(kFrameSizeMs); + } EXPECT_EQ(20, dm_.TargetDelayMs()); } -TEST_F(DelayManagerTest, UpdateLongInterArrivalTime) { - // First packet arrival. - InsertNextPacket(); - // Advance time by two frame size. - IncreaseTime(2 * kFrameSizeMs); - // Second packet arrival. - InsertNextPacket(); - EXPECT_EQ(40, dm_.TargetDelayMs()); -} - TEST_F(DelayManagerTest, MaxDelay) { - const int kExpectedTarget = 5 * kFrameSizeMs; - // First packet arrival. InsertNextPacket(); - // Second packet arrival. - IncreaseTime(kExpectedTarget); - InsertNextPacket(); - - // No limit is set. - EXPECT_EQ(kExpectedTarget, dm_.TargetDelayMs()); - - const int kMaxDelayMs = 3 * kFrameSizeMs; + const int kMaxDelayMs = 60; + EXPECT_GT(dm_.TargetDelayMs(), kMaxDelayMs); EXPECT_TRUE(dm_.SetMaximumDelay(kMaxDelayMs)); - IncreaseTime(kFrameSizeMs); InsertNextPacket(); EXPECT_EQ(kMaxDelayMs, dm_.TargetDelayMs()); @@ -115,17 +94,9 @@ TEST_F(DelayManagerTest, MaxDelay) { } TEST_F(DelayManagerTest, MinDelay) { - const int kExpectedTarget = 5 * kFrameSizeMs; - // First packet arrival. InsertNextPacket(); - // Second packet arrival. - IncreaseTime(kExpectedTarget); - InsertNextPacket(); - - // No limit is applied. - EXPECT_EQ(kExpectedTarget, dm_.TargetDelayMs()); - int kMinDelayMs = 7 * kFrameSizeMs; + EXPECT_LT(dm_.TargetDelayMs(), kMinDelayMs); dm_.SetMinimumDelay(kMinDelayMs); IncreaseTime(kFrameSizeMs); InsertNextPacket(); @@ -251,48 +222,11 @@ TEST_F(DelayManagerTest, MinimumDelayMemorization) { } TEST_F(DelayManagerTest, BaseMinimumDelay) { - const int kExpectedTarget = 5 * kFrameSizeMs; // First packet arrival. InsertNextPacket(); - // Second packet arrival. - IncreaseTime(kExpectedTarget); - InsertNextPacket(); - - // No limit is applied. - EXPECT_EQ(kExpectedTarget, dm_.TargetDelayMs()); constexpr int kBaseMinimumDelayMs = 7 * kFrameSizeMs; - EXPECT_TRUE(dm_.SetBaseMinimumDelay(kBaseMinimumDelayMs)); - EXPECT_EQ(dm_.GetBaseMinimumDelay(), kBaseMinimumDelayMs); - - IncreaseTime(kFrameSizeMs); - InsertNextPacket(); - EXPECT_EQ(dm_.GetBaseMinimumDelay(), kBaseMinimumDelayMs); - EXPECT_EQ(kBaseMinimumDelayMs, dm_.TargetDelayMs()); -} - -TEST_F(DelayManagerTest, BaseMinimumDelayAffectsTargetDelay) { - const int kExpectedTarget = 5; - const int kTimeIncrement = kExpectedTarget * kFrameSizeMs; - // First packet arrival. - InsertNextPacket(); - // Second packet arrival. - IncreaseTime(kTimeIncrement); - InsertNextPacket(); - - // No limit is applied. - EXPECT_EQ(kTimeIncrement, dm_.TargetDelayMs()); - - // Minimum delay is lower than base minimum delay, that is why base minimum - // delay is used to calculate target level. - constexpr int kMinimumDelayPackets = kExpectedTarget + 1; - constexpr int kBaseMinimumDelayPackets = kExpectedTarget + 2; - - constexpr int kMinimumDelayMs = kMinimumDelayPackets * kFrameSizeMs; - constexpr int kBaseMinimumDelayMs = kBaseMinimumDelayPackets * kFrameSizeMs; - - EXPECT_TRUE(kMinimumDelayMs < kBaseMinimumDelayMs); - EXPECT_TRUE(dm_.SetMinimumDelay(kMinimumDelayMs)); + EXPECT_LT(dm_.TargetDelayMs(), kBaseMinimumDelayMs); EXPECT_TRUE(dm_.SetBaseMinimumDelay(kBaseMinimumDelayMs)); EXPECT_EQ(dm_.GetBaseMinimumDelay(), kBaseMinimumDelayMs); diff --git a/modules/audio_coding/neteq/neteq_impl.cc b/modules/audio_coding/neteq/neteq_impl.cc index 45c52298fb..3696427a39 100644 --- a/modules/audio_coding/neteq/neteq_impl.cc +++ b/modules/audio_coding/neteq/neteq_impl.cc @@ -1370,7 +1370,7 @@ int NetEqImpl::GetDecision(Operation* operation, } } - timestamp_ = end_timestamp; + timestamp_ = sync_buffer_->end_timestamp(); return 0; } diff --git a/modules/audio_coding/neteq/neteq_impl_unittest.cc b/modules/audio_coding/neteq/neteq_impl_unittest.cc index 7010adfa40..e6e3eb493b 100644 --- a/modules/audio_coding/neteq/neteq_impl_unittest.cc +++ b/modules/audio_coding/neteq/neteq_impl_unittest.cc @@ -1026,22 +1026,37 @@ TEST_F(NetEqImplTest, CodecInternalCng) { EXPECT_CALL(mock_decoder, PacketDuration(nullptr, 0)) .WillRepeatedly(Return(rtc::checked_cast(kPayloadLengthSamples))); - // Pointee(x) verifies that first byte of the payload equals x, this makes it - // possible to verify that the correct payload is fed to Decode(). - EXPECT_CALL(mock_decoder, DecodeInternal(Pointee(0), kPayloadLengthBytes, - kSampleRateKhz * 1000, _, _)) - .WillOnce(DoAll(SetArrayArgument<3>(dummy_output, - dummy_output + kPayloadLengthSamples), - SetArgPointee<4>(AudioDecoder::kSpeech), - Return(rtc::checked_cast(kPayloadLengthSamples)))); + EXPECT_TRUE(neteq_->RegisterPayloadType(kPayloadType, + SdpAudioFormat("opus", 48000, 2))); - EXPECT_CALL(mock_decoder, DecodeInternal(Pointee(1), kPayloadLengthBytes, - kSampleRateKhz * 1000, _, _)) - .WillOnce(DoAll(SetArrayArgument<3>(dummy_output, - dummy_output + kPayloadLengthSamples), - SetArgPointee<4>(AudioDecoder::kComfortNoise), - Return(rtc::checked_cast(kPayloadLengthSamples)))); + struct Packet { + int sequence_number_delta; + int timestamp_delta; + AudioDecoder::SpeechType decoder_output_type; + }; + std::vector packets = { + {0, 0, AudioDecoder::kSpeech}, + {1, kPayloadLengthSamples, AudioDecoder::kComfortNoise}, + {2, 2 * kPayloadLengthSamples, AudioDecoder::kSpeech}, + {1, kPayloadLengthSamples, AudioDecoder::kSpeech}}; + for (size_t i = 0; i < packets.size(); ++i) { + rtp_header.sequenceNumber += packets[i].sequence_number_delta; + rtp_header.timestamp += packets[i].timestamp_delta; + payload[0] = i; + EXPECT_EQ(NetEq::kOK, neteq_->InsertPacket(rtp_header, payload)); + + // Pointee(x) verifies that first byte of the payload equals x, this makes + // it possible to verify that the correct payload is fed to Decode(). + EXPECT_CALL(mock_decoder, DecodeInternal(Pointee(i), kPayloadLengthBytes, + kSampleRateKhz * 1000, _, _)) + .WillOnce(DoAll(SetArrayArgument<3>( + dummy_output, dummy_output + kPayloadLengthSamples), + SetArgPointee<4>(packets[i].decoder_output_type), + Return(rtc::checked_cast(kPayloadLengthSamples)))); + } + + // Expect comfort noise to be returned by the decoder. EXPECT_CALL(mock_decoder, DecodeInternal(IsNull(), 0, kSampleRateKhz * 1000, _, _)) .WillOnce(DoAll(SetArrayArgument<3>(dummy_output, @@ -1049,87 +1064,24 @@ TEST_F(NetEqImplTest, CodecInternalCng) { SetArgPointee<4>(AudioDecoder::kComfortNoise), Return(rtc::checked_cast(kPayloadLengthSamples)))); - EXPECT_CALL(mock_decoder, DecodeInternal(Pointee(2), kPayloadLengthBytes, - kSampleRateKhz * 1000, _, _)) - .WillOnce(DoAll(SetArrayArgument<3>(dummy_output, - dummy_output + kPayloadLengthSamples), - SetArgPointee<4>(AudioDecoder::kSpeech), - Return(rtc::checked_cast(kPayloadLengthSamples)))); + std::vector expected_output = { + AudioFrame::kNormalSpeech, AudioFrame::kCNG, AudioFrame::kNormalSpeech}; + size_t output_index = 0; - EXPECT_TRUE(neteq_->RegisterPayloadType(kPayloadType, - SdpAudioFormat("opus", 48000, 2))); - - const size_t kMaxOutputSize = static_cast(10 * kSampleRateKhz); - AudioFrame output; - AudioFrame::SpeechType expected_type[8] = { - AudioFrame::kNormalSpeech, AudioFrame::kNormalSpeech, AudioFrame::kCNG, - AudioFrame::kCNG, AudioFrame::kCNG, AudioFrame::kCNG, - AudioFrame::kNormalSpeech, AudioFrame::kNormalSpeech}; - int expected_timestamp_increment[8] = { - -1, // will not be used. - 10 * kSampleRateKhz, - -1, - -1, // timestamp will be empty during CNG mode; indicated by -1 here. - -1, - -1, - 50 * kSampleRateKhz, - 10 * kSampleRateKhz}; - - // Insert one packet (decoder will return speech). - EXPECT_EQ(NetEq::kOK, neteq_->InsertPacket(rtp_header, payload)); - - bool muted; - EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted)); - absl::optional last_timestamp = neteq_->GetPlayoutTimestamp(); - ASSERT_TRUE(last_timestamp); - - // Insert second packet (decoder will return CNG). - payload[0] = 1; - rtp_header.sequenceNumber++; - rtp_header.timestamp += kPayloadLengthSamples; - EXPECT_EQ(NetEq::kOK, neteq_->InsertPacket(rtp_header, payload)); - - // Lambda for verifying the timestamps. - auto verify_timestamp = [&last_timestamp, &expected_timestamp_increment]( - absl::optional ts, size_t i) { - if (expected_timestamp_increment[i] == -1) { - // Expect to get an empty timestamp value during CNG and PLC. - EXPECT_FALSE(ts) << "i = " << i; + int timeout_counter = 0; + while (!packet_buffer_->Empty()) { + ASSERT_LT(timeout_counter++, 20) << "Test timed out"; + AudioFrame output; + bool muted; + EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted)); + if (output_index + 1 < expected_output.size() && + output.speech_type_ == expected_output[output_index + 1]) { + ++output_index; } else { - ASSERT_TRUE(ts) << "i = " << i; - EXPECT_EQ(*ts, *last_timestamp + expected_timestamp_increment[i]) - << "i = " << i; - last_timestamp = ts; + EXPECT_EQ(output.speech_type_, expected_output[output_index]); } - }; - - for (size_t i = 1; i < 6; ++i) { - ASSERT_EQ(kMaxOutputSize, output.samples_per_channel_); - EXPECT_EQ(1u, output.num_channels_); - EXPECT_EQ(expected_type[i - 1], output.speech_type_); - EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted)); - SCOPED_TRACE(""); - verify_timestamp(neteq_->GetPlayoutTimestamp(), i); } - // Insert third packet, which leaves a gap from last packet. - payload[0] = 2; - rtp_header.sequenceNumber += 2; - rtp_header.timestamp += 2 * kPayloadLengthSamples; - EXPECT_EQ(NetEq::kOK, neteq_->InsertPacket(rtp_header, payload)); - - for (size_t i = 6; i < 8; ++i) { - ASSERT_EQ(kMaxOutputSize, output.samples_per_channel_); - EXPECT_EQ(1u, output.num_channels_); - EXPECT_EQ(expected_type[i - 1], output.speech_type_); - EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted)); - SCOPED_TRACE(""); - verify_timestamp(neteq_->GetPlayoutTimestamp(), i); - } - - // Now check the packet buffer, and make sure it is empty. - EXPECT_TRUE(packet_buffer_->Empty()); - EXPECT_CALL(mock_decoder, Die()); } diff --git a/modules/audio_coding/neteq/neteq_network_stats_unittest.cc b/modules/audio_coding/neteq/neteq_network_stats_unittest.cc index 862edaf606..2c68501a98 100644 --- a/modules/audio_coding/neteq/neteq_network_stats_unittest.cc +++ b/modules/audio_coding/neteq/neteq_network_stats_unittest.cc @@ -274,7 +274,7 @@ class NetEqNetworkStatsTest { // Next we introduce packet losses. SetPacketLossRate(0.1); - expects.stats_ref.expand_rate = expects.stats_ref.speech_expand_rate = 1065; + expects.stats_ref.expand_rate = expects.stats_ref.speech_expand_rate = 898; RunTest(50, expects); // Next we enable FEC. diff --git a/modules/audio_coding/neteq/neteq_unittest.cc b/modules/audio_coding/neteq/neteq_unittest.cc index 341ef6ba6c..c55f6f1d74 100644 --- a/modules/audio_coding/neteq/neteq_unittest.cc +++ b/modules/audio_coding/neteq/neteq_unittest.cc @@ -82,17 +82,17 @@ TEST_F(NetEqDecodingTest, MAYBE_TestBitExactness) { const std::string input_rtp_file = webrtc::test::ResourcePath("audio_coding/neteq_universal_new", "rtp"); - const std::string output_checksum = PlatformChecksum( - "6c35140ce4d75874bdd60aa1872400b05fd05ca2", - "ab451bb8301d9a92fbf4de91556b56f1ea38b4ce", "not used", - "6c35140ce4d75874bdd60aa1872400b05fd05ca2", - "64b46bb3c1165537a880ae8404afce2efba456c0"); + const std::string output_checksum = + PlatformChecksum("ba4fae83a52f5e9d95b0910f05d540114285697b", + "aa557f30f7fdcebbbbf99d7f235ccba3a1c98983", "not used", + "ba4fae83a52f5e9d95b0910f05d540114285697b", + "64b46bb3c1165537a880ae8404afce2efba456c0"); - const std::string network_stats_checksum = PlatformChecksum( - "90594d85fa31d3d9584d79293bf7aa4ee55ed751", - "77b9c3640b81aff6a38d69d07dd782d39c15321d", "not used", - "90594d85fa31d3d9584d79293bf7aa4ee55ed751", - "90594d85fa31d3d9584d79293bf7aa4ee55ed751"); + const std::string network_stats_checksum = + PlatformChecksum("fa878a8464ef1cb3d01503b7f927c3e2ce6f02c4", + "300ccc2aaee7ed1971afb2f9a20247ed8760441d", "not used", + "fa878a8464ef1cb3d01503b7f927c3e2ce6f02c4", + "fa878a8464ef1cb3d01503b7f927c3e2ce6f02c4"); DecodeAndCompare(input_rtp_file, output_checksum, network_stats_checksum, absl::GetFlag(FLAGS_gen_ref)); @@ -531,11 +531,16 @@ TEST_F(NetEqDecodingTest, DiscardDuplicateCng) { out_frame_.timestamp_ + out_frame_.samples_per_channel_); } - // Insert speech again. ++seq_no; timestamp += kCngPeriodSamples; - PopulateRtpInfo(seq_no, timestamp, &rtp_info); - ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload)); + uint32_t first_speech_timestamp = timestamp; + // Insert speech again. + for (int i = 0; i < 3; ++i) { + PopulateRtpInfo(seq_no, timestamp, &rtp_info); + ASSERT_EQ(0, neteq_->InsertPacket(rtp_info, payload)); + ++seq_no; + timestamp += kSamples; + } // Pull audio once and verify that the output is speech again. ASSERT_EQ(0, neteq_->GetAudio(&out_frame_, &muted)); @@ -543,7 +548,7 @@ TEST_F(NetEqDecodingTest, DiscardDuplicateCng) { EXPECT_EQ(AudioFrame::kNormalSpeech, out_frame_.speech_type_); absl::optional playout_timestamp = neteq_->GetPlayoutTimestamp(); ASSERT_TRUE(playout_timestamp); - EXPECT_EQ(timestamp + kSamples - algorithmic_delay_samples, + EXPECT_EQ(first_speech_timestamp + kSamples - algorithmic_delay_samples, *playout_timestamp); } @@ -1263,7 +1268,7 @@ TEST(NetEqOutputDelayTest, RunTestWithFieldTrial) { // The base delay values are taken from the resuts of the non-delayed case in // NetEqOutputDelayTest.RunTest above. EXPECT_EQ(20 + kExpectedDelayMs, result.target_delay_ms); - EXPECT_EQ(24 + kExpectedDelayMs, result.filtered_current_delay_ms); + EXPECT_EQ(60 + kExpectedDelayMs, result.filtered_current_delay_ms); } // Set a non-multiple-of-10 value in the field trial, and verify that we don't @@ -1278,7 +1283,7 @@ TEST(NetEqOutputDelayTest, RunTestWithFieldTrialOddValue) { // The base delay values are taken from the resuts of the non-delayed case in // NetEqOutputDelayTest.RunTest above. EXPECT_EQ(20 + kRoundedDelayMs, result.target_delay_ms); - EXPECT_EQ(24 + kRoundedDelayMs, result.filtered_current_delay_ms); + EXPECT_EQ(60 + kRoundedDelayMs, result.filtered_current_delay_ms); } } // namespace test diff --git a/modules/audio_coding/neteq/relative_arrival_delay_tracker.cc b/modules/audio_coding/neteq/relative_arrival_delay_tracker.cc index 02c5a4321e..b50ac80bab 100644 --- a/modules/audio_coding/neteq/relative_arrival_delay_tracker.cc +++ b/modules/audio_coding/neteq/relative_arrival_delay_tracker.cc @@ -49,7 +49,7 @@ absl::optional RelativeArrivalDelayTracker::Update(uint32_t timestamp, void RelativeArrivalDelayTracker::Reset() { delay_history_.clear(); - packet_iat_stopwatch_ = tick_timer_->GetNewStopwatch(); + packet_iat_stopwatch_.reset(); newest_timestamp_ = absl::nullopt; last_timestamp_ = absl::nullopt; } diff --git a/modules/audio_coding/neteq/test/neteq_decoding_test.cc b/modules/audio_coding/neteq/test/neteq_decoding_test.cc index 1c70f1421b..a82f93bea2 100644 --- a/modules/audio_coding/neteq/test/neteq_decoding_test.cc +++ b/modules/audio_coding/neteq/test/neteq_decoding_test.cc @@ -245,15 +245,9 @@ void NetEqDecodingTest::WrapTest(uint16_t start_seq_no, NetEqNetworkStatistics network_stats; ASSERT_EQ(0, neteq_->NetworkStatistics(&network_stats)); - // Due to internal NetEq logic, preferred buffer-size is about 4 times the - // packet size for first few packets. Therefore we refrain from checking - // the criteria. - if (packets_inserted > 4) { - // Expect preferred and actual buffer size to be no more than 2 frames. - EXPECT_LE(network_stats.preferred_buffer_size_ms, kFrameSizeMs * 2); - EXPECT_LE(network_stats.current_buffer_size_ms, - kFrameSizeMs * 2 + algorithmic_delay_ms_); - } + EXPECT_LE(network_stats.preferred_buffer_size_ms, 80); + EXPECT_LE(network_stats.current_buffer_size_ms, + 80 + algorithmic_delay_ms_); last_seq_no = seq_no; last_timestamp = timestamp; diff --git a/modules/audio_coding/neteq/underrun_optimizer.cc b/modules/audio_coding/neteq/underrun_optimizer.cc index dad0424c48..baed812327 100644 --- a/modules/audio_coding/neteq/underrun_optimizer.cc +++ b/modules/audio_coding/neteq/underrun_optimizer.cc @@ -63,7 +63,7 @@ void UnderrunOptimizer::Update(int relative_delay_ms) { void UnderrunOptimizer::Reset() { histogram_.Reset(); - resample_stopwatch_ = tick_timer_->GetNewStopwatch(); + resample_stopwatch_.reset(); max_delay_in_interval_ms_ = 0; optimal_delay_ms_.reset(); }