Introduce FecControllerRplrBased

1. Rename FecController to FecControllerPlrBased.
2. Introduce FecControllerRplrBased - a version of FecController that makes its decision based on RPLR instead of PLR.

BUG=webrtc:7058

Review-Url: https://codereview.webrtc.org/2672933003
Cr-Commit-Position: refs/heads/master@{#17373}
This commit is contained in:
elad.alon
2017-03-24 04:12:56 -07:00
committed by Commit bot
parent 8ed482e6d7
commit 6d7900de66
8 changed files with 797 additions and 113 deletions

View File

@ -909,8 +909,10 @@ rtc_static_library("audio_network_adaptor") {
"audio_network_adaptor/dtx_controller.h",
"audio_network_adaptor/event_log_writer.cc",
"audio_network_adaptor/event_log_writer.h",
"audio_network_adaptor/fec_controller.cc",
"audio_network_adaptor/fec_controller.h",
"audio_network_adaptor/fec_controller_plr_based.cc",
"audio_network_adaptor/fec_controller_plr_based.h",
"audio_network_adaptor/fec_controller_rplr_based.cc",
"audio_network_adaptor/fec_controller_rplr_based.h",
"audio_network_adaptor/frame_length_controller.cc",
"audio_network_adaptor/frame_length_controller.h",
"audio_network_adaptor/include/audio_network_adaptor.h",
@ -1988,7 +1990,8 @@ if (rtc_include_tests) {
"audio_network_adaptor/controller_manager_unittest.cc",
"audio_network_adaptor/dtx_controller_unittest.cc",
"audio_network_adaptor/event_log_writer_unittest.cc",
"audio_network_adaptor/fec_controller_unittest.cc",
"audio_network_adaptor/fec_controller_plr_based_unittest.cc",
"audio_network_adaptor/fec_controller_rplr_based_unittest.cc",
"audio_network_adaptor/frame_length_controller_unittest.cc",
"audio_network_adaptor/mock/mock_controller.h",
"audio_network_adaptor/mock/mock_controller_manager.h",

View File

@ -17,7 +17,7 @@
#include "webrtc/modules/audio_coding/audio_network_adaptor/bitrate_controller.h"
#include "webrtc/modules/audio_coding/audio_network_adaptor/channel_controller.h"
#include "webrtc/modules/audio_coding/audio_network_adaptor/dtx_controller.h"
#include "webrtc/modules/audio_coding/audio_network_adaptor/fec_controller.h"
#include "webrtc/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based.h"
#include "webrtc/modules/audio_coding/audio_network_adaptor/frame_length_controller.h"
#include "webrtc/system_wrappers/include/clock.h"
@ -37,7 +37,7 @@ namespace {
#ifdef WEBRTC_AUDIO_NETWORK_ADAPTOR_DEBUG_DUMP
std::unique_ptr<FecController> CreateFecController(
std::unique_ptr<FecControllerPlrBased> CreateFecControllerPlrBased(
const audio_network_adaptor::config::FecController& config,
bool initial_fec_enabled,
const Clock* clock) {
@ -57,19 +57,20 @@ std::unique_ptr<FecController> CreateFecController(
RTC_CHECK(fec_disabling_threshold.has_high_bandwidth_bps());
RTC_CHECK(fec_disabling_threshold.has_high_bandwidth_packet_loss());
return std::unique_ptr<FecController>(new FecController(FecController::Config(
initial_fec_enabled,
FecController::Config::Threshold(
fec_enabling_threshold.low_bandwidth_bps(),
fec_enabling_threshold.low_bandwidth_packet_loss(),
fec_enabling_threshold.high_bandwidth_bps(),
fec_enabling_threshold.high_bandwidth_packet_loss()),
FecController::Config::Threshold(
fec_disabling_threshold.low_bandwidth_bps(),
fec_disabling_threshold.low_bandwidth_packet_loss(),
fec_disabling_threshold.high_bandwidth_bps(),
fec_disabling_threshold.high_bandwidth_packet_loss()),
config.time_constant_ms(), clock)));
return std::unique_ptr<FecControllerPlrBased>(
new FecControllerPlrBased(FecControllerPlrBased::Config(
initial_fec_enabled,
FecControllerPlrBased::Config::Threshold(
fec_enabling_threshold.low_bandwidth_bps(),
fec_enabling_threshold.low_bandwidth_packet_loss(),
fec_enabling_threshold.high_bandwidth_bps(),
fec_enabling_threshold.high_bandwidth_packet_loss()),
FecControllerPlrBased::Config::Threshold(
fec_disabling_threshold.low_bandwidth_bps(),
fec_disabling_threshold.low_bandwidth_packet_loss(),
fec_disabling_threshold.high_bandwidth_bps(),
fec_disabling_threshold.high_bandwidth_packet_loss()),
config.time_constant_ms(), clock)));
}
std::unique_ptr<FrameLengthController> CreateFrameLengthController(
@ -179,8 +180,8 @@ std::unique_ptr<ControllerManager> ControllerManagerImpl::Create(
std::unique_ptr<Controller> controller;
switch (controller_config.controller_case()) {
case audio_network_adaptor::config::Controller::kFecController:
controller = CreateFecController(controller_config.fec_controller(),
initial_fec_enabled, clock);
controller = CreateFecControllerPlrBased(
controller_config.fec_controller(), initial_fec_enabled, clock);
break;
case audio_network_adaptor::config::Controller::kFrameLengthController:
controller = CreateFrameLengthController(

View File

@ -8,7 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/modules/audio_coding/audio_network_adaptor/fec_controller.h"
#include "webrtc/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based.h"
#include <limits>
#include <utility>
@ -17,28 +17,30 @@
namespace webrtc {
FecController::Config::Threshold::Threshold(int low_bandwidth_bps,
float low_bandwidth_packet_loss,
int high_bandwidth_bps,
float high_bandwidth_packet_loss)
FecControllerPlrBased::Config::Threshold::Threshold(
int low_bandwidth_bps,
float low_bandwidth_packet_loss,
int high_bandwidth_bps,
float high_bandwidth_packet_loss)
: low_bandwidth_bps(low_bandwidth_bps),
low_bandwidth_packet_loss(low_bandwidth_packet_loss),
high_bandwidth_bps(high_bandwidth_bps),
high_bandwidth_packet_loss(high_bandwidth_packet_loss) {}
FecController::Config::Config(bool initial_fec_enabled,
const Threshold& fec_enabling_threshold,
const Threshold& fec_disabling_threshold,
int time_constant_ms,
const Clock* clock)
FecControllerPlrBased::Config::Config(bool initial_fec_enabled,
const Threshold& fec_enabling_threshold,
const Threshold& fec_disabling_threshold,
int time_constant_ms,
const Clock* clock)
: initial_fec_enabled(initial_fec_enabled),
fec_enabling_threshold(fec_enabling_threshold),
fec_disabling_threshold(fec_disabling_threshold),
time_constant_ms(time_constant_ms),
clock(clock) {}
FecController::FecController(const Config& config,
std::unique_ptr<SmoothingFilter> smoothing_filter)
FecControllerPlrBased::FecControllerPlrBased(
const Config& config,
std::unique_ptr<SmoothingFilter> smoothing_filter)
: config_(config),
fec_enabled_(config.initial_fec_enabled),
packet_loss_smoother_(std::move(smoothing_filter)),
@ -58,16 +60,16 @@ FecController::FecController(const Config& config,
config_.fec_enabling_threshold.high_bandwidth_packet_loss);
}
FecController::FecController(const Config& config)
: FecController(
FecControllerPlrBased::FecControllerPlrBased(const Config& config)
: FecControllerPlrBased(
config,
std::unique_ptr<SmoothingFilter>(
new SmoothingFilterImpl(config.time_constant_ms, config.clock))) {
}
FecController::~FecController() = default;
FecControllerPlrBased::~FecControllerPlrBased() = default;
void FecController::UpdateNetworkMetrics(
void FecControllerPlrBased::UpdateNetworkMetrics(
const NetworkMetrics& network_metrics) {
if (network_metrics.uplink_bandwidth_bps)
uplink_bandwidth_bps_ = network_metrics.uplink_bandwidth_bps;
@ -77,7 +79,7 @@ void FecController::UpdateNetworkMetrics(
}
}
void FecController::MakeDecision(
void FecControllerPlrBased::MakeDecision(
AudioNetworkAdaptor::EncoderRuntimeConfig* config) {
RTC_DCHECK(!config->enable_fec);
RTC_DCHECK(!config->uplink_packet_loss_fraction);
@ -93,7 +95,7 @@ void FecController::MakeDecision(
rtc::Optional<float>(packet_loss ? *packet_loss : 0.0);
}
FecController::ThresholdInfo::ThresholdInfo(
FecControllerPlrBased::ThresholdInfo::ThresholdInfo(
const Config::Threshold& threshold) {
int bandwidth_diff_bps =
threshold.high_bandwidth_bps - threshold.low_bandwidth_bps;
@ -104,18 +106,23 @@ FecController::ThresholdInfo::ThresholdInfo(
threshold.low_bandwidth_packet_loss - slope * threshold.low_bandwidth_bps;
}
float FecController::GetPacketLossThreshold(
float FecControllerPlrBased::GetPacketLossThreshold(
int bandwidth_bps,
const Config::Threshold& threshold,
const ThresholdInfo& threshold_info) const {
if (bandwidth_bps < threshold.low_bandwidth_bps)
if (bandwidth_bps < threshold.low_bandwidth_bps) {
return std::numeric_limits<float>::max();
if (bandwidth_bps >= threshold.high_bandwidth_bps)
} else if (bandwidth_bps >= threshold.high_bandwidth_bps) {
return threshold.high_bandwidth_packet_loss;
return threshold_info.offset + threshold_info.slope * bandwidth_bps;
} else {
float rc = threshold_info.offset + threshold_info.slope * bandwidth_bps;
RTC_DCHECK_LE(rc, threshold.low_bandwidth_packet_loss);
RTC_DCHECK_GE(rc, threshold.high_bandwidth_packet_loss);
return rc;
}
}
bool FecController::FecEnablingDecision(
bool FecControllerPlrBased::FecEnablingDecision(
const rtc::Optional<float>& packet_loss) const {
if (!uplink_bandwidth_bps_)
return false;
@ -126,7 +133,7 @@ bool FecController::FecEnablingDecision(
fec_enabling_threshold_info_);
}
bool FecController::FecDisablingDecision(
bool FecControllerPlrBased::FecDisablingDecision(
const rtc::Optional<float>& packet_loss) const {
if (!uplink_bandwidth_bps_)
return false;

View File

@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_MODULES_AUDIO_CODING_AUDIO_NETWORK_ADAPTOR_FEC_CONTROLLER_H_
#define WEBRTC_MODULES_AUDIO_CODING_AUDIO_NETWORK_ADAPTOR_FEC_CONTROLLER_H_
#ifndef WEBRTC_MODULES_AUDIO_CODING_AUDIO_NETWORK_ADAPTOR_FEC_CONTROLLER_PLR_BASED_H_
#define WEBRTC_MODULES_AUDIO_CODING_AUDIO_NETWORK_ADAPTOR_FEC_CONTROLLER_PLR_BASED_H_
#include <memory>
@ -19,7 +19,7 @@
namespace webrtc {
class FecController final : public Controller {
class FecControllerPlrBased final : public Controller {
public:
struct Config {
struct Threshold {
@ -65,12 +65,12 @@ class FecController final : public Controller {
};
// Dependency injection for testing.
FecController(const Config& config,
std::unique_ptr<SmoothingFilter> smoothing_filter);
FecControllerPlrBased(const Config& config,
std::unique_ptr<SmoothingFilter> smoothing_filter);
explicit FecController(const Config& config);
explicit FecControllerPlrBased(const Config& config);
~FecController() override;
~FecControllerPlrBased() override;
void UpdateNetworkMetrics(const NetworkMetrics& network_metrics) override;
@ -99,9 +99,9 @@ class FecController final : public Controller {
const ThresholdInfo fec_enabling_threshold_info_;
const ThresholdInfo fec_disabling_threshold_info_;
RTC_DISALLOW_COPY_AND_ASSIGN(FecController);
RTC_DISALLOW_COPY_AND_ASSIGN(FecControllerPlrBased);
};
} // namespace webrtc
#endif // WEBRTC_MODULES_AUDIO_CODING_AUDIO_NETWORK_ADAPTOR_FEC_CONTROLLER_H_
#endif // WEBRTC_MODULES_AUDIO_CODING_AUDIO_NETWORK_ADAPTOR_FEC_CONTROLLER_PLR_BASED_H_

View File

@ -11,7 +11,7 @@
#include <utility>
#include "webrtc/common_audio/mocks/mock_smoothing_filter.h"
#include "webrtc/modules/audio_coding/audio_network_adaptor/fec_controller.h"
#include "webrtc/modules/audio_coding/audio_network_adaptor/fec_controller_plr_based.h"
#include "webrtc/test/gtest.h"
namespace webrtc {
@ -45,19 +45,20 @@ constexpr float kEnablingPacketLossAtLowBw = 0.1f;
constexpr int kEnablingBandwidthHigh = 64000;
constexpr float kEnablingPacketLossAtHighBw = 0.05f;
struct FecControllerStates {
std::unique_ptr<FecController> controller;
struct FecControllerPlrBasedTestStates {
std::unique_ptr<FecControllerPlrBased> controller;
MockSmoothingFilter* packet_loss_smoother;
};
FecControllerStates CreateFecController(bool initial_fec_enabled) {
FecControllerStates states;
FecControllerPlrBasedTestStates CreateFecControllerPlrBased(
bool initial_fec_enabled) {
FecControllerPlrBasedTestStates states;
std::unique_ptr<MockSmoothingFilter> mock_smoothing_filter(
new NiceMock<MockSmoothingFilter>());
states.packet_loss_smoother = mock_smoothing_filter.get();
using Threshold = FecController::Config::Threshold;
states.controller.reset(new FecController(
FecController::Config(
using Threshold = FecControllerPlrBased::Config::Threshold;
states.controller.reset(new FecControllerPlrBased(
FecControllerPlrBased::Config(
initial_fec_enabled,
Threshold(kEnablingBandwidthLow, kEnablingPacketLossAtLowBw,
kEnablingBandwidthHigh, kEnablingPacketLossAtHighBw),
@ -68,7 +69,7 @@ FecControllerStates CreateFecController(bool initial_fec_enabled) {
return states;
}
void UpdateNetworkMetrics(FecControllerStates* states,
void UpdateNetworkMetrics(FecControllerPlrBasedTestStates* states,
const rtc::Optional<int>& uplink_bandwidth_bps,
const rtc::Optional<float>& uplink_packet_loss) {
// UpdateNetworkMetrics can accept multiple network metric updates at once.
@ -93,7 +94,7 @@ void UpdateNetworkMetrics(FecControllerStates* states,
// 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(FecControllerStates* states,
void CheckDecision(FecControllerPlrBasedTestStates* states,
bool expected_enable_fec,
float expected_uplink_packet_loss_fraction) {
AudioNetworkAdaptor::EncoderRuntimeConfig config;
@ -105,9 +106,9 @@ void CheckDecision(FecControllerStates* states,
} // namespace
TEST(FecControllerTest, OutputInitValueWhenUplinkBandwidthUnknown) {
TEST(FecControllerPlrBasedTest, OutputInitValueWhenUplinkBandwidthUnknown) {
constexpr bool kInitialFecEnabled = true;
auto states = CreateFecController(kInitialFecEnabled);
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>(),
@ -115,9 +116,10 @@ TEST(FecControllerTest, OutputInitValueWhenUplinkBandwidthUnknown) {
CheckDecision(&states, kInitialFecEnabled, kDisablingPacketLossAtHighBw);
}
TEST(FecControllerTest, OutputInitValueWhenUplinkPacketLossFractionUnknown) {
TEST(FecControllerPlrBasedTest,
OutputInitValueWhenUplinkPacketLossFractionUnknown) {
constexpr bool kInitialFecEnabled = true;
auto states = CreateFecController(kInitialFecEnabled);
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),
@ -125,22 +127,22 @@ TEST(FecControllerTest, OutputInitValueWhenUplinkPacketLossFractionUnknown) {
CheckDecision(&states, kInitialFecEnabled, 0.0);
}
TEST(FecControllerTest, EnableFecForHighBandwidth) {
auto states = CreateFecController(false);
TEST(FecControllerPlrBasedTest, EnableFecForHighBandwidth) {
auto states = CreateFecControllerPlrBased(false);
UpdateNetworkMetrics(&states, rtc::Optional<int>(kEnablingBandwidthHigh),
rtc::Optional<float>(kEnablingPacketLossAtHighBw));
CheckDecision(&states, true, kEnablingPacketLossAtHighBw);
}
TEST(FecControllerTest, UpdateMultipleNetworkMetricsAtOnce) {
TEST(FecControllerPlrBasedTest, UpdateMultipleNetworkMetricsAtOnce) {
// This test is similar to EnableFecForHighBandwidth. But instead of
// using ::UpdateNetworkMetrics(...), which calls
// FecController::UpdateNetworkMetrics(...) multiple times, we
// FecControllerPlrBased::UpdateNetworkMetrics(...) multiple times, we
// we call it only once. This is to verify that
// FecController::UpdateNetworkMetrics(...) can handle multiple
// FecControllerPlrBased::UpdateNetworkMetrics(...) can handle multiple
// network updates at once. This is, however, not a common use case in current
// audio_network_adaptor_impl.cc.
auto states = CreateFecController(false);
auto states = CreateFecControllerPlrBased(false);
Controller::NetworkMetrics network_metrics;
network_metrics.uplink_bandwidth_bps =
rtc::Optional<int>(kEnablingBandwidthHigh);
@ -152,16 +154,16 @@ TEST(FecControllerTest, UpdateMultipleNetworkMetricsAtOnce) {
CheckDecision(&states, true, kEnablingPacketLossAtHighBw);
}
TEST(FecControllerTest, MaintainFecOffForHighBandwidth) {
auto states = CreateFecController(false);
TEST(FecControllerPlrBasedTest, MaintainFecOffForHighBandwidth) {
auto states = CreateFecControllerPlrBased(false);
constexpr float kPacketLoss = kEnablingPacketLossAtHighBw * 0.99f;
UpdateNetworkMetrics(&states, rtc::Optional<int>(kEnablingBandwidthHigh),
rtc::Optional<float>(kPacketLoss));
CheckDecision(&states, false, kPacketLoss);
}
TEST(FecControllerTest, EnableFecForMediumBandwidth) {
auto states = CreateFecController(false);
TEST(FecControllerPlrBasedTest, EnableFecForMediumBandwidth) {
auto states = CreateFecControllerPlrBased(false);
constexpr float kPacketLoss =
(kEnablingPacketLossAtLowBw + kEnablingPacketLossAtHighBw) / 2.0;
UpdateNetworkMetrics(
@ -171,8 +173,8 @@ TEST(FecControllerTest, EnableFecForMediumBandwidth) {
CheckDecision(&states, true, kPacketLoss);
}
TEST(FecControllerTest, MaintainFecOffForMediumBandwidth) {
auto states = CreateFecController(false);
TEST(FecControllerPlrBasedTest, MaintainFecOffForMediumBandwidth) {
auto states = CreateFecControllerPlrBased(false);
constexpr float kPacketLoss =
kEnablingPacketLossAtLowBw * 0.49f + kEnablingPacketLossAtHighBw * 0.51f;
UpdateNetworkMetrics(
@ -182,23 +184,23 @@ TEST(FecControllerTest, MaintainFecOffForMediumBandwidth) {
CheckDecision(&states, false, kPacketLoss);
}
TEST(FecControllerTest, EnableFecForLowBandwidth) {
auto states = CreateFecController(false);
TEST(FecControllerPlrBasedTest, EnableFecForLowBandwidth) {
auto states = CreateFecControllerPlrBased(false);
UpdateNetworkMetrics(&states, rtc::Optional<int>(kEnablingBandwidthLow),
rtc::Optional<float>(kEnablingPacketLossAtLowBw));
CheckDecision(&states, true, kEnablingPacketLossAtLowBw);
}
TEST(FecControllerTest, MaintainFecOffForLowBandwidth) {
auto states = CreateFecController(false);
TEST(FecControllerPlrBasedTest, MaintainFecOffForLowBandwidth) {
auto states = CreateFecControllerPlrBased(false);
constexpr float kPacketLoss = kEnablingPacketLossAtLowBw * 0.99f;
UpdateNetworkMetrics(&states, rtc::Optional<int>(kEnablingBandwidthLow),
rtc::Optional<float>(kPacketLoss));
CheckDecision(&states, false, kPacketLoss);
}
TEST(FecControllerTest, MaintainFecOffForVeryLowBandwidth) {
auto states = CreateFecController(false);
TEST(FecControllerPlrBasedTest, MaintainFecOffForVeryLowBandwidth) {
auto states = CreateFecControllerPlrBased(false);
// Below |kEnablingBandwidthLow|, no packet loss fraction can cause FEC to
// turn on.
UpdateNetworkMetrics(&states, rtc::Optional<int>(kEnablingBandwidthLow - 1),
@ -206,34 +208,35 @@ TEST(FecControllerTest, MaintainFecOffForVeryLowBandwidth) {
CheckDecision(&states, false, 1.0);
}
TEST(FecControllerTest, DisableFecForHighBandwidth) {
auto states = CreateFecController(true);
TEST(FecControllerPlrBasedTest, DisableFecForHighBandwidth) {
auto states = CreateFecControllerPlrBased(true);
UpdateNetworkMetrics(&states, rtc::Optional<int>(kDisablingBandwidthHigh),
rtc::Optional<float>(kDisablingPacketLossAtHighBw));
CheckDecision(&states, false, kDisablingPacketLossAtHighBw);
}
TEST(FecControllerTest, MaintainFecOnForHighBandwidth) {
auto states = CreateFecController(true);
TEST(FecControllerPlrBasedTest, MaintainFecOnForHighBandwidth) {
auto states = CreateFecControllerPlrBased(true);
constexpr float kPacketLoss = kDisablingPacketLossAtHighBw * 1.01f;
UpdateNetworkMetrics(&states, rtc::Optional<int>(kDisablingBandwidthHigh),
rtc::Optional<float>(kPacketLoss));
CheckDecision(&states, true, kPacketLoss);
}
TEST(FecControllerTest, DisableFecOnMediumBandwidth) {
auto states = CreateFecController(true);
TEST(FecControllerPlrBasedTest, DisableFecOnMediumBandwidth) {
auto states = CreateFecControllerPlrBased(true);
constexpr float kPacketLoss =
(kDisablingPacketLossAtLowBw + kDisablingPacketLossAtHighBw) / 2.0f;
UpdateNetworkMetrics(
&states, rtc::Optional<int>(
(kDisablingBandwidthHigh + kDisablingBandwidthLow) / 2),
&states,
rtc::Optional<int>((kDisablingBandwidthHigh + kDisablingBandwidthLow) /
2),
rtc::Optional<float>(kPacketLoss));
CheckDecision(&states, false, kPacketLoss);
}
TEST(FecControllerTest, MaintainFecOnForMediumBandwidth) {
auto states = CreateFecController(true);
TEST(FecControllerPlrBasedTest, MaintainFecOnForMediumBandwidth) {
auto states = CreateFecControllerPlrBased(true);
constexpr float kPacketLoss = kDisablingPacketLossAtLowBw * 0.51f +
kDisablingPacketLossAtHighBw * 0.49f;
UpdateNetworkMetrics(
@ -243,15 +246,15 @@ TEST(FecControllerTest, MaintainFecOnForMediumBandwidth) {
CheckDecision(&states, true, kPacketLoss);
}
TEST(FecControllerTest, DisableFecForLowBandwidth) {
auto states = CreateFecController(true);
TEST(FecControllerPlrBasedTest, DisableFecForLowBandwidth) {
auto states = CreateFecControllerPlrBased(true);
UpdateNetworkMetrics(&states, rtc::Optional<int>(kDisablingBandwidthLow),
rtc::Optional<float>(kDisablingPacketLossAtLowBw));
CheckDecision(&states, false, kDisablingPacketLossAtLowBw);
}
TEST(FecControllerTest, DisableFecForVeryLowBandwidth) {
auto states = CreateFecController(true);
TEST(FecControllerPlrBasedTest, DisableFecForVeryLowBandwidth) {
auto states = CreateFecControllerPlrBased(true);
// Below |kEnablingBandwidthLow|, any packet loss fraction can cause FEC to
// turn off.
UpdateNetworkMetrics(&states, rtc::Optional<int>(kDisablingBandwidthLow - 1),
@ -259,7 +262,7 @@ TEST(FecControllerTest, DisableFecForVeryLowBandwidth) {
CheckDecision(&states, false, 1.0);
}
TEST(FecControllerTest, CheckBehaviorOnChangingNetworkMetrics) {
TEST(FecControllerPlrBasedTest, CheckBehaviorOnChangingNetworkMetrics) {
// In this test, we let the network metrics to traverse from 1 to 5.
// packet-loss ^ 1 | |
// | | 2|
@ -268,7 +271,7 @@ TEST(FecControllerTest, CheckBehaviorOnChangingNetworkMetrics) {
// | \_________
// |---------5-------> bandwidth
auto states = CreateFecController(true);
auto states = CreateFecControllerPlrBased(true);
UpdateNetworkMetrics(&states, rtc::Optional<int>(kDisablingBandwidthLow - 1),
rtc::Optional<float>(1.0));
CheckDecision(&states, false, 1.0);
@ -292,7 +295,7 @@ TEST(FecControllerTest, CheckBehaviorOnChangingNetworkMetrics) {
CheckDecision(&states, false, 0.0);
}
TEST(FecControllerTest, CheckBehaviorOnSpecialCurves) {
TEST(FecControllerPlrBasedTest, 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.
@ -306,15 +309,16 @@ TEST(FecControllerTest, CheckBehaviorOnSpecialCurves) {
constexpr int kEnablingBandwidthHigh = kEnablingBandwidthLow;
constexpr float kDisablingPacketLossAtLowBw = kDisablingPacketLossAtHighBw;
FecControllerStates states;
FecControllerPlrBasedTestStates states;
std::unique_ptr<MockSmoothingFilter> mock_smoothing_filter(
new NiceMock<MockSmoothingFilter>());
states.packet_loss_smoother = mock_smoothing_filter.get();
using Threshold = FecController::Config::Threshold;
states.controller.reset(new FecController(
FecController::Config(
true, Threshold(kEnablingBandwidthLow, kEnablingPacketLossAtLowBw,
kEnablingBandwidthHigh, kEnablingPacketLossAtHighBw),
using Threshold = FecControllerPlrBased::Config::Threshold;
states.controller.reset(new FecControllerPlrBased(
FecControllerPlrBased::Config(
true,
Threshold(kEnablingBandwidthLow, kEnablingPacketLossAtLowBw,
kEnablingBandwidthHigh, kEnablingPacketLossAtHighBw),
Threshold(kDisablingBandwidthLow, kDisablingPacketLossAtLowBw,
kDisablingBandwidthHigh, kDisablingPacketLossAtHighBw),
0, nullptr),
@ -344,15 +348,15 @@ TEST(FecControllerTest, CheckBehaviorOnSpecialCurves) {
}
#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
TEST(FecControllerDeathTest, InvalidConfig) {
FecControllerStates states;
TEST(FecControllerPlrBasedDeathTest, InvalidConfig) {
FecControllerPlrBasedTestStates states;
std::unique_ptr<MockSmoothingFilter> mock_smoothing_filter(
new NiceMock<MockSmoothingFilter>());
states.packet_loss_smoother = mock_smoothing_filter.get();
using Threshold = FecController::Config::Threshold;
using Threshold = FecControllerPlrBased::Config::Threshold;
EXPECT_DEATH(
states.controller.reset(new FecController(
FecController::Config(
states.controller.reset(new FecControllerPlrBased(
FecControllerPlrBased::Config(
true,
Threshold(kDisablingBandwidthLow - 1, kEnablingPacketLossAtLowBw,
kEnablingBandwidthHigh, kEnablingPacketLossAtHighBw),

View File

@ -0,0 +1,138 @@
/*
* 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 "webrtc/modules/audio_coding/audio_network_adaptor/fec_controller_rplr_based.h"
#include <limits>
#include <utility>
#include "webrtc/base/checks.h"
namespace webrtc {
FecControllerRplrBased::Config::Threshold::Threshold(
int low_bandwidth_bps,
float low_bandwidth_recoverable_packet_loss,
int high_bandwidth_bps,
float high_bandwidth_recoverable_packet_loss)
: low_bandwidth_bps(low_bandwidth_bps),
low_bandwidth_recoverable_packet_loss(
low_bandwidth_recoverable_packet_loss),
high_bandwidth_bps(high_bandwidth_bps),
high_bandwidth_recoverable_packet_loss(
high_bandwidth_recoverable_packet_loss) {}
FecControllerRplrBased::Config::Config(bool initial_fec_enabled,
const Threshold& fec_enabling_threshold,
const Threshold& fec_disabling_threshold,
int time_constant_ms,
const Clock* clock)
: initial_fec_enabled(initial_fec_enabled),
fec_enabling_threshold(fec_enabling_threshold),
fec_disabling_threshold(fec_disabling_threshold),
time_constant_ms(time_constant_ms),
clock(clock) {}
FecControllerRplrBased::FecControllerRplrBased(const Config& config)
: config_(config),
fec_enabled_(config.initial_fec_enabled),
fec_enabling_threshold_info_(config_.fec_enabling_threshold),
fec_disabling_threshold_info_(config_.fec_disabling_threshold) {
RTC_DCHECK_LE(fec_enabling_threshold_info_.slope, 0);
RTC_DCHECK_LE(fec_enabling_threshold_info_.slope, 0);
RTC_DCHECK_LE(
GetPacketLossThreshold(config_.fec_enabling_threshold.low_bandwidth_bps,
config_.fec_disabling_threshold,
fec_disabling_threshold_info_),
config_.fec_enabling_threshold.low_bandwidth_recoverable_packet_loss);
RTC_DCHECK_LE(
GetPacketLossThreshold(config_.fec_enabling_threshold.high_bandwidth_bps,
config_.fec_disabling_threshold,
fec_disabling_threshold_info_),
config_.fec_enabling_threshold.high_bandwidth_recoverable_packet_loss);
}
FecControllerRplrBased::~FecControllerRplrBased() = default;
void FecControllerRplrBased::UpdateNetworkMetrics(
const NetworkMetrics& network_metrics) {
if (network_metrics.uplink_bandwidth_bps)
uplink_bandwidth_bps_ = network_metrics.uplink_bandwidth_bps;
if (network_metrics.uplink_recoverable_packet_loss_fraction) {
uplink_recoverable_packet_loss_ =
network_metrics.uplink_recoverable_packet_loss_fraction;
}
}
void FecControllerRplrBased::MakeDecision(
AudioNetworkAdaptor::EncoderRuntimeConfig* config) {
RTC_DCHECK(!config->enable_fec);
RTC_DCHECK(!config->uplink_packet_loss_fraction);
fec_enabled_ = fec_enabled_ ? !FecDisablingDecision() : FecEnablingDecision();
config->enable_fec = rtc::Optional<bool>(fec_enabled_);
config->uplink_packet_loss_fraction = rtc::Optional<float>(
uplink_recoverable_packet_loss_ ? *uplink_recoverable_packet_loss_ : 0.0);
}
FecControllerRplrBased::ThresholdInfo::ThresholdInfo(
const Config::Threshold& threshold) {
int bandwidth_diff_bps =
threshold.high_bandwidth_bps - threshold.low_bandwidth_bps;
float recoverable_packet_loss_diff =
threshold.high_bandwidth_recoverable_packet_loss -
threshold.low_bandwidth_recoverable_packet_loss;
slope = bandwidth_diff_bps == 0
? 0.0
: recoverable_packet_loss_diff / bandwidth_diff_bps;
offset = threshold.low_bandwidth_recoverable_packet_loss -
slope * threshold.low_bandwidth_bps;
}
float FecControllerRplrBased::GetPacketLossThreshold(
int bandwidth_bps,
const Config::Threshold& threshold,
const ThresholdInfo& threshold_info) const {
if (bandwidth_bps < threshold.low_bandwidth_bps) {
return std::numeric_limits<float>::max();
} else if (bandwidth_bps >= threshold.high_bandwidth_bps) {
return threshold.high_bandwidth_recoverable_packet_loss;
} else {
float rc = threshold_info.offset + threshold_info.slope * bandwidth_bps;
RTC_DCHECK_LE(rc, threshold.low_bandwidth_recoverable_packet_loss);
RTC_DCHECK_GE(rc, threshold.high_bandwidth_recoverable_packet_loss);
return rc;
}
}
bool FecControllerRplrBased::FecEnablingDecision() const {
if (!uplink_bandwidth_bps_ || !uplink_recoverable_packet_loss_) {
return false;
} else {
return *uplink_recoverable_packet_loss_ >=
GetPacketLossThreshold(*uplink_bandwidth_bps_,
config_.fec_enabling_threshold,
fec_enabling_threshold_info_);
}
}
bool FecControllerRplrBased::FecDisablingDecision() const {
if (!uplink_bandwidth_bps_ || !uplink_recoverable_packet_loss_) {
return false;
} else {
return *uplink_recoverable_packet_loss_ <=
GetPacketLossThreshold(*uplink_bandwidth_bps_,
config_.fec_disabling_threshold,
fec_disabling_threshold_info_);
}
}
} // namespace webrtc

View File

@ -0,0 +1,108 @@
/*
* 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.
*/
#ifndef WEBRTC_MODULES_AUDIO_CODING_AUDIO_NETWORK_ADAPTOR_FEC_CONTROLLER_RPLR_BASED_H_
#define WEBRTC_MODULES_AUDIO_CODING_AUDIO_NETWORK_ADAPTOR_FEC_CONTROLLER_RPLR_BASED_H_
#include <memory>
#include "webrtc/base/constructormagic.h"
#include "webrtc/modules/audio_coding/audio_network_adaptor/controller.h"
#include "webrtc/system_wrappers/include/clock.h"
namespace webrtc {
class FecControllerRplrBased final : public Controller {
public:
struct Config {
struct Threshold {
// Threshold defines a curve in the bandwidth/packet-loss domain. The
// curve is characterized by the two conjunction points: A and B.
//
// recoverable
// packet ^ |
// loss | A |
// | \ A: (low_bandwidth_bps,
// | \ low_bandwidth_recoverable_packet_loss)
// | \ B: (high_bandwidth_bps,
// | \ high_bandwidth_recoverable_packet_loss)
// | B \________
// |---------------> bandwidth
Threshold(int low_bandwidth_bps,
float low_bandwidth_recoverable_packet_loss,
int high_bandwidth_bps,
float high_bandwidth_recoverable_packet_loss);
int low_bandwidth_bps;
float low_bandwidth_recoverable_packet_loss;
int high_bandwidth_bps;
float high_bandwidth_recoverable_packet_loss;
};
// |fec_enabling_threshold| defines a curve, above which FEC should be
// enabled. |fec_disabling_threshold| defines a curve, under which FEC
// should be disabled. See below
//
// recoverable
// packet-loss ^ | |
// | | | FEC
// | \ \ ON
// | FEC \ \_______ fec_enabling_threshold
// | OFF \_________ fec_disabling_threshold
// |-----------------> bandwidth
Config(bool initial_fec_enabled,
const Threshold& fec_enabling_threshold,
const Threshold& fec_disabling_threshold,
int time_constant_ms,
const Clock* clock);
bool initial_fec_enabled;
Threshold fec_enabling_threshold;
Threshold fec_disabling_threshold;
int time_constant_ms;
const Clock* clock;
};
explicit FecControllerRplrBased(const Config& config);
~FecControllerRplrBased() override;
void UpdateNetworkMetrics(const NetworkMetrics& network_metrics) override;
void MakeDecision(AudioNetworkAdaptor::EncoderRuntimeConfig* config) override;
private:
// Characterize Threshold with:
// recoverable_packet_loss = slope * bandwidth + offset.
struct ThresholdInfo {
explicit ThresholdInfo(const Config::Threshold& threshold);
float slope;
float offset;
};
float GetPacketLossThreshold(int bandwidth_bps,
const Config::Threshold& threshold,
const ThresholdInfo& threshold_info) const;
bool FecEnablingDecision() const;
bool FecDisablingDecision() const;
const Config config_;
bool fec_enabled_;
rtc::Optional<int> uplink_bandwidth_bps_;
rtc::Optional<float> uplink_recoverable_packet_loss_;
const ThresholdInfo fec_enabling_threshold_info_;
const ThresholdInfo fec_disabling_threshold_info_;
RTC_DISALLOW_COPY_AND_ASSIGN(FecControllerRplrBased);
};
} // namespace webrtc
#endif // WEBRTC_MODULES_AUDIO_CODING_AUDIO_NETWORK_ADAPTOR_FEC_CONTROLLER_RPLR_BASED_H_

View File

@ -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