Adding FecController to audio network adaptor.
BUG=webrtc:6303 Review-Url: https://codereview.webrtc.org/2337103006 Cr-Commit-Position: refs/heads/master@{#14351}
This commit is contained in:
parent
1c6d3f7eae
commit
d0ede4493e
@ -243,6 +243,7 @@ if (rtc_include_tests) {
|
||||
"audio_coding/audio_network_adaptor/channel_controller_unittest.cc",
|
||||
"audio_coding/audio_network_adaptor/controller_manager_unittest.cc",
|
||||
"audio_coding/audio_network_adaptor/dtx_controller_unittest.cc",
|
||||
"audio_coding/audio_network_adaptor/fec_controller_unittest.cc",
|
||||
"audio_coding/audio_network_adaptor/frame_length_controller_unittest.cc",
|
||||
"audio_coding/audio_network_adaptor/mock/mock_controller.h",
|
||||
"audio_coding/audio_network_adaptor/mock/mock_controller_manager.h",
|
||||
|
||||
@ -711,6 +711,8 @@ source_set("audio_network_adaptor") {
|
||||
"audio_network_adaptor/controller_manager.h",
|
||||
"audio_network_adaptor/dtx_controller.cc",
|
||||
"audio_network_adaptor/dtx_controller.h",
|
||||
"audio_network_adaptor/fec_controller.cc",
|
||||
"audio_network_adaptor/fec_controller.h",
|
||||
"audio_network_adaptor/frame_length_controller.cc",
|
||||
"audio_network_adaptor/frame_length_controller.h",
|
||||
"audio_network_adaptor/include/audio_network_adaptor.h",
|
||||
|
||||
@ -24,6 +24,8 @@
|
||||
'controller_manager.h',
|
||||
'dtx_controller.h',
|
||||
'dtx_controller.cc',
|
||||
'fec_controller.h',
|
||||
'fec_controller.cc',
|
||||
'frame_length_controller.cc',
|
||||
'frame_length_controller.h',
|
||||
'include/audio_network_adaptor.h',
|
||||
|
||||
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/modules/audio_coding/audio_network_adaptor/fec_controller.h"
|
||||
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
FecController::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,
|
||||
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)
|
||||
: config_(config),
|
||||
fec_enabled_(config.initial_fec_enabled),
|
||||
packet_loss_smoothed_(
|
||||
new SmoothingFilterImpl(config_.time_constant_ms, config_.clock)),
|
||||
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_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_packet_loss);
|
||||
}
|
||||
|
||||
FecController::FecController(const Config& config,
|
||||
std::unique_ptr<SmoothingFilter> smoothing_filter)
|
||||
: FecController(config) {
|
||||
packet_loss_smoothed_ = std::move(smoothing_filter);
|
||||
}
|
||||
|
||||
FecController::~FecController() = default;
|
||||
|
||||
void FecController::MakeDecision(
|
||||
const NetworkMetrics& metrics,
|
||||
AudioNetworkAdaptor::EncoderRuntimeConfig* config) {
|
||||
RTC_DCHECK(!config->enable_fec);
|
||||
RTC_DCHECK(!config->uplink_packet_loss_fraction);
|
||||
|
||||
if (metrics.uplink_packet_loss_fraction)
|
||||
packet_loss_smoothed_->AddSample(*metrics.uplink_packet_loss_fraction);
|
||||
|
||||
fec_enabled_ = fec_enabled_ ? !FecDisablingDecision(metrics)
|
||||
: FecEnablingDecision(metrics);
|
||||
|
||||
config->enable_fec = rtc::Optional<bool>(fec_enabled_);
|
||||
|
||||
auto packet_loss_fraction = packet_loss_smoothed_->GetAverage();
|
||||
config->uplink_packet_loss_fraction = rtc::Optional<float>(
|
||||
packet_loss_fraction ? *packet_loss_fraction : 0.0);
|
||||
}
|
||||
|
||||
FecController::ThresholdInfo::ThresholdInfo(
|
||||
const Config::Threshold& threshold) {
|
||||
int bandwidth_diff_bps =
|
||||
threshold.high_bandwidth_bps - threshold.low_bandwidth_bps;
|
||||
float packet_loss_diff = threshold.high_bandwidth_packet_loss -
|
||||
threshold.low_bandwidth_packet_loss;
|
||||
slope = bandwidth_diff_bps == 0 ? 0.0 : packet_loss_diff / bandwidth_diff_bps;
|
||||
offset =
|
||||
threshold.low_bandwidth_packet_loss - slope * threshold.low_bandwidth_bps;
|
||||
}
|
||||
|
||||
float FecController::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();
|
||||
if (bandwidth_bps >= threshold.high_bandwidth_bps)
|
||||
return threshold.high_bandwidth_packet_loss;
|
||||
return threshold_info.offset + threshold_info.slope * bandwidth_bps;
|
||||
}
|
||||
|
||||
bool FecController::FecEnablingDecision(const NetworkMetrics& metrics) const {
|
||||
if (!metrics.uplink_bandwidth_bps)
|
||||
return false;
|
||||
|
||||
auto packet_loss = packet_loss_smoothed_->GetAverage();
|
||||
if (!packet_loss)
|
||||
return false;
|
||||
|
||||
return *packet_loss >= GetPacketLossThreshold(*metrics.uplink_bandwidth_bps,
|
||||
config_.fec_enabling_threshold,
|
||||
fec_enabling_threshold_info_);
|
||||
}
|
||||
|
||||
bool FecController::FecDisablingDecision(const NetworkMetrics& metrics) const {
|
||||
if (!metrics.uplink_bandwidth_bps)
|
||||
return false;
|
||||
|
||||
auto packet_loss = packet_loss_smoothed_->GetAverage();
|
||||
if (!packet_loss)
|
||||
return false;
|
||||
|
||||
return *packet_loss <= GetPacketLossThreshold(*metrics.uplink_bandwidth_bps,
|
||||
config_.fec_disabling_threshold,
|
||||
fec_disabling_threshold_info_);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_AUDIO_NETWORK_ADAPTOR_FEC_CONTROLLER_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_AUDIO_NETWORK_ADAPTOR_FEC_CONTROLLER_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "webrtc/base/constructormagic.h"
|
||||
#include "webrtc/modules/audio_coding/audio_network_adaptor/controller.h"
|
||||
#include "webrtc/modules/audio_coding/audio_network_adaptor/smoothing_filter.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class FecController 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.
|
||||
//
|
||||
// packet ^ |
|
||||
// loss | A|
|
||||
// | \ A: (low_bandwidth_bps, low_bandwidth_packet_loss)
|
||||
// | \ B: (high_bandwidth_bps, high_bandwidth_packet_loss)
|
||||
// | B\________
|
||||
// |---------------> bandwidth
|
||||
Threshold(int low_bandwidth_bps,
|
||||
float low_bandwidth_packet_loss,
|
||||
int high_bandwidth_bps,
|
||||
float high_bandwidth_packet_loss);
|
||||
int low_bandwidth_bps;
|
||||
float low_bandwidth_packet_loss;
|
||||
int high_bandwidth_bps;
|
||||
float high_bandwidth_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
|
||||
//
|
||||
// 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,
|
||||
Clock* clock);
|
||||
bool initial_fec_enabled;
|
||||
Threshold fec_enabling_threshold;
|
||||
Threshold fec_disabling_threshold;
|
||||
int time_constant_ms;
|
||||
Clock* clock;
|
||||
};
|
||||
|
||||
explicit FecController(const Config& config);
|
||||
|
||||
// Dependency injection for testing.
|
||||
FecController(const Config& config,
|
||||
std::unique_ptr<SmoothingFilter> smoothing_filter);
|
||||
|
||||
~FecController() override;
|
||||
|
||||
void MakeDecision(const NetworkMetrics& metrics,
|
||||
AudioNetworkAdaptor::EncoderRuntimeConfig* config) override;
|
||||
|
||||
private:
|
||||
// Characterize Threshold with 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 NetworkMetrics& metrics) const;
|
||||
bool FecDisablingDecision(const NetworkMetrics& metrics) const;
|
||||
|
||||
const Config config_;
|
||||
bool fec_enabled_;
|
||||
std::unique_ptr<SmoothingFilter> packet_loss_smoothed_;
|
||||
|
||||
const ThresholdInfo fec_enabling_threshold_info_;
|
||||
const ThresholdInfo fec_disabling_threshold_info_;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(FecController);
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_AUDIO_NETWORK_ADAPTOR_FEC_CONTROLLER_H_
|
||||
@ -0,0 +1,312 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "webrtc/modules/audio_coding/audio_network_adaptor/fec_controller.h"
|
||||
#include "webrtc/modules/audio_coding/audio_network_adaptor/mock/mock_smoothing_filter.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
using ::testing::NiceMock;
|
||||
using ::testing::Return;
|
||||
using ::testing::_;
|
||||
|
||||
namespace {
|
||||
|
||||
// The test uses the following settings:
|
||||
//
|
||||
// packet-loss ^ | |
|
||||
// | A| C| FEC
|
||||
// | \ \ ON
|
||||
// | FEC \ D\_______
|
||||
// | OFF B\_________
|
||||
// |-----------------> bandwidth
|
||||
//
|
||||
// A : (kDisablingBandwidthLow, kDisablingPacketLossAtLowBw)
|
||||
// B : (kDisablingBandwidthHigh, kDisablingPacketLossAtHighBw)
|
||||
// C : (kEnablingBandwidthLow, kEnablingPacketLossAtLowBw)
|
||||
// D : (kEnablingBandwidthHigh, kEnablingPacketLossAtHighBw)
|
||||
|
||||
constexpr int kDisablingBandwidthLow = 15000;
|
||||
constexpr float kDisablingPacketLossAtLowBw = 0.08f;
|
||||
constexpr int kDisablingBandwidthHigh = 64000;
|
||||
constexpr float kDisablingPacketLossAtHighBw = 0.01f;
|
||||
constexpr int kEnablingBandwidthLow = 17000;
|
||||
constexpr float kEnablingPacketLossAtLowBw = 0.1f;
|
||||
constexpr int kEnablingBandwidthHigh = 64000;
|
||||
constexpr float kEnablingPacketLossAtHighBw = 0.05f;
|
||||
|
||||
struct FecControllerStates {
|
||||
std::unique_ptr<FecController> controller;
|
||||
MockSmoothingFilter* packet_loss_smoothed;
|
||||
};
|
||||
|
||||
FecControllerStates CreateFecController(bool initial_fec_enabled) {
|
||||
FecControllerStates states;
|
||||
std::unique_ptr<MockSmoothingFilter> mock_smoothing_filter(
|
||||
new NiceMock<MockSmoothingFilter>());
|
||||
states.packet_loss_smoothed = mock_smoothing_filter.get();
|
||||
EXPECT_CALL(*states.packet_loss_smoothed, Die());
|
||||
using Threshold = FecController::Config::Threshold;
|
||||
states.controller.reset(new FecController(
|
||||
FecController::Config(
|
||||
initial_fec_enabled,
|
||||
Threshold(kEnablingBandwidthLow, kEnablingPacketLossAtLowBw,
|
||||
kEnablingBandwidthHigh, kEnablingPacketLossAtHighBw),
|
||||
Threshold(kDisablingBandwidthLow, kDisablingPacketLossAtLowBw,
|
||||
kDisablingBandwidthHigh, kDisablingPacketLossAtHighBw),
|
||||
0, nullptr),
|
||||
std::move(mock_smoothing_filter)));
|
||||
return states;
|
||||
}
|
||||
|
||||
// Checks that the FEC decision given by |states->controller->MakeDecision|
|
||||
// matches |expected_enable_fec|. It also checks that
|
||||
// |uplink_packet_loss_fraction| returned by |states->controller->MakeDecision|
|
||||
// matches |uplink_packet_loss|.
|
||||
void CheckDecision(FecControllerStates* states,
|
||||
const rtc::Optional<int>& uplink_bandwidth_bps,
|
||||
const rtc::Optional<float>& uplink_packet_loss,
|
||||
bool expected_enable_fec) {
|
||||
Controller::NetworkMetrics metrics;
|
||||
metrics.uplink_bandwidth_bps = uplink_bandwidth_bps;
|
||||
metrics.uplink_packet_loss_fraction = uplink_packet_loss;
|
||||
|
||||
if (uplink_packet_loss) {
|
||||
// Check that smoothing filter is updated.
|
||||
EXPECT_CALL(*states->packet_loss_smoothed, AddSample(*uplink_packet_loss));
|
||||
}
|
||||
|
||||
EXPECT_CALL(*states->packet_loss_smoothed, GetAverage())
|
||||
.WillRepeatedly(Return(uplink_packet_loss));
|
||||
|
||||
AudioNetworkAdaptor::EncoderRuntimeConfig config;
|
||||
states->controller->MakeDecision(metrics, &config);
|
||||
EXPECT_EQ(rtc::Optional<bool>(expected_enable_fec), config.enable_fec);
|
||||
|
||||
// Check that |config.uplink_packet_loss_fraction| is properly filled.
|
||||
EXPECT_EQ(uplink_packet_loss ? uplink_packet_loss : rtc::Optional<float>(0.0),
|
||||
config.uplink_packet_loss_fraction);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(FecControllerTest, OutputInitValueWhenUplinkBandwidthUnknown) {
|
||||
constexpr bool kInitialFecEnabled = true;
|
||||
auto states = CreateFecController(kInitialFecEnabled);
|
||||
// Let uplink packet loss fraction be so low that would cause FEC to turn off
|
||||
// if uplink bandwidth was known.
|
||||
CheckDecision(&states, rtc::Optional<int>(),
|
||||
rtc::Optional<float>(kDisablingPacketLossAtHighBw),
|
||||
kInitialFecEnabled);
|
||||
}
|
||||
|
||||
TEST(FecControllerTest, OutputInitValueWhenUplinkPacketLossFractionUnknown) {
|
||||
constexpr bool kInitialFecEnabled = true;
|
||||
auto states = CreateFecController(kInitialFecEnabled);
|
||||
// Let uplink bandwidth be so low that would cause FEC to turn off if uplink
|
||||
// bandwidth packet loss fraction was known.
|
||||
CheckDecision(&states, rtc::Optional<int>(kDisablingBandwidthLow - 1),
|
||||
rtc::Optional<float>(), kInitialFecEnabled);
|
||||
}
|
||||
|
||||
TEST(FecControllerTest, EnableFecForHighBandwidth) {
|
||||
auto states = CreateFecController(false);
|
||||
CheckDecision(&states, rtc::Optional<int>(kEnablingBandwidthHigh),
|
||||
rtc::Optional<float>(kEnablingPacketLossAtHighBw), true);
|
||||
}
|
||||
|
||||
TEST(FecControllerTest, MaintainFecOffForHighBandwidth) {
|
||||
auto states = CreateFecController(false);
|
||||
CheckDecision(&states, rtc::Optional<int>(kEnablingBandwidthHigh),
|
||||
rtc::Optional<float>(kEnablingPacketLossAtHighBw * 0.99f),
|
||||
false);
|
||||
}
|
||||
|
||||
TEST(FecControllerTest, EnableFecForMediumBandwidth) {
|
||||
auto states = CreateFecController(false);
|
||||
CheckDecision(
|
||||
&states,
|
||||
rtc::Optional<int>((kEnablingBandwidthHigh + kEnablingBandwidthLow) / 2),
|
||||
rtc::Optional<float>(
|
||||
(kEnablingPacketLossAtLowBw + kEnablingPacketLossAtHighBw) / 2.0),
|
||||
true);
|
||||
}
|
||||
|
||||
TEST(FecControllerTest, MaintainFecOffForMediumBandwidth) {
|
||||
auto states = CreateFecController(false);
|
||||
CheckDecision(
|
||||
&states,
|
||||
rtc::Optional<int>((kEnablingBandwidthHigh + kEnablingBandwidthLow) / 2),
|
||||
rtc::Optional<float>(kEnablingPacketLossAtLowBw * 0.49f +
|
||||
kEnablingPacketLossAtHighBw * 0.51f),
|
||||
false);
|
||||
}
|
||||
|
||||
TEST(FecControllerTest, EnableFecForLowBandwidth) {
|
||||
auto states = CreateFecController(false);
|
||||
CheckDecision(&states, rtc::Optional<int>(kEnablingBandwidthLow),
|
||||
rtc::Optional<float>(kEnablingPacketLossAtLowBw), true);
|
||||
}
|
||||
|
||||
TEST(FecControllerTest, MaintainFecOffForLowBandwidth) {
|
||||
auto states = CreateFecController(false);
|
||||
CheckDecision(&states, rtc::Optional<int>(kEnablingBandwidthLow),
|
||||
rtc::Optional<float>(kEnablingPacketLossAtLowBw * 0.99f),
|
||||
false);
|
||||
}
|
||||
|
||||
TEST(FecControllerTest, MaintainFecOffForVeryLowBandwidth) {
|
||||
auto states = CreateFecController(false);
|
||||
// Below |kEnablingBandwidthLow|, no packet loss fraction can cause FEC to
|
||||
// turn on.
|
||||
CheckDecision(&states, rtc::Optional<int>(kEnablingBandwidthLow - 1),
|
||||
rtc::Optional<float>(1.0), false);
|
||||
}
|
||||
|
||||
TEST(FecControllerTest, DisableFecForHighBandwidth) {
|
||||
auto states = CreateFecController(true);
|
||||
CheckDecision(&states, rtc::Optional<int>(kDisablingBandwidthHigh),
|
||||
rtc::Optional<float>(kDisablingPacketLossAtHighBw), false);
|
||||
}
|
||||
|
||||
TEST(FecControllerTest, MaintainFecOnForHighBandwidth) {
|
||||
auto states = CreateFecController(true);
|
||||
CheckDecision(&states, rtc::Optional<int>(kDisablingBandwidthHigh),
|
||||
rtc::Optional<float>(kDisablingPacketLossAtHighBw * 1.01f),
|
||||
true);
|
||||
}
|
||||
|
||||
TEST(FecControllerTest, DisableFecOnMediumBandwidth) {
|
||||
auto states = CreateFecController(true);
|
||||
CheckDecision(
|
||||
&states, rtc::Optional<int>(
|
||||
(kDisablingBandwidthHigh + kDisablingBandwidthLow) / 2),
|
||||
rtc::Optional<float>(
|
||||
(kDisablingPacketLossAtLowBw + kDisablingPacketLossAtHighBw) / 2.0f),
|
||||
false);
|
||||
}
|
||||
|
||||
TEST(FecControllerTest, MaintainFecOnForMediumBandwidth) {
|
||||
auto states = CreateFecController(true);
|
||||
CheckDecision(
|
||||
&states,
|
||||
rtc::Optional<int>((kEnablingBandwidthHigh + kDisablingBandwidthLow) / 2),
|
||||
rtc::Optional<float>(kDisablingPacketLossAtLowBw * 0.51f +
|
||||
kDisablingPacketLossAtHighBw * 0.49f),
|
||||
true);
|
||||
}
|
||||
|
||||
TEST(FecControllerTest, DisableFecForLowBandwidth) {
|
||||
auto states = CreateFecController(true);
|
||||
CheckDecision(&states, rtc::Optional<int>(kDisablingBandwidthLow),
|
||||
rtc::Optional<float>(kDisablingPacketLossAtLowBw), false);
|
||||
}
|
||||
|
||||
TEST(FecControllerTest, DisableFecForVeryLowBandwidth) {
|
||||
auto states = CreateFecController(true);
|
||||
// Below |kEnablingBandwidthLow|, any packet loss fraction can cause FEC to
|
||||
// turn off.
|
||||
CheckDecision(&states, rtc::Optional<int>(kDisablingBandwidthLow - 1),
|
||||
rtc::Optional<float>(1.0), false);
|
||||
}
|
||||
|
||||
TEST(FecControllerTest, CheckBehaviorOnChangingNetworkMetrics) {
|
||||
// In this test, we let the network metrics to traverse from 1 to 5.
|
||||
// packet-loss ^ 1 | |
|
||||
// | | 2|
|
||||
// | \ \ 3
|
||||
// | \4 \_______
|
||||
// | \_________
|
||||
// |---------5-------> bandwidth
|
||||
|
||||
auto states = CreateFecController(true);
|
||||
CheckDecision(&states, rtc::Optional<int>(kDisablingBandwidthLow - 1),
|
||||
rtc::Optional<float>(1.0), false);
|
||||
CheckDecision(&states, rtc::Optional<int>(kEnablingBandwidthLow),
|
||||
rtc::Optional<float>(kEnablingPacketLossAtLowBw * 0.99f),
|
||||
false);
|
||||
CheckDecision(&states, rtc::Optional<int>(kEnablingBandwidthHigh),
|
||||
rtc::Optional<float>(kEnablingPacketLossAtHighBw), true);
|
||||
CheckDecision(&states, rtc::Optional<int>(kDisablingBandwidthHigh),
|
||||
rtc::Optional<float>(kDisablingPacketLossAtHighBw * 1.01f),
|
||||
true);
|
||||
CheckDecision(&states, rtc::Optional<int>(kDisablingBandwidthHigh + 1),
|
||||
rtc::Optional<float>(0.0), false);
|
||||
}
|
||||
|
||||
TEST(FecControllerTest, 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.
|
||||
//
|
||||
// packet-loss ^ | |
|
||||
// | | C|
|
||||
// | | |
|
||||
// | | D|_______
|
||||
// | A|___B______
|
||||
// |-----------------> bandwidth
|
||||
|
||||
constexpr int kEnablingBandwidthHigh = kEnablingBandwidthLow;
|
||||
constexpr float kDisablingPacketLossAtLowBw = kDisablingPacketLossAtHighBw;
|
||||
FecControllerStates states;
|
||||
std::unique_ptr<MockSmoothingFilter> mock_smoothing_filter(
|
||||
new NiceMock<MockSmoothingFilter>());
|
||||
states.packet_loss_smoothed = mock_smoothing_filter.get();
|
||||
EXPECT_CALL(*states.packet_loss_smoothed, Die());
|
||||
using Threshold = FecController::Config::Threshold;
|
||||
states.controller.reset(new FecController(
|
||||
FecController::Config(
|
||||
true, Threshold(kEnablingBandwidthLow, kEnablingPacketLossAtLowBw,
|
||||
kEnablingBandwidthHigh, kEnablingPacketLossAtHighBw),
|
||||
Threshold(kDisablingBandwidthLow, kDisablingPacketLossAtLowBw,
|
||||
kDisablingBandwidthHigh, kDisablingPacketLossAtHighBw),
|
||||
0, nullptr),
|
||||
std::move(mock_smoothing_filter)));
|
||||
|
||||
CheckDecision(&states, rtc::Optional<int>(kDisablingBandwidthLow - 1),
|
||||
rtc::Optional<float>(1.0), false);
|
||||
CheckDecision(&states, rtc::Optional<int>(kEnablingBandwidthLow),
|
||||
rtc::Optional<float>(kEnablingPacketLossAtHighBw * 0.99f),
|
||||
false);
|
||||
CheckDecision(&states, rtc::Optional<int>(kEnablingBandwidthHigh),
|
||||
rtc::Optional<float>(kEnablingPacketLossAtHighBw), true);
|
||||
CheckDecision(&states, rtc::Optional<int>(kDisablingBandwidthHigh),
|
||||
rtc::Optional<float>(kDisablingPacketLossAtHighBw * 1.01f),
|
||||
true);
|
||||
CheckDecision(&states, rtc::Optional<int>(kDisablingBandwidthHigh + 1),
|
||||
rtc::Optional<float>(0.0), false);
|
||||
}
|
||||
|
||||
#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
|
||||
TEST(FecControllerDeathTest, InvalidConfig) {
|
||||
FecControllerStates states;
|
||||
std::unique_ptr<MockSmoothingFilter> mock_smoothing_filter(
|
||||
new NiceMock<MockSmoothingFilter>());
|
||||
states.packet_loss_smoothed = mock_smoothing_filter.get();
|
||||
EXPECT_CALL(*states.packet_loss_smoothed, Die());
|
||||
using Threshold = FecController::Config::Threshold;
|
||||
EXPECT_DEATH(
|
||||
states.controller.reset(new FecController(
|
||||
FecController::Config(
|
||||
true,
|
||||
Threshold(kDisablingBandwidthLow - 1, kEnablingPacketLossAtLowBw,
|
||||
kEnablingBandwidthHigh, kEnablingPacketLossAtHighBw),
|
||||
Threshold(kDisablingBandwidthLow, kDisablingPacketLossAtLowBw,
|
||||
kDisablingBandwidthHigh, kDisablingPacketLossAtHighBw),
|
||||
0, nullptr),
|
||||
std::move(mock_smoothing_filter))),
|
||||
"Check failed");
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace webrtc
|
||||
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_AUDIO_CODING_AUDIO_NETWORK_ADAPTOR_MOCK_MOCK_SMOOTHING_FILTER_H_
|
||||
#define WEBRTC_MODULES_AUDIO_CODING_AUDIO_NETWORK_ADAPTOR_MOCK_MOCK_SMOOTHING_FILTER_H_
|
||||
|
||||
#include "testing/gmock/include/gmock/gmock.h"
|
||||
#include "webrtc/modules/audio_coding/audio_network_adaptor/smoothing_filter.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class MockSmoothingFilter : public SmoothingFilter {
|
||||
public:
|
||||
virtual ~MockSmoothingFilter() { Die(); }
|
||||
MOCK_METHOD0(Die, void());
|
||||
MOCK_METHOD1(AddSample, void(float));
|
||||
MOCK_CONST_METHOD0(GetAverage, rtc::Optional<float>());
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_AUDIO_CODING_AUDIO_NETWORK_ADAPTOR_MOCK_MOCK_SMOOTHING_FILTER_H_
|
||||
Loading…
x
Reference in New Issue
Block a user