From d0ede4493e89f1e7c3adaf3a2ad66c64578e823e Mon Sep 17 00:00:00 2001 From: minyue Date: Thu, 22 Sep 2016 06:20:50 -0700 Subject: [PATCH] Adding FecController to audio network adaptor. BUG=webrtc:6303 Review-Url: https://codereview.webrtc.org/2337103006 Cr-Commit-Position: refs/heads/master@{#14351} --- webrtc/modules/BUILD.gn | 1 + webrtc/modules/audio_coding/BUILD.gn | 2 + .../audio_network_adaptor.gypi | 2 + .../audio_network_adaptor/fec_controller.cc | 136 ++++++++ .../audio_network_adaptor/fec_controller.h | 105 ++++++ .../fec_controller_unittest.cc | 312 ++++++++++++++++++ .../mock/mock_smoothing_filter.h | 29 ++ 7 files changed, 587 insertions(+) create mode 100644 webrtc/modules/audio_coding/audio_network_adaptor/fec_controller.cc create mode 100644 webrtc/modules/audio_coding/audio_network_adaptor/fec_controller.h create mode 100644 webrtc/modules/audio_coding/audio_network_adaptor/fec_controller_unittest.cc create mode 100644 webrtc/modules/audio_coding/audio_network_adaptor/mock/mock_smoothing_filter.h diff --git a/webrtc/modules/BUILD.gn b/webrtc/modules/BUILD.gn index 11a5ef0973..6b7928f6f5 100644 --- a/webrtc/modules/BUILD.gn +++ b/webrtc/modules/BUILD.gn @@ -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", diff --git a/webrtc/modules/audio_coding/BUILD.gn b/webrtc/modules/audio_coding/BUILD.gn index b55829d786..eaf2e747f8 100644 --- a/webrtc/modules/audio_coding/BUILD.gn +++ b/webrtc/modules/audio_coding/BUILD.gn @@ -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", diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/audio_network_adaptor.gypi b/webrtc/modules/audio_coding/audio_network_adaptor/audio_network_adaptor.gypi index ea3ef13a40..af6ba55c6d 100644 --- a/webrtc/modules/audio_coding/audio_network_adaptor/audio_network_adaptor.gypi +++ b/webrtc/modules/audio_coding/audio_network_adaptor/audio_network_adaptor.gypi @@ -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', diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/fec_controller.cc b/webrtc/modules/audio_coding/audio_network_adaptor/fec_controller.cc new file mode 100644 index 0000000000..fcf19590f6 --- /dev/null +++ b/webrtc/modules/audio_coding/audio_network_adaptor/fec_controller.cc @@ -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 +#include + +#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 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(fec_enabled_); + + auto packet_loss_fraction = packet_loss_smoothed_->GetAverage(); + config->uplink_packet_loss_fraction = rtc::Optional( + 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::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 diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/fec_controller.h b/webrtc/modules/audio_coding/audio_network_adaptor/fec_controller.h new file mode 100644 index 0000000000..17aa65f1e6 --- /dev/null +++ b/webrtc/modules/audio_coding/audio_network_adaptor/fec_controller.h @@ -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 + +#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 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 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_ diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/fec_controller_unittest.cc b/webrtc/modules/audio_coding/audio_network_adaptor/fec_controller_unittest.cc new file mode 100644 index 0000000000..c66482f4e2 --- /dev/null +++ b/webrtc/modules/audio_coding/audio_network_adaptor/fec_controller_unittest.cc @@ -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 + +#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 controller; + MockSmoothingFilter* packet_loss_smoothed; +}; + +FecControllerStates CreateFecController(bool initial_fec_enabled) { + FecControllerStates states; + std::unique_ptr mock_smoothing_filter( + new NiceMock()); + 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& uplink_bandwidth_bps, + const rtc::Optional& 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(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(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(), + rtc::Optional(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(kDisablingBandwidthLow - 1), + rtc::Optional(), kInitialFecEnabled); +} + +TEST(FecControllerTest, EnableFecForHighBandwidth) { + auto states = CreateFecController(false); + CheckDecision(&states, rtc::Optional(kEnablingBandwidthHigh), + rtc::Optional(kEnablingPacketLossAtHighBw), true); +} + +TEST(FecControllerTest, MaintainFecOffForHighBandwidth) { + auto states = CreateFecController(false); + CheckDecision(&states, rtc::Optional(kEnablingBandwidthHigh), + rtc::Optional(kEnablingPacketLossAtHighBw * 0.99f), + false); +} + +TEST(FecControllerTest, EnableFecForMediumBandwidth) { + auto states = CreateFecController(false); + CheckDecision( + &states, + rtc::Optional((kEnablingBandwidthHigh + kEnablingBandwidthLow) / 2), + rtc::Optional( + (kEnablingPacketLossAtLowBw + kEnablingPacketLossAtHighBw) / 2.0), + true); +} + +TEST(FecControllerTest, MaintainFecOffForMediumBandwidth) { + auto states = CreateFecController(false); + CheckDecision( + &states, + rtc::Optional((kEnablingBandwidthHigh + kEnablingBandwidthLow) / 2), + rtc::Optional(kEnablingPacketLossAtLowBw * 0.49f + + kEnablingPacketLossAtHighBw * 0.51f), + false); +} + +TEST(FecControllerTest, EnableFecForLowBandwidth) { + auto states = CreateFecController(false); + CheckDecision(&states, rtc::Optional(kEnablingBandwidthLow), + rtc::Optional(kEnablingPacketLossAtLowBw), true); +} + +TEST(FecControllerTest, MaintainFecOffForLowBandwidth) { + auto states = CreateFecController(false); + CheckDecision(&states, rtc::Optional(kEnablingBandwidthLow), + rtc::Optional(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(kEnablingBandwidthLow - 1), + rtc::Optional(1.0), false); +} + +TEST(FecControllerTest, DisableFecForHighBandwidth) { + auto states = CreateFecController(true); + CheckDecision(&states, rtc::Optional(kDisablingBandwidthHigh), + rtc::Optional(kDisablingPacketLossAtHighBw), false); +} + +TEST(FecControllerTest, MaintainFecOnForHighBandwidth) { + auto states = CreateFecController(true); + CheckDecision(&states, rtc::Optional(kDisablingBandwidthHigh), + rtc::Optional(kDisablingPacketLossAtHighBw * 1.01f), + true); +} + +TEST(FecControllerTest, DisableFecOnMediumBandwidth) { + auto states = CreateFecController(true); + CheckDecision( + &states, rtc::Optional( + (kDisablingBandwidthHigh + kDisablingBandwidthLow) / 2), + rtc::Optional( + (kDisablingPacketLossAtLowBw + kDisablingPacketLossAtHighBw) / 2.0f), + false); +} + +TEST(FecControllerTest, MaintainFecOnForMediumBandwidth) { + auto states = CreateFecController(true); + CheckDecision( + &states, + rtc::Optional((kEnablingBandwidthHigh + kDisablingBandwidthLow) / 2), + rtc::Optional(kDisablingPacketLossAtLowBw * 0.51f + + kDisablingPacketLossAtHighBw * 0.49f), + true); +} + +TEST(FecControllerTest, DisableFecForLowBandwidth) { + auto states = CreateFecController(true); + CheckDecision(&states, rtc::Optional(kDisablingBandwidthLow), + rtc::Optional(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(kDisablingBandwidthLow - 1), + rtc::Optional(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(kDisablingBandwidthLow - 1), + rtc::Optional(1.0), false); + CheckDecision(&states, rtc::Optional(kEnablingBandwidthLow), + rtc::Optional(kEnablingPacketLossAtLowBw * 0.99f), + false); + CheckDecision(&states, rtc::Optional(kEnablingBandwidthHigh), + rtc::Optional(kEnablingPacketLossAtHighBw), true); + CheckDecision(&states, rtc::Optional(kDisablingBandwidthHigh), + rtc::Optional(kDisablingPacketLossAtHighBw * 1.01f), + true); + CheckDecision(&states, rtc::Optional(kDisablingBandwidthHigh + 1), + rtc::Optional(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 mock_smoothing_filter( + new NiceMock()); + 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(kDisablingBandwidthLow - 1), + rtc::Optional(1.0), false); + CheckDecision(&states, rtc::Optional(kEnablingBandwidthLow), + rtc::Optional(kEnablingPacketLossAtHighBw * 0.99f), + false); + CheckDecision(&states, rtc::Optional(kEnablingBandwidthHigh), + rtc::Optional(kEnablingPacketLossAtHighBw), true); + CheckDecision(&states, rtc::Optional(kDisablingBandwidthHigh), + rtc::Optional(kDisablingPacketLossAtHighBw * 1.01f), + true); + CheckDecision(&states, rtc::Optional(kDisablingBandwidthHigh + 1), + rtc::Optional(0.0), false); +} + +#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) +TEST(FecControllerDeathTest, InvalidConfig) { + FecControllerStates states; + std::unique_ptr mock_smoothing_filter( + new NiceMock()); + 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 diff --git a/webrtc/modules/audio_coding/audio_network_adaptor/mock/mock_smoothing_filter.h b/webrtc/modules/audio_coding/audio_network_adaptor/mock/mock_smoothing_filter.h new file mode 100644 index 0000000000..f004d1bc61 --- /dev/null +++ b/webrtc/modules/audio_coding/audio_network_adaptor/mock/mock_smoothing_filter.h @@ -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()); +}; + +} // namespace webrtc + +#endif // WEBRTC_MODULES_AUDIO_CODING_AUDIO_NETWORK_ADAPTOR_MOCK_MOCK_SMOOTHING_FILTER_H_