Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(32)

Unified Diff: webrtc/modules/audio_coding/audio_network_adaptor/fec_controller_rplr_based_unittest.cc

Issue 2672933003: Introduce FecControllerRplrBased (Closed)
Patch Set: Merged Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: webrtc/modules/audio_coding/audio_network_adaptor/fec_controller_rplr_based_unittest.cc
diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/fec_controller_rplr_based_unittest.cc b/webrtc/modules/audio_coding/audio_network_adaptor/fec_controller_rplr_based_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..ce51ff00d80fc9c103b0bdebca99082ff957fc6a
--- /dev/null
+++ b/webrtc/modules/audio_coding/audio_network_adaptor/fec_controller_rplr_based_unittest.cc
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 2017 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 <random>
+#include <utility>
+
+#include "webrtc/modules/audio_coding/audio_network_adaptor/fec_controller_rplr_based.h"
+#include "webrtc/test/gmock.h"
+#include "webrtc/test/gtest.h"
+
+namespace webrtc {
+
+using ::testing::NiceMock;
+using ::testing::Return;
+using ::testing::_;
+
+namespace {
+
+// The test uses the following settings:
+//
+// recoverable ^
+// packet-loss | | |
+// | A| C| FEC
+// | \ \ ON
+// | FEC \ D\_______
+// | OFF B\_________
+// |-----------------> bandwidth
+//
+// A : (kDisablingBandwidthLow, kDisablingRecoverablePacketLossAtLowBw)
+// B : (kDisablingBandwidthHigh, kDisablingRecoverablePacketLossAtHighBw)
+// C : (kEnablingBandwidthLow, kEnablingRecoverablePacketLossAtLowBw)
+// D : (kEnablingBandwidthHigh, kEnablingRecoverablePacketLossAtHighBw)
+
+constexpr int kDisablingBandwidthLow = 15000;
+constexpr float kDisablingRecoverablePacketLossAtLowBw = 0.08f;
+constexpr int kDisablingBandwidthHigh = 64000;
+constexpr float kDisablingRecoverablePacketLossAtHighBw = 0.01f;
+constexpr int kEnablingBandwidthLow = 17000;
+constexpr float kEnablingRecoverablePacketLossAtLowBw = 0.1f;
+constexpr int kEnablingBandwidthHigh = 64000;
+constexpr float kEnablingRecoverablePacketLossAtHighBw = 0.05f;
+
+rtc::Optional<float> GetRandomProbabilityOrUnknown() {
+ std::random_device rd;
+ std::mt19937 generator(rd());
+ std::uniform_real_distribution<> distribution(0, 1);
+
+ if (distribution(generator) < 0.2) {
+ return rtc::Optional<float>();
+ } else {
+ return rtc::Optional<float>(distribution(generator));
+ }
+}
+
+std::unique_ptr<FecControllerRplrBased> CreateFecControllerRplrBased(
+ bool initial_fec_enabled) {
+ using Threshold = FecControllerRplrBased::Config::Threshold;
+ return std::unique_ptr<FecControllerRplrBased>(
+ new FecControllerRplrBased(FecControllerRplrBased::Config(
+ initial_fec_enabled,
+ Threshold(
+ kEnablingBandwidthLow, kEnablingRecoverablePacketLossAtLowBw,
+ kEnablingBandwidthHigh, kEnablingRecoverablePacketLossAtHighBw),
+ Threshold(
+ kDisablingBandwidthLow, kDisablingRecoverablePacketLossAtLowBw,
+ kDisablingBandwidthHigh, kDisablingRecoverablePacketLossAtHighBw),
+ 0, nullptr)));
+}
+
+void UpdateNetworkMetrics(
+ FecControllerRplrBased* controller,
+ const rtc::Optional<int>& uplink_bandwidth_bps,
+ const rtc::Optional<float>& uplink_packet_loss,
+ const rtc::Optional<float>& uplink_recoveralbe_packet_loss) {
+ // UpdateNetworkMetrics can accept multiple network metric updates at once.
+ // However, currently, the most used case is to update one metric at a time.
+ // To reflect this fact, we separate the calls.
+ if (uplink_bandwidth_bps) {
+ Controller::NetworkMetrics network_metrics;
+ network_metrics.uplink_bandwidth_bps = uplink_bandwidth_bps;
+ controller->UpdateNetworkMetrics(network_metrics);
+ }
+ if (uplink_packet_loss) {
+ Controller::NetworkMetrics network_metrics;
+ network_metrics.uplink_packet_loss_fraction = uplink_packet_loss;
+ controller->UpdateNetworkMetrics(network_metrics);
+ }
+ if (uplink_recoveralbe_packet_loss) {
+ Controller::NetworkMetrics network_metrics;
+ network_metrics.uplink_recoverable_packet_loss_fraction =
+ uplink_recoveralbe_packet_loss;
+ controller->UpdateNetworkMetrics(network_metrics);
+ }
+}
+
+void UpdateNetworkMetrics(
+ FecControllerRplrBased* controller,
+ const rtc::Optional<int>& uplink_bandwidth_bps,
+ const rtc::Optional<float>& uplink_recoveralbe_packet_loss) {
+ // FecControllerRplrBased doesn't current use the PLR (general packet-loss
+ // rate) at all. (This might be changed in the future.) The unit-tests will
+ // use a random value (including unknown), to show this does not interfere.
+ UpdateNetworkMetrics(controller, uplink_bandwidth_bps,
+ GetRandomProbabilityOrUnknown(),
+ uplink_recoveralbe_packet_loss);
+}
+
+// Checks that the FEC decision and |uplink_packet_loss_fraction| given by
+// |states->controller->MakeDecision| matches |expected_enable_fec| and
+// |expected_uplink_packet_loss_fraction|, respectively.
+void CheckDecision(FecControllerRplrBased* controller,
+ bool expected_enable_fec,
+ float expected_uplink_packet_loss_fraction) {
+ AudioNetworkAdaptor::EncoderRuntimeConfig config;
+ controller->MakeDecision(&config);
+
+ // Less compact than comparing optionals, but yields more readable errors.
+ EXPECT_TRUE(config.enable_fec);
+ if (config.enable_fec) {
+ EXPECT_EQ(expected_enable_fec, *config.enable_fec);
+ }
+ EXPECT_TRUE(config.uplink_packet_loss_fraction);
+ if (config.uplink_packet_loss_fraction) {
+ EXPECT_EQ(expected_uplink_packet_loss_fraction,
+ *config.uplink_packet_loss_fraction);
+ }
+}
+
+} // namespace
+
+TEST(FecControllerRplrBasedTest, OutputInitValueWhenUplinkBandwidthUnknown) {
+ for (bool initial_fec_enabled : {false, true}) {
+ auto controller = CreateFecControllerRplrBased(initial_fec_enabled);
+ // Let uplink recoverable packet loss fraction be so low that it
+ // would cause FEC to turn off if uplink bandwidth was known.
+ UpdateNetworkMetrics(
+ controller.get(), rtc::Optional<int>(),
+ rtc::Optional<float>(kDisablingRecoverablePacketLossAtHighBw));
+ CheckDecision(controller.get(), initial_fec_enabled,
+ kDisablingRecoverablePacketLossAtHighBw);
+ }
+}
+
+TEST(FecControllerRplrBasedTest,
+ OutputInitValueWhenUplinkPacketLossFractionUnknown) {
+ for (bool initial_fec_enabled : {false, true}) {
+ auto controller = CreateFecControllerRplrBased(initial_fec_enabled);
+ // Let uplink bandwidth be so low that it would cause FEC to turn off
+ // if uplink bandwidth packet loss fraction was known.
+ UpdateNetworkMetrics(controller.get(),
+ rtc::Optional<int>(kDisablingBandwidthLow - 1),
+ rtc::Optional<float>());
+ CheckDecision(controller.get(), initial_fec_enabled, 0.0);
+ }
+}
+
+TEST(FecControllerRplrBasedTest, EnableFecForHighBandwidth) {
+ auto controller = CreateFecControllerRplrBased(false);
+ UpdateNetworkMetrics(
+ controller.get(), rtc::Optional<int>(kEnablingBandwidthHigh),
+ rtc::Optional<float>(kEnablingRecoverablePacketLossAtHighBw));
+ CheckDecision(controller.get(), true, kEnablingRecoverablePacketLossAtHighBw);
+}
+
+TEST(FecControllerRplrBasedTest, UpdateMultipleNetworkMetricsAtOnce) {
+ // This test is similar to EnableFecForHighBandwidth. But instead of
+ // using ::UpdateNetworkMetrics(...), which calls
+ // FecControllerRplrBasedTest::UpdateNetworkMetrics(...) multiple times, we
+ // we call it only once. This is to verify that
+ // FecControllerRplrBasedTest::UpdateNetworkMetrics(...) can handle multiple
+ // network updates at once. This is, however, not a common use case in current
+ // audio_network_adaptor_impl.cc.
+ auto controller = CreateFecControllerRplrBased(false);
+ Controller::NetworkMetrics network_metrics;
+ network_metrics.uplink_bandwidth_bps =
+ rtc::Optional<int>(kEnablingBandwidthHigh);
+ network_metrics.uplink_packet_loss_fraction =
+ rtc::Optional<float>(GetRandomProbabilityOrUnknown());
+ network_metrics.uplink_recoverable_packet_loss_fraction =
+ rtc::Optional<float>(kEnablingRecoverablePacketLossAtHighBw);
+ controller->UpdateNetworkMetrics(network_metrics);
+ CheckDecision(controller.get(), true, kEnablingRecoverablePacketLossAtHighBw);
+}
+
+TEST(FecControllerRplrBasedTest, MaintainFecOffForHighBandwidth) {
+ auto controller = CreateFecControllerRplrBased(false);
+ constexpr float kPacketLoss = kEnablingRecoverablePacketLossAtHighBw * 0.99f;
+ UpdateNetworkMetrics(controller.get(),
+ rtc::Optional<int>(kEnablingBandwidthHigh),
+ rtc::Optional<float>(kPacketLoss));
+ CheckDecision(controller.get(), false, kPacketLoss);
+}
+
+TEST(FecControllerRplrBasedTest, EnableFecForMediumBandwidth) {
+ auto controller = CreateFecControllerRplrBased(false);
+ constexpr float kPacketLoss = (kEnablingRecoverablePacketLossAtLowBw +
+ kEnablingRecoverablePacketLossAtHighBw) /
+ 2.0;
+ UpdateNetworkMetrics(
+ controller.get(),
+ rtc::Optional<int>((kEnablingBandwidthHigh + kEnablingBandwidthLow) / 2),
+ rtc::Optional<float>(kPacketLoss));
+ CheckDecision(controller.get(), true, kPacketLoss);
+}
+
+TEST(FecControllerRplrBasedTest, MaintainFecOffForMediumBandwidth) {
+ auto controller = CreateFecControllerRplrBased(false);
+ constexpr float kPacketLoss = kEnablingRecoverablePacketLossAtLowBw * 0.49f +
+ kEnablingRecoverablePacketLossAtHighBw * 0.51f;
+ UpdateNetworkMetrics(
+ controller.get(),
+ rtc::Optional<int>((kEnablingBandwidthHigh + kEnablingBandwidthLow) / 2),
+ rtc::Optional<float>(kPacketLoss));
+ CheckDecision(controller.get(), false, kPacketLoss);
+}
+
+TEST(FecControllerRplrBasedTest, EnableFecForLowBandwidth) {
+ auto controller = CreateFecControllerRplrBased(false);
+ UpdateNetworkMetrics(
+ controller.get(), rtc::Optional<int>(kEnablingBandwidthLow),
+ rtc::Optional<float>(kEnablingRecoverablePacketLossAtLowBw));
+ CheckDecision(controller.get(), true, kEnablingRecoverablePacketLossAtLowBw);
+}
+
+TEST(FecControllerRplrBasedTest, MaintainFecOffForLowBandwidth) {
+ auto controller = CreateFecControllerRplrBased(false);
+ constexpr float kPacketLoss = kEnablingRecoverablePacketLossAtLowBw * 0.99f;
+ UpdateNetworkMetrics(controller.get(),
+ rtc::Optional<int>(kEnablingBandwidthLow),
+ rtc::Optional<float>(kPacketLoss));
+ CheckDecision(controller.get(), false, kPacketLoss);
+}
+
+TEST(FecControllerRplrBasedTest, MaintainFecOffForVeryLowBandwidth) {
+ auto controller = CreateFecControllerRplrBased(false);
+ // Below |kEnablingBandwidthLow|, no recoverable packet loss fraction can
+ // cause FEC to turn on.
+ UpdateNetworkMetrics(controller.get(),
+ rtc::Optional<int>(kEnablingBandwidthLow - 1),
+ rtc::Optional<float>(1.0));
+ CheckDecision(controller.get(), false, 1.0);
+}
+
+TEST(FecControllerRplrBasedTest, DisableFecForHighBandwidth) {
+ auto controller = CreateFecControllerRplrBased(true);
+ UpdateNetworkMetrics(
+ controller.get(), rtc::Optional<int>(kDisablingBandwidthHigh),
+ rtc::Optional<float>(kDisablingRecoverablePacketLossAtHighBw));
+ CheckDecision(controller.get(), false,
+ kDisablingRecoverablePacketLossAtHighBw);
+}
+
+TEST(FecControllerRplrBasedTest, MaintainFecOnForHighBandwidth) {
+ auto controller = CreateFecControllerRplrBased(true);
+ constexpr float kPacketLoss = kDisablingRecoverablePacketLossAtHighBw * 1.01f;
+ UpdateNetworkMetrics(controller.get(),
+ rtc::Optional<int>(kDisablingBandwidthHigh),
+ rtc::Optional<float>(kPacketLoss));
+ CheckDecision(controller.get(), true, kPacketLoss);
+}
+
+TEST(FecControllerRplrBasedTest, DisableFecOnMediumBandwidth) {
+ auto controller = CreateFecControllerRplrBased(true);
+ constexpr float kPacketLoss = (kDisablingRecoverablePacketLossAtLowBw +
+ kDisablingRecoverablePacketLossAtHighBw) /
+ 2.0f;
+ UpdateNetworkMetrics(
+ controller.get(),
+ rtc::Optional<int>((kDisablingBandwidthHigh + kDisablingBandwidthLow) /
+ 2),
+ rtc::Optional<float>(kPacketLoss));
+ CheckDecision(controller.get(), false, kPacketLoss);
+}
+
+TEST(FecControllerRplrBasedTest, MaintainFecOnForMediumBandwidth) {
+ auto controller = CreateFecControllerRplrBased(true);
+ constexpr float kPacketLoss = kDisablingRecoverablePacketLossAtLowBw * 0.51f +
+ kDisablingRecoverablePacketLossAtHighBw * 0.49f;
+ UpdateNetworkMetrics(
+ controller.get(),
+ rtc::Optional<int>((kEnablingBandwidthHigh + kDisablingBandwidthLow) / 2),
+ rtc::Optional<float>(kPacketLoss));
+ CheckDecision(controller.get(), true, kPacketLoss);
+}
+
+TEST(FecControllerRplrBasedTest, DisableFecForLowBandwidth) {
+ auto controller = CreateFecControllerRplrBased(true);
+ UpdateNetworkMetrics(
+ controller.get(), rtc::Optional<int>(kDisablingBandwidthLow),
+ rtc::Optional<float>(kDisablingRecoverablePacketLossAtLowBw));
+ CheckDecision(controller.get(), false,
+ kDisablingRecoverablePacketLossAtLowBw);
+}
+
+TEST(FecControllerRplrBasedTest, DisableFecForVeryLowBandwidth) {
+ auto controller = CreateFecControllerRplrBased(true);
+ // Below |kEnablingBandwidthLow|, any recoverable packet loss fraction can
+ // cause FEC to turn off.
+ UpdateNetworkMetrics(controller.get(),
+ rtc::Optional<int>(kDisablingBandwidthLow - 1),
+ rtc::Optional<float>(1.0));
+ CheckDecision(controller.get(), false, 1.0);
+}
+
+TEST(FecControllerRplrBasedTest, CheckBehaviorOnChangingNetworkMetrics) {
+ // In this test, we let the network metrics to traverse from 1 to 5.
+ //
+ // recoverable ^
+ // packet-loss | 1 | |
+ // | | 2|
+ // | \ \ 3
+ // | \4 \_______
+ // | \_________
+ // |---------5-------> bandwidth
+
+ auto controller = CreateFecControllerRplrBased(true);
+ UpdateNetworkMetrics(controller.get(),
+ rtc::Optional<int>(kDisablingBandwidthLow - 1),
+ rtc::Optional<float>(1.0));
+ CheckDecision(controller.get(), false, 1.0);
+
+ UpdateNetworkMetrics(
+ controller.get(), rtc::Optional<int>(kEnablingBandwidthLow),
+ rtc::Optional<float>(kEnablingRecoverablePacketLossAtLowBw * 0.99f));
+ CheckDecision(controller.get(), false,
+ kEnablingRecoverablePacketLossAtLowBw * 0.99f);
+
+ UpdateNetworkMetrics(
+ controller.get(), rtc::Optional<int>(kEnablingBandwidthHigh),
+ rtc::Optional<float>(kEnablingRecoverablePacketLossAtHighBw));
+ CheckDecision(controller.get(), true, kEnablingRecoverablePacketLossAtHighBw);
+
+ UpdateNetworkMetrics(
+ controller.get(), rtc::Optional<int>(kDisablingBandwidthHigh),
+ rtc::Optional<float>(kDisablingRecoverablePacketLossAtHighBw * 1.01f));
+ CheckDecision(controller.get(), true,
+ kDisablingRecoverablePacketLossAtHighBw * 1.01f);
+
+ UpdateNetworkMetrics(controller.get(),
+ rtc::Optional<int>(kDisablingBandwidthHigh + 1),
+ rtc::Optional<float>(0.0));
+ CheckDecision(controller.get(), false, 0.0);
+}
+
+TEST(FecControllerRplrBasedTest, 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.
+ //
+ // recoverable ^
+ // packet-loss | | |
+ // | | C|
+ // | | |
+ // | | D|_______
+ // | A|___B______
+ // |-----------------> bandwidth
+
+ constexpr int kEnablingBandwidthHigh = kEnablingBandwidthLow;
+ constexpr float kDisablingRecoverablePacketLossAtLowBw =
+ kDisablingRecoverablePacketLossAtHighBw;
+ using Threshold = FecControllerRplrBased::Config::Threshold;
+ FecControllerRplrBased controller(FecControllerRplrBased::Config(
+ true,
+ Threshold(kEnablingBandwidthLow, kEnablingRecoverablePacketLossAtLowBw,
+ kEnablingBandwidthHigh, kEnablingRecoverablePacketLossAtHighBw),
+ Threshold(kDisablingBandwidthLow, kDisablingRecoverablePacketLossAtLowBw,
+ kDisablingBandwidthHigh,
+ kDisablingRecoverablePacketLossAtHighBw),
+ 0, nullptr));
+
+ UpdateNetworkMetrics(&controller,
+ rtc::Optional<int>(kDisablingBandwidthLow - 1),
+ rtc::Optional<float>(1.0));
+ CheckDecision(&controller, false, 1.0);
+
+ UpdateNetworkMetrics(
+ &controller, rtc::Optional<int>(kEnablingBandwidthLow),
+ rtc::Optional<float>(kEnablingRecoverablePacketLossAtHighBw * 0.99f));
+ CheckDecision(&controller, false,
+ kEnablingRecoverablePacketLossAtHighBw * 0.99f);
+
+ UpdateNetworkMetrics(
+ &controller, rtc::Optional<int>(kEnablingBandwidthHigh),
+ rtc::Optional<float>(kEnablingRecoverablePacketLossAtHighBw));
+ CheckDecision(&controller, true, kEnablingRecoverablePacketLossAtHighBw);
+
+ UpdateNetworkMetrics(
+ &controller, rtc::Optional<int>(kDisablingBandwidthHigh),
+ rtc::Optional<float>(kDisablingRecoverablePacketLossAtHighBw * 1.01f));
+ CheckDecision(&controller, true,
+ kDisablingRecoverablePacketLossAtHighBw * 1.01f);
+
+ UpdateNetworkMetrics(&controller,
+ rtc::Optional<int>(kDisablingBandwidthHigh + 1),
+ rtc::Optional<float>(0.0));
+ CheckDecision(&controller, false, 0.0);
+}
+
+#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
+TEST(FecControllerRplrBasedDeathTest, InvalidConfig) {
+ using Threshold = FecControllerRplrBased::Config::Threshold;
+ EXPECT_DEATH(
+ FecControllerRplrBased controller(FecControllerRplrBased::Config(
+ true,
+ Threshold(
+ kDisablingBandwidthLow - 1, kEnablingRecoverablePacketLossAtLowBw,
+ kEnablingBandwidthHigh, kEnablingRecoverablePacketLossAtHighBw),
+ Threshold(
+ kDisablingBandwidthLow, kDisablingRecoverablePacketLossAtLowBw,
+ kDisablingBandwidthHigh, kDisablingRecoverablePacketLossAtHighBw),
+ 0, nullptr)),
+ "Check failed");
+}
+#endif
+
+} // namespace webrtc

Powered by Google App Engine
This is Rietveld 408576698