Implement congestion window direct pushback to encoders. (Without TaskQueue)

Bug: None
Change-Id: I3c6da916ce5f4a32ff47bfb0894b00f11fbf7823
Reviewed-on: https://webrtc-review.googlesource.com/86605
Commit-Queue: Ying Wang <yinwa@webrtc.org>
Reviewed-by: Sebastian Jansson <srte@webrtc.org>
Reviewed-by: Christoffer Rodbro <crodbro@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24008}
This commit is contained in:
Ying Wang
2018-07-17 16:01:25 +02:00
committed by Commit Bot
parent 62592ce169
commit e1d7b23915
7 changed files with 288 additions and 72 deletions

View File

@ -20,6 +20,8 @@ rtc_static_library("congestion_controller") {
visibility = [ "*" ]
configs += [ ":bwe_test_logging" ]
sources = [
"congestion_window_pushback_controller.cc",
"congestion_window_pushback_controller.h",
"include/network_changed_observer.h",
"include/receive_side_congestion_controller.h",
"include/send_side_congestion_controller.h",
@ -37,7 +39,9 @@ rtc_static_library("congestion_controller") {
":transport_feedback",
"..:module_api",
"../..:webrtc_common",
"../../api/transport:network_control",
"../../rtc_base:checks",
"../../rtc_base:ptr_util",
"../../rtc_base:rate_limiter",
"../../system_wrappers",
"../../system_wrappers:field_trial_api",
@ -95,6 +99,7 @@ if (rtc_include_tests) {
testonly = true
sources = [
"congestion_window_pushback_controller_unittest.cc",
"receive_side_congestion_controller_unittest.cc",
"send_side_congestion_controller_unittest.cc",
"transport_feedback_adapter_unittest.cc",

View File

@ -0,0 +1,93 @@
/*
* Copyright (c) 2018 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 <string>
#include <algorithm>
#include "modules/congestion_controller/congestion_window_pushback_controller.h"
#include "system_wrappers/include/field_trial.h"
namespace webrtc {
// When CongestionWindowPushback is enabled, the pacer is oblivious to
// the congestion window. The relation between outstanding data and
// the congestion window affects encoder allocations directly.
// This experiment is build on top of congestion window experiment.
const char kCongestionPushbackExperiment[] = "WebRTC-CongestionWindowPushback";
const uint32_t kDefaultMinPushbackTargetBitrateBps = 30000;
bool ReadCongestionWindowPushbackExperimentParameter(
uint32_t* min_pushback_target_bitrate_bps) {
RTC_DCHECK(min_pushback_target_bitrate_bps);
std::string experiment_string =
webrtc::field_trial::FindFullName(kCongestionPushbackExperiment);
int parsed_values = sscanf(experiment_string.c_str(), "Enabled-%" PRIu32,
min_pushback_target_bitrate_bps);
if (parsed_values == 1) {
RTC_CHECK_GE(*min_pushback_target_bitrate_bps, 0)
<< "Min pushback target bitrate must be greater than or equal to 0.";
return true;
}
return false;
}
CongestionWindowPushbackController::CongestionWindowPushbackController() {
if (!ReadCongestionWindowPushbackExperimentParameter(
&min_pushback_target_bitrate_bps_)) {
min_pushback_target_bitrate_bps_ = kDefaultMinPushbackTargetBitrateBps;
}
}
void CongestionWindowPushbackController::UpdateOutstandingData(
size_t outstanding_bytes) {
outstanding_bytes_ = outstanding_bytes;
}
void CongestionWindowPushbackController::UpdateMaxOutstandingData(
size_t max_outstanding_bytes) {
DataSize data_window = DataSize::bytes(max_outstanding_bytes);
if (current_data_window_) {
data_window = (data_window + current_data_window_.value()) / 2;
}
current_data_window_ = data_window;
}
void CongestionWindowPushbackController::SetDataWindow(DataSize data_window) {
current_data_window_ = data_window;
}
uint32_t CongestionWindowPushbackController::UpdateTargetBitrate(
uint32_t bitrate_bps) {
if (!current_data_window_ || current_data_window_->IsZero())
return bitrate_bps;
double fill_ratio =
outstanding_bytes_ / static_cast<double>(current_data_window_->bytes());
if (fill_ratio > 1.5) {
encoding_rate_ratio_ *= 0.9;
} else if (fill_ratio > 1) {
encoding_rate_ratio_ *= 0.95;
} else if (fill_ratio < 0.1) {
encoding_rate_ratio_ = 1.0;
} else {
encoding_rate_ratio_ *= 1.05;
encoding_rate_ratio_ = std::min(encoding_rate_ratio_, 1.0);
}
uint32_t adjusted_target_bitrate_bps =
static_cast<uint32_t>(bitrate_bps * encoding_rate_ratio_);
// Do not adjust below the minimum pushback bitrate but do obey if the
// original estimate is below it.
bitrate_bps = adjusted_target_bitrate_bps < min_pushback_target_bitrate_bps_
? std::min(bitrate_bps, min_pushback_target_bitrate_bps_)
: adjusted_target_bitrate_bps;
return bitrate_bps;
}
} // namespace webrtc

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2018 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 MODULES_CONGESTION_CONTROLLER_CONGESTION_WINDOW_PUSHBACK_CONTROLLER_H_
#define MODULES_CONGESTION_CONTROLLER_CONGESTION_WINDOW_PUSHBACK_CONTROLLER_H_
#include "api/transport/network_types.h"
#include "common_types.h" // NOLINT(build/include)
#include "rtc_base/criticalsection.h"
#include "rtc_base/format_macros.h"
namespace webrtc {
// This class enables pushback from congestion window directly to video encoder.
// When the congestion window is filling up, the video encoder target bitrate
// will be reduced accordingly to accommodate the network changes. To avoid
// pausing video too frequently, a minimum encoder target bitrate threshold is
// used to prevent video pause due to a full congestion window.
class CongestionWindowPushbackController {
public:
CongestionWindowPushbackController();
void UpdateOutstandingData(size_t outstanding_bytes);
void UpdateMaxOutstandingData(size_t max_outstanding_bytes);
uint32_t UpdateTargetBitrate(uint32_t bitrate_bps);
void SetDataWindow(DataSize data_window);
private:
absl::optional<DataSize> current_data_window_;
size_t outstanding_bytes_ = 0;
uint32_t min_pushback_target_bitrate_bps_;
double encoding_rate_ratio_ = 1.0;
};
} // namespace webrtc
#endif // MODULES_CONGESTION_CONTROLLER_CONGESTION_WINDOW_PUSHBACK_CONTROLLER_H_

View File

@ -0,0 +1,65 @@
/*
* Copyright (c) 2018 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 "modules/congestion_controller/congestion_window_pushback_controller.h"
#include "test/gmock.h"
#include "test/gtest.h"
using testing::_;
namespace webrtc {
namespace test {
class CongestionWindowPushbackControllerTest : public ::testing::Test {
protected:
CongestionWindowPushbackController cwnd_controller_;
};
TEST_F(CongestionWindowPushbackControllerTest, FullCongestionWindow) {
cwnd_controller_.UpdateOutstandingData(100000);
cwnd_controller_.UpdateMaxOutstandingData(50000);
uint32_t bitrate_bps = 80000;
bitrate_bps = cwnd_controller_.UpdateTargetBitrate(bitrate_bps);
EXPECT_EQ(72000u, bitrate_bps);
cwnd_controller_.UpdateMaxOutstandingData(50000);
bitrate_bps = cwnd_controller_.UpdateTargetBitrate(bitrate_bps);
EXPECT_EQ(static_cast<uint32_t>(72000 * 0.9 * 0.9), bitrate_bps);
}
TEST_F(CongestionWindowPushbackControllerTest, NormalCongestionWindow) {
cwnd_controller_.UpdateOutstandingData(100000);
cwnd_controller_.SetDataWindow(DataSize::bytes(200000));
uint32_t bitrate_bps = 80000;
bitrate_bps = cwnd_controller_.UpdateTargetBitrate(bitrate_bps);
EXPECT_EQ(80000u, bitrate_bps);
cwnd_controller_.UpdateMaxOutstandingData(20000);
bitrate_bps = cwnd_controller_.UpdateTargetBitrate(bitrate_bps);
EXPECT_EQ(80000u, bitrate_bps);
}
TEST_F(CongestionWindowPushbackControllerTest, LowBitrate) {
cwnd_controller_.UpdateOutstandingData(100000);
cwnd_controller_.SetDataWindow(DataSize::bytes(50000));
uint32_t bitrate_bps = 35000;
bitrate_bps = cwnd_controller_.UpdateTargetBitrate(bitrate_bps);
EXPECT_EQ(static_cast<uint32_t>(35000 * 0.9), bitrate_bps);
cwnd_controller_.UpdateMaxOutstandingData(20000);
bitrate_bps = cwnd_controller_.UpdateTargetBitrate(bitrate_bps);
EXPECT_EQ(30000u, bitrate_bps);
}
} // namespace test
} // namespace webrtc

View File

@ -39,6 +39,7 @@ class AcknowledgedBitrateEstimator;
class ProbeController;
class RateLimiter;
class RtcEventLog;
class CongestionWindowPushbackController;
class SendSideCongestionController
: public SendSideCongestionControllerInterface {
@ -169,6 +170,9 @@ class SendSideCongestionController
bool pacer_pushback_experiment_ = false;
float encoding_rate_ = 1.0;
const std::unique_ptr<CongestionWindowPushbackController>
congestion_window_pushback_controller_;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(SendSideCongestionController);
};

View File

@ -16,6 +16,7 @@
#include <vector>
#include "absl/memory/memory.h"
#include "api/transport/network_types.h"
#include "modules/congestion_controller/congestion_window_pushback_controller.h"
#include "modules/congestion_controller/goog_cc/include/goog_cc_factory.h"
#include "modules/remote_bitrate_estimator/include/bwe_defines.h"
#include "rtc_base/bind.h"
@ -38,6 +39,8 @@ namespace webrtc_cc {
namespace {
using send_side_cc_internal::PeriodicTask;
const char kCwndExperiment[] = "WebRTC-CwndExperiment";
// When CongestionWindowPushback is enabled, the pacer is oblivious to
// the congestion window. The relation between outstanding data and
// the congestion window affects encoder allocations directly.
@ -47,22 +50,6 @@ const char kCongestionPushbackExperiment[] = "WebRTC-CongestionWindowPushback";
// the congestion window and/or data spikes reduces encoder allocations.
const char kPacerPushbackExperiment[] = "WebRTC-PacerPushbackExperiment";
const int64_t PacerQueueUpdateIntervalMs = 25;
const uint32_t kDefaultMinPushbackTargetBitrateBps = 30000;
bool ReadCongestionWindowPushbackExperimentParameter(
uint32_t* min_pushback_target_bitrate_bps) {
RTC_DCHECK(min_pushback_target_bitrate_bps);
std::string experiment_string =
webrtc::field_trial::FindFullName(kCongestionPushbackExperiment);
int parsed_values = sscanf(experiment_string.c_str(), "Enabled-%" PRIu32,
min_pushback_target_bitrate_bps);
if (parsed_values == 1) {
RTC_CHECK_GE(*min_pushback_target_bitrate_bps, 0)
<< "Min pushback target bitrate must be greater than or equal to 0.";
return true;
}
return false;
}
bool IsPacerPushbackExperimentEnabled() {
return webrtc::field_trial::IsEnabled(kPacerPushbackExperiment) ||
@ -71,8 +58,16 @@ bool IsPacerPushbackExperimentEnabled() {
webrtc::runtime_enabled_features::kDualStreamModeFeatureName));
}
bool IsCongestionWindowExperimentEnabled() {
return webrtc::field_trial::IsEnabled(kCongestionPushbackExperiment);
bool IsCongestionWindowPushbackExperimentEnabled() {
return webrtc::field_trial::IsEnabled(kCongestionPushbackExperiment) &&
webrtc::field_trial::IsEnabled(kCwndExperiment);
}
std::unique_ptr<CongestionWindowPushbackController>
MaybeInitalizeCongestionWindowPushbackController() {
return IsCongestionWindowPushbackExperimentEnabled()
? absl::make_unique<CongestionWindowPushbackController>()
: nullptr;
}
void SortPacketFeedbackVector(std::vector<webrtc::PacketFeedback>* input) {
@ -200,17 +195,16 @@ class ControlHandler {
PacerController* pacer_controller_;
absl::optional<TargetTransferRate> current_target_rate_msg_;
absl::optional<DataSize> congestion_window_;
DataSize outstanding_data_ = DataSize::Zero();
bool network_available_ = true;
int64_t last_reported_target_bitrate_bps_ = 0;
uint8_t last_reported_fraction_loss_ = 0;
int64_t last_reported_rtt_ms_ = 0;
const bool pacer_pushback_experiment_ = false;
const bool congestion_window_pushback_experiment_ = false;
uint32_t min_pushback_target_bitrate_bps_;
int64_t pacer_expected_queue_ms_ = 0;
double encoding_rate_ratio_ = 1.0;
const std::unique_ptr<CongestionWindowPushbackController>
congestion_window_pushback_controller_;
rtc::SequencedTaskChecker sequenced_checker_;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(ControlHandler);
@ -222,21 +216,18 @@ ControlHandler::ControlHandler(NetworkChangedObserver* observer,
: observer_(observer),
pacer_controller_(pacer_controller),
pacer_pushback_experiment_(IsPacerPushbackExperimentEnabled()),
congestion_window_pushback_experiment_(
IsCongestionWindowExperimentEnabled()) {
congestion_window_pushback_controller_(
MaybeInitalizeCongestionWindowPushbackController()) {
sequenced_checker_.Detach();
if (congestion_window_pushback_experiment_ &&
!ReadCongestionWindowPushbackExperimentParameter(
&min_pushback_target_bitrate_bps_)) {
min_pushback_target_bitrate_bps_ = kDefaultMinPushbackTargetBitrateBps;
}
}
void ControlHandler::PostUpdates(NetworkControlUpdate update) {
RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
if (update.congestion_window) {
congestion_window_ = update.congestion_window;
if (!congestion_window_pushback_experiment_) {
if (congestion_window_pushback_controller_) {
congestion_window_pushback_controller_->SetDataWindow(
update.congestion_window.value());
} else {
pacer_controller_->OnCongestionWindow(*update.congestion_window);
}
}
@ -260,7 +251,10 @@ void ControlHandler::OnNetworkAvailability(NetworkAvailability msg) {
void ControlHandler::OnOutstandingData(DataSize in_flight_data) {
RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
outstanding_data_ = in_flight_data;
if (congestion_window_pushback_controller_) {
congestion_window_pushback_controller_->UpdateOutstandingData(
in_flight_data.bytes());
}
OnNetworkInvalidation();
}
@ -289,29 +283,10 @@ void ControlHandler::OnNetworkInvalidation() {
if (!network_available_) {
target_bitrate_bps = 0;
} else if (congestion_window_pushback_experiment_ && congestion_window_) {
double fill_ratio = outstanding_data_.bytes() /
static_cast<double>(congestion_window_->bytes());
if (fill_ratio > 1.5) {
encoding_rate_ratio_ *= 0.9;
} else if (fill_ratio > 1) {
encoding_rate_ratio_ *= 0.95;
} else if (fill_ratio < 0.1) {
encoding_rate_ratio_ = 1.0;
} else {
encoding_rate_ratio_ *= 1.05;
encoding_rate_ratio_ = std::min(encoding_rate_ratio_, 1.0);
}
uint32_t adjusted_target_bitrate_bps =
static_cast<uint32_t>(target_bitrate_bps * encoding_rate_ratio_);
// If adjusted target bitrate is lower than minimum target bitrate,
// does not reduce target bitrate lower than minimum target bitrate.
} else if (congestion_window_pushback_controller_) {
target_bitrate_bps =
adjusted_target_bitrate_bps < min_pushback_target_bitrate_bps_
? std::min(target_bitrate_bps, min_pushback_target_bitrate_bps_)
: adjusted_target_bitrate_bps;
congestion_window_pushback_controller_->UpdateTargetBitrate(
target_bitrate_bps);
} else if (!pacer_pushback_experiment_) {
target_bitrate_bps = IsSendQueueFull() ? 0 : target_bitrate_bps;
} else {

View File

@ -18,6 +18,7 @@
#include "absl/memory/memory.h"
#include "modules/bitrate_controller/include/bitrate_controller.h"
#include "modules/congestion_controller/congestion_window_pushback_controller.h"
#include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h"
#include "modules/congestion_controller/goog_cc/probe_controller.h"
#include "modules/remote_bitrate_estimator/include/bwe_defines.h"
@ -36,6 +37,12 @@ namespace {
const char kCwndExperiment[] = "WebRTC-CwndExperiment";
const char kPacerPushbackExperiment[] = "WebRTC-PacerPushbackExperiment";
// When CongestionWindowPushback is enabled, the pacer is oblivious to
// the congestion window. The relation between outstanding data and
// the congestion window affects encoder allocations directly.
const char kCongestionPushbackExperiment[] = "WebRTC-CongestionWindowPushback";
const int64_t kDefaultAcceptedQueueMs = 250;
bool CwndExperimentEnabled() {
@ -59,6 +66,18 @@ bool ReadCwndExperimentParameter(int64_t* accepted_queue_ms) {
return false;
}
bool IsCongestionWindowPushbackExperimentEnabled() {
return webrtc::field_trial::IsEnabled(kCongestionPushbackExperiment) &&
webrtc::field_trial::IsEnabled(kCwndExperiment);
}
std::unique_ptr<CongestionWindowPushbackController>
MaybeCreateCongestionWindowPushbackController() {
return IsCongestionWindowPushbackExperimentEnabled()
? absl::make_unique<CongestionWindowPushbackController>()
: nullptr;
}
static const int64_t kRetransmitWindowSizeMs = 500;
// Makes sure that the bitrate and the min, max values are in valid range.
@ -135,7 +154,9 @@ SendSideCongestionController::SendSideCongestionController(
send_side_bwe_with_overhead_(
webrtc::field_trial::IsEnabled("WebRTC-SendSideBwe-WithOverhead")),
transport_overhead_bytes_per_packet_(0),
pacer_pushback_experiment_(IsPacerPushbackExperimentEnabled()) {
pacer_pushback_experiment_(IsPacerPushbackExperimentEnabled()),
congestion_window_pushback_controller_(
MaybeCreateCongestionWindowPushbackController()) {
delay_based_bwe_->SetMinBitrate(min_bitrate_bps_);
if (in_cwnd_experiment_ &&
!ReadCwndExperimentParameter(&accepted_queue_ms_)) {
@ -418,8 +439,9 @@ void SendSideCongestionController::OnTransportFeedback(
pacer_->GetApplicationLimitedRegionStartTime());
probe_controller_->RequestProbe(clock_->TimeInMilliseconds());
}
if (in_cwnd_experiment_)
if (in_cwnd_experiment_) {
LimitOutstandingBytes(transport_feedback_adapter_.GetOutstandingBytes());
}
}
void SendSideCongestionController::LimitOutstandingBytes(
@ -443,7 +465,14 @@ void SendSideCongestionController::LimitOutstandingBytes(
<< " max outstanding: " << max_outstanding_bytes;
RTC_LOG(LS_INFO) << "Feedback rtt: " << *min_rtt_ms
<< " Bitrate: " << last_reported_bitrate_bps_;
pause_pacer_ = num_outstanding_bytes > max_outstanding_bytes;
if (congestion_window_pushback_controller_) {
congestion_window_pushback_controller_->UpdateOutstandingData(
num_outstanding_bytes);
congestion_window_pushback_controller_->UpdateMaxOutstandingData(
max_outstanding_bytes);
} else {
pause_pacer_ = num_outstanding_bytes > max_outstanding_bytes;
}
}
std::vector<PacketFeedback>
@ -478,25 +507,27 @@ void SendSideCongestionController::MaybeTriggerOnNetworkChanged() {
retransmission_rate_limiter_->SetMaxRate(bitrate_bps);
}
if (!pacer_pushback_experiment_) {
bitrate_bps = IsNetworkDown() || IsSendQueueFull() ? 0 : bitrate_bps;
if (IsNetworkDown()) {
bitrate_bps = 0;
} else if (congestion_window_pushback_controller_) {
rtc::CritScope lock(&network_state_lock_);
bitrate_bps = congestion_window_pushback_controller_->UpdateTargetBitrate(
bitrate_bps);
} else if (!pacer_pushback_experiment_) {
bitrate_bps = IsSendQueueFull() ? 0 : bitrate_bps;
} else {
if (IsNetworkDown()) {
bitrate_bps = 0;
} else {
int64_t queue_length_ms = pacer_->ExpectedQueueTimeMs();
int64_t queue_length_ms = pacer_->ExpectedQueueTimeMs();
if (queue_length_ms == 0) {
encoding_rate_ = 1.0;
} else if (queue_length_ms > 50) {
float encoding_rate = 1.0 - queue_length_ms / 1000.0;
encoding_rate_ = std::min(encoding_rate_, encoding_rate);
encoding_rate_ = std::max(encoding_rate_, 0.0f);
}
bitrate_bps *= encoding_rate_;
bitrate_bps = bitrate_bps < 50000 ? 0 : bitrate_bps;
if (queue_length_ms == 0) {
encoding_rate_ = 1.0;
} else if (queue_length_ms > 50) {
float encoding_rate = 1.0 - queue_length_ms / 1000.0;
encoding_rate_ = std::min(encoding_rate_, encoding_rate);
encoding_rate_ = std::max(encoding_rate_, 0.0f);
}
bitrate_bps *= encoding_rate_;
bitrate_bps = bitrate_bps < 50000 ? 0 : bitrate_bps;
}
if (HasNetworkParametersToReportChanged(bitrate_bps, fraction_loss, rtt)) {