Index: webrtc/modules/audio_coding/audio_network_adaptor/fec_controller_unittest.cc |
diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/fec_controller_unittest.cc b/webrtc/modules/audio_coding/audio_network_adaptor/fec_controller_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c66482f4e254d3cea2a72466d7bffc17ea153cb8 |
--- /dev/null |
+++ b/webrtc/modules/audio_coding/audio_network_adaptor/fec_controller_unittest.cc |
@@ -0,0 +1,312 @@ |
+/* |
+ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. |
+ * |
+ * Use of this source code is governed by a BSD-style license |
+ * that can be found in the LICENSE file in the root of the source |
+ * tree. An additional intellectual property rights grant can be found |
+ * in the file PATENTS. All contributing project authors may |
+ * be found in the AUTHORS file in the root of the source tree. |
+ */ |
+ |
+#include <utility> |
+ |
+#include "webrtc/modules/audio_coding/audio_network_adaptor/fec_controller.h" |
+#include "webrtc/modules/audio_coding/audio_network_adaptor/mock/mock_smoothing_filter.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace webrtc { |
+ |
+using ::testing::NiceMock; |
+using ::testing::Return; |
+using ::testing::_; |
+ |
+namespace { |
+ |
+// The test uses the following settings: |
+// |
+// packet-loss ^ | | |
+// | A| C| FEC |
+// | \ \ ON |
+// | FEC \ D\_______ |
+// | OFF B\_________ |
+// |-----------------> bandwidth |
+// |
+// A : (kDisablingBandwidthLow, kDisablingPacketLossAtLowBw) |
+// B : (kDisablingBandwidthHigh, kDisablingPacketLossAtHighBw) |
+// C : (kEnablingBandwidthLow, kEnablingPacketLossAtLowBw) |
+// D : (kEnablingBandwidthHigh, kEnablingPacketLossAtHighBw) |
+ |
+constexpr int kDisablingBandwidthLow = 15000; |
+constexpr float kDisablingPacketLossAtLowBw = 0.08f; |
+constexpr int kDisablingBandwidthHigh = 64000; |
+constexpr float kDisablingPacketLossAtHighBw = 0.01f; |
+constexpr int kEnablingBandwidthLow = 17000; |
+constexpr float kEnablingPacketLossAtLowBw = 0.1f; |
+constexpr int kEnablingBandwidthHigh = 64000; |
+constexpr float kEnablingPacketLossAtHighBw = 0.05f; |
+ |
+struct FecControllerStates { |
+ std::unique_ptr<FecController> controller; |
+ MockSmoothingFilter* packet_loss_smoothed; |
+}; |
+ |
+FecControllerStates CreateFecController(bool initial_fec_enabled) { |
+ FecControllerStates states; |
+ std::unique_ptr<MockSmoothingFilter> mock_smoothing_filter( |
+ new NiceMock<MockSmoothingFilter>()); |
+ states.packet_loss_smoothed = mock_smoothing_filter.get(); |
+ EXPECT_CALL(*states.packet_loss_smoothed, Die()); |
+ using Threshold = FecController::Config::Threshold; |
+ states.controller.reset(new FecController( |
+ FecController::Config( |
+ initial_fec_enabled, |
+ Threshold(kEnablingBandwidthLow, kEnablingPacketLossAtLowBw, |
+ kEnablingBandwidthHigh, kEnablingPacketLossAtHighBw), |
+ Threshold(kDisablingBandwidthLow, kDisablingPacketLossAtLowBw, |
+ kDisablingBandwidthHigh, kDisablingPacketLossAtHighBw), |
+ 0, nullptr), |
+ std::move(mock_smoothing_filter))); |
+ return states; |
+} |
+ |
+// Checks that the FEC decision given by |states->controller->MakeDecision| |
+// matches |expected_enable_fec|. It also checks that |
+// |uplink_packet_loss_fraction| returned by |states->controller->MakeDecision| |
+// matches |uplink_packet_loss|. |
+void CheckDecision(FecControllerStates* states, |
+ const rtc::Optional<int>& uplink_bandwidth_bps, |
+ const rtc::Optional<float>& uplink_packet_loss, |
+ bool expected_enable_fec) { |
+ Controller::NetworkMetrics metrics; |
+ metrics.uplink_bandwidth_bps = uplink_bandwidth_bps; |
+ metrics.uplink_packet_loss_fraction = uplink_packet_loss; |
+ |
+ if (uplink_packet_loss) { |
+ // Check that smoothing filter is updated. |
+ EXPECT_CALL(*states->packet_loss_smoothed, AddSample(*uplink_packet_loss)); |
+ } |
+ |
+ EXPECT_CALL(*states->packet_loss_smoothed, GetAverage()) |
+ .WillRepeatedly(Return(uplink_packet_loss)); |
+ |
+ AudioNetworkAdaptor::EncoderRuntimeConfig config; |
+ states->controller->MakeDecision(metrics, &config); |
+ EXPECT_EQ(rtc::Optional<bool>(expected_enable_fec), config.enable_fec); |
+ |
+ // Check that |config.uplink_packet_loss_fraction| is properly filled. |
+ EXPECT_EQ(uplink_packet_loss ? uplink_packet_loss : rtc::Optional<float>(0.0), |
+ config.uplink_packet_loss_fraction); |
+} |
+ |
+} // namespace |
+ |
+TEST(FecControllerTest, OutputInitValueWhenUplinkBandwidthUnknown) { |
+ constexpr bool kInitialFecEnabled = true; |
+ auto states = CreateFecController(kInitialFecEnabled); |
+ // Let uplink packet loss fraction be so low that would cause FEC to turn off |
+ // if uplink bandwidth was known. |
+ CheckDecision(&states, rtc::Optional<int>(), |
+ rtc::Optional<float>(kDisablingPacketLossAtHighBw), |
+ kInitialFecEnabled); |
+} |
+ |
+TEST(FecControllerTest, OutputInitValueWhenUplinkPacketLossFractionUnknown) { |
+ constexpr bool kInitialFecEnabled = true; |
+ auto states = CreateFecController(kInitialFecEnabled); |
+ // Let uplink bandwidth be so low that would cause FEC to turn off if uplink |
+ // bandwidth packet loss fraction was known. |
+ CheckDecision(&states, rtc::Optional<int>(kDisablingBandwidthLow - 1), |
+ rtc::Optional<float>(), kInitialFecEnabled); |
+} |
+ |
+TEST(FecControllerTest, EnableFecForHighBandwidth) { |
+ auto states = CreateFecController(false); |
+ CheckDecision(&states, rtc::Optional<int>(kEnablingBandwidthHigh), |
+ rtc::Optional<float>(kEnablingPacketLossAtHighBw), true); |
+} |
+ |
+TEST(FecControllerTest, MaintainFecOffForHighBandwidth) { |
+ auto states = CreateFecController(false); |
+ CheckDecision(&states, rtc::Optional<int>(kEnablingBandwidthHigh), |
+ rtc::Optional<float>(kEnablingPacketLossAtHighBw * 0.99f), |
+ false); |
+} |
+ |
+TEST(FecControllerTest, EnableFecForMediumBandwidth) { |
+ auto states = CreateFecController(false); |
+ CheckDecision( |
+ &states, |
+ rtc::Optional<int>((kEnablingBandwidthHigh + kEnablingBandwidthLow) / 2), |
+ rtc::Optional<float>( |
+ (kEnablingPacketLossAtLowBw + kEnablingPacketLossAtHighBw) / 2.0), |
+ true); |
+} |
+ |
+TEST(FecControllerTest, MaintainFecOffForMediumBandwidth) { |
+ auto states = CreateFecController(false); |
+ CheckDecision( |
+ &states, |
+ rtc::Optional<int>((kEnablingBandwidthHigh + kEnablingBandwidthLow) / 2), |
+ rtc::Optional<float>(kEnablingPacketLossAtLowBw * 0.49f + |
+ kEnablingPacketLossAtHighBw * 0.51f), |
+ false); |
+} |
+ |
+TEST(FecControllerTest, EnableFecForLowBandwidth) { |
+ auto states = CreateFecController(false); |
+ CheckDecision(&states, rtc::Optional<int>(kEnablingBandwidthLow), |
+ rtc::Optional<float>(kEnablingPacketLossAtLowBw), true); |
+} |
+ |
+TEST(FecControllerTest, MaintainFecOffForLowBandwidth) { |
+ auto states = CreateFecController(false); |
+ CheckDecision(&states, rtc::Optional<int>(kEnablingBandwidthLow), |
+ rtc::Optional<float>(kEnablingPacketLossAtLowBw * 0.99f), |
+ false); |
+} |
+ |
+TEST(FecControllerTest, MaintainFecOffForVeryLowBandwidth) { |
+ auto states = CreateFecController(false); |
+ // Below |kEnablingBandwidthLow|, no packet loss fraction can cause FEC to |
+ // turn on. |
+ CheckDecision(&states, rtc::Optional<int>(kEnablingBandwidthLow - 1), |
+ rtc::Optional<float>(1.0), false); |
+} |
+ |
+TEST(FecControllerTest, DisableFecForHighBandwidth) { |
+ auto states = CreateFecController(true); |
+ CheckDecision(&states, rtc::Optional<int>(kDisablingBandwidthHigh), |
+ rtc::Optional<float>(kDisablingPacketLossAtHighBw), false); |
+} |
+ |
+TEST(FecControllerTest, MaintainFecOnForHighBandwidth) { |
+ auto states = CreateFecController(true); |
+ CheckDecision(&states, rtc::Optional<int>(kDisablingBandwidthHigh), |
+ rtc::Optional<float>(kDisablingPacketLossAtHighBw * 1.01f), |
+ true); |
+} |
+ |
+TEST(FecControllerTest, DisableFecOnMediumBandwidth) { |
+ auto states = CreateFecController(true); |
+ CheckDecision( |
+ &states, rtc::Optional<int>( |
+ (kDisablingBandwidthHigh + kDisablingBandwidthLow) / 2), |
+ rtc::Optional<float>( |
+ (kDisablingPacketLossAtLowBw + kDisablingPacketLossAtHighBw) / 2.0f), |
+ false); |
+} |
+ |
+TEST(FecControllerTest, MaintainFecOnForMediumBandwidth) { |
+ auto states = CreateFecController(true); |
+ CheckDecision( |
+ &states, |
+ rtc::Optional<int>((kEnablingBandwidthHigh + kDisablingBandwidthLow) / 2), |
+ rtc::Optional<float>(kDisablingPacketLossAtLowBw * 0.51f + |
+ kDisablingPacketLossAtHighBw * 0.49f), |
+ true); |
+} |
+ |
+TEST(FecControllerTest, DisableFecForLowBandwidth) { |
+ auto states = CreateFecController(true); |
+ CheckDecision(&states, rtc::Optional<int>(kDisablingBandwidthLow), |
+ rtc::Optional<float>(kDisablingPacketLossAtLowBw), false); |
+} |
+ |
+TEST(FecControllerTest, DisableFecForVeryLowBandwidth) { |
+ auto states = CreateFecController(true); |
+ // Below |kEnablingBandwidthLow|, any packet loss fraction can cause FEC to |
+ // turn off. |
+ CheckDecision(&states, rtc::Optional<int>(kDisablingBandwidthLow - 1), |
+ rtc::Optional<float>(1.0), false); |
+} |
+ |
+TEST(FecControllerTest, CheckBehaviorOnChangingNetworkMetrics) { |
+ // In this test, we let the network metrics to traverse from 1 to 5. |
+ // packet-loss ^ 1 | | |
+ // | | 2| |
+ // | \ \ 3 |
+ // | \4 \_______ |
+ // | \_________ |
+ // |---------5-------> bandwidth |
+ |
+ auto states = CreateFecController(true); |
+ CheckDecision(&states, rtc::Optional<int>(kDisablingBandwidthLow - 1), |
+ rtc::Optional<float>(1.0), false); |
+ CheckDecision(&states, rtc::Optional<int>(kEnablingBandwidthLow), |
+ rtc::Optional<float>(kEnablingPacketLossAtLowBw * 0.99f), |
+ false); |
+ CheckDecision(&states, rtc::Optional<int>(kEnablingBandwidthHigh), |
+ rtc::Optional<float>(kEnablingPacketLossAtHighBw), true); |
+ CheckDecision(&states, rtc::Optional<int>(kDisablingBandwidthHigh), |
+ rtc::Optional<float>(kDisablingPacketLossAtHighBw * 1.01f), |
+ true); |
+ CheckDecision(&states, rtc::Optional<int>(kDisablingBandwidthHigh + 1), |
+ rtc::Optional<float>(0.0), false); |
+} |
+ |
+TEST(FecControllerTest, CheckBehaviorOnSpecialCurves) { |
+ // We test a special configuration, where the points to define the FEC |
+ // enabling/disabling curves are placed like the following, otherwise the test |
+ // is the same as CheckBehaviorOnChangingNetworkMetrics. |
+ // |
+ // packet-loss ^ | | |
+ // | | C| |
+ // | | | |
+ // | | D|_______ |
+ // | A|___B______ |
+ // |-----------------> bandwidth |
+ |
+ constexpr int kEnablingBandwidthHigh = kEnablingBandwidthLow; |
+ constexpr float kDisablingPacketLossAtLowBw = kDisablingPacketLossAtHighBw; |
+ FecControllerStates states; |
+ std::unique_ptr<MockSmoothingFilter> mock_smoothing_filter( |
+ new NiceMock<MockSmoothingFilter>()); |
+ states.packet_loss_smoothed = mock_smoothing_filter.get(); |
+ EXPECT_CALL(*states.packet_loss_smoothed, Die()); |
+ using Threshold = FecController::Config::Threshold; |
+ states.controller.reset(new FecController( |
+ FecController::Config( |
+ true, Threshold(kEnablingBandwidthLow, kEnablingPacketLossAtLowBw, |
+ kEnablingBandwidthHigh, kEnablingPacketLossAtHighBw), |
+ Threshold(kDisablingBandwidthLow, kDisablingPacketLossAtLowBw, |
+ kDisablingBandwidthHigh, kDisablingPacketLossAtHighBw), |
+ 0, nullptr), |
+ std::move(mock_smoothing_filter))); |
+ |
+ CheckDecision(&states, rtc::Optional<int>(kDisablingBandwidthLow - 1), |
+ rtc::Optional<float>(1.0), false); |
+ CheckDecision(&states, rtc::Optional<int>(kEnablingBandwidthLow), |
+ rtc::Optional<float>(kEnablingPacketLossAtHighBw * 0.99f), |
+ false); |
+ CheckDecision(&states, rtc::Optional<int>(kEnablingBandwidthHigh), |
+ rtc::Optional<float>(kEnablingPacketLossAtHighBw), true); |
+ CheckDecision(&states, rtc::Optional<int>(kDisablingBandwidthHigh), |
+ rtc::Optional<float>(kDisablingPacketLossAtHighBw * 1.01f), |
+ true); |
+ CheckDecision(&states, rtc::Optional<int>(kDisablingBandwidthHigh + 1), |
+ rtc::Optional<float>(0.0), false); |
+} |
+ |
+#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) |
+TEST(FecControllerDeathTest, InvalidConfig) { |
+ FecControllerStates states; |
+ std::unique_ptr<MockSmoothingFilter> mock_smoothing_filter( |
+ new NiceMock<MockSmoothingFilter>()); |
+ states.packet_loss_smoothed = mock_smoothing_filter.get(); |
+ EXPECT_CALL(*states.packet_loss_smoothed, Die()); |
+ using Threshold = FecController::Config::Threshold; |
+ EXPECT_DEATH( |
minyue-webrtc
2016/09/22 11:28:01
It looks like that RTC_DCHECK_IS_ON for some non-d
|
+ states.controller.reset(new FecController( |
+ FecController::Config( |
+ true, |
+ Threshold(kDisablingBandwidthLow - 1, kEnablingPacketLossAtLowBw, |
+ kEnablingBandwidthHigh, kEnablingPacketLossAtHighBw), |
+ Threshold(kDisablingBandwidthLow, kDisablingPacketLossAtLowBw, |
+ kDisablingBandwidthHigh, kDisablingPacketLossAtHighBw), |
+ 0, nullptr), |
+ std::move(mock_smoothing_filter))), |
+ "Check failed"); |
+} |
+#endif |
+ |
+} // namespace webrtc |