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:
@ -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",
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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;
|
||||
@ -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_
|
||||
@ -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),
|
||||
@ -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
|
||||
@ -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_
|
||||
@ -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
|
||||
Reference in New Issue
Block a user