| /* |
| * 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 <memory> |
| #include <utility> |
| |
| #include "webrtc/modules/audio_coding/audio_network_adaptor/frame_length_controller.h" |
| #include "webrtc/test/gtest.h" |
| |
| namespace webrtc { |
| |
| namespace { |
| |
| constexpr float kFlIncreasingPacketLossFraction = 0.04f; |
| constexpr float kFlDecreasingPacketLossFraction = 0.05f; |
| constexpr int kFl20msTo60msBandwidthBps = 22000; |
| constexpr int kFl60msTo20msBandwidthBps = 88000; |
| constexpr int kMinReceiverFrameLengthMs = 10; |
| constexpr int kMaxReceiverFrameLengthMs = 120; |
| constexpr int kMediumBandwidthBps = |
| (kFl60msTo20msBandwidthBps + kFl20msTo60msBandwidthBps) / 2; |
| constexpr float kMediumPacketLossFraction = |
| (kFlDecreasingPacketLossFraction + kFlIncreasingPacketLossFraction) / 2; |
| |
| void SetReceiverFrameLengthRange(FrameLengthController* controller, |
| int min_frame_length_ms, |
| int max_frame_length_ms) { |
| Controller::Constraints constraints; |
| using FrameLengthRange = Controller::Constraints::FrameLengthRange; |
| constraints.receiver_frame_length_range = rtc::Optional<FrameLengthRange>( |
| FrameLengthRange(min_frame_length_ms, max_frame_length_ms)); |
| controller->SetConstraints(constraints); |
| } |
| |
| std::unique_ptr<FrameLengthController> CreateController( |
| int initial_frame_length_ms) { |
| std::unique_ptr<FrameLengthController> controller( |
| new FrameLengthController(FrameLengthController::Config( |
| {20, 60}, initial_frame_length_ms, kFlIncreasingPacketLossFraction, |
| kFlDecreasingPacketLossFraction, kFl20msTo60msBandwidthBps, |
| kFl60msTo20msBandwidthBps))); |
| SetReceiverFrameLengthRange(controller.get(), kMinReceiverFrameLengthMs, |
| kMaxReceiverFrameLengthMs); |
| return controller; |
| } |
| |
| void CheckDecision(FrameLengthController* controller, |
| const rtc::Optional<int>& uplink_bandwidth_bps, |
| const rtc::Optional<float>& uplink_packet_loss_fraction, |
| const rtc::Optional<bool>& enable_fec, |
| int expected_frame_length_ms) { |
| Controller::NetworkMetrics metrics; |
| metrics.uplink_bandwidth_bps = uplink_bandwidth_bps; |
| metrics.uplink_packet_loss_fraction = uplink_packet_loss_fraction; |
| AudioNetworkAdaptor::EncoderRuntimeConfig config; |
| config.enable_fec = enable_fec; |
| controller->MakeDecision(metrics, &config); |
| EXPECT_EQ(rtc::Optional<int>(expected_frame_length_ms), |
| config.frame_length_ms); |
| } |
| |
| } // namespace |
| |
| TEST(FrameLengthControllerTest, |
| OutputInitValueWhenReceiverFrameLengthRangeUnset) { |
| constexpr int kInitialFrameLenghtMs = 60; |
| std::unique_ptr<FrameLengthController> controller( |
| new FrameLengthController(FrameLengthController::Config( |
| {20, 60}, kInitialFrameLenghtMs, kFlIncreasingPacketLossFraction, |
| kFlDecreasingPacketLossFraction, kFl20msTo60msBandwidthBps, |
| kFl60msTo20msBandwidthBps))); |
| // Use a high uplink bandwidth that would cause frame length to decrease if |
| // receiver frame length is set. |
| CheckDecision(controller.get(), rtc::Optional<int>(kFl60msTo20msBandwidthBps), |
| rtc::Optional<float>(), rtc::Optional<bool>(), |
| kInitialFrameLenghtMs); |
| } |
| |
| TEST(FrameLengthControllerTest, DecreaseTo20MsOnHighUplinkBandwidth) { |
| auto controller = CreateController(60); |
| CheckDecision(controller.get(), rtc::Optional<int>(kFl60msTo20msBandwidthBps), |
| rtc::Optional<float>(), rtc::Optional<bool>(), 20); |
| } |
| |
| TEST(FrameLengthControllerTest, DecreaseTo20MsOnHighUplinkPacketLossFraction) { |
| auto controller = CreateController(60); |
| CheckDecision(controller.get(), rtc::Optional<int>(), |
| rtc::Optional<float>(kFlDecreasingPacketLossFraction), |
| rtc::Optional<bool>(), 20); |
| } |
| |
| TEST(FrameLengthControllerTest, DecreaseTo20MsWhenFecIsOn) { |
| auto controller = CreateController(60); |
| CheckDecision(controller.get(), rtc::Optional<int>(), rtc::Optional<float>(), |
| rtc::Optional<bool>(true), 20); |
| } |
| |
| TEST(FrameLengthControllerTest, |
| Maintain60MsIf20MsNotInReceiverFrameLengthRange) { |
| auto controller = CreateController(60); |
| SetReceiverFrameLengthRange(controller.get(), 21, 60); |
| // Set FEC on that would cause frame length to decrease if receiver frame |
| // length range included 20ms. |
| CheckDecision(controller.get(), rtc::Optional<int>(), rtc::Optional<float>(), |
| rtc::Optional<bool>(true), 60); |
| } |
| |
| TEST(FrameLengthControllerTest, Maintain60MsOnMultipleConditions) { |
| // Maintain 60ms frame length if |
| // 1. |uplink_bandwidth_bps| is at medium level, |
| // 2. |uplink_packet_loss_fraction| is at medium, |
| // 3. FEC is not decided ON. |
| auto controller = CreateController(60); |
| CheckDecision(controller.get(), rtc::Optional<int>(kMediumBandwidthBps), |
| rtc::Optional<float>(kMediumPacketLossFraction), |
| rtc::Optional<bool>(), 60); |
| } |
| |
| TEST(FrameLengthControllerTest, IncreaseTo60MsOnMultipleConditions) { |
| // Increase to 60ms frame length if |
| // 1. |uplink_bandwidth_bps| is known to be smaller than a threshold AND |
| // 2. |uplink_packet_loss_fraction| is known to be smaller than a threshold |
| // AND |
| // 3. FEC is not decided or OFF. |
| auto controller = CreateController(20); |
| CheckDecision(controller.get(), rtc::Optional<int>(kFl20msTo60msBandwidthBps), |
| rtc::Optional<float>(kFlIncreasingPacketLossFraction), |
| rtc::Optional<bool>(), 60); |
| } |
| |
| TEST(FrameLengthControllerTest, |
| Maintain20MsIf60MsNotInReceiverFrameLengthRange) { |
| auto controller = CreateController(20); |
| SetReceiverFrameLengthRange(controller.get(), 10, 59); |
| // Use a low uplink bandwidth and a low uplink packet loss fraction that would |
| // cause frame length to increase if receiver frame length included 60ms. |
| CheckDecision(controller.get(), rtc::Optional<int>(kFl20msTo60msBandwidthBps), |
| rtc::Optional<float>(kFlIncreasingPacketLossFraction), |
| rtc::Optional<bool>(), 20); |
| } |
| |
| TEST(FrameLengthControllerTest, Maintain20MsOnMediumUplinkBandwidth) { |
| auto controller = CreateController(20); |
| CheckDecision(controller.get(), rtc::Optional<int>(kMediumBandwidthBps), |
| rtc::Optional<float>(kFlIncreasingPacketLossFraction), |
| rtc::Optional<bool>(), 20); |
| } |
| |
| TEST(FrameLengthControllerTest, Maintain20MsOnMediumUplinkPacketLossFraction) { |
| auto controller = CreateController(20); |
| // Use a low uplink bandwidth that would cause frame length to increase if |
| // uplink packet loss fraction was low. |
| CheckDecision(controller.get(), rtc::Optional<int>(kFl20msTo60msBandwidthBps), |
| rtc::Optional<float>(kMediumPacketLossFraction), |
| rtc::Optional<bool>(), 20); |
| } |
| |
| TEST(FrameLengthControllerTest, Maintain20MsWhenFecIsOn) { |
| auto controller = CreateController(20); |
| // Use a low uplink bandwidth and a low uplink packet loss fraction that would |
| // cause frame length to increase if FEC was not ON. |
| CheckDecision(controller.get(), rtc::Optional<int>(kFl20msTo60msBandwidthBps), |
| rtc::Optional<float>(kFlIncreasingPacketLossFraction), |
| rtc::Optional<bool>(true), 20); |
| } |
| |
| TEST(FrameLengthControllerTest, |
| MaintainFrameLengthOnSetReceiverFrameLengthRange) { |
| auto controller = CreateController(60); |
| CheckDecision(controller.get(), rtc::Optional<int>(), rtc::Optional<float>(), |
| rtc::Optional<bool>(true), 20); |
| SetReceiverFrameLengthRange(controller.get(), 10, 60); |
| CheckDecision(controller.get(), rtc::Optional<int>(), rtc::Optional<float>(), |
| rtc::Optional<bool>(), 20); |
| } |
| |
| namespace { |
| constexpr int kFl60msTo120msBandwidthBps = 18000; |
| constexpr int kFl120msTo60msBandwidthBps = 72000; |
| } |
| |
| class FrameLengthControllerForTest { |
| public: |
| // This class is to test multiple frame lengths. FrameLengthController is |
| // implemented to support this, but is not enabled for the default constructor |
| // for the time being. We use this class to test it. |
| explicit FrameLengthControllerForTest(int initial_frame_length_ms) |
| : frame_length_controller_( |
| FrameLengthController::Config({20, 60, 120}, |
| initial_frame_length_ms, |
| kFlIncreasingPacketLossFraction, |
| kFlDecreasingPacketLossFraction, |
| kFl20msTo60msBandwidthBps, |
| kFl60msTo20msBandwidthBps)) { |
| frame_length_controller_.frame_length_change_criteria_.insert( |
| std::make_pair(FrameLengthController::FrameLengthChange(60, 120), |
| kFl60msTo120msBandwidthBps)); |
| frame_length_controller_.frame_length_change_criteria_.insert( |
| std::make_pair(FrameLengthController::FrameLengthChange(120, 60), |
| kFl120msTo60msBandwidthBps)); |
| frame_length_controller_.SetReceiverFrameLengthRange(20, 120); |
| } |
| FrameLengthController* get() { return &frame_length_controller_; } |
| |
| private: |
| FrameLengthController frame_length_controller_; |
| }; |
| |
| TEST(FrameLengthControllerTest, From120MsTo20MsOnHighUplinkBandwidth) { |
| FrameLengthControllerForTest controller(120); |
| // It takes two steps for frame length to go from 120ms to 20ms. |
| CheckDecision(controller.get(), rtc::Optional<int>(kFl60msTo20msBandwidthBps), |
| rtc::Optional<float>(), rtc::Optional<bool>(), 60); |
| CheckDecision(controller.get(), rtc::Optional<int>(kFl60msTo20msBandwidthBps), |
| rtc::Optional<float>(), rtc::Optional<bool>(), 20); |
| } |
| |
| TEST(FrameLengthControllerTest, From120MsTo20MsOnHighUplinkPacketLossFraction) { |
| FrameLengthControllerForTest controller(120); |
| // It takes two steps for frame length to go from 120ms to 20ms. |
| CheckDecision(controller.get(), rtc::Optional<int>(), |
| rtc::Optional<float>(kFlDecreasingPacketLossFraction), |
| rtc::Optional<bool>(), 60); |
| CheckDecision(controller.get(), rtc::Optional<int>(), |
| rtc::Optional<float>(kFlDecreasingPacketLossFraction), |
| rtc::Optional<bool>(), 20); |
| } |
| |
| TEST(FrameLengthControllerTest, From120MsTo20MsWhenFecIsOn) { |
| FrameLengthControllerForTest controller(120); |
| // It takes two steps for frame length to go from 120ms to 20ms. |
| CheckDecision(controller.get(), rtc::Optional<int>(), rtc::Optional<float>(), |
| rtc::Optional<bool>(true), 60); |
| CheckDecision(controller.get(), rtc::Optional<int>(), rtc::Optional<float>(), |
| rtc::Optional<bool>(true), 20); |
| } |
| |
| TEST(FrameLengthControllerTest, From20MsTo120MsOnMultipleConditions) { |
| // Increase to 120ms frame length if |
| // 1. |uplink_bandwidth_bps| is known to be smaller than a threshold AND |
| // 2. |uplink_packet_loss_fraction| is known to be smaller than a threshold |
| // AND |
| // 3. FEC is not decided or OFF. |
| FrameLengthControllerForTest controller(20); |
| // It takes two steps for frame length to go from 20ms to 120ms. |
| CheckDecision(controller.get(), |
| rtc::Optional<int>(kFl60msTo120msBandwidthBps), |
| rtc::Optional<float>(kFlIncreasingPacketLossFraction), |
| rtc::Optional<bool>(), 60); |
| CheckDecision(controller.get(), |
| rtc::Optional<int>(kFl60msTo120msBandwidthBps), |
| rtc::Optional<float>(kFlIncreasingPacketLossFraction), |
| rtc::Optional<bool>(), 120); |
| } |
| |
| TEST(FrameLengthControllerTest, Stall60MsIf120MsNotInReceiverFrameLengthRange) { |
| FrameLengthControllerForTest controller(20); |
| SetReceiverFrameLengthRange(controller.get(), 20, 119); |
| CheckDecision(controller.get(), |
| rtc::Optional<int>(kFl60msTo120msBandwidthBps), |
| rtc::Optional<float>(kFlIncreasingPacketLossFraction), |
| rtc::Optional<bool>(), 60); |
| CheckDecision(controller.get(), |
| rtc::Optional<int>(kFl60msTo120msBandwidthBps), |
| rtc::Optional<float>(kFlIncreasingPacketLossFraction), |
| rtc::Optional<bool>(), 60); |
| } |
| |
| TEST(FrameLengthControllerTest, CheckBehaviorOnChangingNetworkMetrics) { |
| FrameLengthControllerForTest controller(20); |
| CheckDecision(controller.get(), rtc::Optional<int>(kMediumBandwidthBps), |
| rtc::Optional<float>(kFlIncreasingPacketLossFraction), |
| rtc::Optional<bool>(), 20); |
| CheckDecision(controller.get(), rtc::Optional<int>(kFl20msTo60msBandwidthBps), |
| rtc::Optional<float>(kFlIncreasingPacketLossFraction), |
| rtc::Optional<bool>(), 60); |
| CheckDecision(controller.get(), |
| rtc::Optional<int>(kFl60msTo120msBandwidthBps), |
| rtc::Optional<float>(kMediumPacketLossFraction), |
| rtc::Optional<bool>(), 60); |
| CheckDecision(controller.get(), |
| rtc::Optional<int>(kFl60msTo120msBandwidthBps), |
| rtc::Optional<float>(kFlIncreasingPacketLossFraction), |
| rtc::Optional<bool>(), 120); |
| CheckDecision(controller.get(), |
| rtc::Optional<int>(kFl120msTo60msBandwidthBps), |
| rtc::Optional<float>(kFlIncreasingPacketLossFraction), |
| rtc::Optional<bool>(), 60); |
| CheckDecision(controller.get(), rtc::Optional<int>(kMediumPacketLossFraction), |
| rtc::Optional<float>(kFlDecreasingPacketLossFraction), |
| rtc::Optional<bool>(), 20); |
| } |
| |
| } // namespace webrtc |