Update smoothed bitrate.

BUG=webrtc:6443

Review-Url: https://codereview.webrtc.org/2546493002
Cr-Commit-Position: refs/heads/master@{#16036}
This commit is contained in:
michaelt
2017-01-12 10:17:38 -08:00
committed by Commit bot
parent 891419f8e8
commit 566d820e00
21 changed files with 199 additions and 108 deletions

View File

@ -706,6 +706,26 @@ if (rtc_include_tests) {
} }
} }
rtc_source_set("rtc_base_tests_main") {
testonly = true
sources = [
"unittest_main.cc",
]
public_configs = [ ":rtc_base_tests_utils_exported_config" ]
deps = [
":rtc_base_tests_utils",
]
public_deps = [
"//testing/gmock",
"//testing/gtest",
]
if (!build_with_chromium && is_clang) {
# Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
}
}
rtc_source_set("rtc_base_tests_utils") { rtc_source_set("rtc_base_tests_utils") {
testonly = true testonly = true
sources = [ sources = [
@ -731,7 +751,6 @@ if (rtc_include_tests) {
"testechoserver.h", "testechoserver.h",
"testutils.h", "testutils.h",
"timedelta.h", "timedelta.h",
"unittest_main.cc",
] ]
configs += [ ":rtc_base_tests_utils_warnings_config" ] configs += [ ":rtc_base_tests_utils_warnings_config" ]
public_configs = [ ":rtc_base_tests_utils_exported_config" ] public_configs = [ ":rtc_base_tests_utils_exported_config" ]
@ -763,7 +782,7 @@ if (rtc_include_tests) {
] ]
deps = [ deps = [
":rtc_base", ":rtc_base",
":rtc_base_tests_utils", ":rtc_base_tests_main",
"//testing/gtest", "//testing/gtest",
] ]
if (is_win) { if (is_win) {
@ -818,7 +837,7 @@ if (rtc_include_tests) {
] ]
deps = [ deps = [
":rtc_base_approved", ":rtc_base_approved",
":rtc_base_tests_utils", ":rtc_base_tests_main",
] ]
if (!build_with_chromium && is_clang) { if (!build_with_chromium && is_clang) {
# Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
@ -834,7 +853,7 @@ if (rtc_include_tests) {
"weak_ptr_unittest.cc", "weak_ptr_unittest.cc",
] ]
deps = [ deps = [
":rtc_base_tests_utils", ":rtc_base_tests_main",
":rtc_task_queue", ":rtc_task_queue",
] ]
if (!build_with_chromium && is_clang) { if (!build_with_chromium && is_clang) {
@ -851,7 +870,7 @@ if (rtc_include_tests) {
] ]
deps = [ deps = [
":rtc_analytics", ":rtc_analytics",
":rtc_base_tests_utils", ":rtc_base_tests_main",
] ]
} }
@ -912,7 +931,7 @@ if (rtc_include_tests) {
] ]
} }
deps = [ deps = [
":rtc_base_tests_utils", ":rtc_base_tests_main",
] ]
public_deps = [ public_deps = [
":rtc_base", ":rtc_base",

View File

@ -271,7 +271,7 @@ if (rtc_include_tests) {
} }
deps += [ deps += [
"../base:rtc_base_tests_utils", "../base:rtc_base_tests_main",
"//testing/gtest", "//testing/gtest",
] ]
public_deps += [ "//testing/gmock" ] public_deps += [ "//testing/gmock" ]

View File

@ -631,7 +631,7 @@ if (rtc_include_tests) {
# TODO(jschuh): bugs.webrtc.org/1348: fix this warning. # TODO(jschuh): bugs.webrtc.org/1348: fix this warning.
configs += [ "//build/config/compiler:no_size_t_to_int_warning" ] configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
if (!build_with_chromium && is_clang) { if ((!build_with_chromium || is_win) && is_clang) {
# Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163). # Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
suppressed_configs += [ "//build/config/clang:find_bad_constructs" ] suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
} }
@ -648,9 +648,11 @@ if (rtc_include_tests) {
"..:webrtc_common", "..:webrtc_common",
"../api:transport_api", "../api:transport_api",
"../base:rtc_base", # TODO(kjellander): Cleanup in bugs.webrtc.org/3806. "../base:rtc_base", # TODO(kjellander): Cleanup in bugs.webrtc.org/3806.
"../base:rtc_base_tests_utils",
"../common_audio", "../common_audio",
"../common_video", "../common_video",
"../system_wrappers", "../system_wrappers",
"../system_wrappers:metrics_default",
"../test:rtp_test_utils", "../test:rtp_test_utils",
"../test:test_common", "../test:test_common",
"../test:test_main", "../test:test_main",

View File

@ -839,6 +839,7 @@ rtc_static_library("webrtc_opus") {
"../..:webrtc_common", "../..:webrtc_common",
"../../base:rtc_analytics", "../../base:rtc_analytics",
"../../base:rtc_base_approved", "../../base:rtc_base_approved",
"../../common_audio",
"../../system_wrappers", "../../system_wrappers",
] ]
public_deps = [ public_deps = [

View File

@ -648,7 +648,8 @@ int AudioCodingModuleImpl::SendFrequency() const {
void AudioCodingModuleImpl::SetBitRate(int bitrate_bps) { void AudioCodingModuleImpl::SetBitRate(int bitrate_bps) {
rtc::CritScope lock(&acm_crit_sect_); rtc::CritScope lock(&acm_crit_sect_);
if (encoder_stack_) { if (encoder_stack_) {
encoder_stack_->OnReceivedTargetAudioBitrate(bitrate_bps); encoder_stack_->OnReceivedUplinkBandwidth(bitrate_bps,
rtc::Optional<int64_t>());
} }
} }

View File

@ -72,12 +72,16 @@ bool AudioEncoder::EnableAudioNetworkAdaptor(const std::string& config_string,
void AudioEncoder::DisableAudioNetworkAdaptor() {} void AudioEncoder::DisableAudioNetworkAdaptor() {}
void AudioEncoder::OnReceivedUplinkBandwidth(int uplink_bandwidth_bps) {}
void AudioEncoder::OnReceivedUplinkPacketLossFraction( void AudioEncoder::OnReceivedUplinkPacketLossFraction(
float uplink_packet_loss_fraction) {} float uplink_packet_loss_fraction) {}
void AudioEncoder::OnReceivedTargetAudioBitrate(int target_audio_bitrate_bps) {} void AudioEncoder::OnReceivedTargetAudioBitrate(int target_audio_bitrate_bps) {
OnReceivedUplinkBandwidth(target_audio_bitrate_bps, rtc::Optional<int64_t>());
}
void AudioEncoder::OnReceivedUplinkBandwidth(
int target_audio_bitrate_bps,
rtc::Optional<int64_t> probing_interval_ms) {}
void AudioEncoder::OnReceivedRtt(int rtt_ms) {} void AudioEncoder::OnReceivedRtt(int rtt_ms) {}

View File

@ -17,6 +17,7 @@
#include "webrtc/base/array_view.h" #include "webrtc/base/array_view.h"
#include "webrtc/base/buffer.h" #include "webrtc/base/buffer.h"
#include "webrtc/base/deprecation.h" #include "webrtc/base/deprecation.h"
#include "webrtc/base/optional.h"
#include "webrtc/typedefs.h" #include "webrtc/typedefs.h"
namespace webrtc { namespace webrtc {
@ -167,16 +168,19 @@ class AudioEncoder {
// Disables audio network adaptor. // Disables audio network adaptor.
virtual void DisableAudioNetworkAdaptor(); virtual void DisableAudioNetworkAdaptor();
// Provides uplink bandwidth to this encoder to allow it to adapt.
virtual void OnReceivedUplinkBandwidth(int uplink_bandwidth_bps);
// Provides uplink packet loss fraction to this encoder to allow it to adapt. // Provides uplink packet loss fraction to this encoder to allow it to adapt.
// |uplink_packet_loss_fraction| is in the range [0.0, 1.0]. // |uplink_packet_loss_fraction| is in the range [0.0, 1.0].
virtual void OnReceivedUplinkPacketLossFraction( virtual void OnReceivedUplinkPacketLossFraction(
float uplink_packet_loss_fraction); float uplink_packet_loss_fraction);
// Provides target audio bitrate to this encoder to allow it to adapt. // Provides target audio bitrate to this encoder to allow it to adapt.
virtual void OnReceivedTargetAudioBitrate(int target_audio_bitrate_bps); virtual void OnReceivedTargetAudioBitrate(int target_bps);
// Provides target audio bitrate and corresponding probing interval of
// the bandwidth estimator to this encoder to allow it to adapt.
virtual void OnReceivedUplinkBandwidth(
int target_audio_bitrate_bps,
rtc::Optional<int64_t> probing_interval_ms);
// Provides RTT to this encoder to allow it to adapt. // Provides RTT to this encoder to allow it to adapt.
virtual void OnReceivedRtt(int rtt_ms); virtual void OnReceivedRtt(int rtt_ms);

View File

@ -190,9 +190,11 @@ void AudioEncoderCng::OnReceivedUplinkPacketLossFraction(
uplink_packet_loss_fraction); uplink_packet_loss_fraction);
} }
void AudioEncoderCng::OnReceivedTargetAudioBitrate( void AudioEncoderCng::OnReceivedUplinkBandwidth(
int target_audio_bitrate_bps) { int target_audio_bitrate_bps,
speech_encoder_->OnReceivedTargetAudioBitrate(target_audio_bitrate_bps); rtc::Optional<int64_t> probing_interval_ms) {
speech_encoder_->OnReceivedUplinkBandwidth(target_audio_bitrate_bps,
probing_interval_ms);
} }
AudioEncoder::EncodedInfo AudioEncoderCng::EncodePassive( AudioEncoder::EncodedInfo AudioEncoderCng::EncodePassive(

View File

@ -65,7 +65,9 @@ class AudioEncoderCng final : public AudioEncoder {
override; override;
void OnReceivedUplinkPacketLossFraction( void OnReceivedUplinkPacketLossFraction(
float uplink_packet_loss_fraction) override; float uplink_packet_loss_fraction) override;
void OnReceivedTargetAudioBitrate(int target_audio_bitrate_bps) override; void OnReceivedUplinkBandwidth(
int target_audio_bitrate_bps,
rtc::Optional<int64_t> probing_interval_ms) override;
private: private:
EncodedInfo EncodePassive(size_t frames_to_encode, EncodedInfo EncodePassive(size_t frames_to_encode,

View File

@ -219,8 +219,9 @@ TEST_F(AudioEncoderCngTest, CheckFrameSizePropagation) {
TEST_F(AudioEncoderCngTest, CheckTargetAudioBitratePropagation) { TEST_F(AudioEncoderCngTest, CheckTargetAudioBitratePropagation) {
CreateCng(MakeCngConfig()); CreateCng(MakeCngConfig());
EXPECT_CALL(*mock_encoder_, OnReceivedTargetAudioBitrate(4711)); EXPECT_CALL(*mock_encoder_,
cng_->OnReceivedTargetAudioBitrate(4711); OnReceivedUplinkBandwidth(4711, rtc::Optional<int64_t>()));
cng_->OnReceivedUplinkBandwidth(4711, rtc::Optional<int64_t>());
} }
TEST_F(AudioEncoderCngTest, CheckPacketLossFractionPropagation) { TEST_F(AudioEncoderCngTest, CheckPacketLossFractionPropagation) {

View File

@ -41,8 +41,9 @@ class MockAudioEncoder : public AudioEncoder {
MOCK_METHOD1(SetMaxPlaybackRate, void(int frequency_hz)); MOCK_METHOD1(SetMaxPlaybackRate, void(int frequency_hz));
MOCK_METHOD1(SetMaxBitrate, void(int max_bps)); MOCK_METHOD1(SetMaxBitrate, void(int max_bps));
MOCK_METHOD1(SetMaxPayloadSize, void(int max_payload_size_bytes)); MOCK_METHOD1(SetMaxPayloadSize, void(int max_payload_size_bytes));
MOCK_METHOD1(OnReceivedTargetAudioBitrate, MOCK_METHOD2(OnReceivedUplinkBandwidth,
void(int target_audio_bitrate_bps)); void(int target_audio_bitrate_bps,
rtc::Optional<int64_t> probing_interval_ms));
MOCK_METHOD1(OnReceivedUplinkPacketLossFraction, MOCK_METHOD1(OnReceivedUplinkPacketLossFraction,
void(float uplink_packet_loss_fraction)); void(float uplink_packet_loss_fraction));

View File

@ -17,11 +17,11 @@
#include "webrtc/base/checks.h" #include "webrtc/base/checks.h"
#include "webrtc/base/logging.h" #include "webrtc/base/logging.h"
#include "webrtc/base/safe_conversions.h" #include "webrtc/base/safe_conversions.h"
#include "webrtc/base/timeutils.h"
#include "webrtc/common_types.h" #include "webrtc/common_types.h"
#include "webrtc/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.h" #include "webrtc/modules/audio_coding/audio_network_adaptor/audio_network_adaptor_impl.h"
#include "webrtc/modules/audio_coding/audio_network_adaptor/controller_manager.h" #include "webrtc/modules/audio_coding/audio_network_adaptor/controller_manager.h"
#include "webrtc/modules/audio_coding/codecs/opus/opus_interface.h" #include "webrtc/modules/audio_coding/codecs/opus/opus_interface.h"
#include "webrtc/system_wrappers/include/clock.h"
#include "webrtc/system_wrappers/include/field_trial.h" #include "webrtc/system_wrappers/include/field_trial.h"
namespace webrtc { namespace webrtc {
@ -172,18 +172,23 @@ rtc::Optional<int> AudioEncoderOpus::Config::GetNewComplexity() const {
AudioEncoderOpus::AudioEncoderOpus( AudioEncoderOpus::AudioEncoderOpus(
const Config& config, const Config& config,
AudioNetworkAdaptorCreator&& audio_network_adaptor_creator) AudioNetworkAdaptorCreator&& audio_network_adaptor_creator,
std::unique_ptr<SmoothingFilter> bitrate_smoother)
: packet_loss_rate_(0.0), : packet_loss_rate_(0.0),
inst_(nullptr), inst_(nullptr),
packet_loss_fraction_smoother_(new PacketLossFractionSmoother( packet_loss_fraction_smoother_(new PacketLossFractionSmoother(
config.clock ? config.clock : Clock::GetRealTimeClock())), config.clock)),
audio_network_adaptor_creator_( audio_network_adaptor_creator_(
audio_network_adaptor_creator audio_network_adaptor_creator
? std::move(audio_network_adaptor_creator) ? std::move(audio_network_adaptor_creator)
: [this](const std::string& config_string, const Clock* clock) { : [this](const std::string& config_string, const Clock* clock) {
return DefaultAudioNetworkAdaptorCreator(config_string, return DefaultAudioNetworkAdaptorCreator(config_string,
clock); clock);
}) { }),
bitrate_smoother_(bitrate_smoother
? std::move(bitrate_smoother) : std::unique_ptr<SmoothingFilter>(
// We choose 5sec as initial time constant due to empirical data.
new SmoothingFilterImpl(5000, config.clock))) {
RTC_CHECK(RecreateEncoderInstance(config)); RTC_CHECK(RecreateEncoderInstance(config));
} }
@ -272,13 +277,6 @@ void AudioEncoderOpus::DisableAudioNetworkAdaptor() {
audio_network_adaptor_.reset(nullptr); audio_network_adaptor_.reset(nullptr);
} }
void AudioEncoderOpus::OnReceivedUplinkBandwidth(int uplink_bandwidth_bps) {
if (!audio_network_adaptor_)
return;
audio_network_adaptor_->SetUplinkBandwidth(uplink_bandwidth_bps);
ApplyAudioNetworkAdaptor();
}
void AudioEncoderOpus::OnReceivedUplinkPacketLossFraction( void AudioEncoderOpus::OnReceivedUplinkPacketLossFraction(
float uplink_packet_loss_fraction) { float uplink_packet_loss_fraction) {
if (!audio_network_adaptor_) { if (!audio_network_adaptor_) {
@ -291,10 +289,26 @@ void AudioEncoderOpus::OnReceivedUplinkPacketLossFraction(
ApplyAudioNetworkAdaptor(); ApplyAudioNetworkAdaptor();
} }
void AudioEncoderOpus::OnReceivedTargetAudioBitrate( void AudioEncoderOpus::OnReceivedUplinkBandwidth(
int target_audio_bitrate_bps) { int target_audio_bitrate_bps,
rtc::Optional<int64_t> probing_interval_ms) {
if (audio_network_adaptor_) { if (audio_network_adaptor_) {
audio_network_adaptor_->SetTargetAudioBitrate(target_audio_bitrate_bps); audio_network_adaptor_->SetTargetAudioBitrate(target_audio_bitrate_bps);
// We give smoothed bitrate allocation to audio network adaptor as
// the uplink bandwidth.
// The probing spikes should not affect the bitrate smoother more than 25%.
// To simplify the calculations we use a step response as input signal.
// The step response of an exponential filter is
// u(t) = 1 - e^(-t / time_constant).
// In order to limit the affect of a BWE spike within 25% of its value
// before
// the next probing, we would choose a time constant that fulfills
// 1 - e^(-probing_interval_ms / time_constant) < 0.25
// Then 4 * probing_interval_ms is a good choice.
if (probing_interval_ms)
bitrate_smoother_->SetTimeConstantMs(*probing_interval_ms * 4);
bitrate_smoother_->AddSample(target_audio_bitrate_bps);
ApplyAudioNetworkAdaptor(); ApplyAudioNetworkAdaptor();
} else if (webrtc::field_trial::FindFullName( } else if (webrtc::field_trial::FindFullName(
"WebRTC-SendSideBwe-WithOverhead") == "Enabled") { "WebRTC-SendSideBwe-WithOverhead") == "Enabled") {
@ -354,6 +368,7 @@ AudioEncoder::EncodedInfo AudioEncoderOpus::EncodeImpl(
uint32_t rtp_timestamp, uint32_t rtp_timestamp,
rtc::ArrayView<const int16_t> audio, rtc::ArrayView<const int16_t> audio,
rtc::Buffer* encoded) { rtc::Buffer* encoded) {
MaybeUpdateUplinkBandwidth();
if (input_buffer_.empty()) if (input_buffer_.empty())
first_timestamp_in_buffer_ = rtp_timestamp; first_timestamp_in_buffer_ = rtp_timestamp;
@ -521,4 +536,18 @@ AudioEncoderOpus::DefaultAudioNetworkAdaptorCreator(
GetTargetBitrate(), config_.fec_enabled, GetDtx(), clock))); GetTargetBitrate(), config_.fec_enabled, GetDtx(), clock)));
} }
void AudioEncoderOpus::MaybeUpdateUplinkBandwidth() {
if (audio_network_adaptor_) {
int64_t now_ms = rtc::TimeMillis();
if (!bitrate_smoother_last_update_time_ ||
now_ms - *bitrate_smoother_last_update_time_ >=
config_.uplink_bandwidth_update_interval_ms) {
rtc::Optional<float> smoothed_bitrate = bitrate_smoother_->GetAverage();
if (smoothed_bitrate)
audio_network_adaptor_->SetUplinkBandwidth(*smoothed_bitrate);
bitrate_smoother_last_update_time_ = rtc::Optional<int64_t>(now_ms);
}
}
}
} // namespace webrtc } // namespace webrtc

View File

@ -18,6 +18,7 @@
#include "webrtc/base/constructormagic.h" #include "webrtc/base/constructormagic.h"
#include "webrtc/base/optional.h" #include "webrtc/base/optional.h"
#include "webrtc/common_audio/smoothing_filter.h"
#include "webrtc/modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h" #include "webrtc/modules/audio_coding/audio_network_adaptor/include/audio_network_adaptor.h"
#include "webrtc/modules/audio_coding/codecs/opus/opus_interface.h" #include "webrtc/modules/audio_coding/codecs/opus/opus_interface.h"
#include "webrtc/modules/audio_coding/codecs/audio_encoder.h" #include "webrtc/modules/audio_coding/codecs/audio_encoder.h"
@ -62,7 +63,8 @@ class AudioEncoderOpus final : public AudioEncoder {
int complexity_threshold_window_bps = 1500; int complexity_threshold_window_bps = 1500;
bool dtx_enabled = false; bool dtx_enabled = false;
std::vector<int> supported_frame_lengths_ms; std::vector<int> supported_frame_lengths_ms;
const Clock* clock = nullptr; const Clock* clock = Clock::GetRealTimeClock();
int uplink_bandwidth_update_interval_ms = 200;
private: private:
#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) || defined(WEBRTC_ARCH_ARM) #if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) || defined(WEBRTC_ARCH_ARM)
@ -79,7 +81,8 @@ class AudioEncoderOpus final : public AudioEncoder {
const Clock*)>; const Clock*)>;
AudioEncoderOpus( AudioEncoderOpus(
const Config& config, const Config& config,
AudioNetworkAdaptorCreator&& audio_network_adaptor_creator = nullptr); AudioNetworkAdaptorCreator&& audio_network_adaptor_creator = nullptr,
std::unique_ptr<SmoothingFilter> bitrate_smoother = nullptr);
explicit AudioEncoderOpus(const CodecInst& codec_inst); explicit AudioEncoderOpus(const CodecInst& codec_inst);
@ -105,10 +108,11 @@ class AudioEncoderOpus final : public AudioEncoder {
bool EnableAudioNetworkAdaptor(const std::string& config_string, bool EnableAudioNetworkAdaptor(const std::string& config_string,
const Clock* clock) override; const Clock* clock) override;
void DisableAudioNetworkAdaptor() override; void DisableAudioNetworkAdaptor() override;
void OnReceivedUplinkBandwidth(int uplink_bandwidth_bps) override;
void OnReceivedUplinkPacketLossFraction( void OnReceivedUplinkPacketLossFraction(
float uplink_packet_loss_fraction) override; float uplink_packet_loss_fraction) override;
void OnReceivedTargetAudioBitrate(int target_audio_bitrate_bps) override; void OnReceivedUplinkBandwidth(
int target_audio_bitrate_bps,
rtc::Optional<int64_t> probing_interval_ms) override;
void OnReceivedRtt(int rtt_ms) override; void OnReceivedRtt(int rtt_ms) override;
void OnReceivedOverhead(size_t overhead_bytes_per_packet) override; void OnReceivedOverhead(size_t overhead_bytes_per_packet) override;
void SetReceiverFrameLengthRange(int min_frame_length_ms, void SetReceiverFrameLengthRange(int min_frame_length_ms,
@ -149,6 +153,8 @@ class AudioEncoderOpus final : public AudioEncoder {
const std::string& config_string, const std::string& config_string,
const Clock* clock) const; const Clock* clock) const;
void MaybeUpdateUplinkBandwidth();
Config config_; Config config_;
float packet_loss_rate_; float packet_loss_rate_;
std::vector<int16_t> input_buffer_; std::vector<int16_t> input_buffer_;
@ -161,6 +167,8 @@ class AudioEncoderOpus final : public AudioEncoder {
AudioNetworkAdaptorCreator audio_network_adaptor_creator_; AudioNetworkAdaptorCreator audio_network_adaptor_creator_;
std::unique_ptr<AudioNetworkAdaptor> audio_network_adaptor_; std::unique_ptr<AudioNetworkAdaptor> audio_network_adaptor_;
rtc::Optional<size_t> overhead_bytes_per_packet_; rtc::Optional<size_t> overhead_bytes_per_packet_;
const std::unique_ptr<SmoothingFilter> bitrate_smoother_;
rtc::Optional<int64_t> bitrate_smoother_last_update_time_;
RTC_DISALLOW_COPY_AND_ASSIGN(AudioEncoderOpus); RTC_DISALLOW_COPY_AND_ASSIGN(AudioEncoderOpus);
}; };

View File

@ -8,9 +8,12 @@
* be found in the AUTHORS file in the root of the source tree. * be found in the AUTHORS file in the root of the source tree.
*/ */
#include <array>
#include <memory> #include <memory>
#include "webrtc/base/checks.h" #include "webrtc/base/checks.h"
#include "webrtc/base/fakeclock.h"
#include "webrtc/common_audio/mocks/mock_smoothing_filter.h"
#include "webrtc/common_types.h" #include "webrtc/common_types.h"
#include "webrtc/modules/audio_coding/audio_network_adaptor/mock/mock_audio_network_adaptor.h" #include "webrtc/modules/audio_coding/audio_network_adaptor/mock/mock_audio_network_adaptor.h"
#include "webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h" #include "webrtc/modules/audio_coding/codecs/opus/audio_encoder_opus.h"
@ -42,8 +45,10 @@ AudioEncoderOpus::Config CreateConfig(const CodecInst& codec_inst) {
struct AudioEncoderOpusStates { struct AudioEncoderOpusStates {
std::shared_ptr<MockAudioNetworkAdaptor*> mock_audio_network_adaptor; std::shared_ptr<MockAudioNetworkAdaptor*> mock_audio_network_adaptor;
MockSmoothingFilter* mock_bitrate_smoother;
std::unique_ptr<AudioEncoderOpus> encoder; std::unique_ptr<AudioEncoderOpus> encoder;
std::unique_ptr<SimulatedClock> simulated_clock; std::unique_ptr<SimulatedClock> simulated_clock;
AudioEncoderOpus::Config config;
}; };
AudioEncoderOpusStates CreateCodec(size_t num_channels) { AudioEncoderOpusStates CreateCodec(size_t num_channels) {
@ -68,11 +73,15 @@ AudioEncoderOpusStates CreateCodec(size_t num_channels) {
CodecInst codec_inst = kDefaultOpusSettings; CodecInst codec_inst = kDefaultOpusSettings;
codec_inst.channels = num_channels; codec_inst.channels = num_channels;
auto config = CreateConfig(codec_inst); states.config = CreateConfig(codec_inst);
std::unique_ptr<MockSmoothingFilter> bitrate_smoother(
new MockSmoothingFilter());
states.mock_bitrate_smoother = bitrate_smoother.get();
states.simulated_clock.reset(new SimulatedClock(kInitialTimeUs)); states.simulated_clock.reset(new SimulatedClock(kInitialTimeUs));
config.clock = states.simulated_clock.get(); states.config.clock = states.simulated_clock.get();
states.encoder.reset(new AudioEncoderOpus(config, std::move(creator))); states.encoder.reset(new AudioEncoderOpus(states.config, std::move(creator),
std::move(bitrate_smoother)));
return states; return states;
} }
@ -153,26 +162,30 @@ TEST(AudioEncoderOpusTest, ToggleDtx) {
} }
TEST(AudioEncoderOpusTest, TEST(AudioEncoderOpusTest,
OnReceivedTargetAudioBitrateWithoutAudioNetworkAdaptor) { OnReceivedUplinkBandwidthWithoutAudioNetworkAdaptor) {
auto states = CreateCodec(1); auto states = CreateCodec(1);
// Constants are replicated from audio_states.encoderopus.cc. // Constants are replicated from audio_states.encoderopus.cc.
const int kMinBitrateBps = 500; const int kMinBitrateBps = 500;
const int kMaxBitrateBps = 512000; const int kMaxBitrateBps = 512000;
// Set a too low bitrate. // Set a too low bitrate.
states.encoder->OnReceivedTargetAudioBitrate(kMinBitrateBps - 1); states.encoder->OnReceivedUplinkBandwidth(kMinBitrateBps - 1,
rtc::Optional<int64_t>());
EXPECT_EQ(kMinBitrateBps, states.encoder->GetTargetBitrate()); EXPECT_EQ(kMinBitrateBps, states.encoder->GetTargetBitrate());
// Set a too high bitrate. // Set a too high bitrate.
states.encoder->OnReceivedTargetAudioBitrate(kMaxBitrateBps + 1); states.encoder->OnReceivedUplinkBandwidth(kMaxBitrateBps + 1,
rtc::Optional<int64_t>());
EXPECT_EQ(kMaxBitrateBps, states.encoder->GetTargetBitrate()); EXPECT_EQ(kMaxBitrateBps, states.encoder->GetTargetBitrate());
// Set the minimum rate. // Set the minimum rate.
states.encoder->OnReceivedTargetAudioBitrate(kMinBitrateBps); states.encoder->OnReceivedUplinkBandwidth(kMinBitrateBps,
rtc::Optional<int64_t>());
EXPECT_EQ(kMinBitrateBps, states.encoder->GetTargetBitrate()); EXPECT_EQ(kMinBitrateBps, states.encoder->GetTargetBitrate());
// Set the maximum rate. // Set the maximum rate.
states.encoder->OnReceivedTargetAudioBitrate(kMaxBitrateBps); states.encoder->OnReceivedUplinkBandwidth(kMaxBitrateBps,
rtc::Optional<int64_t>());
EXPECT_EQ(kMaxBitrateBps, states.encoder->GetTargetBitrate()); EXPECT_EQ(kMaxBitrateBps, states.encoder->GetTargetBitrate());
// Set rates from 1000 up to 32000 bps. // Set rates from 1000 up to 32000 bps.
for (int rate = 1000; rate <= 32000; rate += 1000) { for (int rate = 1000; rate <= 32000; rate += 1000) {
states.encoder->OnReceivedTargetAudioBitrate(rate); states.encoder->OnReceivedUplinkBandwidth(rate, rtc::Optional<int64_t>());
EXPECT_EQ(rate, states.encoder->GetTargetBitrate()); EXPECT_EQ(rate, states.encoder->GetTargetBitrate());
} }
} }
@ -250,23 +263,6 @@ TEST(AudioEncoderOpusTest, SetReceiverFrameLengthRange) {
EXPECT_THAT(states.encoder->supported_frame_lengths_ms(), ElementsAre(20)); EXPECT_THAT(states.encoder->supported_frame_lengths_ms(), ElementsAre(20));
} }
TEST(AudioEncoderOpusTest, InvokeAudioNetworkAdaptorOnReceivedUplinkBandwidth) {
auto states = CreateCodec(2);
states.encoder->EnableAudioNetworkAdaptor("", nullptr);
auto config = CreateEncoderRuntimeConfig();
EXPECT_CALL(**states.mock_audio_network_adaptor, GetEncoderRuntimeConfig())
.WillOnce(Return(config));
// Since using mock audio network adaptor, any bandwidth value is fine.
constexpr int kUplinkBandwidth = 50000;
EXPECT_CALL(**states.mock_audio_network_adaptor,
SetUplinkBandwidth(kUplinkBandwidth));
states.encoder->OnReceivedUplinkBandwidth(kUplinkBandwidth);
CheckEncoderRuntimeConfig(states.encoder.get(), config);
}
TEST(AudioEncoderOpusTest, TEST(AudioEncoderOpusTest,
InvokeAudioNetworkAdaptorOnReceivedUplinkPacketLossFraction) { InvokeAudioNetworkAdaptorOnReceivedUplinkPacketLossFraction) {
auto states = CreateCodec(2); auto states = CreateCodec(2);
@ -285,8 +281,7 @@ TEST(AudioEncoderOpusTest,
CheckEncoderRuntimeConfig(states.encoder.get(), config); CheckEncoderRuntimeConfig(states.encoder.get(), config);
} }
TEST(AudioEncoderOpusTest, TEST(AudioEncoderOpusTest, InvokeAudioNetworkAdaptorOnReceivedUplinkBandwidth) {
InvokeAudioNetworkAdaptorOnReceivedTargetAudioBitrate) {
auto states = CreateCodec(2); auto states = CreateCodec(2);
states.encoder->EnableAudioNetworkAdaptor("", nullptr); states.encoder->EnableAudioNetworkAdaptor("", nullptr);
@ -296,9 +291,14 @@ TEST(AudioEncoderOpusTest,
// Since using mock audio network adaptor, any target audio bitrate is fine. // Since using mock audio network adaptor, any target audio bitrate is fine.
constexpr int kTargetAudioBitrate = 30000; constexpr int kTargetAudioBitrate = 30000;
constexpr int64_t kProbingIntervalMs = 3000;
EXPECT_CALL(**states.mock_audio_network_adaptor, EXPECT_CALL(**states.mock_audio_network_adaptor,
SetTargetAudioBitrate(kTargetAudioBitrate)); SetTargetAudioBitrate(kTargetAudioBitrate));
states.encoder->OnReceivedTargetAudioBitrate(kTargetAudioBitrate); EXPECT_CALL(*states.mock_bitrate_smoother,
SetTimeConstantMs(kProbingIntervalMs * 4));
EXPECT_CALL(*states.mock_bitrate_smoother, AddSample(kTargetAudioBitrate));
states.encoder->OnReceivedUplinkBandwidth(
kTargetAudioBitrate, rtc::Optional<int64_t>(kProbingIntervalMs));
CheckEncoderRuntimeConfig(states.encoder.get(), config); CheckEncoderRuntimeConfig(states.encoder.get(), config);
} }
@ -367,7 +367,8 @@ TEST(AudioEncoderOpusTest, DoNotInvokeSetTargetBitrateIfOverheadUnknown) {
auto states = CreateCodec(2); auto states = CreateCodec(2);
states.encoder->OnReceivedTargetAudioBitrate(kDefaultOpusSettings.rate * 2); states.encoder->OnReceivedUplinkBandwidth(kDefaultOpusSettings.rate * 2,
rtc::Optional<int64_t>());
// Since |OnReceivedOverhead| has not been called, the codec bitrate should // Since |OnReceivedOverhead| has not been called, the codec bitrate should
// not change. // not change.
@ -384,7 +385,8 @@ TEST(AudioEncoderOpusTest, OverheadRemovedFromTargetAudioBitrate) {
states.encoder->OnReceivedOverhead(kOverheadBytesPerPacket); states.encoder->OnReceivedOverhead(kOverheadBytesPerPacket);
constexpr int kTargetBitrateBps = 40000; constexpr int kTargetBitrateBps = 40000;
states.encoder->OnReceivedTargetAudioBitrate(kTargetBitrateBps); states.encoder->OnReceivedUplinkBandwidth(kTargetBitrateBps,
rtc::Optional<int64_t>());
int packet_rate = rtc::CheckedDivExact(48000, kDefaultOpusSettings.pacsize); int packet_rate = rtc::CheckedDivExact(48000, kDefaultOpusSettings.pacsize);
EXPECT_EQ(kTargetBitrateBps - EXPECT_EQ(kTargetBitrateBps -
@ -410,14 +412,16 @@ TEST(AudioEncoderOpusTest, BitrateBounded) {
// subtracted. The eventual codec rate should be bounded by |kMinBitrateBps|. // subtracted. The eventual codec rate should be bounded by |kMinBitrateBps|.
int target_bitrate = int target_bitrate =
kOverheadBytesPerPacket * 8 * packet_rate + kMinBitrateBps - 1; kOverheadBytesPerPacket * 8 * packet_rate + kMinBitrateBps - 1;
states.encoder->OnReceivedTargetAudioBitrate(target_bitrate); states.encoder->OnReceivedUplinkBandwidth(target_bitrate,
rtc::Optional<int64_t>());
EXPECT_EQ(kMinBitrateBps, states.encoder->GetTargetBitrate()); EXPECT_EQ(kMinBitrateBps, states.encoder->GetTargetBitrate());
// Set a target rate that is greater than |kMaxBitrateBps| when overhead is // Set a target rate that is greater than |kMaxBitrateBps| when overhead is
// subtracted. The eventual codec rate should be bounded by |kMaxBitrateBps|. // subtracted. The eventual codec rate should be bounded by |kMaxBitrateBps|.
target_bitrate = target_bitrate =
kOverheadBytesPerPacket * 8 * packet_rate + kMaxBitrateBps + 1; kOverheadBytesPerPacket * 8 * packet_rate + kMaxBitrateBps + 1;
states.encoder->OnReceivedTargetAudioBitrate(target_bitrate); states.encoder->OnReceivedUplinkBandwidth(target_bitrate,
rtc::Optional<int64_t>());
EXPECT_EQ(kMaxBitrateBps, states.encoder->GetTargetBitrate()); EXPECT_EQ(kMaxBitrateBps, states.encoder->GetTargetBitrate());
} }
@ -464,4 +468,35 @@ TEST(AudioEncoderOpusTest, EmptyConfigDoesNotAffectEncoderSettings) {
CheckEncoderRuntimeConfig(states.encoder.get(), config); CheckEncoderRuntimeConfig(states.encoder.get(), config);
} }
TEST(AudioEncoderOpusTest, UpdateUplinkBandwidthInAudioNetworkAdaptor) {
rtc::ScopedFakeClock fake_clock;
auto states = CreateCodec(2);
states.encoder->EnableAudioNetworkAdaptor("", nullptr);
std::array<int16_t, 480 * 2> audio;
audio.fill(0);
rtc::Buffer encoded;
EXPECT_CALL(*states.mock_bitrate_smoother, GetAverage())
.WillOnce(Return(rtc::Optional<float>(50000)));
EXPECT_CALL(**states.mock_audio_network_adaptor, SetUplinkBandwidth(50000));
states.encoder->Encode(
0, rtc::ArrayView<const int16_t>(audio.data(), audio.size()), &encoded);
// Repeat update uplink bandwidth tests.
for (int i = 0; i < 5; i++) {
// Don't update till it is time to update again.
fake_clock.AdvanceTime(rtc::TimeDelta::FromMilliseconds(
states.config.uplink_bandwidth_update_interval_ms - 1));
states.encoder->Encode(
0, rtc::ArrayView<const int16_t>(audio.data(), audio.size()), &encoded);
// Update when it is time to update.
EXPECT_CALL(*states.mock_bitrate_smoother, GetAverage())
.WillOnce(Return(rtc::Optional<float>(40000)));
EXPECT_CALL(**states.mock_audio_network_adaptor, SetUplinkBandwidth(40000));
fake_clock.AdvanceTime(rtc::TimeDelta::FromMilliseconds(1));
states.encoder->Encode(
0, rtc::ArrayView<const int16_t>(audio.data(), audio.size()), &encoded);
}
}
} // namespace webrtc } // namespace webrtc

View File

@ -126,9 +126,11 @@ void AudioEncoderCopyRed::OnReceivedUplinkPacketLossFraction(
uplink_packet_loss_fraction); uplink_packet_loss_fraction);
} }
void AudioEncoderCopyRed::OnReceivedTargetAudioBitrate( void AudioEncoderCopyRed::OnReceivedUplinkBandwidth(
int target_audio_bitrate_bps) { int target_audio_bitrate_bps,
speech_encoder_->OnReceivedTargetAudioBitrate(target_audio_bitrate_bps); rtc::Optional<int64_t> probing_interval_ms) {
speech_encoder_->OnReceivedUplinkBandwidth(target_audio_bitrate_bps,
probing_interval_ms);
} }
} // namespace webrtc } // namespace webrtc

View File

@ -53,7 +53,9 @@ class AudioEncoderCopyRed final : public AudioEncoder {
override; override;
void OnReceivedUplinkPacketLossFraction( void OnReceivedUplinkPacketLossFraction(
float uplink_packet_loss_fraction) override; float uplink_packet_loss_fraction) override;
void OnReceivedTargetAudioBitrate(int target_audio_bitrate_bps) override; void OnReceivedUplinkBandwidth(
int target_audio_bitrate_bps,
rtc::Optional<int64_t> probing_interval_ms) override;
protected: protected:
EncodedInfo EncodeImpl(uint32_t rtp_timestamp, EncodedInfo EncodeImpl(uint32_t rtp_timestamp,

View File

@ -98,8 +98,9 @@ TEST_F(AudioEncoderCopyRedTest, CheckMaxFrameSizePropagation) {
} }
TEST_F(AudioEncoderCopyRedTest, CheckTargetAudioBitratePropagation) { TEST_F(AudioEncoderCopyRedTest, CheckTargetAudioBitratePropagation) {
EXPECT_CALL(*mock_encoder_, OnReceivedTargetAudioBitrate(4711)); EXPECT_CALL(*mock_encoder_,
red_->OnReceivedTargetAudioBitrate(4711); OnReceivedUplinkBandwidth(4711, rtc::Optional<int64_t>()));
red_->OnReceivedUplinkBandwidth(4711, rtc::Optional<int64_t>());
} }
TEST_F(AudioEncoderCopyRedTest, CheckPacketLossFractionPropagation) { TEST_F(AudioEncoderCopyRedTest, CheckPacketLossFractionPropagation) {

View File

@ -469,7 +469,7 @@ TEST_F(AudioDecoderPcmUTest, EncodeDecode) {
namespace { namespace {
int SetAndGetTargetBitrate(AudioEncoder* audio_encoder, int rate) { int SetAndGetTargetBitrate(AudioEncoder* audio_encoder, int rate) {
audio_encoder->OnReceivedTargetAudioBitrate(rate); audio_encoder->OnReceivedUplinkBandwidth(rate, rtc::Optional<int64_t>());
return audio_encoder->GetTargetBitrate(); return audio_encoder->GetTargetBitrate();
} }
void TestSetAndGetTargetBitratesWithFixedCodec(AudioEncoder* audio_encoder, void TestSetAndGetTargetBitratesWithFixedCodec(AudioEncoder* audio_encoder,

View File

@ -57,7 +57,7 @@ if (rtc_include_tests) {
deps = [ deps = [
":rtc_stats", ":rtc_stats",
":rtc_stats_test_utils", ":rtc_stats_test_utils",
"../base:rtc_base_tests_utils", "../base:rtc_base_tests_main",
"../system_wrappers:metrics_default", "../system_wrappers:metrics_default",
"//testing/gmock", "//testing/gmock",
] ]

View File

@ -926,10 +926,7 @@ Channel::Channel(int32_t channelId,
rtp_packet_sender_proxy_(new RtpPacketSenderProxy()), rtp_packet_sender_proxy_(new RtpPacketSenderProxy()),
retransmission_rate_limiter_(new RateLimiter(Clock::GetRealTimeClock(), retransmission_rate_limiter_(new RateLimiter(Clock::GetRealTimeClock(),
kMaxRetransmissionWindowMs)), kMaxRetransmissionWindowMs)),
decoder_factory_(config.acm_config.decoder_factory), decoder_factory_(config.acm_config.decoder_factory) {
// Bitrate smoother can be initialized with arbitrary time constant
// (0 used here). The actual time constant will be set in SetBitRate.
bitrate_smoother_(0, Clock::GetRealTimeClock()) {
WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId, _channelId), WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId, _channelId),
"Channel::Channel() - ctor"); "Channel::Channel() - ctor");
AudioCodingModule::Config acm_config(config.acm_config); AudioCodingModule::Config acm_config(config.acm_config);
@ -1332,30 +1329,13 @@ int32_t Channel::SetSendCodec(const CodecInst& codec) {
void Channel::SetBitRate(int bitrate_bps, int64_t probing_interval_ms) { void Channel::SetBitRate(int bitrate_bps, int64_t probing_interval_ms) {
WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId), WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, _channelId),
"Channel::SetBitRate(bitrate_bps=%d)", bitrate_bps); "Channel::SetBitRate(bitrate_bps=%d)", bitrate_bps);
audio_coding_->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* encoder) {
if (*encoder)
(*encoder)->OnReceivedTargetAudioBitrate(bitrate_bps);
});
retransmission_rate_limiter_->SetMaxRate(bitrate_bps);
// We give smoothed bitrate allocation to audio network adaptor as
// the uplink bandwidth.
// The probing spikes should not affect the bitrate smoother more than 25%.
// To simplify the calculations we use a step response as input signal.
// The step response of an exponential filter is
// u(t) = 1 - e^(-t / time_constant).
// In order to limit the affect of a BWE spike within 25% of its value before
// the next probing, we would choose a time constant that fulfills
// 1 - e^(-probing_interval_ms / time_constant) < 0.25
// Then 4 * probing_interval_ms is a good choice.
bitrate_smoother_.SetTimeConstantMs(probing_interval_ms * 4);
bitrate_smoother_.AddSample(bitrate_bps);
audio_coding_->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* encoder) { audio_coding_->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* encoder) {
if (*encoder) { if (*encoder) {
(*encoder)->OnReceivedUplinkBandwidth( (*encoder)->OnReceivedUplinkBandwidth(
static_cast<int>(*bitrate_smoother_.GetAverage())); bitrate_bps, rtc::Optional<int64_t>(probing_interval_ms));
} }
}); });
retransmission_rate_limiter_->SetMaxRate(bitrate_bps);
} }
void Channel::OnIncomingFractionLoss(int fraction_lost) { void Channel::OnIncomingFractionLoss(int fraction_lost) {

View File

@ -17,7 +17,6 @@
#include "webrtc/api/call/audio_sink.h" #include "webrtc/api/call/audio_sink.h"
#include "webrtc/base/criticalsection.h" #include "webrtc/base/criticalsection.h"
#include "webrtc/base/optional.h" #include "webrtc/base/optional.h"
#include "webrtc/common_audio/smoothing_filter.h"
#include "webrtc/common_audio/resampler/include/push_resampler.h" #include "webrtc/common_audio/resampler/include/push_resampler.h"
#include "webrtc/common_types.h" #include "webrtc/common_types.h"
#include "webrtc/modules/audio_coding/acm2/codec_manager.h" #include "webrtc/modules/audio_coding/acm2/codec_manager.h"
@ -554,8 +553,6 @@ class Channel
// TODO(ossu): Remove once GetAudioDecoderFactory() is no longer needed. // TODO(ossu): Remove once GetAudioDecoderFactory() is no longer needed.
rtc::scoped_refptr<AudioDecoderFactory> decoder_factory_; rtc::scoped_refptr<AudioDecoderFactory> decoder_factory_;
SmoothingFilterImpl bitrate_smoother_;
}; };
} // namespace voe } // namespace voe