| Index: webrtc/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based_unittest.cc
|
| diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based_unittest.cc b/webrtc/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based_unittest.cc
|
| index fceae874f3dffc242d677778f98cc0e3c478fbda..0e23cb01f239e2341df888f65324e59f3a714b6c 100644
|
| --- a/webrtc/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based_unittest.cc
|
| +++ b/webrtc/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based_unittest.cc
|
| @@ -45,29 +45,38 @@ constexpr float kEnablingPacketLossAtLowBw = 0.1f;
|
| constexpr int kEnablingBandwidthHigh = 64000;
|
| constexpr float kEnablingPacketLossAtHighBw = 0.05f;
|
|
|
| +constexpr float kEpsilon = 1e-5f;
|
| +
|
| struct FecControllerPlrBasedTestStates {
|
| std::unique_ptr<FecControllerPlrBased> controller;
|
| MockSmoothingFilter* packet_loss_smoother;
|
| };
|
|
|
| FecControllerPlrBasedTestStates CreateFecControllerPlrBased(
|
| - bool initial_fec_enabled) {
|
| + bool initial_fec_enabled,
|
| + const ThresholdCurve& enabling_curve,
|
| + const ThresholdCurve& disabling_curve) {
|
| FecControllerPlrBasedTestStates states;
|
| std::unique_ptr<MockSmoothingFilter> mock_smoothing_filter(
|
| new NiceMock<MockSmoothingFilter>());
|
| states.packet_loss_smoother = mock_smoothing_filter.get();
|
| states.controller.reset(new FecControllerPlrBased(
|
| - FecControllerPlrBased::Config(
|
| - initial_fec_enabled,
|
| - ThresholdCurve(kEnablingBandwidthLow, kEnablingPacketLossAtLowBw,
|
| - kEnablingBandwidthHigh, kEnablingPacketLossAtHighBw),
|
| - ThresholdCurve(kDisablingBandwidthLow, kDisablingPacketLossAtLowBw,
|
| - kDisablingBandwidthHigh, kDisablingPacketLossAtHighBw),
|
| - 0),
|
| + FecControllerPlrBased::Config(initial_fec_enabled, enabling_curve,
|
| + disabling_curve, 0),
|
| std::move(mock_smoothing_filter)));
|
| return states;
|
| }
|
|
|
| +FecControllerPlrBasedTestStates CreateFecControllerPlrBased(
|
| + bool initial_fec_enabled) {
|
| + return CreateFecControllerPlrBased(
|
| + initial_fec_enabled,
|
| + ThresholdCurve(kEnablingBandwidthLow, kEnablingPacketLossAtLowBw,
|
| + kEnablingBandwidthHigh, kEnablingPacketLossAtHighBw),
|
| + ThresholdCurve(kDisablingBandwidthLow, kDisablingPacketLossAtLowBw,
|
| + kDisablingBandwidthHigh, kDisablingPacketLossAtHighBw));
|
| +}
|
| +
|
| void UpdateNetworkMetrics(FecControllerPlrBasedTestStates* states,
|
| const rtc::Optional<int>& uplink_bandwidth_bps,
|
| const rtc::Optional<float>& uplink_packet_loss) {
|
| @@ -90,6 +99,15 @@ void UpdateNetworkMetrics(FecControllerPlrBasedTestStates* states,
|
| }
|
| }
|
|
|
| +// TODO(eladalon): In a separate CL (to make reviewers' lives easier), use
|
| +// this where applicable.
|
| +void UpdateNetworkMetrics(FecControllerPlrBasedTestStates* states,
|
| + int uplink_bandwidth_bps,
|
| + float uplink_packet_loss) {
|
| + UpdateNetworkMetrics(states, rtc::Optional<int>(uplink_bandwidth_bps),
|
| + rtc::Optional<float>(uplink_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.
|
| @@ -105,25 +123,44 @@ void CheckDecision(FecControllerPlrBasedTestStates* states,
|
|
|
| } // namespace
|
|
|
| +TEST(FecControllerPlrBasedTest, OutputInitValueBeforeAnyInputsAreReceived) {
|
| + for (bool initial_fec_enabled : {false, true}) {
|
| + auto states = CreateFecControllerPlrBased(initial_fec_enabled);
|
| + CheckDecision(&states, initial_fec_enabled, 0);
|
| + }
|
| +}
|
| +
|
| TEST(FecControllerPlrBasedTest, OutputInitValueWhenUplinkBandwidthUnknown) {
|
| - constexpr bool kInitialFecEnabled = true;
|
| - auto states = CreateFecControllerPlrBased(kInitialFecEnabled);
|
| - // Let uplink packet loss fraction be so low that would cause FEC to turn off
|
| - // if uplink bandwidth was known.
|
| - UpdateNetworkMetrics(&states, rtc::Optional<int>(),
|
| - rtc::Optional<float>(kDisablingPacketLossAtHighBw));
|
| - CheckDecision(&states, kInitialFecEnabled, kDisablingPacketLossAtHighBw);
|
| + // Regardless of the initial FEC state and the packet-loss rate,
|
| + // the initial FEC state is maintained as long as the BWE is unknown.
|
| + for (bool initial_fec_enabled : {false, true}) {
|
| + for (float packet_loss :
|
| + {kDisablingPacketLossAtLowBw - kEpsilon, kDisablingPacketLossAtLowBw,
|
| + kDisablingPacketLossAtLowBw + kEpsilon,
|
| + kEnablingPacketLossAtLowBw - kEpsilon, kEnablingPacketLossAtLowBw,
|
| + kEnablingPacketLossAtLowBw + kEpsilon}) {
|
| + auto states = CreateFecControllerPlrBased(initial_fec_enabled);
|
| + UpdateNetworkMetrics(&states, rtc::Optional<int>(),
|
| + rtc::Optional<float>(packet_loss));
|
| + CheckDecision(&states, initial_fec_enabled, packet_loss);
|
| + }
|
| + }
|
| }
|
|
|
| TEST(FecControllerPlrBasedTest,
|
| OutputInitValueWhenUplinkPacketLossFractionUnknown) {
|
| - constexpr bool kInitialFecEnabled = true;
|
| - auto states = CreateFecControllerPlrBased(kInitialFecEnabled);
|
| - // Let uplink bandwidth be so low that would cause FEC to turn off if uplink
|
| - // bandwidth packet loss fraction was known.
|
| - UpdateNetworkMetrics(&states, rtc::Optional<int>(kDisablingBandwidthLow - 1),
|
| - rtc::Optional<float>());
|
| - CheckDecision(&states, kInitialFecEnabled, 0.0);
|
| + // Regardless of the initial FEC state and the BWE, the initial FEC state
|
| + // is maintained as long as the packet-loss rate is unknown.
|
| + for (bool initial_fec_enabled : {false, true}) {
|
| + for (int bandwidth : {kDisablingBandwidthLow - 1, kDisablingBandwidthLow,
|
| + kDisablingBandwidthLow + 1, kEnablingBandwidthLow - 1,
|
| + kEnablingBandwidthLow, kEnablingBandwidthLow + 1}) {
|
| + auto states = CreateFecControllerPlrBased(initial_fec_enabled);
|
| + UpdateNetworkMetrics(&states, rtc::Optional<int>(bandwidth),
|
| + rtc::Optional<float>());
|
| + CheckDecision(&states, initial_fec_enabled, 0.0);
|
| + }
|
| + }
|
| }
|
|
|
| TEST(FecControllerPlrBasedTest, EnableFecForHighBandwidth) {
|
| @@ -209,23 +246,25 @@ TEST(FecControllerPlrBasedTest, MaintainFecOffForVeryLowBandwidth) {
|
|
|
| TEST(FecControllerPlrBasedTest, DisableFecForHighBandwidth) {
|
| auto states = CreateFecControllerPlrBased(true);
|
| + constexpr float kPacketLoss = kDisablingPacketLossAtHighBw - kEpsilon;
|
| UpdateNetworkMetrics(&states, rtc::Optional<int>(kDisablingBandwidthHigh),
|
| - rtc::Optional<float>(kDisablingPacketLossAtHighBw));
|
| - CheckDecision(&states, false, kDisablingPacketLossAtHighBw);
|
| + rtc::Optional<float>(kPacketLoss));
|
| + CheckDecision(&states, false, kPacketLoss);
|
| }
|
|
|
| TEST(FecControllerPlrBasedTest, MaintainFecOnForHighBandwidth) {
|
| + // Note: Disabling happens when the value is strictly below the threshold.
|
| auto states = CreateFecControllerPlrBased(true);
|
| - constexpr float kPacketLoss = kDisablingPacketLossAtHighBw * 1.01f;
|
| UpdateNetworkMetrics(&states, rtc::Optional<int>(kDisablingBandwidthHigh),
|
| - rtc::Optional<float>(kPacketLoss));
|
| - CheckDecision(&states, true, kPacketLoss);
|
| + rtc::Optional<float>(kDisablingPacketLossAtHighBw));
|
| + CheckDecision(&states, true, kDisablingPacketLossAtHighBw);
|
| }
|
|
|
| TEST(FecControllerPlrBasedTest, DisableFecOnMediumBandwidth) {
|
| auto states = CreateFecControllerPlrBased(true);
|
| constexpr float kPacketLoss =
|
| - (kDisablingPacketLossAtLowBw + kDisablingPacketLossAtHighBw) / 2.0f;
|
| + (kDisablingPacketLossAtLowBw + kDisablingPacketLossAtHighBw) / 2.0f -
|
| + kEpsilon;
|
| UpdateNetworkMetrics(
|
| &states,
|
| rtc::Optional<int>((kDisablingBandwidthHigh + kDisablingBandwidthLow) /
|
| @@ -237,7 +276,7 @@ TEST(FecControllerPlrBasedTest, DisableFecOnMediumBandwidth) {
|
| TEST(FecControllerPlrBasedTest, MaintainFecOnForMediumBandwidth) {
|
| auto states = CreateFecControllerPlrBased(true);
|
| constexpr float kPacketLoss = kDisablingPacketLossAtLowBw * 0.51f +
|
| - kDisablingPacketLossAtHighBw * 0.49f;
|
| + kDisablingPacketLossAtHighBw * 0.49f - kEpsilon;
|
| UpdateNetworkMetrics(
|
| &states,
|
| rtc::Optional<int>((kEnablingBandwidthHigh + kDisablingBandwidthLow) / 2),
|
| @@ -247,9 +286,10 @@ TEST(FecControllerPlrBasedTest, MaintainFecOnForMediumBandwidth) {
|
|
|
| TEST(FecControllerPlrBasedTest, DisableFecForLowBandwidth) {
|
| auto states = CreateFecControllerPlrBased(true);
|
| + constexpr float kPacketLoss = kDisablingPacketLossAtLowBw - kEpsilon;
|
| UpdateNetworkMetrics(&states, rtc::Optional<int>(kDisablingBandwidthLow),
|
| - rtc::Optional<float>(kDisablingPacketLossAtLowBw));
|
| - CheckDecision(&states, false, kDisablingPacketLossAtLowBw);
|
| + rtc::Optional<float>(kPacketLoss));
|
| + CheckDecision(&states, false, kPacketLoss);
|
| }
|
|
|
| TEST(FecControllerPlrBasedTest, DisableFecForVeryLowBandwidth) {
|
| @@ -284,10 +324,9 @@ TEST(FecControllerPlrBasedTest, CheckBehaviorOnChangingNetworkMetrics) {
|
| rtc::Optional<float>(kEnablingPacketLossAtHighBw));
|
| CheckDecision(&states, true, kEnablingPacketLossAtHighBw);
|
|
|
| - UpdateNetworkMetrics(
|
| - &states, rtc::Optional<int>(kDisablingBandwidthHigh),
|
| - rtc::Optional<float>(kDisablingPacketLossAtHighBw * 1.01f));
|
| - CheckDecision(&states, true, kDisablingPacketLossAtHighBw * 1.01f);
|
| + UpdateNetworkMetrics(&states, rtc::Optional<int>(kDisablingBandwidthHigh),
|
| + rtc::Optional<float>(kDisablingPacketLossAtHighBw));
|
| + CheckDecision(&states, true, kDisablingPacketLossAtHighBw);
|
|
|
| UpdateNetworkMetrics(&states, rtc::Optional<int>(kDisablingBandwidthHigh + 1),
|
| rtc::Optional<float>(0.0));
|
| @@ -335,16 +374,125 @@ TEST(FecControllerPlrBasedTest, CheckBehaviorOnSpecialCurves) {
|
| rtc::Optional<float>(kEnablingPacketLossAtHighBw));
|
| CheckDecision(&states, true, kEnablingPacketLossAtHighBw);
|
|
|
| - UpdateNetworkMetrics(
|
| - &states, rtc::Optional<int>(kDisablingBandwidthHigh),
|
| - rtc::Optional<float>(kDisablingPacketLossAtHighBw * 1.01f));
|
| - CheckDecision(&states, true, kDisablingPacketLossAtHighBw * 1.01f);
|
| + UpdateNetworkMetrics(&states, rtc::Optional<int>(kDisablingBandwidthHigh),
|
| + rtc::Optional<float>(kDisablingPacketLossAtHighBw));
|
| + CheckDecision(&states, true, kDisablingPacketLossAtHighBw);
|
|
|
| UpdateNetworkMetrics(&states, rtc::Optional<int>(kDisablingBandwidthHigh + 1),
|
| rtc::Optional<float>(0.0));
|
| CheckDecision(&states, false, 0.0);
|
| }
|
|
|
| +TEST(FecControllerPlrBasedTest, SingleThresholdCurveForEnablingAndDisabling) {
|
| + // Note: To avoid numerical errors, keep kPacketLossAtLowBw and
|
| + // kPacketLossAthighBw as (negative) integer powers of 2.
|
| + // This is mostly relevant for the O3 case.
|
| + constexpr int kBandwidthLow = 10000;
|
| + constexpr float kPacketLossAtLowBw = 0.25f;
|
| + constexpr int kBandwidthHigh = 20000;
|
| + constexpr float kPacketLossAtHighBw = 0.125f;
|
| + auto curve = ThresholdCurve(kBandwidthLow, kPacketLossAtLowBw, kBandwidthHigh,
|
| + kPacketLossAtHighBw);
|
| +
|
| + // B* stands for "below-curve", O* for "on-curve", and A* for "above-curve".
|
| + //
|
| + // //
|
| + // packet-loss ^ //
|
| + // | | //
|
| + // | B1 O1 //
|
| + // | | //
|
| + // | O2 //
|
| + // | \ A1 //
|
| + // | \ //
|
| + // | O3 A2 //
|
| + // | B2 \ //
|
| + // | \ //
|
| + // | O4--O5---- //
|
| + // | //
|
| + // | B3 //
|
| + // |-----------------> bandwidth //
|
| +
|
| + struct NetworkState {
|
| + int bandwidth;
|
| + float packet_loss;
|
| + };
|
| +
|
| + std::vector<NetworkState> below{
|
| + {kBandwidthLow - 1, kPacketLossAtLowBw + 0.1f}, // B1
|
| + {(kBandwidthLow + kBandwidthHigh) / 2,
|
| + (kPacketLossAtLowBw + kPacketLossAtHighBw) / 2 - kEpsilon}, // B2
|
| + {kBandwidthHigh + 1, kPacketLossAtHighBw - kEpsilon} // B3
|
| + };
|
| +
|
| + std::vector<NetworkState> on{
|
| + {kBandwidthLow, kPacketLossAtLowBw + 0.1f}, // O1
|
| + {kBandwidthLow, kPacketLossAtLowBw}, // O2
|
| + {(kBandwidthLow + kBandwidthHigh) / 2,
|
| + (kPacketLossAtLowBw + kPacketLossAtHighBw) / 2}, // O3
|
| + {kBandwidthHigh, kPacketLossAtHighBw}, // O4
|
| + {kBandwidthHigh + 1, kPacketLossAtHighBw}, // O5
|
| + };
|
| +
|
| + std::vector<NetworkState> above{
|
| + {(kBandwidthLow + kBandwidthHigh) / 2,
|
| + (kPacketLossAtLowBw + kPacketLossAtHighBw) / 2 + kEpsilon}, // A1
|
| + {kBandwidthHigh + 1, kPacketLossAtHighBw + kEpsilon}, // A2
|
| + };
|
| +
|
| + // Test that FEC is turned off whenever we're below the curve, independent
|
| + // of the starting FEC state.
|
| + for (NetworkState net_state : below) {
|
| + for (bool initial_fec_enabled : {false, true}) {
|
| + auto states =
|
| + CreateFecControllerPlrBased(initial_fec_enabled, curve, curve);
|
| + UpdateNetworkMetrics(&states, net_state.bandwidth, net_state.packet_loss);
|
| + CheckDecision(&states, false, net_state.packet_loss);
|
| + }
|
| + }
|
| +
|
| + // Test that FEC is turned on whenever we're on the curve or above it,
|
| + // independent of the starting FEC state.
|
| + for (std::vector<NetworkState> states_list : {on, above}) {
|
| + for (NetworkState net_state : states_list) {
|
| + for (bool initial_fec_enabled : {false, true}) {
|
| + auto states =
|
| + CreateFecControllerPlrBased(initial_fec_enabled, curve, curve);
|
| + UpdateNetworkMetrics(&states, net_state.bandwidth,
|
| + net_state.packet_loss);
|
| + CheckDecision(&states, true, net_state.packet_loss);
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +TEST(FecControllerPlrBasedTest, FecAlwaysOff) {
|
| + ThresholdCurve always_off_curve(0, 1.0f + kEpsilon, 0, 1.0f + kEpsilon);
|
| + for (bool initial_fec_enabled : {false, true}) {
|
| + for (int bandwidth : {0, 10000}) {
|
| + for (float packet_loss : {0.0f, 0.5f, 1.0f}) {
|
| + auto states = CreateFecControllerPlrBased(
|
| + initial_fec_enabled, always_off_curve, always_off_curve);
|
| + UpdateNetworkMetrics(&states, bandwidth, packet_loss);
|
| + CheckDecision(&states, false, packet_loss);
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +TEST(FecControllerPlrBasedTest, FecAlwaysOn) {
|
| + ThresholdCurve always_on_curve(0, 0.0f, 0, 0.0f);
|
| + for (bool initial_fec_enabled : {false, true}) {
|
| + for (int bandwidth : {0, 10000}) {
|
| + for (float packet_loss : {0.0f, 0.5f, 1.0f}) {
|
| + auto states = CreateFecControllerPlrBased(
|
| + initial_fec_enabled, always_on_curve, always_on_curve);
|
| + UpdateNetworkMetrics(&states, bandwidth, packet_loss);
|
| + CheckDecision(&states, true, packet_loss);
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
|
| TEST(FecControllerPlrBasedDeathTest, InvalidConfig) {
|
| FecControllerPlrBasedTestStates states;
|
|
|