Moved congestion controller to task queue.

The goal of this work is to make it easier to experiment with the
bandwidth estimation implementation. For this reason network control
functionality is moved from SendSideCongestionController(SSCC),
PacedSender and BitrateController to the newly created
GoogCcNetworkController which implements the newly created
NetworkControllerInterface. This allows the implementation to be
replaced at runtime in the future.

This is the first part of a split of a larger CL, see:
https://webrtc-review.googlesource.com/c/src/+/39788/8
For further explanations.

Bug: webrtc:8415
Change-Id: I770189c04cc31b313bd4e57821acff55fbcb1ad3
Reviewed-on: https://webrtc-review.googlesource.com/43840
Commit-Queue: Sebastian Jansson <srte@webrtc.org>
Reviewed-by: Björn Terelius <terelius@webrtc.org>
Reviewed-by: Stefan Holmer <stefan@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#21868}
This commit is contained in:
Sebastian Jansson 2018-02-02 12:57:33 +01:00 committed by Commit Bot
parent 98a867ccd2
commit 0cbcba7ea0
57 changed files with 2993 additions and 834 deletions

View file

@ -46,7 +46,8 @@ const RtpKeepAliveConfig& RtpTransportControllerSend::keepalive_config() const {
void RtpTransportControllerSend::SetAllocatedSendBitrateLimits( void RtpTransportControllerSend::SetAllocatedSendBitrateLimits(
int min_send_bitrate_bps, int min_send_bitrate_bps,
int max_padding_bitrate_bps) { int max_padding_bitrate_bps) {
pacer_.SetSendBitrateLimits(min_send_bitrate_bps, max_padding_bitrate_bps); send_side_cc_.SetSendBitrateLimits(min_send_bitrate_bps,
max_padding_bitrate_bps);
} }
void RtpTransportControllerSend::SetKeepAliveConfig( void RtpTransportControllerSend::SetKeepAliveConfig(

View file

@ -340,11 +340,11 @@ TEST_F(BitrateControllerTest, OneBitrateObserverMultipleReportBlocks) {
report_blocks.clear(); report_blocks.clear();
// All packets lost on stream with few packets, no back-off. // All packets lost on stream with few packets, no back-off.
report_blocks.push_back(CreateReportBlock(1, 2, 1, sequence_number[0])); report_blocks.push_back(CreateReportBlock(1, 2, 0, sequence_number[0]));
report_blocks.push_back(CreateReportBlock(1, 3, 255, sequence_number[1])); report_blocks.push_back(CreateReportBlock(1, 3, 255, sequence_number[1]));
bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms); bandwidth_observer_->OnReceivedRtcpReceiverReport(report_blocks, 50, time_ms);
EXPECT_EQ(bitrate_observer_.last_bitrate_, last_bitrate); EXPECT_EQ(bitrate_observer_.last_bitrate_, last_bitrate);
EXPECT_EQ(WeightedLoss(20, 1, 1, 255), bitrate_observer_.last_fraction_loss_); EXPECT_EQ(WeightedLoss(20, 0, 1, 255), bitrate_observer_.last_fraction_loss_);
EXPECT_EQ(50, bitrate_observer_.last_rtt_); EXPECT_EQ(50, bitrate_observer_.last_rtt_);
last_bitrate = bitrate_observer_.last_bitrate_; last_bitrate = bitrate_observer_.last_bitrate_;
sequence_number[0] += 20; sequence_number[0] += 20;

View file

@ -105,7 +105,7 @@ bool ReadBweLossExperimentParameters(float* low_loss_threshold,
} // namespace } // namespace
SendSideBandwidthEstimation::SendSideBandwidthEstimation(RtcEventLog* event_log) SendSideBandwidthEstimation::SendSideBandwidthEstimation(RtcEventLog* event_log)
: lost_packets_since_last_loss_update_Q8_(0), : lost_packets_since_last_loss_update_(0),
expected_packets_since_last_loss_update_(0), expected_packets_since_last_loss_update_(0),
current_bitrate_bps_(0), current_bitrate_bps_(0),
min_bitrate_configured_(congestion_controller::GetMinBitrateBps()), min_bitrate_configured_(congestion_controller::GetMinBitrateBps()),
@ -125,6 +125,7 @@ SendSideBandwidthEstimation::SendSideBandwidthEstimation(RtcEventLog* event_log)
initially_lost_packets_(0), initially_lost_packets_(0),
bitrate_at_2_seconds_kbps_(0), bitrate_at_2_seconds_kbps_(0),
uma_update_state_(kNoUpdate), uma_update_state_(kNoUpdate),
uma_rtt_state_(kNoUpdate),
rampup_uma_stats_updated_(kNumUmaRampupMetrics, false), rampup_uma_stats_updated_(kNumUmaRampupMetrics, false),
event_log_(event_log), event_log_(event_log),
last_rtc_event_log_ms_(-1), last_rtc_event_log_ms_(-1),
@ -206,24 +207,28 @@ void SendSideBandwidthEstimation::UpdateDelayBasedEstimate(
} }
void SendSideBandwidthEstimation::UpdateReceiverBlock(uint8_t fraction_loss, void SendSideBandwidthEstimation::UpdateReceiverBlock(uint8_t fraction_loss,
int64_t rtt, int64_t rtt_ms,
int number_of_packets, int number_of_packets,
int64_t now_ms) { int64_t now_ms) {
const int kRoundingConstant = 128;
int packets_lost = (static_cast<int>(fraction_loss) * number_of_packets +
kRoundingConstant) >>
8;
UpdatePacketsLost(packets_lost, number_of_packets, now_ms);
UpdateRtt(rtt_ms, now_ms);
}
void SendSideBandwidthEstimation::UpdatePacketsLost(int packets_lost,
int number_of_packets,
int64_t now_ms) {
last_feedback_ms_ = now_ms; last_feedback_ms_ = now_ms;
if (first_report_time_ms_ == -1) if (first_report_time_ms_ == -1)
first_report_time_ms_ = now_ms; first_report_time_ms_ = now_ms;
// Update RTT if we were able to compute an RTT based on this RTCP.
// FlexFEC doesn't send RTCP SR, which means we won't be able to compute RTT.
if (rtt > 0)
last_round_trip_time_ms_ = rtt;
// Check sequence number diff and weight loss report // Check sequence number diff and weight loss report
if (number_of_packets > 0) { if (number_of_packets > 0) {
// Calculate number of lost packets.
const int num_lost_packets_Q8 = fraction_loss * number_of_packets;
// Accumulate reports. // Accumulate reports.
lost_packets_since_last_loss_update_Q8_ += num_lost_packets_Q8; lost_packets_since_last_loss_update_ += packets_lost;
expected_packets_since_last_loss_update_ += number_of_packets; expected_packets_since_last_loss_update_ += number_of_packets;
// Don't generate a loss rate until it can be based on enough packets. // Don't generate a loss rate until it can be based on enough packets.
@ -231,21 +236,22 @@ void SendSideBandwidthEstimation::UpdateReceiverBlock(uint8_t fraction_loss,
return; return;
has_decreased_since_last_fraction_loss_ = false; has_decreased_since_last_fraction_loss_ = false;
last_fraction_loss_ = lost_packets_since_last_loss_update_Q8_ / int64_t lost_q8 = lost_packets_since_last_loss_update_ << 8;
expected_packets_since_last_loss_update_; int64_t expected = expected_packets_since_last_loss_update_;
last_fraction_loss_ = std::min<int>(lost_q8 / expected, 255);
// Reset accumulators. // Reset accumulators.
lost_packets_since_last_loss_update_Q8_ = 0;
lost_packets_since_last_loss_update_ = 0;
expected_packets_since_last_loss_update_ = 0; expected_packets_since_last_loss_update_ = 0;
last_packet_report_ms_ = now_ms; last_packet_report_ms_ = now_ms;
UpdateEstimate(now_ms); UpdateEstimate(now_ms);
} }
UpdateUmaStats(now_ms, rtt, (fraction_loss * number_of_packets) >> 8); UpdateUmaStatsPacketsLost(now_ms, packets_lost);
} }
void SendSideBandwidthEstimation::UpdateUmaStats(int64_t now_ms, void SendSideBandwidthEstimation::UpdateUmaStatsPacketsLost(int64_t now_ms,
int64_t rtt, int packets_lost) {
int lost_packets) {
int bitrate_kbps = static_cast<int>((current_bitrate_bps_ + 500) / 1000); int bitrate_kbps = static_cast<int>((current_bitrate_bps_ + 500) / 1000);
for (size_t i = 0; i < kNumUmaRampupMetrics; ++i) { for (size_t i = 0; i < kNumUmaRampupMetrics; ++i) {
if (!rampup_uma_stats_updated_[i] && if (!rampup_uma_stats_updated_[i] &&
@ -256,14 +262,12 @@ void SendSideBandwidthEstimation::UpdateUmaStats(int64_t now_ms,
} }
} }
if (IsInStartPhase(now_ms)) { if (IsInStartPhase(now_ms)) {
initially_lost_packets_ += lost_packets; initially_lost_packets_ += packets_lost;
} else if (uma_update_state_ == kNoUpdate) { } else if (uma_update_state_ == kNoUpdate) {
uma_update_state_ = kFirstDone; uma_update_state_ = kFirstDone;
bitrate_at_2_seconds_kbps_ = bitrate_kbps; bitrate_at_2_seconds_kbps_ = bitrate_kbps;
RTC_HISTOGRAM_COUNTS("WebRTC.BWE.InitiallyLostPackets", RTC_HISTOGRAM_COUNTS("WebRTC.BWE.InitiallyLostPackets",
initially_lost_packets_, 0, 100, 50); initially_lost_packets_, 0, 100, 50);
RTC_HISTOGRAM_COUNTS("WebRTC.BWE.InitialRtt", static_cast<int>(rtt), 0,
2000, 50);
RTC_HISTOGRAM_COUNTS("WebRTC.BWE.InitialBandwidthEstimate", RTC_HISTOGRAM_COUNTS("WebRTC.BWE.InitialBandwidthEstimate",
bitrate_at_2_seconds_kbps_, 0, 2000, 50); bitrate_at_2_seconds_kbps_, 0, 2000, 50);
} else if (uma_update_state_ == kFirstDone && } else if (uma_update_state_ == kFirstDone &&
@ -276,6 +280,19 @@ void SendSideBandwidthEstimation::UpdateUmaStats(int64_t now_ms,
} }
} }
void SendSideBandwidthEstimation::UpdateRtt(int64_t rtt_ms, int64_t now_ms) {
// Update RTT if we were able to compute an RTT based on this RTCP.
// FlexFEC doesn't send RTCP SR, which means we won't be able to compute RTT.
if (rtt_ms > 0)
last_round_trip_time_ms_ = rtt_ms;
if (!IsInStartPhase(now_ms) && uma_rtt_state_ == kNoUpdate) {
uma_rtt_state_ = kDone;
RTC_HISTOGRAM_COUNTS("WebRTC.BWE.InitialRtt", static_cast<int>(rtt_ms), 0,
2000, 50);
}
}
void SendSideBandwidthEstimation::UpdateEstimate(int64_t now_ms) { void SendSideBandwidthEstimation::UpdateEstimate(int64_t now_ms) {
uint32_t new_bitrate = current_bitrate_bps_; uint32_t new_bitrate = current_bitrate_bps_;
// We trust the REMB and/or delay-based estimate during the first 2 seconds if // We trust the REMB and/or delay-based estimate during the first 2 seconds if
@ -357,7 +374,7 @@ void SendSideBandwidthEstimation::UpdateEstimate(int64_t now_ms) {
new_bitrate *= 0.8; new_bitrate *= 0.8;
// Reset accumulators since we've already acted on missing feedback and // Reset accumulators since we've already acted on missing feedback and
// shouldn't to act again on these old lost packets. // shouldn't to act again on these old lost packets.
lost_packets_since_last_loss_update_Q8_ = 0; lost_packets_since_last_loss_update_ = 0;
expected_packets_since_last_loss_update_ = 0; expected_packets_since_last_loss_update_ = 0;
last_timeout_ms_ = now_ms; last_timeout_ms_ = now_ms;
} }

View file

@ -42,10 +42,18 @@ class SendSideBandwidthEstimation {
// Call when we receive a RTCP message with a ReceiveBlock. // Call when we receive a RTCP message with a ReceiveBlock.
void UpdateReceiverBlock(uint8_t fraction_loss, void UpdateReceiverBlock(uint8_t fraction_loss,
int64_t rtt, int64_t rtt_ms,
int number_of_packets, int number_of_packets,
int64_t now_ms); int64_t now_ms);
// Call when we receive a RTCP message with a ReceiveBlock.
void UpdatePacketsLost(int packets_lost,
int number_of_packets,
int64_t now_ms);
// Call when we receive a RTCP message with a ReceiveBlock.
void UpdateRtt(int64_t rtt, int64_t now_ms);
void SetBitrates(int send_bitrate, void SetBitrates(int send_bitrate,
int min_bitrate, int min_bitrate,
int max_bitrate); int max_bitrate);
@ -58,7 +66,7 @@ class SendSideBandwidthEstimation {
bool IsInStartPhase(int64_t now_ms) const; bool IsInStartPhase(int64_t now_ms) const;
void UpdateUmaStats(int64_t now_ms, int64_t rtt, int lost_packets); void UpdateUmaStatsPacketsLost(int64_t now_ms, int packets_lost);
// Updates history of min bitrates. // Updates history of min bitrates.
// After this method returns min_bitrate_history_.front().second contains the // After this method returns min_bitrate_history_.front().second contains the
@ -72,7 +80,7 @@ class SendSideBandwidthEstimation {
std::deque<std::pair<int64_t, uint32_t> > min_bitrate_history_; std::deque<std::pair<int64_t, uint32_t> > min_bitrate_history_;
// incoming filters // incoming filters
int lost_packets_since_last_loss_update_Q8_; int lost_packets_since_last_loss_update_;
int expected_packets_since_last_loss_update_; int expected_packets_since_last_loss_update_;
uint32_t current_bitrate_bps_; uint32_t current_bitrate_bps_;
@ -95,6 +103,7 @@ class SendSideBandwidthEstimation {
int initially_lost_packets_; int initially_lost_packets_;
int bitrate_at_2_seconds_kbps_; int bitrate_at_2_seconds_kbps_;
UmaState uma_update_state_; UmaState uma_update_state_;
UmaState uma_rtt_state_;
std::vector<bool> rampup_uma_stats_updated_; std::vector<bool> rampup_uma_stats_updated_;
RtcEventLog* event_log_; RtcEventLog* event_log_;
int64_t last_rtc_event_log_ms_; int64_t last_rtc_event_log_ms_;

View file

@ -22,8 +22,8 @@ rtc_static_library("congestion_controller") {
sources = [ sources = [
"include/receive_side_congestion_controller.h", "include/receive_side_congestion_controller.h",
"include/send_side_congestion_controller.h", "include/send_side_congestion_controller.h",
"probe_controller.cc", "pacer_controller.cc",
"probe_controller.h", "pacer_controller.h",
"receive_side_congestion_controller.cc", "receive_side_congestion_controller.cc",
"send_side_congestion_controller.cc", "send_side_congestion_controller.cc",
] ]
@ -37,13 +37,14 @@ rtc_static_library("congestion_controller") {
} }
deps = [ deps = [
":delay_based_bwe", ":goog_cc",
":estimators",
":transport_feedback", ":transport_feedback",
"..:module_api", "..:module_api",
"../..:webrtc_common", "../..:webrtc_common",
"../../rtc_base:checks", "../../rtc_base:checks",
"../../rtc_base:rate_limiter", "../../rtc_base:rate_limiter",
"../../rtc_base:rtc_task_queue_api",
"../../rtc_base:sequenced_task_checker",
"../../system_wrappers", "../../system_wrappers",
"../../system_wrappers:field_trial_api", "../../system_wrappers:field_trial_api",
"../../system_wrappers:metrics_api", "../../system_wrappers:metrics_api",
@ -52,6 +53,7 @@ rtc_static_library("congestion_controller") {
"../pacing", "../pacing",
"../remote_bitrate_estimator", "../remote_bitrate_estimator",
"../rtp_rtcp:rtp_rtcp_format", "../rtp_rtcp:rtp_rtcp_format",
"./network_control",
] ]
if (!build_with_mozilla) { if (!build_with_mozilla) {
@ -69,14 +71,57 @@ rtc_static_library("transport_feedback") {
] ]
deps = [ deps = [
"../../modules:module_api", "..:module_api",
"../../rtc_base:checks", "../../rtc_base:checks",
"../../rtc_base:rtc_base_approved", "../../rtc_base:rtc_base_approved",
"../../system_wrappers:system_wrappers", "../../system_wrappers",
"../rtp_rtcp:rtp_rtcp_format", "../rtp_rtcp:rtp_rtcp_format",
] ]
} }
rtc_static_library("goog_cc") {
configs += [ ":bwe_test_logging" ]
sources = [
"alr_detector.cc",
"alr_detector.h",
"goog_cc_network_control.cc",
"goog_cc_network_control.h",
"include/goog_cc_factory.h",
"probe_controller.cc",
"probe_controller.h",
]
# TODO(jschuh): Bug 1348: fix this warning.
configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
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" ]
}
deps = [
":delay_based_bwe",
":estimators",
"..:module_api",
"../..:webrtc_common",
"../../:typedefs",
"../../api:optional",
"../../logging:rtc_event_log_api",
"../../logging:rtc_event_pacing",
"../../rtc_base:checks",
"../../rtc_base:rtc_base_approved",
"../../rtc_base/experiments:alr_experiment",
"../../system_wrappers",
"../../system_wrappers:field_trial_api",
"../../system_wrappers:metrics_api",
"../bitrate_controller",
"../pacing",
"../remote_bitrate_estimator",
"../rtp_rtcp:rtp_rtcp_format",
"./network_control",
]
}
rtc_source_set("estimators") { rtc_source_set("estimators") {
configs += [ ":bwe_test_logging" ] configs += [ ":bwe_test_logging" ]
sources = [ sources = [
@ -110,7 +155,7 @@ rtc_source_set("estimators") {
"../../rtc_base:rtc_numerics", "../../rtc_base:rtc_numerics",
"../../system_wrappers:field_trial_api", "../../system_wrappers:field_trial_api",
"../../system_wrappers:metrics_api", "../../system_wrappers:metrics_api",
"../remote_bitrate_estimator:remote_bitrate_estimator", "../remote_bitrate_estimator",
"../rtp_rtcp:rtp_rtcp_format", "../rtp_rtcp:rtp_rtcp_format",
] ]
} }
@ -145,25 +190,16 @@ if (rtc_include_tests) {
testonly = true testonly = true
sources = [ sources = [
"acknowledged_bitrate_estimator_unittest.cc",
"congestion_controller_unittests_helper.cc", "congestion_controller_unittests_helper.cc",
"congestion_controller_unittests_helper.h", "congestion_controller_unittests_helper.h",
"delay_based_bwe_unittest.cc",
"delay_based_bwe_unittest_helper.cc",
"delay_based_bwe_unittest_helper.h",
"median_slope_estimator_unittest.cc",
"probe_bitrate_estimator_unittest.cc",
"probe_controller_unittest.cc",
"receive_side_congestion_controller_unittest.cc", "receive_side_congestion_controller_unittest.cc",
"send_side_congestion_controller_unittest.cc", "send_side_congestion_controller_unittest.cc",
"send_time_history_unittest.cc", "send_time_history_unittest.cc",
"transport_feedback_adapter_unittest.cc", "transport_feedback_adapter_unittest.cc",
"trendline_estimator_unittest.cc",
] ]
deps = [ deps = [
":congestion_controller", ":congestion_controller",
":delay_based_bwe", ":goog_cc_unittests",
":estimators",
":mock_congestion_controller", ":mock_congestion_controller",
":transport_feedback", ":transport_feedback",
"../../logging:mocks", "../../logging:mocks",
@ -174,12 +210,51 @@ if (rtc_include_tests) {
"../../system_wrappers", "../../system_wrappers",
"../../test:field_trial", "../../test:field_trial",
"../../test:test_support", "../../test:test_support",
"../bitrate_controller:bitrate_controller",
"../bitrate_controller:mocks", "../bitrate_controller:mocks",
"../pacing:mock_paced_sender", "../pacing:mock_paced_sender",
"../pacing:pacing", "../pacing:pacing",
"../remote_bitrate_estimator:remote_bitrate_estimator", "../remote_bitrate_estimator:remote_bitrate_estimator",
"../rtp_rtcp:rtp_rtcp_format", "../rtp_rtcp:rtp_rtcp_format",
"./network_control",
"//testing/gmock",
]
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("goog_cc_unittests") {
testonly = true
sources = [
"acknowledged_bitrate_estimator_unittest.cc",
"alr_detector_unittest.cc",
"delay_based_bwe_unittest.cc",
"delay_based_bwe_unittest_helper.cc",
"delay_based_bwe_unittest_helper.h",
"median_slope_estimator_unittest.cc",
"probe_bitrate_estimator_unittest.cc",
"probe_controller_unittest.cc",
"trendline_estimator_unittest.cc",
]
deps = [
":delay_based_bwe",
":estimators",
":goog_cc",
"../../rtc_base:checks",
"../../rtc_base:rtc_base_approved",
"../../rtc_base:rtc_base_tests_utils",
"../../rtc_base/experiments:alr_experiment",
"../../system_wrappers",
"../../test:field_trial",
"../../test:test_support",
"../pacing",
"../remote_bitrate_estimator",
"../rtp_rtcp:rtp_rtcp_format",
"./network_control",
"./network_control:network_control_unittests",
"//testing/gmock",
] ]
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).

View file

@ -27,6 +27,8 @@ bool IsInSendTimeHistory(const PacketFeedback& packet) {
AcknowledgedBitrateEstimator::AcknowledgedBitrateEstimator() AcknowledgedBitrateEstimator::AcknowledgedBitrateEstimator()
: AcknowledgedBitrateEstimator(rtc::MakeUnique<BitrateEstimator>()) {} : AcknowledgedBitrateEstimator(rtc::MakeUnique<BitrateEstimator>()) {}
AcknowledgedBitrateEstimator::~AcknowledgedBitrateEstimator() {}
AcknowledgedBitrateEstimator::AcknowledgedBitrateEstimator( AcknowledgedBitrateEstimator::AcknowledgedBitrateEstimator(
std::unique_ptr<BitrateEstimator> bitrate_estimator) std::unique_ptr<BitrateEstimator> bitrate_estimator)
: bitrate_estimator_(std::move(bitrate_estimator)) {} : bitrate_estimator_(std::move(bitrate_estimator)) {}

View file

@ -27,6 +27,7 @@ class AcknowledgedBitrateEstimator {
std::unique_ptr<BitrateEstimator> bitrate_estimator); std::unique_ptr<BitrateEstimator> bitrate_estimator);
AcknowledgedBitrateEstimator(); AcknowledgedBitrateEstimator();
~AcknowledgedBitrateEstimator();
void IncomingPacketFeedbackVector( void IncomingPacketFeedbackVector(
const std::vector<PacketFeedback>& packet_feedback_vector); const std::vector<PacketFeedback>& packet_feedback_vector);

View file

@ -8,11 +8,11 @@
* 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 "modules/pacing/alr_detector.h" #include "modules/congestion_controller/alr_detector.h"
#include <algorithm> #include <algorithm>
#include <string>
#include <cstdio> #include <cstdio>
#include <string>
#include "logging/rtc_event_log/events/rtc_event_alr_state.h" #include "logging/rtc_event_log/events/rtc_event_alr_state.h"
#include "logging/rtc_event_log/rtc_event_log.h" #include "logging/rtc_event_log/rtc_event_log.h"
@ -52,7 +52,16 @@ AlrDetector::AlrDetector(RtcEventLog* event_log)
AlrDetector::~AlrDetector() {} AlrDetector::~AlrDetector() {}
void AlrDetector::OnBytesSent(size_t bytes_sent, int64_t delta_time_ms) { void AlrDetector::OnBytesSent(size_t bytes_sent, int64_t send_time_ms) {
if (!last_send_time_ms_.has_value()) {
last_send_time_ms_ = send_time_ms;
// Since the duration for sending the bytes is unknwon, return without
// updating alr state.
return;
}
int64_t delta_time_ms = send_time_ms - *last_send_time_ms_;
last_send_time_ms_ = send_time_ms;
alr_budget_.UseBudget(bytes_sent); alr_budget_.UseBudget(bytes_sent);
alr_budget_.IncreaseBudget(delta_time_ms); alr_budget_.IncreaseBudget(delta_time_ms);
bool state_changed = false; bool state_changed = false;

View file

@ -8,8 +8,8 @@
* 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.
*/ */
#ifndef MODULES_PACING_ALR_DETECTOR_H_ #ifndef MODULES_CONGESTION_CONTROLLER_ALR_DETECTOR_H_
#define MODULES_PACING_ALR_DETECTOR_H_ #define MODULES_CONGESTION_CONTROLLER_ALR_DETECTOR_H_
#include "api/optional.h" #include "api/optional.h"
#include "common_types.h" // NOLINT(build/include) #include "common_types.h" // NOLINT(build/include)
@ -35,7 +35,7 @@ class AlrDetector {
explicit AlrDetector(RtcEventLog* event_log); explicit AlrDetector(RtcEventLog* event_log);
~AlrDetector(); ~AlrDetector();
void OnBytesSent(size_t bytes_sent, int64_t delta_time_ms); void OnBytesSent(size_t bytes_sent, int64_t send_time_ms);
// Set current estimated bandwidth. // Set current estimated bandwidth.
void SetEstimatedBitrate(int bitrate_bps); void SetEstimatedBitrate(int bitrate_bps);
@ -61,6 +61,8 @@ class AlrDetector {
int alr_start_budget_level_percent_; int alr_start_budget_level_percent_;
int alr_stop_budget_level_percent_; int alr_stop_budget_level_percent_;
rtc::Optional<int64_t> last_send_time_ms_;
IntervalBudget alr_budget_; IntervalBudget alr_budget_;
rtc::Optional<int64_t> alr_started_time_ms_; rtc::Optional<int64_t> alr_started_time_ms_;
@ -69,4 +71,4 @@ class AlrDetector {
} // namespace webrtc } // namespace webrtc
#endif // MODULES_PACING_ALR_DETECTOR_H_ #endif // MODULES_CONGESTION_CONTROLLER_ALR_DETECTOR_H_

View file

@ -8,7 +8,7 @@
* 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 "modules/pacing/alr_detector.h" #include "modules/congestion_controller/alr_detector.h"
#include "rtc_base/experiments/alr_experiment.h" #include "rtc_base/experiments/alr_experiment.h"
#include "test/field_trial.h" #include "test/field_trial.h"
@ -25,8 +25,9 @@ namespace webrtc {
namespace { namespace {
class SimulateOutgoingTrafficIn { class SimulateOutgoingTrafficIn {
public: public:
explicit SimulateOutgoingTrafficIn(AlrDetector* alr_detector) explicit SimulateOutgoingTrafficIn(AlrDetector* alr_detector,
: alr_detector_(alr_detector) { int64_t* timestamp_ms)
: alr_detector_(alr_detector), timestamp_ms_(timestamp_ms) {
RTC_CHECK(alr_detector_); RTC_CHECK(alr_detector_);
} }
@ -48,18 +49,21 @@ class SimulateOutgoingTrafficIn {
return; return;
const int kTimeStepMs = 10; const int kTimeStepMs = 10;
for (int t = 0; t < *interval_ms_; t += kTimeStepMs) { for (int t = 0; t < *interval_ms_; t += kTimeStepMs) {
*timestamp_ms_ += kTimeStepMs;
alr_detector_->OnBytesSent(kEstimatedBitrateBps * *usage_percentage_ * alr_detector_->OnBytesSent(kEstimatedBitrateBps * *usage_percentage_ *
kTimeStepMs / (8 * 100 * 1000), kTimeStepMs / (8 * 100 * 1000),
kTimeStepMs); *timestamp_ms_);
} }
int remainder_ms = *interval_ms_ % kTimeStepMs; int remainder_ms = *interval_ms_ % kTimeStepMs;
if (remainder_ms > 0) { if (remainder_ms > 0) {
*timestamp_ms_ += kTimeStepMs;
alr_detector_->OnBytesSent(kEstimatedBitrateBps * *usage_percentage_ * alr_detector_->OnBytesSent(kEstimatedBitrateBps * *usage_percentage_ *
remainder_ms / (8 * 100 * 1000), remainder_ms / (8 * 100 * 1000),
kTimeStepMs); *timestamp_ms_);
} }
} }
AlrDetector* const alr_detector_; AlrDetector* const alr_detector_;
int64_t* timestamp_ms_;
rtc::Optional<int> interval_ms_; rtc::Optional<int> interval_ms_;
rtc::Optional<int> usage_percentage_; rtc::Optional<int> usage_percentage_;
}; };
@ -73,6 +77,7 @@ class AlrDetectorTest : public testing::Test {
protected: protected:
AlrDetector alr_detector_; AlrDetector alr_detector_;
int64_t timestamp_ms_ = 1000;
}; };
TEST_F(AlrDetectorTest, AlrDetection) { TEST_F(AlrDetectorTest, AlrDetection) {
@ -80,19 +85,19 @@ TEST_F(AlrDetectorTest, AlrDetection) {
EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime()); EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime());
// Stay in non-ALR state when usage is close to 100%. // Stay in non-ALR state when usage is close to 100%.
SimulateOutgoingTrafficIn(&alr_detector_) SimulateOutgoingTrafficIn(&alr_detector_, &timestamp_ms_)
.ForTimeMs(1000) .ForTimeMs(1000)
.AtPercentOfEstimatedBitrate(90); .AtPercentOfEstimatedBitrate(90);
EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime()); EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime());
// Verify that we ALR starts when bitrate drops below 20%. // Verify that we ALR starts when bitrate drops below 20%.
SimulateOutgoingTrafficIn(&alr_detector_) SimulateOutgoingTrafficIn(&alr_detector_, &timestamp_ms_)
.ForTimeMs(1500) .ForTimeMs(1500)
.AtPercentOfEstimatedBitrate(20); .AtPercentOfEstimatedBitrate(20);
EXPECT_TRUE(alr_detector_.GetApplicationLimitedRegionStartTime()); EXPECT_TRUE(alr_detector_.GetApplicationLimitedRegionStartTime());
// Verify that ALR ends when usage is above 65%. // Verify that ALR ends when usage is above 65%.
SimulateOutgoingTrafficIn(&alr_detector_) SimulateOutgoingTrafficIn(&alr_detector_, &timestamp_ms_)
.ForTimeMs(4000) .ForTimeMs(4000)
.AtPercentOfEstimatedBitrate(100); .AtPercentOfEstimatedBitrate(100);
EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime()); EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime());
@ -103,19 +108,19 @@ TEST_F(AlrDetectorTest, ShortSpike) {
EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime()); EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime());
// Verify that we ALR starts when bitrate drops below 20%. // Verify that we ALR starts when bitrate drops below 20%.
SimulateOutgoingTrafficIn(&alr_detector_) SimulateOutgoingTrafficIn(&alr_detector_, &timestamp_ms_)
.ForTimeMs(1000) .ForTimeMs(1000)
.AtPercentOfEstimatedBitrate(20); .AtPercentOfEstimatedBitrate(20);
EXPECT_TRUE(alr_detector_.GetApplicationLimitedRegionStartTime()); EXPECT_TRUE(alr_detector_.GetApplicationLimitedRegionStartTime());
// Verify that we stay in ALR region even after a short bitrate spike. // Verify that we stay in ALR region even after a short bitrate spike.
SimulateOutgoingTrafficIn(&alr_detector_) SimulateOutgoingTrafficIn(&alr_detector_, &timestamp_ms_)
.ForTimeMs(100) .ForTimeMs(100)
.AtPercentOfEstimatedBitrate(150); .AtPercentOfEstimatedBitrate(150);
EXPECT_TRUE(alr_detector_.GetApplicationLimitedRegionStartTime()); EXPECT_TRUE(alr_detector_.GetApplicationLimitedRegionStartTime());
// ALR ends when usage is above 65%. // ALR ends when usage is above 65%.
SimulateOutgoingTrafficIn(&alr_detector_) SimulateOutgoingTrafficIn(&alr_detector_, &timestamp_ms_)
.ForTimeMs(3000) .ForTimeMs(3000)
.AtPercentOfEstimatedBitrate(100); .AtPercentOfEstimatedBitrate(100);
EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime()); EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime());
@ -126,7 +131,7 @@ TEST_F(AlrDetectorTest, BandwidthEstimateChanges) {
EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime()); EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime());
// ALR starts when bitrate drops below 20%. // ALR starts when bitrate drops below 20%.
SimulateOutgoingTrafficIn(&alr_detector_) SimulateOutgoingTrafficIn(&alr_detector_, &timestamp_ms_)
.ForTimeMs(1000) .ForTimeMs(1000)
.AtPercentOfEstimatedBitrate(20); .AtPercentOfEstimatedBitrate(20);
EXPECT_TRUE(alr_detector_.GetApplicationLimitedRegionStartTime()); EXPECT_TRUE(alr_detector_.GetApplicationLimitedRegionStartTime());
@ -137,7 +142,7 @@ TEST_F(AlrDetectorTest, BandwidthEstimateChanges) {
// to the BWE drop by initiating a new probe. // to the BWE drop by initiating a new probe.
alr_detector_.SetEstimatedBitrate(kEstimatedBitrateBps / 5); alr_detector_.SetEstimatedBitrate(kEstimatedBitrateBps / 5);
EXPECT_TRUE(alr_detector_.GetApplicationLimitedRegionStartTime()); EXPECT_TRUE(alr_detector_.GetApplicationLimitedRegionStartTime());
SimulateOutgoingTrafficIn(&alr_detector_) SimulateOutgoingTrafficIn(&alr_detector_, &timestamp_ms_)
.ForTimeMs(1000) .ForTimeMs(1000)
.AtPercentOfEstimatedBitrate(50); .AtPercentOfEstimatedBitrate(50);
EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime()); EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime());

View file

@ -85,9 +85,8 @@ DelayBasedBwe::Result::Result(bool probe, uint32_t target_bitrate_bps)
DelayBasedBwe::Result::~Result() {} DelayBasedBwe::Result::~Result() {}
DelayBasedBwe::DelayBasedBwe(RtcEventLog* event_log, const Clock* clock) DelayBasedBwe::DelayBasedBwe(RtcEventLog* event_log)
: event_log_(event_log), : event_log_(event_log),
clock_(clock),
inter_arrival_(), inter_arrival_(),
delay_detector_(), delay_detector_(),
last_seen_packet_ms_(-1), last_seen_packet_ms_(-1),
@ -114,7 +113,8 @@ DelayBasedBwe::~DelayBasedBwe() {}
DelayBasedBwe::Result DelayBasedBwe::IncomingPacketFeedbackVector( DelayBasedBwe::Result DelayBasedBwe::IncomingPacketFeedbackVector(
const std::vector<PacketFeedback>& packet_feedback_vector, const std::vector<PacketFeedback>& packet_feedback_vector,
rtc::Optional<uint32_t> acked_bitrate_bps) { rtc::Optional<uint32_t> acked_bitrate_bps,
int64_t at_time_ms) {
RTC_DCHECK(std::is_sorted(packet_feedback_vector.begin(), RTC_DCHECK(std::is_sorted(packet_feedback_vector.begin(),
packet_feedback_vector.end(), packet_feedback_vector.end(),
PacketFeedbackComparator())); PacketFeedbackComparator()));
@ -141,7 +141,7 @@ DelayBasedBwe::Result DelayBasedBwe::IncomingPacketFeedbackVector(
if (packet_feedback.send_time_ms < 0) if (packet_feedback.send_time_ms < 0)
continue; continue;
delayed_feedback = false; delayed_feedback = false;
IncomingPacketFeedback(packet_feedback); IncomingPacketFeedback(packet_feedback, at_time_ms);
if (prev_detector_state == BandwidthUsage::kBwUnderusing && if (prev_detector_state == BandwidthUsage::kBwUnderusing &&
delay_detector_->State() == BandwidthUsage::kBwNormal) { delay_detector_->State() == BandwidthUsage::kBwNormal) {
recovered_from_overuse = true; recovered_from_overuse = true;
@ -157,7 +157,8 @@ DelayBasedBwe::Result DelayBasedBwe::IncomingPacketFeedbackVector(
} }
} else { } else {
consecutive_delayed_feedbacks_ = 0; consecutive_delayed_feedbacks_ = 0;
return MaybeUpdateEstimate(acked_bitrate_bps, recovered_from_overuse); return MaybeUpdateEstimate(acked_bitrate_bps, recovered_from_overuse,
at_time_ms);
} }
return Result(); return Result();
} }
@ -180,8 +181,9 @@ DelayBasedBwe::Result DelayBasedBwe::OnLongFeedbackDelay(
} }
void DelayBasedBwe::IncomingPacketFeedback( void DelayBasedBwe::IncomingPacketFeedback(
const PacketFeedback& packet_feedback) { const PacketFeedback& packet_feedback,
int64_t now_ms = clock_->TimeInMilliseconds(); int64_t at_time_ms) {
int64_t now_ms = at_time_ms;
// Reset if the stream has timed out. // Reset if the stream has timed out.
if (last_seen_packet_ms_ == -1 || if (last_seen_packet_ms_ == -1 ||
now_ms - last_seen_packet_ms_ > kStreamTimeOutMs) { now_ms - last_seen_packet_ms_ > kStreamTimeOutMs) {
@ -223,9 +225,10 @@ void DelayBasedBwe::IncomingPacketFeedback(
DelayBasedBwe::Result DelayBasedBwe::MaybeUpdateEstimate( DelayBasedBwe::Result DelayBasedBwe::MaybeUpdateEstimate(
rtc::Optional<uint32_t> acked_bitrate_bps, rtc::Optional<uint32_t> acked_bitrate_bps,
bool recovered_from_overuse) { bool recovered_from_overuse,
int64_t at_time_ms) {
Result result; Result result;
int64_t now_ms = clock_->TimeInMilliseconds(); int64_t now_ms = at_time_ms;
rtc::Optional<int> probe_bitrate_bps = rtc::Optional<int> probe_bitrate_bps =
probe_bitrate_estimator_.FetchAndResetLastEstimatedBitrateBps(); probe_bitrate_estimator_.FetchAndResetLastEstimatedBitrateBps();
@ -289,7 +292,7 @@ bool DelayBasedBwe::UpdateEstimate(int64_t now_ms,
return rate_control_.ValidEstimate(); return rate_control_.ValidEstimate();
} }
void DelayBasedBwe::OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_ms) { void DelayBasedBwe::OnRttUpdate(int64_t avg_rtt_ms) {
rate_control_.SetRtt(avg_rtt_ms); rate_control_.SetRtt(avg_rtt_ms);
} }

View file

@ -42,13 +42,14 @@ class DelayBasedBwe {
bool recovered_from_overuse; bool recovered_from_overuse;
}; };
DelayBasedBwe(RtcEventLog* event_log, const Clock* clock); explicit DelayBasedBwe(RtcEventLog* event_log);
virtual ~DelayBasedBwe(); virtual ~DelayBasedBwe();
Result IncomingPacketFeedbackVector( Result IncomingPacketFeedbackVector(
const std::vector<PacketFeedback>& packet_feedback_vector, const std::vector<PacketFeedback>& packet_feedback_vector,
rtc::Optional<uint32_t> acked_bitrate_bps); rtc::Optional<uint32_t> acked_bitrate_bps,
void OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_ms); int64_t at_time_ms);
void OnRttUpdate(int64_t avg_rtt_ms);
bool LatestEstimate(std::vector<uint32_t>* ssrcs, bool LatestEstimate(std::vector<uint32_t>* ssrcs,
uint32_t* bitrate_bps) const; uint32_t* bitrate_bps) const;
void SetStartBitrate(int start_bitrate_bps); void SetStartBitrate(int start_bitrate_bps);
@ -56,10 +57,12 @@ class DelayBasedBwe {
int64_t GetExpectedBwePeriodMs() const; int64_t GetExpectedBwePeriodMs() const;
private: private:
void IncomingPacketFeedback(const PacketFeedback& packet_feedback); void IncomingPacketFeedback(const PacketFeedback& packet_feedback,
int64_t at_time_ms);
Result OnLongFeedbackDelay(int64_t arrival_time_ms); Result OnLongFeedbackDelay(int64_t arrival_time_ms);
Result MaybeUpdateEstimate(rtc::Optional<uint32_t> acked_bitrate_bps, Result MaybeUpdateEstimate(rtc::Optional<uint32_t> acked_bitrate_bps,
bool request_probe); bool request_probe,
int64_t at_time_ms);
// Updates the current remote rate estimate and returns true if a valid // Updates the current remote rate estimate and returns true if a valid
// estimate exists. // estimate exists.
bool UpdateEstimate(int64_t now_ms, bool UpdateEstimate(int64_t now_ms,
@ -68,7 +71,6 @@ class DelayBasedBwe {
rtc::RaceChecker network_race_; rtc::RaceChecker network_race_;
RtcEventLog* const event_log_; RtcEventLog* const event_log_;
const Clock* const clock_;
std::unique_ptr<InterArrival> inter_arrival_; std::unique_ptr<InterArrival> inter_arrival_;
std::unique_ptr<DelayIncreaseDetectorInterface> delay_detector_; std::unique_ptr<DelayIncreaseDetectorInterface> delay_detector_;
int64_t last_seen_packet_ms_; int64_t last_seen_packet_ms_;

View file

@ -24,12 +24,13 @@ constexpr int kNumProbesCluster1 = 8;
const PacedPacketInfo kPacingInfo0(0, kNumProbesCluster0, 2000); const PacedPacketInfo kPacingInfo0(0, kNumProbesCluster0, 2000);
const PacedPacketInfo kPacingInfo1(1, kNumProbesCluster1, 4000); const PacedPacketInfo kPacingInfo1(1, kNumProbesCluster1, 4000);
constexpr float kTargetUtilizationFraction = 0.95f; constexpr float kTargetUtilizationFraction = 0.95f;
constexpr int64_t kDummyTimestamp = 1000;
} // namespace } // namespace
TEST_F(DelayBasedBweTest, NoCrashEmptyFeedback) { TEST_F(DelayBasedBweTest, NoCrashEmptyFeedback) {
std::vector<PacketFeedback> packet_feedback_vector; std::vector<PacketFeedback> packet_feedback_vector;
bitrate_estimator_->IncomingPacketFeedbackVector(packet_feedback_vector, bitrate_estimator_->IncomingPacketFeedbackVector(
rtc::nullopt); packet_feedback_vector, rtc::nullopt, kDummyTimestamp);
} }
TEST_F(DelayBasedBweTest, NoCrashOnlyLostFeedback) { TEST_F(DelayBasedBweTest, NoCrashOnlyLostFeedback) {
@ -40,8 +41,8 @@ TEST_F(DelayBasedBweTest, NoCrashOnlyLostFeedback) {
packet_feedback_vector.push_back(PacketFeedback(PacketFeedback::kNotReceived, packet_feedback_vector.push_back(PacketFeedback(PacketFeedback::kNotReceived,
PacketFeedback::kNoSendTime, PacketFeedback::kNoSendTime,
1, 1500, PacedPacketInfo())); 1, 1500, PacedPacketInfo()));
bitrate_estimator_->IncomingPacketFeedbackVector(packet_feedback_vector, bitrate_estimator_->IncomingPacketFeedbackVector(
rtc::nullopt); packet_feedback_vector, rtc::nullopt, kDummyTimestamp);
} }
TEST_F(DelayBasedBweTest, ProbeDetection) { TEST_F(DelayBasedBweTest, ProbeDetection) {

View file

@ -152,7 +152,7 @@ DelayBasedBweTest::DelayBasedBweTest()
: clock_(100000000), : clock_(100000000),
acknowledged_bitrate_estimator_( acknowledged_bitrate_estimator_(
rtc::MakeUnique<AcknowledgedBitrateEstimator>()), rtc::MakeUnique<AcknowledgedBitrateEstimator>()),
bitrate_estimator_(new DelayBasedBwe(nullptr, &clock_)), bitrate_estimator_(new DelayBasedBwe(nullptr)),
stream_generator_(new test::StreamGenerator(1e6, // Capacity. stream_generator_(new test::StreamGenerator(1e6, // Capacity.
clock_.TimeInMicroseconds())), clock_.TimeInMicroseconds())),
arrival_time_offset_ms_(0), arrival_time_offset_ms_(0),
@ -187,7 +187,8 @@ void DelayBasedBweTest::IncomingFeedback(int64_t arrival_time_ms,
acknowledged_bitrate_estimator_->IncomingPacketFeedbackVector(packets); acknowledged_bitrate_estimator_->IncomingPacketFeedbackVector(packets);
DelayBasedBwe::Result result = DelayBasedBwe::Result result =
bitrate_estimator_->IncomingPacketFeedbackVector( bitrate_estimator_->IncomingPacketFeedbackVector(
packets, acknowledged_bitrate_estimator_->bitrate_bps()); packets, acknowledged_bitrate_estimator_->bitrate_bps(),
clock_.TimeInMilliseconds());
const uint32_t kDummySsrc = 0; const uint32_t kDummySsrc = 0;
if (result.updated) { if (result.updated) {
bitrate_observer_.OnReceiveBitrateChanged({kDummySsrc}, bitrate_observer_.OnReceiveBitrateChanged({kDummySsrc},
@ -222,7 +223,8 @@ bool DelayBasedBweTest::GenerateAndProcessFrame(uint32_t ssrc,
acknowledged_bitrate_estimator_->IncomingPacketFeedbackVector(packets); acknowledged_bitrate_estimator_->IncomingPacketFeedbackVector(packets);
DelayBasedBwe::Result result = DelayBasedBwe::Result result =
bitrate_estimator_->IncomingPacketFeedbackVector( bitrate_estimator_->IncomingPacketFeedbackVector(
packets, acknowledged_bitrate_estimator_->bitrate_bps()); packets, acknowledged_bitrate_estimator_->bitrate_bps(),
clock_.TimeInMilliseconds());
const uint32_t kDummySsrc = 0; const uint32_t kDummySsrc = 0;
if (result.updated) { if (result.updated) {
bitrate_observer_.OnReceiveBitrateChanged({kDummySsrc}, bitrate_observer_.OnReceiveBitrateChanged({kDummySsrc},

View file

@ -0,0 +1,415 @@
/*
* 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/goog_cc_network_control.h"
#include <algorithm>
#include <functional>
#include <limits>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "modules/congestion_controller/acknowledged_bitrate_estimator.h"
#include "modules/congestion_controller/alr_detector.h"
#include "modules/congestion_controller/include/goog_cc_factory.h"
#include "modules/congestion_controller/probe_controller.h"
#include "modules/remote_bitrate_estimator/include/bwe_defines.h"
#include "modules/remote_bitrate_estimator/test/bwe_test_logging.h"
#include "rtc_base/checks.h"
#include "rtc_base/format_macros.h"
#include "rtc_base/logging.h"
#include "rtc_base/ptr_util.h"
#include "rtc_base/timeutils.h"
#include "system_wrappers/include/field_trial.h"
namespace webrtc {
namespace {
const char kCwndExperiment[] = "WebRTC-CwndExperiment";
const int64_t kDefaultAcceptedQueueMs = 250;
// Pacing-rate relative to our target send rate.
// Multiplicative factor that is applied to the target bitrate to calculate
// the number of bytes that can be transmitted per interval.
// Increasing this factor will result in lower delays in cases of bitrate
// overshoots from the encoder.
const float kDefaultPaceMultiplier = 2.5f;
bool CwndExperimentEnabled() {
std::string experiment_string =
webrtc::field_trial::FindFullName(kCwndExperiment);
// The experiment is enabled iff the field trial string begins with "Enabled".
return experiment_string.find("Enabled") == 0;
}
bool ReadCwndExperimentParameter(int64_t* accepted_queue_ms) {
RTC_DCHECK(accepted_queue_ms);
std::string experiment_string =
webrtc::field_trial::FindFullName(kCwndExperiment);
int parsed_values =
sscanf(experiment_string.c_str(), "Enabled-%" PRId64, accepted_queue_ms);
if (parsed_values == 1) {
RTC_CHECK_GE(*accepted_queue_ms, 0)
<< "Accepted must be greater than or equal to 0.";
return true;
}
return false;
}
// Makes sure that the bitrate and the min, max values are in valid range.
static void ClampBitrates(int64_t* bitrate_bps,
int64_t* min_bitrate_bps,
int64_t* max_bitrate_bps) {
// TODO(holmer): We should make sure the default bitrates are set to 10 kbps,
// and that we don't try to set the min bitrate to 0 from any applications.
// The congestion controller should allow a min bitrate of 0.
if (*min_bitrate_bps < congestion_controller::GetMinBitrateBps())
*min_bitrate_bps = congestion_controller::GetMinBitrateBps();
if (*max_bitrate_bps > 0)
*max_bitrate_bps = std::max(*min_bitrate_bps, *max_bitrate_bps);
if (*bitrate_bps > 0)
*bitrate_bps = std::max(*min_bitrate_bps, *bitrate_bps);
}
std::vector<PacketFeedback> ReceivedPacketsFeedbackAsRtp(
const TransportPacketsFeedback report) {
std::vector<PacketFeedback> packet_feedback_vector;
for (auto& fb : report.PacketsWithFeedback()) {
if (fb.receive_time.IsFinite()) {
PacketFeedback pf(fb.receive_time.ms(), 0);
pf.creation_time_ms = report.feedback_time.ms();
if (fb.sent_packet.has_value()) {
pf.payload_size = fb.sent_packet->size.bytes();
pf.pacing_info = fb.sent_packet->pacing_info;
pf.send_time_ms = fb.sent_packet->send_time.ms();
} else {
pf.send_time_ms = PacketFeedback::kNoSendTime;
}
packet_feedback_vector.push_back(pf);
}
}
return packet_feedback_vector;
}
} // namespace
GoogCcNetworkControllerFactory::GoogCcNetworkControllerFactory(
RtcEventLog* event_log)
: event_log_(event_log) {}
NetworkControllerInterface::uptr GoogCcNetworkControllerFactory::Create(
NetworkControllerObserver* observer) {
return rtc::MakeUnique<GoogCcNetworkController>(event_log_, observer);
}
TimeDelta GoogCcNetworkControllerFactory::GetProcessInterval() const {
const int64_t kUpdateIntervalMs = 25;
return TimeDelta::ms(kUpdateIntervalMs);
}
GoogCcNetworkController::GoogCcNetworkController(
RtcEventLog* event_log,
NetworkControllerObserver* observer)
: event_log_(event_log),
observer_(observer),
probe_controller_(new ProbeController(observer_)),
bandwidth_estimation_(
rtc::MakeUnique<SendSideBandwidthEstimation>(event_log_)),
alr_detector_(rtc::MakeUnique<AlrDetector>()),
delay_based_bwe_(new DelayBasedBwe(event_log_)),
acknowledged_bitrate_estimator_(
rtc::MakeUnique<AcknowledgedBitrateEstimator>()),
in_cwnd_experiment_(CwndExperimentEnabled()),
accepted_queue_ms_(kDefaultAcceptedQueueMs) {
streams_config_.pacing_factor = kDefaultPaceMultiplier;
delay_based_bwe_->SetMinBitrate(congestion_controller::GetMinBitrateBps());
if (in_cwnd_experiment_ &&
!ReadCwndExperimentParameter(&accepted_queue_ms_)) {
RTC_LOG(LS_WARNING) << "Failed to parse parameters for CwndExperiment "
"from field trial string. Experiment disabled.";
in_cwnd_experiment_ = false;
}
}
GoogCcNetworkController::~GoogCcNetworkController() {}
void GoogCcNetworkController::OnNetworkAvailability(NetworkAvailability msg) {
probe_controller_->OnNetworkAvailability(msg);
}
void GoogCcNetworkController::OnNetworkRouteChange(NetworkRouteChange msg) {
int64_t min_bitrate_bps = msg.constraints.min_data_rate.bps();
int64_t max_bitrate_bps = -1;
int64_t start_bitrate_bps = -1;
if (msg.constraints.max_data_rate.IsFinite())
max_bitrate_bps = msg.constraints.max_data_rate.bps();
if (msg.constraints.starting_rate.IsFinite())
start_bitrate_bps = msg.constraints.starting_rate.bps();
ClampBitrates(&start_bitrate_bps, &min_bitrate_bps, &max_bitrate_bps);
bandwidth_estimation_ =
rtc::MakeUnique<SendSideBandwidthEstimation>(event_log_);
bandwidth_estimation_->SetBitrates(start_bitrate_bps, min_bitrate_bps,
max_bitrate_bps);
delay_based_bwe_.reset(new DelayBasedBwe(event_log_));
acknowledged_bitrate_estimator_.reset(new AcknowledgedBitrateEstimator());
delay_based_bwe_->SetStartBitrate(start_bitrate_bps);
delay_based_bwe_->SetMinBitrate(min_bitrate_bps);
probe_controller_->Reset(msg.at_time.ms());
probe_controller_->SetBitrates(min_bitrate_bps, start_bitrate_bps,
max_bitrate_bps, msg.at_time.ms());
MaybeTriggerOnNetworkChanged(msg.at_time);
}
void GoogCcNetworkController::OnProcessInterval(ProcessInterval msg) {
bandwidth_estimation_->UpdateEstimate(msg.at_time.ms());
rtc::Optional<int64_t> start_time_ms =
alr_detector_->GetApplicationLimitedRegionStartTime();
probe_controller_->SetAlrStartTimeMs(start_time_ms);
probe_controller_->Process(msg.at_time.ms());
MaybeTriggerOnNetworkChanged(msg.at_time);
}
void GoogCcNetworkController::OnRemoteBitrateReport(RemoteBitrateReport msg) {
bandwidth_estimation_->UpdateReceiverEstimate(msg.receive_time.ms(),
msg.bandwidth.bps());
BWE_TEST_LOGGING_PLOT(1, "REMB_kbps", msg.receive_time.ms(),
msg.bandwidth.bps() / 1000);
}
void GoogCcNetworkController::OnRoundTripTimeUpdate(RoundTripTimeUpdate msg) {
if (msg.smoothed) {
delay_based_bwe_->OnRttUpdate(msg.round_trip_time.ms());
} else {
bandwidth_estimation_->UpdateRtt(msg.round_trip_time.ms(),
msg.receive_time.ms());
}
}
void GoogCcNetworkController::OnSentPacket(SentPacket sent_packet) {
alr_detector_->OnBytesSent(sent_packet.size.bytes(),
sent_packet.send_time.ms());
}
void GoogCcNetworkController::OnStreamsConfig(StreamsConfig msg) {
bool pacing_changed =
(msg.pacing_factor != streams_config_.pacing_factor) ||
(msg.min_pacing_rate != streams_config_.min_pacing_rate) ||
(msg.max_padding_rate != streams_config_.max_padding_rate);
streams_config_ = msg;
probe_controller_->EnablePeriodicAlrProbing(msg.requests_alr_probing);
if (pacing_changed)
UpdatePacingRates(msg.at_time);
}
void GoogCcNetworkController::OnTargetRateConstraints(
TargetRateConstraints constraints) {
int64_t min_bitrate_bps = constraints.min_data_rate.bps();
int64_t max_bitrate_bps = -1;
int64_t start_bitrate_bps = -1;
if (constraints.max_data_rate.IsFinite())
max_bitrate_bps = constraints.max_data_rate.bps();
if (constraints.starting_rate.IsFinite())
start_bitrate_bps = constraints.starting_rate.bps();
ClampBitrates(&start_bitrate_bps, &min_bitrate_bps, &max_bitrate_bps);
probe_controller_->SetBitrates(min_bitrate_bps, start_bitrate_bps,
max_bitrate_bps, constraints.at_time.ms());
bandwidth_estimation_->SetBitrates(start_bitrate_bps, min_bitrate_bps,
max_bitrate_bps);
if (start_bitrate_bps > 0)
delay_based_bwe_->SetStartBitrate(start_bitrate_bps);
delay_based_bwe_->SetMinBitrate(min_bitrate_bps);
MaybeTriggerOnNetworkChanged(constraints.at_time);
}
void GoogCcNetworkController::OnTransportLossReport(TransportLossReport msg) {
int64_t total_packets_delta =
msg.packets_received_delta + msg.packets_lost_delta;
bandwidth_estimation_->UpdatePacketsLost(
msg.packets_lost_delta, total_packets_delta, msg.receive_time.ms());
}
void GoogCcNetworkController::OnTransportPacketsFeedback(
TransportPacketsFeedback report) {
int64_t feedback_rtt = -1;
for (const auto& packet_feedback : report.PacketsWithFeedback()) {
if (packet_feedback.sent_packet.has_value() &&
packet_feedback.receive_time.IsFinite()) {
int64_t rtt = report.feedback_time.ms() -
packet_feedback.sent_packet->send_time.ms();
// max() is used to account for feedback being delayed by the
// receiver.
feedback_rtt = std::max(rtt, feedback_rtt);
}
}
if (feedback_rtt > -1) {
feedback_rtts_.push_back(feedback_rtt);
const size_t kFeedbackRttWindow = 32;
if (feedback_rtts_.size() > kFeedbackRttWindow)
feedback_rtts_.pop_front();
min_feedback_rtt_ms_.emplace(
*std::min_element(feedback_rtts_.begin(), feedback_rtts_.end()));
}
std::vector<PacketFeedback> received_feedback_vector =
ReceivedPacketsFeedbackAsRtp(report);
rtc::Optional<int64_t> alr_start_time =
alr_detector_->GetApplicationLimitedRegionStartTime();
if (previously_in_alr && !alr_start_time.has_value()) {
int64_t now_ms = report.feedback_time.ms();
acknowledged_bitrate_estimator_->SetAlrEndedTimeMs(now_ms);
probe_controller_->SetAlrEndedTimeMs(now_ms);
}
previously_in_alr = alr_start_time.has_value();
acknowledged_bitrate_estimator_->IncomingPacketFeedbackVector(
received_feedback_vector);
DelayBasedBwe::Result result;
result = delay_based_bwe_->IncomingPacketFeedbackVector(
received_feedback_vector, acknowledged_bitrate_estimator_->bitrate_bps(),
report.feedback_time.ms());
if (result.updated) {
if (result.probe) {
bandwidth_estimation_->SetSendBitrate(result.target_bitrate_bps);
}
// Since SetSendBitrate now resets the delay-based estimate, we have to call
// UpdateDelayBasedEstimate after SetSendBitrate.
bandwidth_estimation_->UpdateDelayBasedEstimate(report.feedback_time.ms(),
result.target_bitrate_bps);
// Update the estimate in the ProbeController, in case we want to probe.
MaybeTriggerOnNetworkChanged(report.feedback_time);
}
if (result.recovered_from_overuse) {
probe_controller_->SetAlrStartTimeMs(alr_start_time);
probe_controller_->RequestProbe(report.feedback_time.ms());
}
MaybeUpdateCongestionWindow();
}
void GoogCcNetworkController::MaybeUpdateCongestionWindow() {
if (!in_cwnd_experiment_)
return;
// No valid RTT. Could be because send-side BWE isn't used, in which case
// we don't try to limit the outstanding packets.
if (!min_feedback_rtt_ms_)
return;
if (!last_estimate_.has_value())
return;
const DataSize kMinCwnd = DataSize::bytes(2 * 1500);
TimeDelta time_window =
TimeDelta::ms(*min_feedback_rtt_ms_ + accepted_queue_ms_);
DataSize data_window = last_estimate_->bandwidth * time_window;
CongestionWindow msg;
msg.enabled = true;
msg.data_window = std::max(kMinCwnd, data_window);
observer_->OnCongestionWindow(msg);
RTC_LOG(LS_INFO) << "Feedback rtt: " << *min_feedback_rtt_ms_
<< " Bitrate: " << last_estimate_->bandwidth.bps();
}
void GoogCcNetworkController::MaybeTriggerOnNetworkChanged(Timestamp at_time) {
int32_t estimated_bitrate_bps;
uint8_t fraction_loss;
int64_t rtt_ms;
bool estimate_changed = GetNetworkParameters(
&estimated_bitrate_bps, &fraction_loss, &rtt_ms, at_time);
if (estimate_changed) {
TimeDelta bwe_period =
TimeDelta::ms(delay_based_bwe_->GetExpectedBwePeriodMs());
NetworkEstimate new_estimate;
new_estimate.at_time = at_time;
new_estimate.round_trip_time = TimeDelta::ms(rtt_ms);
new_estimate.bandwidth = DataRate::bps(estimated_bitrate_bps);
new_estimate.loss_rate_ratio = fraction_loss / 255.0f;
new_estimate.bwe_period = bwe_period;
new_estimate.changed = true;
last_estimate_ = new_estimate;
OnNetworkEstimate(new_estimate);
}
}
bool GoogCcNetworkController::GetNetworkParameters(
int32_t* estimated_bitrate_bps,
uint8_t* fraction_loss,
int64_t* rtt_ms,
Timestamp at_time) {
bandwidth_estimation_->CurrentEstimate(estimated_bitrate_bps, fraction_loss,
rtt_ms);
*estimated_bitrate_bps = std::max<int32_t>(
*estimated_bitrate_bps, bandwidth_estimation_->GetMinBitrate());
bool estimate_changed = false;
if ((*estimated_bitrate_bps != last_estimated_bitrate_bps_) ||
(*fraction_loss != last_estimated_fraction_loss_) ||
(*rtt_ms != last_estimated_rtt_ms_)) {
last_estimated_bitrate_bps_ = *estimated_bitrate_bps;
last_estimated_fraction_loss_ = *fraction_loss;
last_estimated_rtt_ms_ = *rtt_ms;
estimate_changed = true;
}
BWE_TEST_LOGGING_PLOT(1, "fraction_loss_%", at_time.ms(),
(*fraction_loss * 100) / 256);
BWE_TEST_LOGGING_PLOT(1, "rtt_ms", at_time.ms(), *rtt_ms);
BWE_TEST_LOGGING_PLOT(1, "Target_bitrate_kbps", at_time.ms(),
*estimated_bitrate_bps / 1000);
return estimate_changed;
}
void GoogCcNetworkController::OnNetworkEstimate(NetworkEstimate estimate) {
if (!estimate.changed)
return;
UpdatePacingRates(estimate.at_time);
alr_detector_->SetEstimatedBitrate(estimate.bandwidth.bps());
probe_controller_->SetEstimatedBitrate(estimate.bandwidth.bps(),
estimate.at_time.ms());
TargetTransferRate target_rate;
target_rate.at_time = estimate.at_time;
// Set the target rate to the full estimated bandwidth since the estimation
// for legacy reasons includes target rate constraints.
target_rate.target_rate = estimate.bandwidth;
target_rate.network_estimate = estimate;
observer_->OnTargetTransferRate(target_rate);
}
void GoogCcNetworkController::UpdatePacingRates(Timestamp at_time) {
if (!last_estimate_)
return;
DataRate pacing_rate =
std::max(streams_config_.min_pacing_rate, last_estimate_->bandwidth) *
streams_config_.pacing_factor;
DataRate padding_rate =
std::min(streams_config_.max_padding_rate, last_estimate_->bandwidth);
PacerConfig msg;
msg.at_time = at_time;
msg.time_window = TimeDelta::s(1);
msg.data_window = pacing_rate * msg.time_window;
msg.pad_window = padding_rate * msg.time_window;
observer_->OnPacerConfig(msg);
}
} // namespace webrtc

View file

@ -0,0 +1,90 @@
/*
* 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_GOOG_CC_NETWORK_CONTROL_H_
#define MODULES_CONGESTION_CONTROLLER_GOOG_CC_NETWORK_CONTROL_H_
#include <stdint.h>
#include <deque>
#include <memory>
#include <vector>
#include "api/optional.h"
#include "logging/rtc_event_log/rtc_event_log.h"
#include "modules/bitrate_controller/send_side_bandwidth_estimation.h"
#include "modules/congestion_controller/acknowledged_bitrate_estimator.h"
#include "modules/congestion_controller/alr_detector.h"
#include "modules/congestion_controller/delay_based_bwe.h"
#include "modules/congestion_controller/network_control/include/network_control.h"
#include "modules/congestion_controller/probe_controller.h"
#include "rtc_base/constructormagic.h"
namespace webrtc {
class GoogCcNetworkController : public NetworkControllerInterface {
public:
GoogCcNetworkController(RtcEventLog* event_log,
NetworkControllerObserver* observer);
~GoogCcNetworkController() override;
// NetworkControllerInterface
void OnNetworkAvailability(NetworkAvailability msg) override;
void OnNetworkRouteChange(NetworkRouteChange msg) override;
void OnProcessInterval(ProcessInterval msg) override;
void OnRemoteBitrateReport(RemoteBitrateReport msg) override;
void OnRoundTripTimeUpdate(RoundTripTimeUpdate msg) override;
void OnSentPacket(SentPacket msg) override;
void OnStreamsConfig(StreamsConfig msg) override;
void OnTargetRateConstraints(TargetRateConstraints msg) override;
void OnTransportLossReport(TransportLossReport msg) override;
void OnTransportPacketsFeedback(TransportPacketsFeedback msg) override;
private:
void MaybeUpdateCongestionWindow();
void MaybeTriggerOnNetworkChanged(Timestamp at_time);
bool GetNetworkParameters(int32_t* estimated_bitrate_bps,
uint8_t* fraction_loss,
int64_t* rtt_ms,
Timestamp at_time);
void OnNetworkEstimate(NetworkEstimate msg);
void UpdatePacingRates(Timestamp at_time);
RtcEventLog* const event_log_;
NetworkControllerObserver* const observer_;
const std::unique_ptr<ProbeController> probe_controller_;
std::unique_ptr<SendSideBandwidthEstimation> bandwidth_estimation_;
std::unique_ptr<AlrDetector> alr_detector_;
std::unique_ptr<DelayBasedBwe> delay_based_bwe_;
std::unique_ptr<AcknowledgedBitrateEstimator> acknowledged_bitrate_estimator_;
std::deque<int64_t> feedback_rtts_;
rtc::Optional<int64_t> min_feedback_rtt_ms_;
rtc::Optional<NetworkEstimate> last_estimate_;
rtc::Optional<TargetTransferRate> last_target_rate_;
int32_t last_estimated_bitrate_bps_ = 0;
uint8_t last_estimated_fraction_loss_ = 0;
int64_t last_estimated_rtt_ms_ = 0;
StreamsConfig streams_config_;
bool in_cwnd_experiment_;
int64_t accepted_queue_ms_;
bool previously_in_alr = false;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(GoogCcNetworkController);
};
} // namespace webrtc
#endif // MODULES_CONGESTION_CONTROLLER_GOOG_CC_NETWORK_CONTROL_H_

View file

@ -0,0 +1,32 @@
/*
* 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_INCLUDE_GOOG_CC_FACTORY_H_
#define MODULES_CONGESTION_CONTROLLER_INCLUDE_GOOG_CC_FACTORY_H_
#include "modules/congestion_controller/network_control/include/network_control.h"
namespace webrtc {
class Clock;
class RtcEventLog;
class GoogCcNetworkControllerFactory
: public NetworkControllerFactoryInterface {
public:
explicit GoogCcNetworkControllerFactory(RtcEventLog*);
NetworkControllerInterface::uptr Create(
NetworkControllerObserver* observer) override;
TimeDelta GetProcessInterval() const override;
private:
RtcEventLog* const event_log_;
};
} // namespace webrtc
#endif // MODULES_CONGESTION_CONTROLLER_INCLUDE_GOOG_CC_FACTORY_H_

View file

@ -11,19 +11,27 @@
#ifndef MODULES_CONGESTION_CONTROLLER_INCLUDE_SEND_SIDE_CONGESTION_CONTROLLER_H_ #ifndef MODULES_CONGESTION_CONTROLLER_INCLUDE_SEND_SIDE_CONGESTION_CONTROLLER_H_
#define MODULES_CONGESTION_CONTROLLER_INCLUDE_SEND_SIDE_CONGESTION_CONTROLLER_H_ #define MODULES_CONGESTION_CONTROLLER_INCLUDE_SEND_SIDE_CONGESTION_CONTROLLER_H_
#include <atomic>
#include <functional>
#include <map>
#include <memory> #include <memory>
#include <vector> #include <vector>
#include "common_types.h" // NOLINT(build/include) #include "common_types.h" // NOLINT(build/include)
#include "modules/congestion_controller/delay_based_bwe.h" #include "modules/congestion_controller/network_control/include/network_control.h"
#include "modules/congestion_controller/network_control/include/network_types.h"
#include "modules/congestion_controller/pacer_controller.h"
#include "modules/congestion_controller/transport_feedback_adapter.h" #include "modules/congestion_controller/transport_feedback_adapter.h"
#include "modules/include/module.h" #include "modules/include/module.h"
#include "modules/include/module_common_types.h" #include "modules/include/module_common_types.h"
#include "modules/pacing/paced_sender.h" #include "modules/pacing/paced_sender.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "rtc_base/constructormagic.h" #include "rtc_base/constructormagic.h"
#include "rtc_base/criticalsection.h" #include "rtc_base/criticalsection.h"
#include "rtc_base/networkroute.h" #include "rtc_base/networkroute.h"
#include "rtc_base/race_checker.h" #include "rtc_base/race_checker.h"
#include "rtc_base/refcountedobject.h"
#include "rtc_base/task_queue.h"
namespace rtc { namespace rtc {
struct SentPacket; struct SentPacket;
@ -31,16 +39,23 @@ struct SentPacket;
namespace webrtc { namespace webrtc {
class BitrateController;
class Clock; class Clock;
class AcknowledgedBitrateEstimator;
class ProbeController;
class RateLimiter; class RateLimiter;
class RtcEventLog; class RtcEventLog;
namespace send_side_cc_internal {
// This is used to observe the network controller state and route calls to
// the proper handler. It also keeps cached values for safe asynchronous use.
// This makes sure that things running on the worker queue can't access state
// in SendSideCongestionController, which would risk causing data race on
// destruction unless members are properly ordered.
class ControlHandler;
} // namespace send_side_cc_internal
class SendSideCongestionController : public CallStatsObserver, class SendSideCongestionController : public CallStatsObserver,
public Module, public Module,
public TransportFeedbackObserver { public TransportFeedbackObserver,
public RtcpBandwidthObserver {
public: public:
// Observer class for bitrate changes announced due to change in bandwidth // Observer class for bitrate changes announced due to change in bandwidth
// estimate or due to that the send pacer is full. Fraction loss and rtt is // estimate or due to that the send pacer is full. Fraction loss and rtt is
@ -61,6 +76,13 @@ class SendSideCongestionController : public CallStatsObserver,
Observer* observer, Observer* observer,
RtcEventLog* event_log, RtcEventLog* event_log,
PacedSender* pacer); PacedSender* pacer);
SendSideCongestionController(
const Clock* clock,
RtcEventLog* event_log,
PacedSender* pacer,
NetworkControllerFactoryInterface::uptr controller_factory);
~SendSideCongestionController() override; ~SendSideCongestionController() override;
void RegisterPacketFeedbackObserver(PacketFeedbackObserver* observer); void RegisterPacketFeedbackObserver(PacketFeedbackObserver* observer);
@ -86,10 +108,7 @@ class SendSideCongestionController : public CallStatsObserver,
virtual void SignalNetworkState(NetworkState state); virtual void SignalNetworkState(NetworkState state);
virtual void SetTransportOverhead(size_t transport_overhead_bytes_per_packet); virtual void SetTransportOverhead(size_t transport_overhead_bytes_per_packet);
// Deprecated: Use GetBandwidthObserver instead. virtual RtcpBandwidthObserver* GetBandwidthObserver();
RTC_DEPRECATED virtual BitrateController* GetBitrateController() const;
virtual RtcpBandwidthObserver* GetBandwidthObserver() const;
virtual bool AvailableBandwidth(uint32_t* bandwidth) const; virtual bool AvailableBandwidth(uint32_t* bandwidth) const;
virtual int64_t GetPacerQueuingDelayMs() const; virtual int64_t GetPacerQueuingDelayMs() const;
@ -99,10 +118,17 @@ class SendSideCongestionController : public CallStatsObserver,
RateLimiter* GetRetransmissionRateLimiter(); RateLimiter* GetRetransmissionRateLimiter();
void EnablePeriodicAlrProbing(bool enable); void EnablePeriodicAlrProbing(bool enable);
void UpdateStreamsConfig();
virtual void OnSentPacket(const rtc::SentPacket& sent_packet); virtual void OnSentPacket(const rtc::SentPacket& sent_packet);
// Implements CallStatsObserver. // Implements RtcpBandwidthObserver
void OnReceivedEstimatedBitrate(uint32_t bitrate) override;
void OnReceivedRtcpReceiverReport(const ReportBlockList& report_blocks,
int64_t rtt,
int64_t now_ms) override;
// Ignored
void OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_ms) override; void OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_ms) override;
// Implements Module. // Implements Module.
@ -117,52 +143,59 @@ class SendSideCongestionController : public CallStatsObserver,
void OnTransportFeedback(const rtcp::TransportFeedback& feedback) override; void OnTransportFeedback(const rtcp::TransportFeedback& feedback) override;
std::vector<PacketFeedback> GetTransportFeedbackVector() const override; std::vector<PacketFeedback> GetTransportFeedbackVector() const override;
private: // Sets the minimum send bitrate and maximum padding bitrate requested by send
void MaybeTriggerOnNetworkChanged(); // streams.
// |min_send_bitrate_bps| might be higher that the estimated available network
// bitrate and if so, the pacer will send with |min_send_bitrate_bps|.
// |max_padding_bitrate_bps| might be higher than the estimate available
// network bitrate and if so, the pacer will send padding packets to reach
// the min of the estimated available bitrate and |max_padding_bitrate_bps|.
void SetSendBitrateLimits(int64_t min_send_bitrate_bps,
int64_t max_padding_bitrate_bps);
void SetPacingFactor(float pacing_factor);
protected:
// Waits long enough that any outstanding tasks should be finished.
void WaitOnTasks();
private:
void WaitOnTask(std::function<void()> closure);
void MaybeUpdateOutstandingData();
void OnReceivedRtcpReceiverReportBlocks(const ReportBlockList& report_blocks,
int64_t now_ms);
bool IsSendQueueFull() const;
bool IsNetworkDown() const;
bool HasNetworkParametersToReportChanged(uint32_t bitrate_bps,
uint8_t fraction_loss,
int64_t rtt);
void LimitOutstandingBytes(size_t num_outstanding_bytes);
const Clock* const clock_; const Clock* const clock_;
rtc::CriticalSection observer_lock_;
Observer* observer_ RTC_GUARDED_BY(observer_lock_);
RtcEventLog* const event_log_;
PacedSender* const pacer_; PacedSender* const pacer_;
const std::unique_ptr<BitrateController> bitrate_controller_;
std::unique_ptr<AcknowledgedBitrateEstimator> acknowledged_bitrate_estimator_;
const std::unique_ptr<ProbeController> probe_controller_;
const std::unique_ptr<RateLimiter> retransmission_rate_limiter_;
TransportFeedbackAdapter transport_feedback_adapter_; TransportFeedbackAdapter transport_feedback_adapter_;
rtc::CriticalSection network_state_lock_;
uint32_t last_reported_bitrate_bps_ RTC_GUARDED_BY(network_state_lock_); const std::unique_ptr<PacerController> pacer_controller_;
uint8_t last_reported_fraction_loss_ RTC_GUARDED_BY(network_state_lock_); const std::unique_ptr<send_side_cc_internal::ControlHandler> control_handler;
int64_t last_reported_rtt_ RTC_GUARDED_BY(network_state_lock_); const std::unique_ptr<NetworkControllerInterface> controller_;
NetworkState network_state_ RTC_GUARDED_BY(network_state_lock_);
bool pause_pacer_ RTC_GUARDED_BY(network_state_lock_); TimeDelta process_interval_;
// Duplicate the pacer paused state to avoid grabbing a lock when int64_t last_process_update_ms_ = 0;
// pausing the pacer. This can be removed when we move this class
// over to the task queue. std::map<uint32_t, RTCPReportBlock> last_report_blocks_;
bool pacer_paused_; Timestamp last_report_block_time_;
rtc::CriticalSection bwe_lock_;
int min_bitrate_bps_ RTC_GUARDED_BY(bwe_lock_); StreamsConfig streams_config_;
std::unique_ptr<DelayBasedBwe> delay_based_bwe_ RTC_GUARDED_BY(bwe_lock_);
bool in_cwnd_experiment_;
int64_t accepted_queue_ms_;
bool was_in_alr_;
const bool send_side_bwe_with_overhead_; const bool send_side_bwe_with_overhead_;
size_t transport_overhead_bytes_per_packet_ RTC_GUARDED_BY(bwe_lock_); std::atomic<size_t> transport_overhead_bytes_per_packet_;
std::atomic<bool> network_available_;
rtc::RaceChecker worker_race_; rtc::RaceChecker worker_race_;
bool pacer_pushback_experiment_ = false; // Note that moving ownership of the task queue makes it neccessary to make
float encoding_rate_ = 1.0; // sure that there is no outstanding tasks on it using destructed objects.
// This is currently guranteed by using explicit reset in the destructor of
// this class. It is declared last to indicate that it's lifetime is shorter
// than all other members.
std::unique_ptr<rtc::TaskQueue> task_queue_;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(SendSideCongestionController); RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(SendSideCongestionController);
}; };
} // namespace webrtc } // namespace webrtc
#endif // MODULES_CONGESTION_CONTROLLER_INCLUDE_SEND_SIDE_CONGESTION_CONTROLLER_H_ #endif // MODULES_CONGESTION_CONTROLLER_INCLUDE_SEND_SIDE_CONGESTION_CONTROLLER_H_

View file

@ -0,0 +1,40 @@
# 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.
import("../../../webrtc.gni")
rtc_static_library("network_control") {
sources = [
"include/network_control.h",
"include/network_types.h",
"include/network_units.h",
"network_types.cc",
"network_units.cc",
]
deps = [
"../../:module_api",
"../../../api:optional",
"../../../rtc_base:checks",
"../../../rtc_base:rtc_base_approved",
]
}
if (rtc_include_tests) {
rtc_source_set("network_control_unittests") {
testonly = true
sources = [
"network_units_unittest.cc",
]
deps = [
":network_control",
"../../../test:test_support",
]
}
}

View file

@ -0,0 +1,89 @@
/*
* 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_NETWORK_CONTROL_INCLUDE_NETWORK_CONTROL_H_
#define MODULES_CONGESTION_CONTROLLER_NETWORK_CONTROL_INCLUDE_NETWORK_CONTROL_H_
#include <stdint.h>
#include <memory>
#include "modules/congestion_controller/network_control/include/network_types.h"
#include "modules/congestion_controller/network_control/include/network_units.h"
namespace webrtc {
// NetworkControllerObserver is an interface implemented by observers of network
// controllers. It contains declarations of the possible configuration messages
// that can be sent from a network controller implementation.
class NetworkControllerObserver {
public:
// Called when congestion window configutation is changed.
virtual void OnCongestionWindow(CongestionWindow) = 0;
// Called when pacer configuration has changed.
virtual void OnPacerConfig(PacerConfig) = 0;
// Called to indicate that a new probe should be sent.
virtual void OnProbeClusterConfig(ProbeClusterConfig) = 0;
// Called to indicate target transfer rate as well as giving information about
// the current estimate of network parameters.
virtual void OnTargetTransferRate(TargetTransferRate) = 0;
protected:
virtual ~NetworkControllerObserver() = default;
};
// NetworkControllerInterface is implemented by network controllers. A network
// controller is a class that uses information about network state and traffic
// to estimate network parameters such as round trip time and bandwidth. Network
// controllers does not guarantee thread safety, the interface must be used in a
// non-concurrent fashion.
class NetworkControllerInterface {
public:
using uptr = std::unique_ptr<NetworkControllerInterface>;
virtual ~NetworkControllerInterface() = default;
// Called when network availabilty changes.
virtual void OnNetworkAvailability(NetworkAvailability) = 0;
// Called when the receiving or sending endpoint changes address.
virtual void OnNetworkRouteChange(NetworkRouteChange) = 0;
// Called periodically with a periodicy as specified by
// NetworkControllerFactoryInterface::GetProcessInterval.
virtual void OnProcessInterval(ProcessInterval) = 0;
// Called when remotely calculated bitrate is received.
virtual void OnRemoteBitrateReport(RemoteBitrateReport) = 0;
// Called round trip time has been calculated by protocol specific mechanisms.
virtual void OnRoundTripTimeUpdate(RoundTripTimeUpdate) = 0;
// Called when a packet is sent on the network.
virtual void OnSentPacket(SentPacket) = 0;
// Called when the stream specific configuration has been updated.
virtual void OnStreamsConfig(StreamsConfig) = 0;
// Called when target transfer rate constraints has been changed.
virtual void OnTargetRateConstraints(TargetRateConstraints) = 0;
// Called when a protocol specific calculation of packet loss has been made.
virtual void OnTransportLossReport(TransportLossReport) = 0;
// Called with per packet feedback regarding receive time.
virtual void OnTransportPacketsFeedback(TransportPacketsFeedback) = 0;
};
// NetworkControllerFactoryInterface is an interface for creating a network
// controller.
class NetworkControllerFactoryInterface {
public:
using uptr = std::unique_ptr<NetworkControllerFactoryInterface>;
// Used to create a new network controller, requires an observer to be
// provided to handle callbacks.
virtual NetworkControllerInterface::uptr Create(
NetworkControllerObserver* observer) = 0;
// Returns the interval by which the network controller expects
// OnProcessInterval calls.
virtual TimeDelta GetProcessInterval() const = 0;
virtual ~NetworkControllerFactoryInterface() = default;
};
} // namespace webrtc
#endif // MODULES_CONGESTION_CONTROLLER_NETWORK_CONTROL_INCLUDE_NETWORK_CONTROL_H_

View file

@ -0,0 +1,168 @@
/*
* 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_NETWORK_CONTROL_INCLUDE_NETWORK_TYPES_H_
#define MODULES_CONGESTION_CONTROLLER_NETWORK_CONTROL_INCLUDE_NETWORK_TYPES_H_
#include <stdint.h>
#include <ostream>
#include <vector>
#include "modules/congestion_controller/network_control/include/network_units.h"
#include "modules/include/module_common_types.h"
#include "rtc_base/constructormagic.h"
namespace webrtc {
// Configuration
// Use StreamsConfig for information about streams that is required for specific
// adjustments to the algorithms in network controllers. Especially useful
// for experiments.
struct StreamsConfig {
Timestamp at_time;
bool requests_alr_probing = false;
double pacing_factor = 1;
DataRate min_pacing_rate = DataRate::kZero;
DataRate max_padding_rate = DataRate::kZero;
};
struct TargetRateConstraints {
Timestamp at_time;
DataRate starting_rate;
DataRate min_data_rate;
DataRate max_data_rate;
};
// Send side information
struct NetworkAvailability {
Timestamp at_time;
bool network_available = false;
};
struct NetworkRouteChange {
Timestamp at_time;
// The TargetRateConstraints are set here so they can be changed synchronously
// when network route changes.
TargetRateConstraints constraints;
};
struct SentPacket {
Timestamp send_time;
DataSize size;
PacedPacketInfo pacing_info;
};
struct PacerQueueUpdate {
TimeDelta expected_queue_time;
};
// Transport level feedback
struct RemoteBitrateReport {
Timestamp receive_time;
DataRate bandwidth;
};
struct RoundTripTimeUpdate {
Timestamp receive_time;
TimeDelta round_trip_time;
bool smoothed = false;
};
struct TransportLossReport {
Timestamp receive_time;
Timestamp start_time;
Timestamp end_time;
uint64_t packets_lost_delta = 0;
uint64_t packets_received_delta = 0;
};
struct OutstandingData {
DataSize in_flight_data;
};
// Packet level feedback
struct PacketResult {
rtc::Optional<SentPacket> sent_packet;
Timestamp receive_time;
PacketResult();
PacketResult(const PacketResult&);
~PacketResult();
};
struct TransportPacketsFeedback {
TransportPacketsFeedback();
TransportPacketsFeedback(const TransportPacketsFeedback& other);
~TransportPacketsFeedback();
Timestamp feedback_time;
DataSize data_in_flight;
DataSize prior_in_flight;
std::vector<PacketResult> packet_feedbacks;
std::vector<PacketResult> ReceivedWithSendInfo() const;
std::vector<PacketResult> LostWithSendInfo() const;
std::vector<PacketResult> PacketsWithFeedback() const;
};
// Network estimation
struct NetworkEstimate {
Timestamp at_time;
DataRate bandwidth;
TimeDelta round_trip_time;
TimeDelta bwe_period;
float loss_rate_ratio = 0;
bool changed = true;
};
// Network control
struct CongestionWindow {
bool enabled = true;
DataSize data_window;
};
struct PacerConfig {
Timestamp at_time;
// Pacer should send at most data_window data over time_window duration.
DataSize data_window;
TimeDelta time_window;
// Pacer should send at least pad_window data over time_window duration.
DataSize pad_window;
DataRate data_rate() const { return data_window / time_window; }
};
struct ProbeClusterConfig {
Timestamp at_time;
DataRate target_data_rate;
TimeDelta target_duration;
uint32_t target_probe_count;
};
struct TargetTransferRate {
Timestamp at_time;
DataRate target_rate;
// The estimate on which the target rate is based on.
NetworkEstimate network_estimate;
};
// Process control
struct ProcessInterval {
Timestamp at_time;
};
::std::ostream& operator<<(::std::ostream& os,
const ProbeClusterConfig& config);
::std::ostream& operator<<(::std::ostream& os, const PacerConfig& config);
} // namespace webrtc
#endif // MODULES_CONGESTION_CONTROLLER_NETWORK_CONTROL_INCLUDE_NETWORK_TYPES_H_

View file

@ -0,0 +1,353 @@
/*
* 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_NETWORK_CONTROL_INCLUDE_NETWORK_UNITS_H_
#define MODULES_CONGESTION_CONTROLLER_NETWORK_CONTROL_INCLUDE_NETWORK_UNITS_H_
#include <stdint.h>
#include <limits>
#include <ostream>
#include "rtc_base/checks.h"
namespace webrtc {
namespace units_internal {
inline int64_t DivideAndRound(int64_t numerator, int64_t denominators) {
if (numerator >= 0) {
return (numerator + (denominators / 2)) / denominators;
} else {
return (numerator + (denominators / 2)) / denominators - 1;
}
}
} // namespace units_internal
// TimeDelta represents the difference between two timestamps. Connomly this can
// be a duration. However since two Timestamps are not guaranteed to have the
// same epoch (they might come from different computers, making exact
// synchronisation infeasible), the duration covered by a TimeDelta can be
// undefined. To simplify usage, it can be constructed and converted to
// different units, specifically seconds (s), milliseconds (ms) and
// microseconds (us).
class TimeDelta {
public:
static const TimeDelta kPlusInfinity;
static const TimeDelta kMinusInfinity;
static const TimeDelta kNotInitialized;
static const TimeDelta kZero;
TimeDelta() : TimeDelta(kNotInitialized) {}
static TimeDelta Zero() { return kZero; }
static TimeDelta Infinity() { return kPlusInfinity; }
static TimeDelta seconds(int64_t seconds) { return TimeDelta::s(seconds); }
static TimeDelta s(int64_t seconds) {
return TimeDelta::us(seconds * 1000000);
}
static TimeDelta ms(int64_t milliseconds) {
return TimeDelta::us(milliseconds * 1000);
}
static TimeDelta us(int64_t microseconds) {
// Infinities only allowed via use of explicit constants.
RTC_DCHECK(microseconds > std::numeric_limits<int64_t>::min());
RTC_DCHECK(microseconds < std::numeric_limits<int64_t>::max());
return TimeDelta(microseconds);
}
int64_t s() const { return units_internal::DivideAndRound(us(), 1000000); }
int64_t ms() const { return units_internal::DivideAndRound(us(), 1000); }
int64_t us() const {
RTC_DCHECK(IsFinite());
return microseconds_;
}
TimeDelta Abs() const { return TimeDelta::us(std::abs(us())); }
bool IsZero() const { return microseconds_ == 0; }
bool IsFinite() const { return IsInitialized() && !IsInfinite(); }
bool IsInitialized() const {
return microseconds_ != kNotInitialized.microseconds_;
}
bool IsInfinite() const {
return *this == kPlusInfinity || *this == kMinusInfinity;
}
TimeDelta operator+(const TimeDelta& other) const {
return TimeDelta::us(us() + other.us());
}
TimeDelta operator-(const TimeDelta& other) const {
return TimeDelta::us(us() - other.us());
}
TimeDelta operator*(double scalar) const {
return TimeDelta::us(us() * scalar);
}
TimeDelta operator*(int64_t scalar) const {
return TimeDelta::us(us() * scalar);
}
TimeDelta operator*(int32_t scalar) const {
return TimeDelta::us(us() * scalar);
}
bool operator==(const TimeDelta& other) const {
return microseconds_ == other.microseconds_;
}
bool operator!=(const TimeDelta& other) const {
return microseconds_ != other.microseconds_;
}
bool operator<=(const TimeDelta& other) const {
return microseconds_ <= other.microseconds_;
}
bool operator>=(const TimeDelta& other) const {
return microseconds_ >= other.microseconds_;
}
bool operator>(const TimeDelta& other) const {
return microseconds_ > other.microseconds_;
}
bool operator<(const TimeDelta& other) const {
return microseconds_ < other.microseconds_;
}
private:
explicit TimeDelta(int64_t us) : microseconds_(us) {}
int64_t microseconds_;
};
inline TimeDelta operator*(const double& scalar, const TimeDelta& delta) {
return delta * scalar;
}
inline TimeDelta operator*(const int64_t& scalar, const TimeDelta& delta) {
return delta * scalar;
}
inline TimeDelta operator*(const int32_t& scalar, const TimeDelta& delta) {
return delta * scalar;
}
// Timestamp represents the time that has passed since some unspecified epoch.
// The epoch is assumed to be before any represented timestamps, this means that
// negative values are not valid. The most notable feature is that the
// difference of of two Timestamps results in a TimeDelta.
class Timestamp {
public:
static const Timestamp kPlusInfinity;
static const Timestamp kNotInitialized;
Timestamp() : Timestamp(kNotInitialized) {}
static Timestamp Infinity() { return kPlusInfinity; }
static Timestamp s(int64_t seconds) { return Timestamp(seconds * 1000000); }
static Timestamp ms(int64_t millis) { return Timestamp(millis * 1000); }
static Timestamp us(int64_t micros) { return Timestamp(micros); }
int64_t s() const { return units_internal::DivideAndRound(us(), 1000000); }
int64_t ms() const { return units_internal::DivideAndRound(us(), 1000); }
int64_t us() const {
RTC_DCHECK(IsFinite());
return microseconds_;
}
bool IsInfinite() const {
return microseconds_ == kPlusInfinity.microseconds_;
}
bool IsInitialized() const {
return microseconds_ != kNotInitialized.microseconds_;
}
bool IsFinite() const { return IsInitialized() && !IsInfinite(); }
TimeDelta operator-(const Timestamp& other) const {
return TimeDelta::us(us() - other.us());
}
Timestamp operator-(const TimeDelta& delta) const {
return Timestamp::us(us() - delta.us());
}
Timestamp operator+(const TimeDelta& delta) const {
return Timestamp::us(us() + delta.us());
}
bool operator==(const Timestamp& other) const {
return microseconds_ == other.microseconds_;
}
bool operator!=(const Timestamp& other) const {
return microseconds_ != other.microseconds_;
}
bool operator<=(const Timestamp& other) const { return us() <= other.us(); }
bool operator>=(const Timestamp& other) const { return us() >= other.us(); }
bool operator>(const Timestamp& other) const { return us() > other.us(); }
bool operator<(const Timestamp& other) const { return us() < other.us(); }
private:
explicit Timestamp(int64_t us) : microseconds_(us) {}
int64_t microseconds_;
};
// DataSize is a class represeting a count of bytes. Note that while it can be
// initialized by a number of bits, it does not guarantee that the resolution is
// kept and the internal storage is in bytes. The number of bits will be
// truncated to fit.
class DataSize {
public:
static const DataSize kZero;
static const DataSize kPlusInfinity;
static const DataSize kNotInitialized;
DataSize() : DataSize(kNotInitialized) {}
static DataSize Zero() { return kZero; }
static DataSize Infinity() { return kPlusInfinity; }
static DataSize bytes(int64_t bytes) { return DataSize(bytes); }
static DataSize bits(int64_t bits) { return DataSize(bits / 8); }
int64_t bytes() const {
RTC_DCHECK(IsFinite());
return bytes_;
}
int64_t kilobytes() const {
return units_internal::DivideAndRound(bytes(), 1000);
}
int64_t bits() const { return bytes() * 8; }
int64_t kilobits() const {
return units_internal::DivideAndRound(bits(), 1000);
}
bool IsZero() const { return bytes_ == 0; }
bool IsInfinite() const { return bytes_ == kPlusInfinity.bytes_; }
bool IsInitialized() const { return bytes_ != kNotInitialized.bytes_; }
bool IsFinite() const { return IsInitialized() && !IsInfinite(); }
DataSize operator-(const DataSize& other) const {
return DataSize::bytes(bytes() - other.bytes());
}
DataSize operator+(const DataSize& other) const {
return DataSize::bytes(bytes() + other.bytes());
}
DataSize operator*(double scalar) const {
return DataSize::bytes(bytes() * scalar);
}
DataSize operator*(int64_t scalar) const {
return DataSize::bytes(bytes() * scalar);
}
DataSize operator*(int32_t scalar) const {
return DataSize::bytes(bytes() * scalar);
}
DataSize operator/(int64_t scalar) const {
return DataSize::bytes(bytes() / scalar);
}
DataSize& operator-=(const DataSize& other) {
bytes_ -= other.bytes();
return *this;
}
DataSize& operator+=(const DataSize& other) {
bytes_ += other.bytes();
return *this;
}
bool operator==(const DataSize& other) const {
return bytes_ == other.bytes_;
}
bool operator!=(const DataSize& other) const {
return bytes_ != other.bytes_;
}
bool operator<=(const DataSize& other) const {
return bytes_ <= other.bytes_;
}
bool operator>=(const DataSize& other) const {
return bytes_ >= other.bytes_;
}
bool operator>(const DataSize& other) const { return bytes_ > other.bytes_; }
bool operator<(const DataSize& other) const { return bytes_ < other.bytes_; }
private:
explicit DataSize(int64_t bytes) : bytes_(bytes) {}
int64_t bytes_;
};
inline DataSize operator*(const double& scalar, const DataSize& size) {
return size * scalar;
}
inline DataSize operator*(const int64_t& scalar, const DataSize& size) {
return size * scalar;
}
inline DataSize operator*(const int32_t& scalar, const DataSize& size) {
return size * scalar;
}
// DataRate is a class that represents a given data rate. This can be used to
// represent bandwidth, encoding bitrate, etc. The internal storage is currently
// bits per second (bps) since this makes it easier to intepret the raw value
// when debugging. The promised precision, however is only that it will
// represent bytes per second accurately. Any implementation depending on bps
// resolution should document this by changing this comment.
class DataRate {
public:
static const DataRate kZero;
static const DataRate kPlusInfinity;
static const DataRate kNotInitialized;
DataRate() : DataRate(kNotInitialized) {}
static DataRate Zero() { return kZero; }
static DataRate Infinity() { return kPlusInfinity; }
static DataRate bytes_per_second(int64_t bytes_per_sec) {
return DataRate(bytes_per_sec * 8);
}
static DataRate bits_per_second(int64_t bits_per_sec) {
return DataRate(bits_per_sec);
}
static DataRate bps(int64_t bits_per_sec) {
return DataRate::bits_per_second(bits_per_sec);
}
static DataRate kbps(int64_t kilobits_per_sec) {
return DataRate::bits_per_second(kilobits_per_sec * 1000);
}
int64_t bits_per_second() const {
RTC_DCHECK(IsFinite());
return bits_per_sec_;
}
int64_t bytes_per_second() const { return bits_per_second() / 8; }
int64_t bps() const { return bits_per_second(); }
int64_t kbps() const { return units_internal::DivideAndRound(bps(), 1000); }
bool IsZero() const { return bits_per_sec_ == 0; }
bool IsInfinite() const {
return bits_per_sec_ == kPlusInfinity.bits_per_sec_;
}
bool IsInitialized() const {
return bits_per_sec_ != kNotInitialized.bits_per_sec_;
}
bool IsFinite() const { return IsInitialized() && !IsInfinite(); }
DataRate operator*(double scalar) const {
return DataRate::bytes_per_second(bytes_per_second() * scalar);
}
DataRate operator*(int64_t scalar) const {
return DataRate::bytes_per_second(bytes_per_second() * scalar);
}
DataRate operator*(int32_t scalar) const {
return DataRate::bytes_per_second(bytes_per_second() * scalar);
}
bool operator==(const DataRate& other) const {
return bits_per_sec_ == other.bits_per_sec_;
}
bool operator!=(const DataRate& other) const {
return bits_per_sec_ != other.bits_per_sec_;
}
bool operator<=(const DataRate& other) const {
return bits_per_sec_ <= other.bits_per_sec_;
}
bool operator>=(const DataRate& other) const {
return bits_per_sec_ >= other.bits_per_sec_;
}
bool operator>(const DataRate& other) const {
return bits_per_sec_ > other.bits_per_sec_;
}
bool operator<(const DataRate& other) const {
return bits_per_sec_ < other.bits_per_sec_;
}
private:
// Bits per second used internally to simplify debugging by making the value
// more recognizable.
explicit DataRate(int64_t bits_per_second) : bits_per_sec_(bits_per_second) {}
int64_t bits_per_sec_;
};
inline DataRate operator*(const double& scalar, const DataRate& rate) {
return rate * scalar;
}
inline DataRate operator*(const int64_t& scalar, const DataRate& rate) {
return rate * scalar;
}
inline DataRate operator*(const int32_t& scalar, const DataRate& rate) {
return rate * scalar;
}
DataRate operator/(const DataSize& size, const TimeDelta& duration);
TimeDelta operator/(const DataSize& size, const DataRate& rate);
DataSize operator*(const DataRate& rate, const TimeDelta& duration);
DataSize operator*(const TimeDelta& duration, const DataRate& rate);
::std::ostream& operator<<(::std::ostream& os, const DataRate& datarate);
::std::ostream& operator<<(::std::ostream& os, const DataSize& datasize);
::std::ostream& operator<<(::std::ostream& os, const Timestamp& timestamp);
::std::ostream& operator<<(::std::ostream& os, const TimeDelta& delta);
} // namespace webrtc
#endif // MODULES_CONGESTION_CONTROLLER_NETWORK_CONTROL_INCLUDE_NETWORK_UNITS_H_

View file

@ -0,0 +1,63 @@
/*
* 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/network_control/include/network_types.h"
namespace webrtc {
::std::ostream& operator<<(::std::ostream& os,
const ProbeClusterConfig& config) {
return os << "ProbeClusterConfig(...)";
}
::std::ostream& operator<<(::std::ostream& os, const PacerConfig& config) {
return os << "PacerConfig(...)";
}
PacketResult::PacketResult() {}
PacketResult::PacketResult(const PacketResult& other) = default;
PacketResult::~PacketResult() {}
std::vector<PacketResult> TransportPacketsFeedback::ReceivedWithSendInfo()
const {
std::vector<PacketResult> res;
for (const PacketResult& fb : packet_feedbacks) {
if (fb.receive_time.IsFinite() && fb.sent_packet.has_value()) {
res.push_back(fb);
}
}
return res;
}
std::vector<PacketResult> TransportPacketsFeedback::LostWithSendInfo() const {
std::vector<PacketResult> res;
for (const PacketResult& fb : packet_feedbacks) {
if (fb.receive_time.IsInfinite() && fb.sent_packet.has_value()) {
res.push_back(fb);
}
}
return res;
}
std::vector<PacketResult> TransportPacketsFeedback::PacketsWithFeedback()
const {
return packet_feedbacks;
}
TransportPacketsFeedback::TransportPacketsFeedback() {}
TransportPacketsFeedback::TransportPacketsFeedback(
const TransportPacketsFeedback& other) = default;
TransportPacketsFeedback::~TransportPacketsFeedback() {}
} // namespace webrtc

View file

@ -0,0 +1,101 @@
/*
* 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/network_control/include/network_units.h"
namespace webrtc {
namespace {
int64_t kPlusInfinityVal = std::numeric_limits<int64_t>::max();
int64_t kMinusInfinityVal = std::numeric_limits<int64_t>::min();
int64_t kSignedNotInitializedVal = kMinusInfinityVal + 1;
int64_t kNotInitializedVal = -1;
} // namespace
const TimeDelta TimeDelta::kZero = TimeDelta(0);
const TimeDelta TimeDelta::kMinusInfinity = TimeDelta(kMinusInfinityVal);
const TimeDelta TimeDelta::kPlusInfinity = TimeDelta(kPlusInfinityVal);
const TimeDelta TimeDelta::kNotInitialized =
TimeDelta(kSignedNotInitializedVal);
const Timestamp Timestamp::kPlusInfinity = Timestamp(kPlusInfinityVal);
const Timestamp Timestamp::kNotInitialized = Timestamp(kNotInitializedVal);
const DataRate DataRate::kZero = DataRate(0);
const DataRate DataRate::kPlusInfinity = DataRate(kPlusInfinityVal);
const DataRate DataRate::kNotInitialized = DataRate(kNotInitializedVal);
const DataSize DataSize::kZero = DataSize(0);
const DataSize DataSize::kPlusInfinity = DataSize(kPlusInfinityVal);
const DataSize DataSize::kNotInitialized = DataSize(kNotInitializedVal);
DataRate operator/(const DataSize& size, const TimeDelta& duration) {
RTC_DCHECK(size.bytes() < std::numeric_limits<int64_t>::max() / 1000000)
<< "size is too large, size: " << size.bytes() << " is not less than "
<< std::numeric_limits<int64_t>::max() / 1000000;
auto bytes_per_sec = size.bytes() * 1000000 / duration.us();
return DataRate::bytes_per_second(bytes_per_sec);
}
TimeDelta operator/(const DataSize& size, const DataRate& rate) {
RTC_DCHECK(size.bytes() < std::numeric_limits<int64_t>::max() / 1000000)
<< "size is too large, size: " << size.bytes() << " is not less than "
<< std::numeric_limits<int64_t>::max() / 1000000;
auto microseconds = size.bytes() * 1000000 / rate.bytes_per_second();
return TimeDelta::us(microseconds);
}
DataSize operator*(const DataRate& rate, const TimeDelta& duration) {
auto micro_bytes = rate.bytes_per_second() * duration.us();
auto bytes = units_internal::DivideAndRound(micro_bytes, 1000000);
return DataSize::bytes(bytes);
}
DataSize operator*(const TimeDelta& duration, const DataRate& rate) {
return rate * duration;
}
::std::ostream& operator<<(::std::ostream& os, const DataRate& value) {
if (value == DataRate::kPlusInfinity) {
return os << "inf bps";
} else if (value == DataRate::kNotInitialized) {
return os << "? bps";
} else {
return os << value.bps() << " bps";
}
}
::std::ostream& operator<<(::std::ostream& os, const DataSize& value) {
if (value == DataSize::kPlusInfinity) {
return os << "inf bytes";
} else if (value == DataSize::kNotInitialized) {
return os << "? bytes";
} else {
return os << value.bytes() << " bytes";
}
}
::std::ostream& operator<<(::std::ostream& os, const Timestamp& value) {
if (value == Timestamp::kPlusInfinity) {
return os << "inf ms";
} else if (value == Timestamp::kNotInitialized) {
return os << "? ms";
} else {
return os << value.ms() << " ms";
}
}
::std::ostream& operator<<(::std::ostream& os, const TimeDelta& value) {
if (value == TimeDelta::kPlusInfinity) {
return os << "+inf ms";
} else if (value == TimeDelta::kMinusInfinity) {
return os << "-inf ms";
} else if (value == TimeDelta::kNotInitialized) {
return os << "? ms";
} else {
return os << value.ms() << " ms";
}
}
} // namespace webrtc

View file

@ -0,0 +1,307 @@
/*
* 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/network_control/include/network_units.h"
#include "test/gtest.h"
namespace webrtc {
namespace test {
TEST(TimeDeltaTest, GetBackSameValues) {
const int64_t kValue = 499;
for (int sign = -1; sign <= 1; ++sign) {
int64_t value = kValue * sign;
EXPECT_EQ(TimeDelta::ms(value).ms(), value);
EXPECT_EQ(TimeDelta::us(value).us(), value);
EXPECT_EQ(TimeDelta::s(value).s(), value);
EXPECT_EQ(TimeDelta::seconds(value).s(), value);
}
EXPECT_EQ(TimeDelta::Zero().us(), 0);
}
TEST(TimeDeltaTest, GetDifferentPrefix) {
const int64_t kValue = 3000000;
EXPECT_EQ(TimeDelta::us(kValue).s(), kValue / 1000000);
EXPECT_EQ(TimeDelta::ms(kValue).s(), kValue / 1000);
EXPECT_EQ(TimeDelta::us(kValue).ms(), kValue / 1000);
EXPECT_EQ(TimeDelta::ms(kValue).us(), kValue * 1000);
EXPECT_EQ(TimeDelta::s(kValue).ms(), kValue * 1000);
EXPECT_EQ(TimeDelta::s(kValue).us(), kValue * 1000000);
}
TEST(TimeDeltaTest, IdentityChecks) {
const int64_t kValue = 3000;
EXPECT_TRUE(TimeDelta::Zero().IsZero());
EXPECT_FALSE(TimeDelta::ms(kValue).IsZero());
EXPECT_TRUE(TimeDelta::Infinity().IsInfinite());
EXPECT_TRUE(TimeDelta::kPlusInfinity.IsInfinite());
EXPECT_TRUE(TimeDelta::kMinusInfinity.IsInfinite());
EXPECT_FALSE(TimeDelta::Zero().IsInfinite());
EXPECT_FALSE(TimeDelta::ms(-kValue).IsInfinite());
EXPECT_FALSE(TimeDelta::ms(kValue).IsInfinite());
EXPECT_FALSE(TimeDelta::Infinity().IsFinite());
EXPECT_FALSE(TimeDelta::kPlusInfinity.IsFinite());
EXPECT_FALSE(TimeDelta::kMinusInfinity.IsFinite());
EXPECT_TRUE(TimeDelta::ms(-kValue).IsFinite());
EXPECT_TRUE(TimeDelta::ms(kValue).IsFinite());
EXPECT_TRUE(TimeDelta::Zero().IsFinite());
}
TEST(TimeDeltaTest, ComparisonOperators) {
const int64_t kSmall = 450;
const int64_t kLarge = 451;
const TimeDelta small = TimeDelta::ms(kSmall);
const TimeDelta large = TimeDelta::ms(kLarge);
EXPECT_EQ(TimeDelta::Zero(), TimeDelta::Zero());
EXPECT_EQ(TimeDelta::Infinity(), TimeDelta::Infinity());
EXPECT_EQ(small, TimeDelta::ms(kSmall));
EXPECT_LE(small, TimeDelta::ms(kSmall));
EXPECT_GE(small, TimeDelta::ms(kSmall));
EXPECT_NE(small, TimeDelta::ms(kLarge));
EXPECT_LE(small, TimeDelta::ms(kLarge));
EXPECT_LT(small, TimeDelta::ms(kLarge));
EXPECT_GE(large, TimeDelta::ms(kSmall));
EXPECT_GT(large, TimeDelta::ms(kSmall));
EXPECT_LT(TimeDelta::kZero, small);
EXPECT_GT(TimeDelta::kZero, TimeDelta::ms(-kSmall));
EXPECT_GT(TimeDelta::kZero, TimeDelta::ms(-kSmall));
EXPECT_GT(TimeDelta::kPlusInfinity, large);
EXPECT_LT(TimeDelta::kMinusInfinity, TimeDelta::kZero);
}
TEST(TimeDeltaTest, MathOperations) {
const int64_t kValueA = 267;
const int64_t kValueB = 450;
const TimeDelta delta_a = TimeDelta::ms(kValueA);
const TimeDelta delta_b = TimeDelta::ms(kValueB);
EXPECT_EQ((delta_a + delta_b).ms(), kValueA + kValueB);
EXPECT_EQ((delta_a - delta_b).ms(), kValueA - kValueB);
const int32_t kInt32Value = 123;
const double kFloatValue = 123.0;
EXPECT_EQ((TimeDelta::us(kValueA) * kValueB).us(), kValueA * kValueB);
EXPECT_EQ((TimeDelta::us(kValueA) * kInt32Value).us(), kValueA * kInt32Value);
EXPECT_EQ((TimeDelta::us(kValueA) * kFloatValue).us(), kValueA * kFloatValue);
EXPECT_EQ(TimeDelta::us(-kValueA).Abs().us(), kValueA);
EXPECT_EQ(TimeDelta::us(kValueA).Abs().us(), kValueA);
}
TEST(TimestampTest, GetBackSameValues) {
const int64_t kValue = 499;
EXPECT_EQ(Timestamp::ms(kValue).ms(), kValue);
EXPECT_EQ(Timestamp::us(kValue).us(), kValue);
EXPECT_EQ(Timestamp::s(kValue).s(), kValue);
}
TEST(TimestampTest, GetDifferentPrefix) {
const int64_t kValue = 3000000;
EXPECT_EQ(Timestamp::us(kValue).s(), kValue / 1000000);
EXPECT_EQ(Timestamp::ms(kValue).s(), kValue / 1000);
EXPECT_EQ(Timestamp::us(kValue).ms(), kValue / 1000);
EXPECT_EQ(Timestamp::ms(kValue).us(), kValue * 1000);
EXPECT_EQ(Timestamp::s(kValue).ms(), kValue * 1000);
EXPECT_EQ(Timestamp::s(kValue).us(), kValue * 1000000);
}
TEST(TimestampTest, IdentityChecks) {
const int64_t kValue = 3000;
EXPECT_TRUE(Timestamp::Infinity().IsInfinite());
EXPECT_FALSE(Timestamp::ms(kValue).IsInfinite());
EXPECT_FALSE(Timestamp::kNotInitialized.IsFinite());
EXPECT_FALSE(Timestamp::Infinity().IsFinite());
EXPECT_TRUE(Timestamp::ms(kValue).IsFinite());
}
TEST(TimestampTest, ComparisonOperators) {
const int64_t kSmall = 450;
const int64_t kLarge = 451;
EXPECT_EQ(Timestamp::Infinity(), Timestamp::Infinity());
EXPECT_EQ(Timestamp::ms(kSmall), Timestamp::ms(kSmall));
EXPECT_LE(Timestamp::ms(kSmall), Timestamp::ms(kSmall));
EXPECT_GE(Timestamp::ms(kSmall), Timestamp::ms(kSmall));
EXPECT_NE(Timestamp::ms(kSmall), Timestamp::ms(kLarge));
EXPECT_LE(Timestamp::ms(kSmall), Timestamp::ms(kLarge));
EXPECT_LT(Timestamp::ms(kSmall), Timestamp::ms(kLarge));
EXPECT_GE(Timestamp::ms(kLarge), Timestamp::ms(kSmall));
EXPECT_GT(Timestamp::ms(kLarge), Timestamp::ms(kSmall));
}
TEST(UnitConversionTest, TimestampAndTimeDeltaMath) {
const int64_t kValueA = 267;
const int64_t kValueB = 450;
const Timestamp time_a = Timestamp::ms(kValueA);
const Timestamp time_b = Timestamp::ms(kValueB);
const TimeDelta delta_a = TimeDelta::ms(kValueA);
EXPECT_EQ((time_a - time_b), TimeDelta::ms(kValueA - kValueB));
EXPECT_EQ((time_b - delta_a), Timestamp::ms(kValueB - kValueA));
EXPECT_EQ((time_b + delta_a), Timestamp::ms(kValueB + kValueA));
}
TEST(DataSizeTest, GetBackSameValues) {
const int64_t kValue = 123 * 8;
EXPECT_EQ(DataSize::bytes(kValue).bytes(), kValue);
EXPECT_EQ(DataSize::bits(kValue).bits(), kValue);
}
TEST(DataSizeTest, GetDifferentPrefix) {
const int64_t kValue = 123 * 8000;
EXPECT_EQ(DataSize::bytes(kValue).bits(), kValue * 8);
EXPECT_EQ(DataSize::bits(kValue).bytes(), kValue / 8);
EXPECT_EQ(DataSize::bits(kValue).kilobits(), kValue / 1000);
EXPECT_EQ(DataSize::bytes(kValue).kilobytes(), kValue / 1000);
}
TEST(DataSizeTest, IdentityChecks) {
const int64_t kValue = 3000;
EXPECT_TRUE(DataSize::Zero().IsZero());
EXPECT_FALSE(DataSize::bytes(kValue).IsZero());
EXPECT_TRUE(DataSize::Infinity().IsInfinite());
EXPECT_TRUE(DataSize::kPlusInfinity.IsInfinite());
EXPECT_FALSE(DataSize::Zero().IsInfinite());
EXPECT_FALSE(DataSize::bytes(kValue).IsInfinite());
EXPECT_FALSE(DataSize::Infinity().IsFinite());
EXPECT_FALSE(DataSize::kPlusInfinity.IsFinite());
EXPECT_TRUE(DataSize::bytes(kValue).IsFinite());
EXPECT_TRUE(DataSize::Zero().IsFinite());
}
TEST(DataSizeTest, ComparisonOperators) {
const int64_t kSmall = 450;
const int64_t kLarge = 451;
const DataSize small = DataSize::bytes(kSmall);
const DataSize large = DataSize::bytes(kLarge);
EXPECT_EQ(DataSize::Zero(), DataSize::Zero());
EXPECT_EQ(DataSize::Infinity(), DataSize::Infinity());
EXPECT_EQ(small, small);
EXPECT_LE(small, small);
EXPECT_GE(small, small);
EXPECT_NE(small, large);
EXPECT_LE(small, large);
EXPECT_LT(small, large);
EXPECT_GE(large, small);
EXPECT_GT(large, small);
EXPECT_LT(DataSize::kZero, small);
EXPECT_GT(DataSize::kPlusInfinity, large);
}
TEST(DataSizeTest, MathOperations) {
const int64_t kValueA = 450;
const int64_t kValueB = 267;
const DataSize size_a = DataSize::bytes(kValueA);
const DataSize size_b = DataSize::bytes(kValueB);
EXPECT_EQ((size_a + size_b).bytes(), kValueA + kValueB);
EXPECT_EQ((size_a - size_b).bytes(), kValueA - kValueB);
const int32_t kInt32Value = 123;
const double kFloatValue = 123.0;
EXPECT_EQ((size_a * kValueB).bytes(), kValueA * kValueB);
EXPECT_EQ((size_a * kInt32Value).bytes(), kValueA * kInt32Value);
EXPECT_EQ((size_a * kFloatValue).bytes(), kValueA * kFloatValue);
EXPECT_EQ((size_a / 10).bytes(), kValueA / 10);
DataSize mutable_size = DataSize::bytes(kValueA);
mutable_size += size_b;
EXPECT_EQ(mutable_size.bytes(), kValueA + kValueB);
mutable_size -= size_a;
EXPECT_EQ(mutable_size.bytes(), kValueB);
}
TEST(DataRateTest, GetBackSameValues) {
const int64_t kValue = 123 * 8;
EXPECT_EQ(DataRate::bytes_per_second(kValue).bytes_per_second(), kValue);
EXPECT_EQ(DataRate::bits_per_second(kValue).bits_per_second(), kValue);
EXPECT_EQ(DataRate::bps(kValue).bps(), kValue);
EXPECT_EQ(DataRate::kbps(kValue).kbps(), kValue);
}
TEST(DataRateTest, GetDifferentPrefix) {
const int64_t kValue = 123 * 8000;
EXPECT_EQ(DataRate::bytes_per_second(kValue).bps(), kValue * 8);
EXPECT_EQ(DataRate::bits_per_second(kValue).bytes_per_second(), kValue / 8);
EXPECT_EQ(DataRate::bps(kValue).kbps(), kValue / 1000);
}
TEST(DataRateTest, IdentityChecks) {
const int64_t kValue = 3000;
EXPECT_TRUE(DataRate::Zero().IsZero());
EXPECT_FALSE(DataRate::bytes_per_second(kValue).IsZero());
EXPECT_TRUE(DataRate::Infinity().IsInfinite());
EXPECT_TRUE(DataRate::kPlusInfinity.IsInfinite());
EXPECT_FALSE(DataRate::Zero().IsInfinite());
EXPECT_FALSE(DataRate::bytes_per_second(kValue).IsInfinite());
EXPECT_FALSE(DataRate::Infinity().IsFinite());
EXPECT_FALSE(DataRate::kPlusInfinity.IsFinite());
EXPECT_TRUE(DataRate::bytes_per_second(kValue).IsFinite());
EXPECT_TRUE(DataRate::Zero().IsFinite());
}
TEST(DataRateTest, ComparisonOperators) {
const int64_t kSmall = 450;
const int64_t kLarge = 451;
const DataRate small = DataRate::bytes_per_second(kSmall);
const DataRate large = DataRate::bytes_per_second(kLarge);
EXPECT_EQ(DataRate::Zero(), DataRate::Zero());
EXPECT_EQ(DataRate::Infinity(), DataRate::Infinity());
EXPECT_EQ(small, small);
EXPECT_LE(small, small);
EXPECT_GE(small, small);
EXPECT_NE(small, large);
EXPECT_LE(small, large);
EXPECT_LT(small, large);
EXPECT_GE(large, small);
EXPECT_GT(large, small);
EXPECT_LT(DataRate::kZero, small);
EXPECT_GT(DataRate::kPlusInfinity, large);
}
TEST(DataRateTest, MathOperations) {
const int64_t kValueA = 450;
const int64_t kValueB = 267;
const DataRate size_a = DataRate::bytes_per_second(kValueA);
const int32_t kInt32Value = 123;
const double kFloatValue = 123.0;
EXPECT_EQ((size_a * kValueB).bytes_per_second(), kValueA * kValueB);
EXPECT_EQ((size_a * kInt32Value).bytes_per_second(), kValueA * kInt32Value);
EXPECT_EQ((size_a * kFloatValue).bytes_per_second(), kValueA * kFloatValue);
}
TEST(UnitConversionTest, DataRateAndDataSizeAndTimeDelta) {
const int64_t kValueA = 5;
const int64_t kValueB = 450;
const int64_t kValueC = 45000;
const TimeDelta delta_a = TimeDelta::seconds(kValueA);
const DataRate rate_b = DataRate::bytes_per_second(kValueB);
const DataSize size_c = DataSize::bytes(kValueC);
EXPECT_EQ((delta_a * rate_b).bytes(), kValueA * kValueB);
EXPECT_EQ((size_c / delta_a).bytes_per_second(), kValueC / kValueA);
EXPECT_EQ((size_c / rate_b).s(), kValueC / kValueB);
}
} // namespace test
} // namespace webrtc

View file

@ -0,0 +1,83 @@
/*
* 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/pacer_controller.h"
#include "modules/congestion_controller/network_control/include/network_units.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
namespace webrtc {
PacerController::PacerController(PacedSender* pacer) : pacer_(pacer) {
sequenced_checker_.Detach();
}
PacerController::~PacerController() = default;
void PacerController::OnCongestionWindow(CongestionWindow congestion_window) {
RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
if (congestion_window.enabled) {
congestion_window_ = congestion_window;
} else {
congestion_window_ = rtc::nullopt;
congested_ = false;
UpdatePacerState();
}
}
void PacerController::OnNetworkAvailability(NetworkAvailability msg) {
RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
network_available_ = msg.network_available;
congested_ = false;
UpdatePacerState();
}
void PacerController::OnNetworkRouteChange(NetworkRouteChange) {
RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
congested_ = false;
UpdatePacerState();
}
void PacerController::OnPacerConfig(PacerConfig msg) {
RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
DataRate pacing_rate = msg.data_window / msg.time_window;
DataRate padding_rate = msg.pad_window / msg.time_window;
pacer_->SetPacingRates(pacing_rate.bps(), padding_rate.bps());
}
void PacerController::OnProbeClusterConfig(ProbeClusterConfig config) {
RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
int64_t bitrate_bps = config.target_data_rate.bps();
pacer_->CreateProbeCluster(bitrate_bps);
}
void PacerController::OnOutstandingData(OutstandingData msg) {
RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
if (congestion_window_.has_value()) {
congested_ = msg.in_flight_data > congestion_window_->data_window;
}
UpdatePacerState();
}
void PacerController::UpdatePacerState() {
bool pause = congested_ || !network_available_;
SetPacerState(pause);
}
void PacerController::SetPacerState(bool paused) {
if (paused && !pacer_paused_)
pacer_->Pause();
else if (!paused && pacer_paused_)
pacer_->Resume();
pacer_paused_ = paused;
}
} // namespace webrtc

View file

@ -0,0 +1,53 @@
/*
* 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_PACER_CONTROLLER_H_
#define MODULES_CONGESTION_CONTROLLER_PACER_CONTROLLER_H_
#include <memory>
#include "modules/congestion_controller/network_control/include/network_types.h"
#include "modules/pacing/paced_sender.h"
#include "rtc_base/sequenced_task_checker.h"
namespace webrtc {
class Clock;
// Wrapper class to control pacer using task queues. Note that this class is
// only designed to be used from a single task queue and has no built in
// concurrency safety.
// TODO(srte): Integrate this interface directly into PacedSender.
class PacerController {
public:
explicit PacerController(PacedSender* pacer);
~PacerController();
void OnCongestionWindow(CongestionWindow msg);
void OnNetworkAvailability(NetworkAvailability msg);
void OnNetworkRouteChange(NetworkRouteChange msg);
void OnOutstandingData(OutstandingData msg);
void OnPacerConfig(PacerConfig msg);
void OnProbeClusterConfig(ProbeClusterConfig msg);
private:
void UpdatePacerState();
void SetPacerState(bool paused);
PacedSender* const pacer_;
rtc::Optional<PacerConfig> current_pacer_config_;
rtc::Optional<CongestionWindow> congestion_window_;
bool congested_ = false;
bool pacer_paused_ = false;
bool network_available_ = true;
rtc::SequencedTaskChecker sequenced_checker_;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(PacerController);
};
} // namespace webrtc
#endif // MODULES_CONGESTION_CONTROLLER_PACER_CONTROLLER_H_

View file

@ -66,8 +66,8 @@ int ProbeBitrateEstimator::HandleProbeAndEstimateBitrate(
EraseOldClusters(packet_feedback.arrival_time_ms - kMaxClusterHistoryMs); EraseOldClusters(packet_feedback.arrival_time_ms - kMaxClusterHistoryMs);
int payload_size_bits = rtc::dchecked_cast<int>( int payload_size_bits =
packet_feedback.payload_size * 8); rtc::dchecked_cast<int>(packet_feedback.payload_size * 8);
AggregatedCluster* cluster = &clusters_[cluster_id]; AggregatedCluster* cluster = &clusters_[cluster_id];
if (packet_feedback.send_time_ms < cluster->first_send_ms) { if (packet_feedback.send_time_ms < cluster->first_send_ms) {

View file

@ -11,8 +11,8 @@
#ifndef MODULES_CONGESTION_CONTROLLER_PROBE_BITRATE_ESTIMATOR_H_ #ifndef MODULES_CONGESTION_CONTROLLER_PROBE_BITRATE_ESTIMATOR_H_
#define MODULES_CONGESTION_CONTROLLER_PROBE_BITRATE_ESTIMATOR_H_ #define MODULES_CONGESTION_CONTROLLER_PROBE_BITRATE_ESTIMATOR_H_
#include <map>
#include <limits> #include <limits>
#include <map>
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"

View file

@ -10,8 +10,8 @@
#include "modules/congestion_controller/probe_bitrate_estimator.h" #include "modules/congestion_controller/probe_bitrate_estimator.h"
#include <vector>
#include <utility> #include <utility>
#include <vector>
#include "modules/remote_bitrate_estimator/aimd_rate_control.h" #include "modules/remote_bitrate_estimator/aimd_rate_control.h"
#include "test/gmock.h" #include "test/gmock.h"

View file

@ -21,6 +21,12 @@
namespace webrtc { namespace webrtc {
namespace { namespace {
// The minimum number probing packets used.
constexpr int kMinProbePacketsSent = 5;
// The minimum probing duration in ms.
constexpr int kMinProbeDurationMs = 15;
// Maximum waiting time from the time of initiating probing to getting // Maximum waiting time from the time of initiating probing to getting
// the measured results back. // the measured results back.
constexpr int64_t kMaxWaitingTimeForProbingResultMs = 1000; constexpr int64_t kMaxWaitingTimeForProbingResultMs = 1000;
@ -69,19 +75,20 @@ constexpr char kBweRapidRecoveryExperiment[] =
} // namespace } // namespace
ProbeController::ProbeController(PacedSender* pacer, const Clock* clock) ProbeController::ProbeController(NetworkControllerObserver* observer)
: pacer_(pacer), clock_(clock), enable_periodic_alr_probing_(false) { : observer_(observer), enable_periodic_alr_probing_(false) {
Reset(); Reset(0);
in_rapid_recovery_experiment_ = webrtc::field_trial::FindFullName( in_rapid_recovery_experiment_ = webrtc::field_trial::FindFullName(
kBweRapidRecoveryExperiment) == "Enabled"; kBweRapidRecoveryExperiment) == "Enabled";
} }
ProbeController::~ProbeController() {}
void ProbeController::SetBitrates(int64_t min_bitrate_bps, void ProbeController::SetBitrates(int64_t min_bitrate_bps,
int64_t start_bitrate_bps, int64_t start_bitrate_bps,
int64_t max_bitrate_bps) { int64_t max_bitrate_bps,
rtc::CritScope cs(&critsect_); int64_t at_time_ms) {
if (start_bitrate_bps > 0) {
if (start_bitrate_bps > 0) {
start_bitrate_bps_ = start_bitrate_bps; start_bitrate_bps_ = start_bitrate_bps;
estimated_bitrate_bps_ = start_bitrate_bps; estimated_bitrate_bps_ = start_bitrate_bps;
} else if (start_bitrate_bps_ == 0) { } else if (start_bitrate_bps_ == 0) {
@ -95,8 +102,8 @@ void ProbeController::SetBitrates(int64_t min_bitrate_bps,
switch (state_) { switch (state_) {
case State::kInit: case State::kInit:
if (network_state_ == kNetworkUp) if (network_available_)
InitiateExponentialProbing(); InitiateExponentialProbing(at_time_ms);
break; break;
case State::kWaitingForProbingResult: case State::kWaitingForProbingResult:
@ -119,33 +126,32 @@ void ProbeController::SetBitrates(int64_t min_bitrate_bps,
RTC_HISTOGRAM_COUNTS_10000("WebRTC.BWE.MidCallProbing.Initiated", RTC_HISTOGRAM_COUNTS_10000("WebRTC.BWE.MidCallProbing.Initiated",
max_bitrate_bps_ / 1000); max_bitrate_bps_ / 1000);
InitiateProbing(clock_->TimeInMilliseconds(), {max_bitrate_bps}, false); InitiateProbing(at_time_ms, {max_bitrate_bps}, false);
} }
break; break;
} }
} }
void ProbeController::OnNetworkStateChanged(NetworkState network_state) { void ProbeController::OnNetworkAvailability(NetworkAvailability msg) {
rtc::CritScope cs(&critsect_); network_available_ = msg.network_available;
network_state_ = network_state; if (network_available_ && state_ == State::kInit && start_bitrate_bps_ > 0)
if (network_state_ == kNetworkUp && state_ == State::kInit) InitiateExponentialProbing(msg.at_time.ms());
InitiateExponentialProbing();
} }
void ProbeController::InitiateExponentialProbing() { void ProbeController::InitiateExponentialProbing(int64_t at_time_ms) {
RTC_DCHECK(network_state_ == kNetworkUp); RTC_DCHECK(network_available_);
RTC_DCHECK(state_ == State::kInit); RTC_DCHECK(state_ == State::kInit);
RTC_DCHECK_GT(start_bitrate_bps_, 0); RTC_DCHECK_GT(start_bitrate_bps_, 0);
// When probing at 1.8 Mbps ( 6x 300), this represents a threshold of // When probing at 1.8 Mbps ( 6x 300), this represents a threshold of
// 1.2 Mbps to continue probing. // 1.2 Mbps to continue probing.
InitiateProbing(clock_->TimeInMilliseconds(), InitiateProbing(at_time_ms, {3 * start_bitrate_bps_, 6 * start_bitrate_bps_},
{3 * start_bitrate_bps_, 6 * start_bitrate_bps_}, true); true);
} }
void ProbeController::SetEstimatedBitrate(int64_t bitrate_bps) { void ProbeController::SetEstimatedBitrate(int64_t bitrate_bps,
rtc::CritScope cs(&critsect_); int64_t at_time_ms) {
int64_t now_ms = clock_->TimeInMilliseconds(); int64_t now_ms = at_time_ms;
if (mid_call_probing_waiting_for_result_ && if (mid_call_probing_waiting_for_result_ &&
bitrate_bps >= mid_call_probing_succcess_threshold_) { bitrate_bps >= mid_call_probing_succcess_threshold_) {
@ -179,25 +185,26 @@ void ProbeController::SetEstimatedBitrate(int64_t bitrate_bps) {
} }
void ProbeController::EnablePeriodicAlrProbing(bool enable) { void ProbeController::EnablePeriodicAlrProbing(bool enable) {
rtc::CritScope cs(&critsect_);
enable_periodic_alr_probing_ = enable; enable_periodic_alr_probing_ = enable;
} }
void ProbeController::SetAlrStartTimeMs(
rtc::Optional<int64_t> alr_start_time_ms) {
alr_start_time_ms_ = alr_start_time_ms;
}
void ProbeController::SetAlrEndedTimeMs(int64_t alr_end_time_ms) { void ProbeController::SetAlrEndedTimeMs(int64_t alr_end_time_ms) {
rtc::CritScope cs(&critsect_);
alr_end_time_ms_.emplace(alr_end_time_ms); alr_end_time_ms_.emplace(alr_end_time_ms);
} }
void ProbeController::RequestProbe() { void ProbeController::RequestProbe(int64_t at_time_ms) {
int64_t now_ms = clock_->TimeInMilliseconds(); int64_t now_ms = at_time_ms;
rtc::CritScope cs(&critsect_);
// Called once we have returned to normal state after a large drop in // Called once we have returned to normal state after a large drop in
// estimated bandwidth. The current response is to initiate a single probe // estimated bandwidth. The current response is to initiate a single probe
// session (if not already probing) at the previous bitrate. // session (if not already probing) at the previous bitrate.
// //
// If the probe session fails, the assumption is that this drop was a // If the probe session fails, the assumption is that this drop was a
// real one from a competing flow or a network change. // real one from a competing flow or a network change.
bool in_alr = pacer_->GetApplicationLimitedRegionStartTime().has_value(); bool in_alr = alr_start_time_ms_.has_value();
bool alr_ended_recently = bool alr_ended_recently =
(alr_end_time_ms_.has_value() && (alr_end_time_ms_.has_value() &&
now_ms - alr_end_time_ms_.value() < kAlrEndedTimeoutMs); now_ms - alr_end_time_ms_.value() < kAlrEndedTimeoutMs);
@ -224,16 +231,15 @@ void ProbeController::RequestProbe() {
} }
} }
void ProbeController::Reset() { void ProbeController::Reset(int64_t at_time_ms) {
rtc::CritScope cs(&critsect_); network_available_ = true;
network_state_ = kNetworkUp;
state_ = State::kInit; state_ = State::kInit;
min_bitrate_to_probe_further_bps_ = kExponentialProbingDisabled; min_bitrate_to_probe_further_bps_ = kExponentialProbingDisabled;
time_last_probing_initiated_ms_ = 0; time_last_probing_initiated_ms_ = 0;
estimated_bitrate_bps_ = 0; estimated_bitrate_bps_ = 0;
start_bitrate_bps_ = 0; start_bitrate_bps_ = 0;
max_bitrate_bps_ = 0; max_bitrate_bps_ = 0;
int64_t now_ms = clock_->TimeInMilliseconds(); int64_t now_ms = at_time_ms;
last_bwe_drop_probing_time_ms_ = now_ms; last_bwe_drop_probing_time_ms_ = now_ms;
alr_end_time_ms_.reset(); alr_end_time_ms_.reset();
mid_call_probing_waiting_for_result_ = false; mid_call_probing_waiting_for_result_ = false;
@ -241,10 +247,8 @@ void ProbeController::Reset() {
bitrate_before_last_large_drop_bps_ = 0; bitrate_before_last_large_drop_bps_ = 0;
} }
void ProbeController::Process() { void ProbeController::Process(int64_t at_time_ms) {
rtc::CritScope cs(&critsect_); int64_t now_ms = at_time_ms;
int64_t now_ms = clock_->TimeInMilliseconds();
if (now_ms - time_last_probing_initiated_ms_ > if (now_ms - time_last_probing_initiated_ms_ >
kMaxWaitingTimeForProbingResultMs) { kMaxWaitingTimeForProbingResultMs) {
@ -261,11 +265,9 @@ void ProbeController::Process() {
return; return;
// Probe bandwidth periodically when in ALR state. // Probe bandwidth periodically when in ALR state.
rtc::Optional<int64_t> alr_start_time = if (alr_start_time_ms_ && estimated_bitrate_bps_ > 0) {
pacer_->GetApplicationLimitedRegionStartTime();
if (alr_start_time && estimated_bitrate_bps_ > 0) {
int64_t next_probe_time_ms = int64_t next_probe_time_ms =
std::max(*alr_start_time, time_last_probing_initiated_ms_) + std::max(*alr_start_time_ms_, time_last_probing_initiated_ms_) +
kAlrPeriodicProbingIntervalMs; kAlrPeriodicProbingIntervalMs;
if (now_ms >= next_probe_time_ms) { if (now_ms >= next_probe_time_ms) {
InitiateProbing(now_ms, {estimated_bitrate_bps_ * 2}, true); InitiateProbing(now_ms, {estimated_bitrate_bps_ * 2}, true);
@ -285,7 +287,13 @@ void ProbeController::InitiateProbing(
bitrate = max_probe_bitrate_bps; bitrate = max_probe_bitrate_bps;
probe_further = false; probe_further = false;
} }
pacer_->CreateProbeCluster(rtc::dchecked_cast<int>(bitrate));
ProbeClusterConfig config;
config.at_time = Timestamp::ms(now_ms);
config.target_data_rate = DataRate::bps(rtc::dchecked_cast<int>(bitrate));
config.target_duration = TimeDelta::ms(kMinProbeDurationMs);
config.target_probe_count = kMinProbePacketsSent;
observer_->OnProbeClusterConfig(config);
} }
time_last_probing_initiated_ms_ = now_ms; time_last_probing_initiated_ms_ = now_ms;
if (probe_further) { if (probe_further) {

View file

@ -14,8 +14,8 @@
#include <initializer_list> #include <initializer_list>
#include "common_types.h" // NOLINT(build/include) #include "common_types.h" // NOLINT(build/include)
#include "modules/pacing/paced_sender.h" #include "modules/congestion_controller/network_control/include/network_control.h"
#include "rtc_base/criticalsection.h" #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
namespace webrtc { namespace webrtc {
@ -26,27 +26,30 @@ class Clock;
// bitrate is adjusted by an application. // bitrate is adjusted by an application.
class ProbeController { class ProbeController {
public: public:
ProbeController(PacedSender* pacer, const Clock* clock); explicit ProbeController(NetworkControllerObserver* observer);
~ProbeController();
void SetBitrates(int64_t min_bitrate_bps, void SetBitrates(int64_t min_bitrate_bps,
int64_t start_bitrate_bps, int64_t start_bitrate_bps,
int64_t max_bitrate_bps); int64_t max_bitrate_bps,
int64_t at_time_ms);
void OnNetworkStateChanged(NetworkState state); void OnNetworkAvailability(NetworkAvailability msg);
void SetEstimatedBitrate(int64_t bitrate_bps); void SetEstimatedBitrate(int64_t bitrate_bps, int64_t at_time_ms);
void EnablePeriodicAlrProbing(bool enable); void EnablePeriodicAlrProbing(bool enable);
void SetAlrStartTimeMs(rtc::Optional<int64_t> alr_start_time);
void SetAlrEndedTimeMs(int64_t alr_end_time); void SetAlrEndedTimeMs(int64_t alr_end_time);
void RequestProbe(); void RequestProbe(int64_t at_time_ms);
// Resets the ProbeController to a state equivalent to as if it was just // Resets the ProbeController to a state equivalent to as if it was just
// created EXCEPT for |enable_periodic_alr_probing_|. // created EXCEPT for |enable_periodic_alr_probing_|.
void Reset(); void Reset(int64_t at_time_ms);
void Process(); void Process(int64_t at_time_ms);
private: private:
enum class State { enum class State {
@ -58,33 +61,32 @@ class ProbeController {
kProbingComplete, kProbingComplete,
}; };
void InitiateExponentialProbing() RTC_EXCLUSIVE_LOCKS_REQUIRED(critsect_); void InitiateExponentialProbing(int64_t at_time_ms);
void InitiateProbing(int64_t now_ms, void InitiateProbing(int64_t now_ms,
std::initializer_list<int64_t> bitrates_to_probe, std::initializer_list<int64_t> bitrates_to_probe,
bool probe_further) bool probe_further);
RTC_EXCLUSIVE_LOCKS_REQUIRED(critsect_);
rtc::CriticalSection critsect_; NetworkControllerObserver* const observer_;
PacedSender* const pacer_;
const Clock* const clock_;
NetworkState network_state_ RTC_GUARDED_BY(critsect_);
State state_ RTC_GUARDED_BY(critsect_);
int64_t min_bitrate_to_probe_further_bps_ RTC_GUARDED_BY(critsect_);
int64_t time_last_probing_initiated_ms_ RTC_GUARDED_BY(critsect_);
int64_t estimated_bitrate_bps_ RTC_GUARDED_BY(critsect_);
int64_t start_bitrate_bps_ RTC_GUARDED_BY(critsect_);
int64_t max_bitrate_bps_ RTC_GUARDED_BY(critsect_);
int64_t last_bwe_drop_probing_time_ms_ RTC_GUARDED_BY(critsect_);
rtc::Optional<int64_t> alr_end_time_ms_ RTC_GUARDED_BY(critsect_);
bool enable_periodic_alr_probing_ RTC_GUARDED_BY(critsect_);
int64_t time_of_last_large_drop_ms_ RTC_GUARDED_BY(critsect_);
int64_t bitrate_before_last_large_drop_bps_ RTC_GUARDED_BY(critsect_);
bool in_rapid_recovery_experiment_ RTC_GUARDED_BY(critsect_); bool network_available_;
State state_;
int64_t min_bitrate_to_probe_further_bps_;
int64_t time_last_probing_initiated_ms_;
int64_t estimated_bitrate_bps_;
int64_t start_bitrate_bps_;
int64_t max_bitrate_bps_;
int64_t last_bwe_drop_probing_time_ms_;
rtc::Optional<int64_t> alr_start_time_ms_;
rtc::Optional<int64_t> alr_end_time_ms_;
bool enable_periodic_alr_probing_;
int64_t time_of_last_large_drop_ms_;
int64_t bitrate_before_last_large_drop_bps_;
bool in_rapid_recovery_experiment_;
// For WebRTC.BWE.MidCallProbing.* metric. // For WebRTC.BWE.MidCallProbing.* metric.
bool mid_call_probing_waiting_for_result_ RTC_GUARDED_BY(&critsect_); bool mid_call_probing_waiting_for_result_;
int64_t mid_call_probing_bitrate_bps_ RTC_GUARDED_BY(&critsect_); int64_t mid_call_probing_bitrate_bps_;
int64_t mid_call_probing_succcess_threshold_ RTC_GUARDED_BY(&critsect_); int64_t mid_call_probing_succcess_threshold_;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(ProbeController); RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(ProbeController);
}; };

View file

@ -9,8 +9,8 @@
*/ */
#include <memory> #include <memory>
#include "modules/congestion_controller/network_control/include/network_types.h"
#include "modules/congestion_controller/probe_controller.h" #include "modules/congestion_controller/probe_controller.h"
#include "modules/pacing/mock/mock_paced_sender.h"
#include "rtc_base/logging.h" #include "rtc_base/logging.h"
#include "system_wrappers/include/clock.h" #include "system_wrappers/include/clock.h"
#include "test/gmock.h" #include "test/gmock.h"
@ -18,9 +18,13 @@
using testing::_; using testing::_;
using testing::AtLeast; using testing::AtLeast;
using testing::Field;
using testing::Matcher;
using testing::NiceMock; using testing::NiceMock;
using testing::Return; using testing::Return;
using webrtc::ProbeClusterConfig;
namespace webrtc { namespace webrtc {
namespace test { namespace test {
@ -36,234 +40,252 @@ constexpr int kAlrProbeInterval = 5000;
constexpr int kAlrEndedTimeoutMs = 3000; constexpr int kAlrEndedTimeoutMs = 3000;
constexpr int kBitrateDropTimeoutMs = 5000; constexpr int kBitrateDropTimeoutMs = 5000;
inline Matcher<ProbeClusterConfig> DataRateEqBps(int bps) {
return Field(&ProbeClusterConfig::target_data_rate, DataRate::bps(bps));
}
class MockNetworkControllerObserver : public NetworkControllerObserver {
public:
MOCK_METHOD1(OnCongestionWindow, void(CongestionWindow));
MOCK_METHOD1(OnPacerConfig, void(PacerConfig));
MOCK_METHOD1(OnProbeClusterConfig, void(ProbeClusterConfig));
MOCK_METHOD1(OnTargetTransferRate, void(TargetTransferRate));
};
} // namespace } // namespace
class ProbeControllerTest : public ::testing::Test { class ProbeControllerTest : public ::testing::Test {
protected: protected:
ProbeControllerTest() : clock_(100000000L) { ProbeControllerTest() : clock_(100000000L) {
probe_controller_.reset(new ProbeController(&pacer_, &clock_)); probe_controller_.reset(new ProbeController(&cluster_handler_));
} }
~ProbeControllerTest() override {} ~ProbeControllerTest() override {}
void SetNetworkAvailable(bool available) {
NetworkAvailability msg;
msg.at_time = Timestamp::ms(clock_.TimeInMicroseconds());
msg.network_available = available;
probe_controller_->OnNetworkAvailability(msg);
}
int64_t NowMs() { return clock_.TimeInMilliseconds(); }
SimulatedClock clock_; SimulatedClock clock_;
NiceMock<MockPacedSender> pacer_; NiceMock<MockNetworkControllerObserver> cluster_handler_;
std::unique_ptr<ProbeController> probe_controller_; std::unique_ptr<ProbeController> probe_controller_;
}; };
TEST_F(ProbeControllerTest, InitiatesProbingAtStart) { TEST_F(ProbeControllerTest, InitiatesProbingAtStart) {
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(AtLeast(2)); EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(AtLeast(2));
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps, probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
kMaxBitrateBps); kMaxBitrateBps, NowMs());
} }
TEST_F(ProbeControllerTest, ProbeOnlyWhenNetworkIsUp) { TEST_F(ProbeControllerTest, ProbeOnlyWhenNetworkIsUp) {
probe_controller_->OnNetworkStateChanged(kNetworkDown); SetNetworkAvailable(false);
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(0); EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(0);
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps, probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
kMaxBitrateBps); kMaxBitrateBps, NowMs());
testing::Mock::VerifyAndClearExpectations(&pacer_); testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(AtLeast(2)); EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(AtLeast(2));
probe_controller_->OnNetworkStateChanged(kNetworkUp); SetNetworkAvailable(true);
} }
TEST_F(ProbeControllerTest, InitiatesProbingOnMaxBitrateIncrease) { TEST_F(ProbeControllerTest, InitiatesProbingOnMaxBitrateIncrease) {
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(AtLeast(2)); EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(AtLeast(2));
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps, probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
kMaxBitrateBps); kMaxBitrateBps, NowMs());
// Long enough to time out exponential probing. // Long enough to time out exponential probing.
clock_.AdvanceTimeMilliseconds(kExponentialProbingTimeoutMs); clock_.AdvanceTimeMilliseconds(kExponentialProbingTimeoutMs);
probe_controller_->SetEstimatedBitrate(kStartBitrateBps); probe_controller_->SetEstimatedBitrate(kStartBitrateBps, NowMs());
probe_controller_->Process(); probe_controller_->Process(NowMs());
EXPECT_CALL(pacer_, CreateProbeCluster(kMaxBitrateBps + 100)); EXPECT_CALL(cluster_handler_,
OnProbeClusterConfig(DataRateEqBps(kMaxBitrateBps + 100)));
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps, probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
kMaxBitrateBps + 100); kMaxBitrateBps + 100, NowMs());
} }
TEST_F(ProbeControllerTest, InitiatesProbingOnMaxBitrateIncreaseAtMaxBitrate) { TEST_F(ProbeControllerTest, InitiatesProbingOnMaxBitrateIncreaseAtMaxBitrate) {
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(AtLeast(2)); EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(AtLeast(2));
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps, probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
kMaxBitrateBps); kMaxBitrateBps, NowMs());
// Long enough to time out exponential probing. // Long enough to time out exponential probing.
clock_.AdvanceTimeMilliseconds(kExponentialProbingTimeoutMs); clock_.AdvanceTimeMilliseconds(kExponentialProbingTimeoutMs);
probe_controller_->SetEstimatedBitrate(kStartBitrateBps); probe_controller_->SetEstimatedBitrate(kStartBitrateBps, NowMs());
probe_controller_->Process(); probe_controller_->Process(NowMs());
probe_controller_->SetEstimatedBitrate(kMaxBitrateBps); probe_controller_->SetEstimatedBitrate(kMaxBitrateBps, NowMs());
EXPECT_CALL(pacer_, CreateProbeCluster(kMaxBitrateBps + 100)); EXPECT_CALL(cluster_handler_,
OnProbeClusterConfig(DataRateEqBps(kMaxBitrateBps + 100)));
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps, probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
kMaxBitrateBps + 100); kMaxBitrateBps + 100, NowMs());
} }
TEST_F(ProbeControllerTest, TestExponentialProbing) { TEST_F(ProbeControllerTest, TestExponentialProbing) {
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps, probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
kMaxBitrateBps); kMaxBitrateBps, NowMs());
// Repeated probe should only be sent when estimated bitrate climbs above // Repeated probe should only be sent when estimated bitrate climbs above
// 0.7 * 6 * kStartBitrateBps = 1260. // 0.7 * 6 * kStartBitrateBps = 1260.
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(0); EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(0);
probe_controller_->SetEstimatedBitrate(1000); probe_controller_->SetEstimatedBitrate(1000, NowMs());
testing::Mock::VerifyAndClearExpectations(&pacer_); testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
EXPECT_CALL(pacer_, CreateProbeCluster(2 * 1800)); EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(DataRateEqBps(2 * 1800)));
probe_controller_->SetEstimatedBitrate(1800); probe_controller_->SetEstimatedBitrate(1800, NowMs());
} }
TEST_F(ProbeControllerTest, TestExponentialProbingTimeout) { TEST_F(ProbeControllerTest, TestExponentialProbingTimeout) {
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps, probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
kMaxBitrateBps); kMaxBitrateBps, NowMs());
// Advance far enough to cause a time out in waiting for probing result. // Advance far enough to cause a time out in waiting for probing result.
clock_.AdvanceTimeMilliseconds(kExponentialProbingTimeoutMs); clock_.AdvanceTimeMilliseconds(kExponentialProbingTimeoutMs);
probe_controller_->Process(); probe_controller_->Process(NowMs());
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(0); EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(0);
probe_controller_->SetEstimatedBitrate(1800); probe_controller_->SetEstimatedBitrate(1800, NowMs());
} }
TEST_F(ProbeControllerTest, RequestProbeInAlr) { TEST_F(ProbeControllerTest, RequestProbeInAlr) {
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(2); EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(2);
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps, probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
kMaxBitrateBps); kMaxBitrateBps, NowMs());
probe_controller_->SetEstimatedBitrate(500); probe_controller_->SetEstimatedBitrate(500, NowMs());
testing::Mock::VerifyAndClearExpectations(&pacer_); testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
EXPECT_CALL(pacer_, CreateProbeCluster(0.85 * 500)).Times(1); EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(DataRateEqBps(0.85 * 500)))
EXPECT_CALL(pacer_, GetApplicationLimitedRegionStartTime()) .Times(1);
.WillRepeatedly(Return(clock_.TimeInMilliseconds())); probe_controller_->SetAlrStartTimeMs(clock_.TimeInMilliseconds());
clock_.AdvanceTimeMilliseconds(kAlrProbeInterval + 1); clock_.AdvanceTimeMilliseconds(kAlrProbeInterval + 1);
probe_controller_->Process(); probe_controller_->Process(NowMs());
probe_controller_->SetEstimatedBitrate(250); probe_controller_->SetEstimatedBitrate(250, NowMs());
probe_controller_->RequestProbe(); probe_controller_->RequestProbe(NowMs());
} }
TEST_F(ProbeControllerTest, RequestProbeWhenAlrEndedRecently) { TEST_F(ProbeControllerTest, RequestProbeWhenAlrEndedRecently) {
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(2); EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(2);
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps, probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
kMaxBitrateBps); kMaxBitrateBps, NowMs());
probe_controller_->SetEstimatedBitrate(500); probe_controller_->SetEstimatedBitrate(500, NowMs());
testing::Mock::VerifyAndClearExpectations(&pacer_); testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
EXPECT_CALL(pacer_, CreateProbeCluster(0.85 * 500)).Times(1); EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(DataRateEqBps(0.85 * 500)))
EXPECT_CALL(pacer_, GetApplicationLimitedRegionStartTime()) .Times(1);
.WillRepeatedly(Return(rtc::nullopt)); probe_controller_->SetAlrStartTimeMs(rtc::nullopt);
clock_.AdvanceTimeMilliseconds(kAlrProbeInterval + 1); clock_.AdvanceTimeMilliseconds(kAlrProbeInterval + 1);
probe_controller_->Process(); probe_controller_->Process(NowMs());
probe_controller_->SetEstimatedBitrate(250); probe_controller_->SetEstimatedBitrate(250, NowMs());
probe_controller_->SetAlrEndedTimeMs(clock_.TimeInMilliseconds()); probe_controller_->SetAlrEndedTimeMs(clock_.TimeInMilliseconds());
clock_.AdvanceTimeMilliseconds(kAlrEndedTimeoutMs - 1); clock_.AdvanceTimeMilliseconds(kAlrEndedTimeoutMs - 1);
probe_controller_->RequestProbe(); probe_controller_->RequestProbe(NowMs());
} }
TEST_F(ProbeControllerTest, RequestProbeWhenAlrNotEndedRecently) { TEST_F(ProbeControllerTest, RequestProbeWhenAlrNotEndedRecently) {
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(2); EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(2);
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps, probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
kMaxBitrateBps); kMaxBitrateBps, NowMs());
probe_controller_->SetEstimatedBitrate(500); probe_controller_->SetEstimatedBitrate(500, NowMs());
testing::Mock::VerifyAndClearExpectations(&pacer_); testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(0); EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(0);
EXPECT_CALL(pacer_, GetApplicationLimitedRegionStartTime()) probe_controller_->SetAlrStartTimeMs(rtc::nullopt);
.WillRepeatedly(Return(rtc::nullopt));
clock_.AdvanceTimeMilliseconds(kAlrProbeInterval + 1); clock_.AdvanceTimeMilliseconds(kAlrProbeInterval + 1);
probe_controller_->Process(); probe_controller_->Process(NowMs());
probe_controller_->SetEstimatedBitrate(250); probe_controller_->SetEstimatedBitrate(250, NowMs());
probe_controller_->SetAlrEndedTimeMs(clock_.TimeInMilliseconds()); probe_controller_->SetAlrEndedTimeMs(clock_.TimeInMilliseconds());
clock_.AdvanceTimeMilliseconds(kAlrEndedTimeoutMs + 1); clock_.AdvanceTimeMilliseconds(kAlrEndedTimeoutMs + 1);
probe_controller_->RequestProbe(); probe_controller_->RequestProbe(NowMs());
} }
TEST_F(ProbeControllerTest, RequestProbeWhenBweDropNotRecent) { TEST_F(ProbeControllerTest, RequestProbeWhenBweDropNotRecent) {
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(2); EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(2);
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps, probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
kMaxBitrateBps); kMaxBitrateBps, NowMs());
probe_controller_->SetEstimatedBitrate(500); probe_controller_->SetEstimatedBitrate(500, NowMs());
testing::Mock::VerifyAndClearExpectations(&pacer_); testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(0); EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(0);
EXPECT_CALL(pacer_, GetApplicationLimitedRegionStartTime()) probe_controller_->SetAlrStartTimeMs(clock_.TimeInMilliseconds());
.WillRepeatedly(Return(clock_.TimeInMilliseconds()));
clock_.AdvanceTimeMilliseconds(kAlrProbeInterval + 1); clock_.AdvanceTimeMilliseconds(kAlrProbeInterval + 1);
probe_controller_->Process(); probe_controller_->Process(NowMs());
probe_controller_->SetEstimatedBitrate(250); probe_controller_->SetEstimatedBitrate(250, NowMs());
clock_.AdvanceTimeMilliseconds(kBitrateDropTimeoutMs + 1); clock_.AdvanceTimeMilliseconds(kBitrateDropTimeoutMs + 1);
probe_controller_->RequestProbe(); probe_controller_->RequestProbe(NowMs());
} }
TEST_F(ProbeControllerTest, PeriodicProbing) { TEST_F(ProbeControllerTest, PeriodicProbing) {
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(2); EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(2);
probe_controller_->EnablePeriodicAlrProbing(true); probe_controller_->EnablePeriodicAlrProbing(true);
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps, probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
kMaxBitrateBps); kMaxBitrateBps, NowMs());
probe_controller_->SetEstimatedBitrate(500); probe_controller_->SetEstimatedBitrate(500, NowMs());
testing::Mock::VerifyAndClearExpectations(&pacer_); testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
int64_t start_time = clock_.TimeInMilliseconds(); int64_t start_time = clock_.TimeInMilliseconds();
// Expect the controller to send a new probe after 5s has passed. // Expect the controller to send a new probe after 5s has passed.
EXPECT_CALL(pacer_, CreateProbeCluster(1000)).Times(1); EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(DataRateEqBps(1000)))
EXPECT_CALL(pacer_, GetApplicationLimitedRegionStartTime()) .Times(1);
.WillRepeatedly(Return(start_time)); probe_controller_->SetAlrStartTimeMs(start_time);
clock_.AdvanceTimeMilliseconds(5000); clock_.AdvanceTimeMilliseconds(5000);
probe_controller_->Process(); probe_controller_->Process(NowMs());
probe_controller_->SetEstimatedBitrate(500); probe_controller_->SetEstimatedBitrate(500, NowMs());
testing::Mock::VerifyAndClearExpectations(&pacer_); testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
// The following probe should be sent at 10s into ALR. // The following probe should be sent at 10s into ALR.
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(0); EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(0);
EXPECT_CALL(pacer_, GetApplicationLimitedRegionStartTime()) probe_controller_->SetAlrStartTimeMs(start_time);
.WillRepeatedly(Return(start_time));
clock_.AdvanceTimeMilliseconds(4000); clock_.AdvanceTimeMilliseconds(4000);
probe_controller_->Process(); probe_controller_->Process(NowMs());
probe_controller_->SetEstimatedBitrate(500); probe_controller_->SetEstimatedBitrate(500, NowMs());
testing::Mock::VerifyAndClearExpectations(&pacer_); testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(1); EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(1);
EXPECT_CALL(pacer_, GetApplicationLimitedRegionStartTime()) probe_controller_->SetAlrStartTimeMs(start_time);
.WillRepeatedly(Return(start_time));
clock_.AdvanceTimeMilliseconds(1000); clock_.AdvanceTimeMilliseconds(1000);
probe_controller_->Process(); probe_controller_->Process(NowMs());
probe_controller_->SetEstimatedBitrate(500); probe_controller_->SetEstimatedBitrate(500, NowMs());
testing::Mock::VerifyAndClearExpectations(&pacer_); testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
} }
TEST_F(ProbeControllerTest, PeriodicProbingAfterReset) { TEST_F(ProbeControllerTest, PeriodicProbingAfterReset) {
testing::StrictMock<MockPacedSender> local_pacer; NiceMock<MockNetworkControllerObserver> local_handler;
probe_controller_.reset(new ProbeController(&local_pacer, &clock_)); probe_controller_.reset(new ProbeController(&local_handler));
int64_t alr_start_time = clock_.TimeInMilliseconds(); int64_t alr_start_time = clock_.TimeInMilliseconds();
EXPECT_CALL(local_pacer, GetApplicationLimitedRegionStartTime())
.WillRepeatedly(Return(alr_start_time));
EXPECT_CALL(local_pacer, CreateProbeCluster(_)).Times(2); probe_controller_->SetAlrStartTimeMs(alr_start_time);
EXPECT_CALL(local_handler, OnProbeClusterConfig(_)).Times(2);
probe_controller_->EnablePeriodicAlrProbing(true); probe_controller_->EnablePeriodicAlrProbing(true);
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps, probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
kMaxBitrateBps); kMaxBitrateBps, NowMs());
probe_controller_->Reset(); probe_controller_->Reset(NowMs());
clock_.AdvanceTimeMilliseconds(10000); clock_.AdvanceTimeMilliseconds(10000);
probe_controller_->Process(); probe_controller_->Process(NowMs());
EXPECT_CALL(local_pacer, CreateProbeCluster(_)).Times(2); EXPECT_CALL(local_handler, OnProbeClusterConfig(_)).Times(2);
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps, probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
kMaxBitrateBps); kMaxBitrateBps, NowMs());
// Make sure we use |kStartBitrateBps| as the estimated bitrate // Make sure we use |kStartBitrateBps| as the estimated bitrate
// until SetEstimatedBitrate is called with an updated estimate. // until SetEstimatedBitrate is called with an updated estimate.
clock_.AdvanceTimeMilliseconds(10000); clock_.AdvanceTimeMilliseconds(10000);
EXPECT_CALL(local_pacer, CreateProbeCluster(kStartBitrateBps*2)); EXPECT_CALL(local_handler,
probe_controller_->Process(); OnProbeClusterConfig(DataRateEqBps(kStartBitrateBps * 2)));
probe_controller_->Process(NowMs());
} }
TEST_F(ProbeControllerTest, TestExponentialProbingOverflow) { TEST_F(ProbeControllerTest, TestExponentialProbingOverflow) {
const int64_t kMbpsMultiplier = 1000000; const int64_t kMbpsMultiplier = 1000000;
probe_controller_->SetBitrates(kMinBitrateBps, 10 * kMbpsMultiplier, probe_controller_->SetBitrates(kMinBitrateBps, 10 * kMbpsMultiplier,
100 * kMbpsMultiplier); 100 * kMbpsMultiplier, NowMs());
// Verify that probe bitrate is capped at the specified max bitrate // Verify that probe bitrate is capped at the specified max bitrate.
EXPECT_CALL(pacer_, CreateProbeCluster(100 * kMbpsMultiplier)); EXPECT_CALL(cluster_handler_,
probe_controller_->SetEstimatedBitrate(60 * kMbpsMultiplier); OnProbeClusterConfig(DataRateEqBps(100 * kMbpsMultiplier)));
testing::Mock::VerifyAndClearExpectations(&pacer_); probe_controller_->SetEstimatedBitrate(60 * kMbpsMultiplier, NowMs());
testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
// Verify that repeated probes aren't sent. // Verify that repeated probes aren't sent.
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(0); EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(0);
probe_controller_->SetEstimatedBitrate(100 * kMbpsMultiplier); probe_controller_->SetEstimatedBitrate(100 * kMbpsMultiplier, NowMs());
} }
} // namespace test } // namespace test

View file

@ -11,141 +11,330 @@
#include "modules/congestion_controller/include/send_side_congestion_controller.h" #include "modules/congestion_controller/include/send_side_congestion_controller.h"
#include <algorithm> #include <algorithm>
#include <cstdio> #include <functional>
#include <memory> #include <memory>
#include <vector> #include <vector>
#include "modules/congestion_controller/include/goog_cc_factory.h"
#include "modules/bitrate_controller/include/bitrate_controller.h" #include "modules/congestion_controller/network_control/include/network_types.h"
#include "modules/congestion_controller/acknowledged_bitrate_estimator.h" #include "modules/congestion_controller/network_control/include/network_units.h"
#include "modules/congestion_controller/probe_controller.h"
#include "modules/pacing/alr_detector.h"
#include "modules/remote_bitrate_estimator/include/bwe_defines.h" #include "modules/remote_bitrate_estimator/include/bwe_defines.h"
#include "rtc_base/checks.h" #include "rtc_base/checks.h"
#include "rtc_base/format_macros.h" #include "rtc_base/format_macros.h"
#include "rtc_base/logging.h" #include "rtc_base/logging.h"
#include "rtc_base/numerics/safe_conversions.h" #include "rtc_base/numerics/safe_conversions.h"
#include "rtc_base/numerics/safe_minmax.h"
#include "rtc_base/ptr_util.h" #include "rtc_base/ptr_util.h"
#include "rtc_base/rate_limiter.h" #include "rtc_base/rate_limiter.h"
#include "rtc_base/sequenced_task_checker.h"
#include "rtc_base/socket.h" #include "rtc_base/socket.h"
#include "rtc_base/timeutils.h" #include "rtc_base/timeutils.h"
#include "system_wrappers/include/field_trial.h" #include "system_wrappers/include/field_trial.h"
#include "system_wrappers/include/runtime_enabled_features.h" #include "system_wrappers/include/runtime_enabled_features.h"
using rtc::MakeUnique;
namespace webrtc { namespace webrtc {
namespace { namespace {
const char kCwndExperiment[] = "WebRTC-CwndExperiment";
const char kPacerPushbackExperiment[] = "WebRTC-PacerPushbackExperiment";
const int64_t kDefaultAcceptedQueueMs = 250;
bool CwndExperimentEnabled() {
std::string experiment_string =
webrtc::field_trial::FindFullName(kCwndExperiment);
// The experiment is enabled iff the field trial string begins with "Enabled".
return experiment_string.find("Enabled") == 0;
}
bool ReadCwndExperimentParameter(int64_t* accepted_queue_ms) {
RTC_DCHECK(accepted_queue_ms);
std::string experiment_string =
webrtc::field_trial::FindFullName(kCwndExperiment);
int parsed_values =
sscanf(experiment_string.c_str(), "Enabled-%" PRId64, accepted_queue_ms);
if (parsed_values == 1) {
RTC_CHECK_GE(*accepted_queue_ms, 0)
<< "Accepted must be greater than or equal to 0.";
return true;
}
return false;
}
static const int64_t kRetransmitWindowSizeMs = 500; static const int64_t kRetransmitWindowSizeMs = 500;
// Makes sure that the bitrate and the min, max values are in valid range. const char kPacerPushbackExperiment[] = "WebRTC-PacerPushbackExperiment";
static void ClampBitrates(int* bitrate_bps,
int* min_bitrate_bps, bool IsPacerPushbackExperimentEnabled() {
int* max_bitrate_bps) { return webrtc::field_trial::IsEnabled(kPacerPushbackExperiment) ||
// TODO(holmer): We should make sure the default bitrates are set to 10 kbps, (!webrtc::field_trial::IsDisabled(kPacerPushbackExperiment) &&
// and that we don't try to set the min bitrate to 0 from any applications. webrtc::runtime_enabled_features::IsFeatureEnabled(
// The congestion controller should allow a min bitrate of 0. webrtc::runtime_enabled_features::kDualStreamModeFeatureName));
if (*min_bitrate_bps < congestion_controller::GetMinBitrateBps())
*min_bitrate_bps = congestion_controller::GetMinBitrateBps();
if (*max_bitrate_bps > 0)
*max_bitrate_bps = std::max(*min_bitrate_bps, *max_bitrate_bps);
if (*bitrate_bps > 0)
*bitrate_bps = std::max(*min_bitrate_bps, *bitrate_bps);
} }
std::vector<webrtc::PacketFeedback> ReceivedPacketFeedbackVector( NetworkControllerFactoryInterface::uptr ControllerFactory(
const std::vector<webrtc::PacketFeedback>& input) { RtcEventLog* event_log) {
std::vector<PacketFeedback> received_packet_feedback_vector; return rtc::MakeUnique<GoogCcNetworkControllerFactory>(event_log);
auto is_received = [](const webrtc::PacketFeedback& packet_feedback) {
return packet_feedback.arrival_time_ms !=
webrtc::PacketFeedback::kNotReceived;
};
std::copy_if(input.begin(), input.end(),
std::back_inserter(received_packet_feedback_vector),
is_received);
return received_packet_feedback_vector;
} }
void SortPacketFeedbackVector( void SortPacketFeedbackVector(std::vector<webrtc::PacketFeedback>* input) {
std::vector<webrtc::PacketFeedback>* const input) {
RTC_DCHECK(input);
std::sort(input->begin(), input->end(), PacketFeedbackComparator()); std::sort(input->begin(), input->end(), PacketFeedbackComparator());
} }
bool IsPacerPushbackExperimentEnabled() { PacketResult NetworkPacketFeedbackFromRtpPacketFeedback(
return webrtc::field_trial::IsEnabled(kPacerPushbackExperiment) || ( const webrtc::PacketFeedback& pf) {
!webrtc::field_trial::IsDisabled(kPacerPushbackExperiment) && PacketResult feedback;
webrtc::runtime_enabled_features::IsFeatureEnabled( if (pf.arrival_time_ms == webrtc::PacketFeedback::kNotReceived)
webrtc::runtime_enabled_features::kDualStreamModeFeatureName)); feedback.receive_time = Timestamp::Infinity();
else
feedback.receive_time = Timestamp::ms(pf.arrival_time_ms);
if (pf.send_time_ms != webrtc::PacketFeedback::kNoSendTime) {
feedback.sent_packet = SentPacket();
feedback.sent_packet->send_time = Timestamp::ms(pf.send_time_ms);
feedback.sent_packet->size = DataSize::bytes(pf.payload_size);
feedback.sent_packet->pacing_info = pf.pacing_info;
}
return feedback;
} }
std::vector<PacketResult> PacketResultsFromRtpFeedbackVector(
const std::vector<PacketFeedback>& feedback_vector) {
RTC_DCHECK(std::is_sorted(feedback_vector.begin(), feedback_vector.end(),
PacketFeedbackComparator()));
std::vector<PacketResult> packet_feedbacks;
packet_feedbacks.reserve(feedback_vector.size());
for (const PacketFeedback& rtp_feedback : feedback_vector) {
auto feedback = NetworkPacketFeedbackFromRtpPacketFeedback(rtp_feedback);
packet_feedbacks.push_back(feedback);
}
return packet_feedbacks;
}
TargetRateConstraints ConvertConstraints(int min_bitrate_bps,
int max_bitrate_bps,
int start_bitrate_bps,
const Clock* clock) {
TargetRateConstraints msg;
msg.at_time = Timestamp::ms(clock->TimeInMilliseconds());
msg.min_data_rate =
min_bitrate_bps >= 0 ? DataRate::bps(min_bitrate_bps) : DataRate::Zero();
msg.starting_rate = start_bitrate_bps > 0 ? DataRate::bps(start_bitrate_bps)
: DataRate::kNotInitialized;
msg.max_data_rate = max_bitrate_bps > 0 ? DataRate::bps(max_bitrate_bps)
: DataRate::Infinity();
return msg;
}
} // namespace } // namespace
namespace send_side_cc_internal {
class ControlHandler : public NetworkControllerObserver {
public:
ControlHandler(PacerController* pacer_controller, const Clock* clock);
void OnCongestionWindow(CongestionWindow window) override;
void OnPacerConfig(PacerConfig config) override;
void OnProbeClusterConfig(ProbeClusterConfig config) override;
void OnTargetTransferRate(TargetTransferRate target_rate) override;
void OnNetworkAvailability(NetworkAvailability msg);
void OnPacerQueueUpdate(PacerQueueUpdate msg);
void RegisterNetworkObserver(
SendSideCongestionController::Observer* observer);
void DeRegisterNetworkObserver(
SendSideCongestionController::Observer* observer);
rtc::Optional<TargetTransferRate> last_transfer_rate();
bool pacer_configured();
RateLimiter* retransmission_rate_limiter();
private:
void OnNetworkInvalidation();
bool GetNetworkParameters(int32_t* estimated_bitrate_bps,
uint8_t* fraction_loss,
int64_t* rtt_ms);
bool IsSendQueueFull() const;
bool HasNetworkParametersToReportChanged(int64_t bitrate_bps,
uint8_t fraction_loss,
int64_t rtt);
PacerController* pacer_controller_;
RateLimiter retransmission_rate_limiter_;
rtc::CriticalSection state_lock_;
rtc::Optional<TargetTransferRate> last_target_rate_
RTC_GUARDED_BY(state_lock_);
bool pacer_configured_ RTC_GUARDED_BY(state_lock_) = false;
SendSideCongestionController::Observer* observer_ = nullptr;
rtc::Optional<TargetTransferRate> current_target_rate_msg_;
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;
int64_t pacer_expected_queue_ms_ = 0;
float encoding_rate_ratio_ = 1.0;
rtc::SequencedTaskChecker sequenced_checker_;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(ControlHandler);
};
ControlHandler::ControlHandler(PacerController* pacer_controller,
const Clock* clock)
: pacer_controller_(pacer_controller),
retransmission_rate_limiter_(clock, kRetransmitWindowSizeMs),
pacer_pushback_experiment_(IsPacerPushbackExperimentEnabled()) {
sequenced_checker_.Detach();
}
void ControlHandler::OnCongestionWindow(CongestionWindow window) {
RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
pacer_controller_->OnCongestionWindow(window);
}
void ControlHandler::OnPacerConfig(PacerConfig config) {
RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
pacer_controller_->OnPacerConfig(config);
rtc::CritScope cs(&state_lock_);
pacer_configured_ = true;
}
void ControlHandler::OnProbeClusterConfig(ProbeClusterConfig config) {
RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
pacer_controller_->OnProbeClusterConfig(config);
}
void ControlHandler::OnTargetTransferRate(TargetTransferRate target_rate) {
RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
retransmission_rate_limiter_.SetMaxRate(
target_rate.network_estimate.bandwidth.bps());
current_target_rate_msg_ = target_rate;
OnNetworkInvalidation();
rtc::CritScope cs(&state_lock_);
last_target_rate_ = target_rate;
}
void ControlHandler::OnNetworkAvailability(NetworkAvailability msg) {
RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
network_available_ = msg.network_available;
OnNetworkInvalidation();
}
void ControlHandler::OnPacerQueueUpdate(PacerQueueUpdate msg) {
RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
pacer_expected_queue_ms_ = msg.expected_queue_time.ms();
OnNetworkInvalidation();
}
void ControlHandler::RegisterNetworkObserver(
SendSideCongestionController::Observer* observer) {
RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
RTC_DCHECK(observer_ == nullptr);
observer_ = observer;
}
void ControlHandler::DeRegisterNetworkObserver(
SendSideCongestionController::Observer* observer) {
RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
RTC_DCHECK_EQ(observer_, observer);
observer_ = nullptr;
}
void ControlHandler::OnNetworkInvalidation() {
if (!current_target_rate_msg_.has_value())
return;
uint32_t target_bitrate_bps = current_target_rate_msg_->target_rate.bps();
int64_t rtt_ms =
current_target_rate_msg_->network_estimate.round_trip_time.ms();
float loss_rate_ratio =
current_target_rate_msg_->network_estimate.loss_rate_ratio;
int loss_ratio_255 = loss_rate_ratio * 255;
uint8_t fraction_loss =
rtc::dchecked_cast<uint8_t>(rtc::SafeClamp(loss_ratio_255, 0, 255));
int64_t probing_interval_ms =
current_target_rate_msg_->network_estimate.bwe_period.ms();
if (!network_available_) {
target_bitrate_bps = 0;
} else if (!pacer_pushback_experiment_) {
target_bitrate_bps = IsSendQueueFull() ? 0 : target_bitrate_bps;
} else {
int64_t queue_length_ms = pacer_expected_queue_ms_;
if (queue_length_ms == 0) {
encoding_rate_ratio_ = 1.0;
} else if (queue_length_ms > 50) {
float encoding_ratio = 1.0 - queue_length_ms / 1000.0;
encoding_rate_ratio_ = std::min(encoding_rate_ratio_, encoding_ratio);
encoding_rate_ratio_ = std::max(encoding_rate_ratio_, 0.0f);
}
target_bitrate_bps *= encoding_rate_ratio_;
target_bitrate_bps = target_bitrate_bps < 50000 ? 0 : target_bitrate_bps;
}
if (HasNetworkParametersToReportChanged(target_bitrate_bps, fraction_loss,
rtt_ms)) {
if (observer_) {
observer_->OnNetworkChanged(target_bitrate_bps, fraction_loss, rtt_ms,
probing_interval_ms);
}
}
}
bool ControlHandler::HasNetworkParametersToReportChanged(
int64_t target_bitrate_bps,
uint8_t fraction_loss,
int64_t rtt_ms) {
bool changed = last_reported_target_bitrate_bps_ != target_bitrate_bps ||
(target_bitrate_bps > 0 &&
(last_reported_fraction_loss_ != fraction_loss ||
last_reported_rtt_ms_ != rtt_ms));
if (changed &&
(last_reported_target_bitrate_bps_ == 0 || target_bitrate_bps == 0)) {
RTC_LOG(LS_INFO) << "Bitrate estimate state changed, BWE: "
<< target_bitrate_bps << " bps.";
}
last_reported_target_bitrate_bps_ = target_bitrate_bps;
last_reported_fraction_loss_ = fraction_loss;
last_reported_rtt_ms_ = rtt_ms;
return changed;
}
bool ControlHandler::IsSendQueueFull() const {
return pacer_expected_queue_ms_ > PacedSender::kMaxQueueLengthMs;
}
rtc::Optional<TargetTransferRate> ControlHandler::last_transfer_rate() {
rtc::CritScope cs(&state_lock_);
return last_target_rate_;
}
bool ControlHandler::pacer_configured() {
rtc::CritScope cs(&state_lock_);
return pacer_configured_;
}
RateLimiter* ControlHandler::retransmission_rate_limiter() {
return &retransmission_rate_limiter_;
}
} // namespace send_side_cc_internal
SendSideCongestionController::SendSideCongestionController( SendSideCongestionController::SendSideCongestionController(
const Clock* clock, const Clock* clock,
Observer* observer, Observer* observer,
RtcEventLog* event_log, RtcEventLog* event_log,
PacedSender* pacer) PacedSender* pacer)
: SendSideCongestionController(clock,
event_log,
pacer,
ControllerFactory(event_log)) {
if (observer != nullptr)
RegisterNetworkObserver(observer);
}
SendSideCongestionController::SendSideCongestionController(
const Clock* clock,
RtcEventLog* event_log,
PacedSender* pacer,
NetworkControllerFactoryInterface::uptr controller_factory)
: clock_(clock), : clock_(clock),
observer_(observer),
event_log_(event_log),
pacer_(pacer), pacer_(pacer),
bitrate_controller_(
BitrateController::CreateBitrateController(clock_, event_log)),
acknowledged_bitrate_estimator_(
rtc::MakeUnique<AcknowledgedBitrateEstimator>()),
probe_controller_(new ProbeController(pacer_, clock_)),
retransmission_rate_limiter_(
new RateLimiter(clock, kRetransmitWindowSizeMs)),
transport_feedback_adapter_(clock_), transport_feedback_adapter_(clock_),
last_reported_bitrate_bps_(0), pacer_controller_(MakeUnique<PacerController>(pacer_)),
last_reported_fraction_loss_(0), control_handler(MakeUnique<send_side_cc_internal::ControlHandler>(
last_reported_rtt_(0), pacer_controller_.get(),
network_state_(kNetworkUp), clock_)),
pause_pacer_(false), controller_(controller_factory->Create(control_handler.get())),
pacer_paused_(false), process_interval_(controller_factory->GetProcessInterval()),
min_bitrate_bps_(congestion_controller::GetMinBitrateBps()),
delay_based_bwe_(new DelayBasedBwe(event_log_, clock_)),
in_cwnd_experiment_(CwndExperimentEnabled()),
accepted_queue_ms_(kDefaultAcceptedQueueMs),
was_in_alr_(false),
send_side_bwe_with_overhead_( send_side_bwe_with_overhead_(
webrtc::field_trial::IsEnabled("WebRTC-SendSideBwe-WithOverhead")), webrtc::field_trial::IsEnabled("WebRTC-SendSideBwe-WithOverhead")),
transport_overhead_bytes_per_packet_(0), transport_overhead_bytes_per_packet_(0),
pacer_pushback_experiment_(IsPacerPushbackExperimentEnabled()) { network_available_(true),
delay_based_bwe_->SetMinBitrate(min_bitrate_bps_); task_queue_(MakeUnique<rtc::TaskQueue>("SendSideCCQueue")) {}
if (in_cwnd_experiment_ &&
!ReadCwndExperimentParameter(&accepted_queue_ms_)) {
RTC_LOG(LS_WARNING) << "Failed to parse parameters for CwndExperiment "
"from field trial string. Experiment disabled.";
in_cwnd_experiment_ = false;
}
}
SendSideCongestionController::~SendSideCongestionController() {} SendSideCongestionController::~SendSideCongestionController() {
// Must be destructed before any objects used by calls on the task queue.
task_queue_.reset();
}
void SendSideCongestionController::RegisterPacketFeedbackObserver( void SendSideCongestionController::RegisterPacketFeedbackObserver(
PacketFeedbackObserver* observer) { PacketFeedbackObserver* observer) {
@ -158,92 +347,84 @@ void SendSideCongestionController::DeRegisterPacketFeedbackObserver(
} }
void SendSideCongestionController::RegisterNetworkObserver(Observer* observer) { void SendSideCongestionController::RegisterNetworkObserver(Observer* observer) {
rtc::CritScope cs(&observer_lock_); WaitOnTask([this, observer]() {
RTC_DCHECK(observer_ == nullptr); control_handler->RegisterNetworkObserver(observer);
observer_ = observer; });
} }
void SendSideCongestionController::DeRegisterNetworkObserver( void SendSideCongestionController::DeRegisterNetworkObserver(
Observer* observer) { Observer* observer) {
rtc::CritScope cs(&observer_lock_); WaitOnTask([this, observer]() {
RTC_DCHECK_EQ(observer_, observer); control_handler->DeRegisterNetworkObserver(observer);
observer_ = nullptr; });
} }
void SendSideCongestionController::SetBweBitrates(int min_bitrate_bps, void SendSideCongestionController::SetBweBitrates(int min_bitrate_bps,
int start_bitrate_bps, int start_bitrate_bps,
int max_bitrate_bps) { int max_bitrate_bps) {
ClampBitrates(&start_bitrate_bps, &min_bitrate_bps, &max_bitrate_bps); TargetRateConstraints msg = ConvertConstraints(
bitrate_controller_->SetBitrates(start_bitrate_bps, min_bitrate_bps, min_bitrate_bps, max_bitrate_bps, start_bitrate_bps, clock_);
max_bitrate_bps); WaitOnTask([this, msg]() { controller_->OnTargetRateConstraints(msg); });
probe_controller_->SetBitrates(min_bitrate_bps, start_bitrate_bps,
max_bitrate_bps);
{
rtc::CritScope cs(&bwe_lock_);
if (start_bitrate_bps > 0)
delay_based_bwe_->SetStartBitrate(start_bitrate_bps);
min_bitrate_bps_ = min_bitrate_bps;
delay_based_bwe_->SetMinBitrate(min_bitrate_bps_);
}
MaybeTriggerOnNetworkChanged();
} }
// TODO(holmer): Split this up and use SetBweBitrates in combination with // TODO(holmer): Split this up and use SetBweBitrates in combination with
// OnNetworkRouteChanged. // OnNetworkRouteChanged.
void SendSideCongestionController::OnNetworkRouteChanged( void SendSideCongestionController::OnNetworkRouteChanged(
const rtc::NetworkRoute& network_route, const rtc::NetworkRoute& network_route,
int bitrate_bps, int start_bitrate_bps,
int min_bitrate_bps, int min_bitrate_bps,
int max_bitrate_bps) { int max_bitrate_bps) {
ClampBitrates(&bitrate_bps, &min_bitrate_bps, &max_bitrate_bps);
// TODO(honghaiz): Recreate this object once the bitrate controller is
// no longer exposed outside SendSideCongestionController.
bitrate_controller_->ResetBitrates(bitrate_bps, min_bitrate_bps,
max_bitrate_bps);
transport_feedback_adapter_.SetNetworkIds(network_route.local_network_id, transport_feedback_adapter_.SetNetworkIds(network_route.local_network_id,
network_route.remote_network_id); network_route.remote_network_id);
{
rtc::CritScope cs(&bwe_lock_);
min_bitrate_bps_ = min_bitrate_bps;
delay_based_bwe_.reset(new DelayBasedBwe(event_log_, clock_));
acknowledged_bitrate_estimator_.reset(new AcknowledgedBitrateEstimator());
delay_based_bwe_->SetStartBitrate(bitrate_bps);
delay_based_bwe_->SetMinBitrate(min_bitrate_bps);
}
probe_controller_->Reset(); NetworkRouteChange msg;
probe_controller_->SetBitrates(min_bitrate_bps, bitrate_bps, max_bitrate_bps); msg.at_time = Timestamp::ms(clock_->TimeInMilliseconds());
msg.constraints = ConvertConstraints(min_bitrate_bps, max_bitrate_bps,
MaybeTriggerOnNetworkChanged(); start_bitrate_bps, clock_);
} WaitOnTask([this, msg]() {
controller_->OnNetworkRouteChange(msg);
BitrateController* SendSideCongestionController::GetBitrateController() const { pacer_controller_->OnNetworkRouteChange(msg);
return bitrate_controller_.get(); });
} }
bool SendSideCongestionController::AvailableBandwidth( bool SendSideCongestionController::AvailableBandwidth(
uint32_t* bandwidth) const { uint32_t* bandwidth) const {
return bitrate_controller_->AvailableBandwidth(bandwidth); // TODO(srte): Remove this interface and push information about bandwidth
// estimation to users of this class, thereby reducing synchronous calls.
if (control_handler->last_transfer_rate().has_value()) {
*bandwidth =
control_handler->last_transfer_rate()->network_estimate.bandwidth.bps();
return true;
}
return false;
} }
RtcpBandwidthObserver* SendSideCongestionController::GetBandwidthObserver() RtcpBandwidthObserver* SendSideCongestionController::GetBandwidthObserver() {
const { return this;
return bitrate_controller_.get();
} }
RateLimiter* SendSideCongestionController::GetRetransmissionRateLimiter() { RateLimiter* SendSideCongestionController::GetRetransmissionRateLimiter() {
return retransmission_rate_limiter_.get(); return control_handler->retransmission_rate_limiter();
} }
void SendSideCongestionController::EnablePeriodicAlrProbing(bool enable) { void SendSideCongestionController::EnablePeriodicAlrProbing(bool enable) {
probe_controller_->EnablePeriodicAlrProbing(enable); WaitOnTask([this, enable]() {
streams_config_.requests_alr_probing = enable;
UpdateStreamsConfig();
});
}
void SendSideCongestionController::UpdateStreamsConfig() {
RTC_DCHECK(task_queue_->IsCurrent());
streams_config_.at_time = Timestamp::ms(clock_->TimeInMilliseconds());
controller_->OnStreamsConfig(streams_config_);
} }
int64_t SendSideCongestionController::GetPacerQueuingDelayMs() const { int64_t SendSideCongestionController::GetPacerQueuingDelayMs() const {
return IsNetworkDown() ? 0 : pacer_->QueueInMs(); // TODO(srte): This should be made less synchronous. Now it grabs a lock in
// the pacer just for stats usage. Some kind of push interface might make
// sense.
return network_available_ ? pacer_->QueueInMs() : 0;
} }
int64_t SendSideCongestionController::GetFirstPacketTimeMs() const { int64_t SendSideCongestionController::GetFirstPacketTimeMs() const {
@ -258,18 +439,19 @@ SendSideCongestionController::GetTransportFeedbackObserver() {
void SendSideCongestionController::SignalNetworkState(NetworkState state) { void SendSideCongestionController::SignalNetworkState(NetworkState state) {
RTC_LOG(LS_INFO) << "SignalNetworkState " RTC_LOG(LS_INFO) << "SignalNetworkState "
<< (state == kNetworkUp ? "Up" : "Down"); << (state == kNetworkUp ? "Up" : "Down");
{ NetworkAvailability msg;
rtc::CritScope cs(&network_state_lock_); msg.at_time = Timestamp::ms(clock_->TimeInMilliseconds());
pause_pacer_ = state == kNetworkDown; msg.network_available = state == kNetworkUp;
network_state_ = state; network_available_ = msg.network_available;
} WaitOnTask([this, msg]() {
probe_controller_->OnNetworkStateChanged(state); controller_->OnNetworkAvailability(msg);
MaybeTriggerOnNetworkChanged(); pacer_controller_->OnNetworkAvailability(msg);
control_handler->OnNetworkAvailability(msg);
});
} }
void SendSideCongestionController::SetTransportOverhead( void SendSideCongestionController::SetTransportOverhead(
size_t transport_overhead_bytes_per_packet) { size_t transport_overhead_bytes_per_packet) {
rtc::CritScope cs(&bwe_lock_);
transport_overhead_bytes_per_packet_ = transport_overhead_bytes_per_packet; transport_overhead_bytes_per_packet_ = transport_overhead_bytes_per_packet;
} }
@ -281,38 +463,52 @@ void SendSideCongestionController::OnSentPacket(
return; return;
transport_feedback_adapter_.OnSentPacket(sent_packet.packet_id, transport_feedback_adapter_.OnSentPacket(sent_packet.packet_id,
sent_packet.send_time_ms); sent_packet.send_time_ms);
if (in_cwnd_experiment_) MaybeUpdateOutstandingData();
LimitOutstandingBytes(transport_feedback_adapter_.GetOutstandingBytes()); auto packet = transport_feedback_adapter_.GetPacket(sent_packet.packet_id);
if (packet.has_value()) {
SentPacket msg;
msg.size = DataSize::bytes(packet->payload_size);
msg.send_time = Timestamp::ms(packet->send_time_ms);
task_queue_->PostTask([this, msg]() { controller_->OnSentPacket(msg); });
}
} }
void SendSideCongestionController::OnRttUpdate(int64_t avg_rtt_ms, void SendSideCongestionController::OnRttUpdate(int64_t avg_rtt_ms,
int64_t max_rtt_ms) { int64_t max_rtt_ms) {
rtc::CritScope cs(&bwe_lock_); int64_t now_ms = clock_->TimeInMilliseconds();
delay_based_bwe_->OnRttUpdate(avg_rtt_ms, max_rtt_ms); RoundTripTimeUpdate report;
report.receive_time = Timestamp::ms(now_ms);
report.round_trip_time = TimeDelta::ms(avg_rtt_ms);
report.smoothed = true;
task_queue_->PostTask(
[this, report]() { controller_->OnRoundTripTimeUpdate(report); });
} }
int64_t SendSideCongestionController::TimeUntilNextProcess() { int64_t SendSideCongestionController::TimeUntilNextProcess() {
return bitrate_controller_->TimeUntilNextProcess(); const int kMaxProcessInterval = 60 * 1000;
if (process_interval_.IsInfinite())
return kMaxProcessInterval;
int64_t next_process_ms = last_process_update_ms_ + process_interval_.ms();
int64_t time_until_next_process =
next_process_ms - clock_->TimeInMilliseconds();
return std::max<int64_t>(time_until_next_process, 0);
} }
void SendSideCongestionController::Process() { void SendSideCongestionController::Process() {
bool pause_pacer; int64_t now_ms = clock_->TimeInMilliseconds();
// TODO(holmer): Once this class is running on a task queue we should last_process_update_ms_ = now_ms;
// replace this with a task instead.
{ {
rtc::CritScope lock(&network_state_lock_); ProcessInterval msg;
pause_pacer = pause_pacer_; msg.at_time = Timestamp::ms(now_ms);
task_queue_->PostTask(
[this, msg]() { controller_->OnProcessInterval(msg); });
} }
if (pause_pacer && !pacer_paused_) { if (control_handler->pacer_configured()) {
pacer_->Pause(); PacerQueueUpdate msg;
pacer_paused_ = true; msg.expected_queue_time = TimeDelta::ms(pacer_->ExpectedQueueTimeMs());
} else if (!pause_pacer && pacer_paused_) { task_queue_->PostTask(
pacer_->Resume(); [this, msg]() { control_handler->OnPacerQueueUpdate(msg); });
pacer_paused_ = false;
} }
bitrate_controller_->Process();
probe_controller_->Process();
MaybeTriggerOnNetworkChanged();
} }
void SendSideCongestionController::AddPacket( void SendSideCongestionController::AddPacket(
@ -321,7 +517,6 @@ void SendSideCongestionController::AddPacket(
size_t length, size_t length,
const PacedPacketInfo& pacing_info) { const PacedPacketInfo& pacing_info) {
if (send_side_bwe_with_overhead_) { if (send_side_bwe_with_overhead_) {
rtc::CritScope cs(&bwe_lock_);
length += transport_overhead_bytes_per_packet_; length += transport_overhead_bytes_per_packet_;
} }
transport_feedback_adapter_.AddPacket(ssrc, sequence_number, length, transport_feedback_adapter_.AddPacket(ssrc, sequence_number, length,
@ -331,61 +526,35 @@ void SendSideCongestionController::AddPacket(
void SendSideCongestionController::OnTransportFeedback( void SendSideCongestionController::OnTransportFeedback(
const rtcp::TransportFeedback& feedback) { const rtcp::TransportFeedback& feedback) {
RTC_DCHECK_RUNS_SERIALIZED(&worker_race_); RTC_DCHECK_RUNS_SERIALIZED(&worker_race_);
int64_t feedback_time_ms = clock_->TimeInMilliseconds();
DataSize prior_in_flight =
DataSize::bytes(transport_feedback_adapter_.GetOutstandingBytes());
transport_feedback_adapter_.OnTransportFeedback(feedback); transport_feedback_adapter_.OnTransportFeedback(feedback);
std::vector<PacketFeedback> feedback_vector = ReceivedPacketFeedbackVector( MaybeUpdateOutstandingData();
transport_feedback_adapter_.GetTransportFeedbackVector());
std::vector<PacketFeedback> feedback_vector =
transport_feedback_adapter_.GetTransportFeedbackVector();
SortPacketFeedbackVector(&feedback_vector); SortPacketFeedbackVector(&feedback_vector);
bool currently_in_alr = if (!feedback_vector.empty()) {
pacer_->GetApplicationLimitedRegionStartTime().has_value(); TransportPacketsFeedback msg;
if (was_in_alr_ && !currently_in_alr) { msg.packet_feedbacks = PacketResultsFromRtpFeedbackVector(feedback_vector);
int64_t now_ms = rtc::TimeMillis(); msg.feedback_time = Timestamp::ms(feedback_time_ms);
acknowledged_bitrate_estimator_->SetAlrEndedTimeMs(now_ms); msg.prior_in_flight = prior_in_flight;
probe_controller_->SetAlrEndedTimeMs(now_ms); msg.data_in_flight =
DataSize::bytes(transport_feedback_adapter_.GetOutstandingBytes());
task_queue_->PostTask(
[this, msg]() { controller_->OnTransportPacketsFeedback(msg); });
} }
was_in_alr_ = currently_in_alr;
acknowledged_bitrate_estimator_->IncomingPacketFeedbackVector(
feedback_vector);
DelayBasedBwe::Result result;
{
rtc::CritScope cs(&bwe_lock_);
result = delay_based_bwe_->IncomingPacketFeedbackVector(
feedback_vector, acknowledged_bitrate_estimator_->bitrate_bps());
}
if (result.updated) {
bitrate_controller_->OnDelayBasedBweResult(result);
// Update the estimate in the ProbeController, in case we want to probe.
MaybeTriggerOnNetworkChanged();
}
if (result.recovered_from_overuse)
probe_controller_->RequestProbe();
if (in_cwnd_experiment_)
LimitOutstandingBytes(transport_feedback_adapter_.GetOutstandingBytes());
} }
void SendSideCongestionController::LimitOutstandingBytes( void SendSideCongestionController::MaybeUpdateOutstandingData() {
size_t num_outstanding_bytes) { OutstandingData msg;
RTC_DCHECK(in_cwnd_experiment_); msg.in_flight_data =
rtc::CritScope lock(&network_state_lock_); DataSize::bytes(transport_feedback_adapter_.GetOutstandingBytes());
rtc::Optional<int64_t> min_rtt_ms = task_queue_->PostTask(
transport_feedback_adapter_.GetMinFeedbackLoopRtt(); [this, msg]() { pacer_controller_->OnOutstandingData(msg); });
// No valid RTT. Could be because send-side BWE isn't used, in which case
// we don't try to limit the outstanding packets.
if (!min_rtt_ms)
return;
const size_t kMinCwndBytes = 2 * 1500;
size_t max_outstanding_bytes =
std::max<size_t>((*min_rtt_ms + accepted_queue_ms_) *
last_reported_bitrate_bps_ / 1000 / 8,
kMinCwndBytes);
RTC_LOG(LS_INFO) << clock_->TimeInMilliseconds()
<< " Outstanding bytes: " << num_outstanding_bytes
<< " pacer queue: " << pacer_->QueueInMs()
<< " 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;
} }
std::vector<PacketFeedback> std::vector<PacketFeedback>
@ -394,81 +563,99 @@ SendSideCongestionController::GetTransportFeedbackVector() const {
return transport_feedback_adapter_.GetTransportFeedbackVector(); return transport_feedback_adapter_.GetTransportFeedbackVector();
} }
void SendSideCongestionController::MaybeTriggerOnNetworkChanged() { void SendSideCongestionController::WaitOnTasks() {
uint32_t bitrate_bps; rtc::Event event(false, false);
uint8_t fraction_loss; task_queue_->PostTask([&event]() { event.Set(); });
int64_t rtt; event.Wait(rtc::Event::kForever);
bool estimate_changed = bitrate_controller_->GetNetworkParameters( }
&bitrate_bps, &fraction_loss, &rtt);
if (estimate_changed) {
pacer_->SetEstimatedBitrate(bitrate_bps);
probe_controller_->SetEstimatedBitrate(bitrate_bps);
retransmission_rate_limiter_->SetMaxRate(bitrate_bps);
}
if (!pacer_pushback_experiment_) { void SendSideCongestionController::WaitOnTask(std::function<void()> closure) {
bitrate_bps = IsNetworkDown() || IsSendQueueFull() ? 0 : bitrate_bps; rtc::Event done(false, false);
} else { task_queue_->PostTask(rtc::NewClosure(closure, [&done] { done.Set(); }));
if (IsNetworkDown()) { done.Wait(rtc::Event::kForever);
bitrate_bps = 0; }
} else {
int64_t queue_length_ms = pacer_->ExpectedQueueTimeMs();
if (queue_length_ms == 0) { void SendSideCongestionController::SetSendBitrateLimits(
encoding_rate_ = 1.0; int64_t min_send_bitrate_bps,
} else if (queue_length_ms > 50) { int64_t max_padding_bitrate_bps) {
float encoding_rate = 1.0 - queue_length_ms / 1000.0; WaitOnTask([this, min_send_bitrate_bps, max_padding_bitrate_bps]() {
encoding_rate_ = std::min(encoding_rate_, encoding_rate); streams_config_.min_pacing_rate = DataRate::bps(min_send_bitrate_bps);
encoding_rate_ = std::max(encoding_rate_, 0.0f); streams_config_.max_padding_rate = DataRate::bps(max_padding_bitrate_bps);
} UpdateStreamsConfig();
});
}
bitrate_bps *= encoding_rate_; void SendSideCongestionController::SetPacingFactor(float pacing_factor) {
bitrate_bps = bitrate_bps < 50000 ? 0 : bitrate_bps; WaitOnTask([this, pacing_factor]() {
streams_config_.pacing_factor = pacing_factor;
UpdateStreamsConfig();
});
}
void SendSideCongestionController::OnReceivedEstimatedBitrate(
uint32_t bitrate) {
RemoteBitrateReport msg;
msg.receive_time = Timestamp::ms(clock_->TimeInMilliseconds());
msg.bandwidth = DataRate::bps(bitrate);
task_queue_->PostTask(
[this, msg]() { controller_->OnRemoteBitrateReport(msg); });
}
void SendSideCongestionController::OnReceivedRtcpReceiverReport(
const webrtc::ReportBlockList& report_blocks,
int64_t rtt_ms,
int64_t now_ms) {
OnReceivedRtcpReceiverReportBlocks(report_blocks, now_ms);
RoundTripTimeUpdate report;
report.receive_time = Timestamp::ms(now_ms);
report.round_trip_time = TimeDelta::ms(rtt_ms);
report.smoothed = false;
task_queue_->PostTask(
[this, report]() { controller_->OnRoundTripTimeUpdate(report); });
}
void SendSideCongestionController::OnReceivedRtcpReceiverReportBlocks(
const ReportBlockList& report_blocks,
int64_t now_ms) {
if (report_blocks.empty())
return;
int total_packets_lost_delta = 0;
int total_packets_delta = 0;
// Compute the packet loss from all report blocks.
for (const RTCPReportBlock& report_block : report_blocks) {
auto it = last_report_blocks_.find(report_block.source_ssrc);
if (it != last_report_blocks_.end()) {
auto number_of_packets = report_block.extended_highest_sequence_number -
it->second.extended_highest_sequence_number;
total_packets_delta += number_of_packets;
auto lost_delta = report_block.packets_lost - it->second.packets_lost;
total_packets_lost_delta += lost_delta;
} }
last_report_blocks_[report_block.source_ssrc] = report_block;
} }
// Can only compute delta if there has been previous blocks to compare to. If
// not, total_packets_delta will be unchanged and there's nothing more to do.
if (!total_packets_delta)
return;
int packets_received_delta = total_packets_delta - total_packets_lost_delta;
// To detect lost packets, at least one packet has to be received. This check
// is needed to avoid bandwith detection update in
// VideoSendStreamTest.SuspendBelowMinBitrate
if (HasNetworkParametersToReportChanged(bitrate_bps, fraction_loss, rtt)) { if (packets_received_delta < 1)
int64_t probing_interval_ms; return;
{ Timestamp now = Timestamp::ms(now_ms);
rtc::CritScope cs(&bwe_lock_); TransportLossReport msg;
probing_interval_ms = delay_based_bwe_->GetExpectedBwePeriodMs(); msg.packets_lost_delta = total_packets_lost_delta;
} msg.packets_received_delta = packets_received_delta;
{ msg.receive_time = now;
rtc::CritScope cs(&observer_lock_); msg.start_time = last_report_block_time_;
if (observer_) { msg.end_time = now;
observer_->OnNetworkChanged(bitrate_bps, fraction_loss, rtt, task_queue_->PostTask(
probing_interval_ms); [this, msg]() { controller_->OnTransportLossReport(msg); });
} last_report_block_time_ = now;
}
}
} }
bool SendSideCongestionController::HasNetworkParametersToReportChanged(
uint32_t bitrate_bps,
uint8_t fraction_loss,
int64_t rtt) {
rtc::CritScope cs(&network_state_lock_);
bool changed =
last_reported_bitrate_bps_ != bitrate_bps ||
(bitrate_bps > 0 && (last_reported_fraction_loss_ != fraction_loss ||
last_reported_rtt_ != rtt));
if (changed && (last_reported_bitrate_bps_ == 0 || bitrate_bps == 0)) {
RTC_LOG(LS_INFO) << "Bitrate estimate state changed, BWE: " << bitrate_bps
<< " bps.";
}
last_reported_bitrate_bps_ = bitrate_bps;
last_reported_fraction_loss_ = fraction_loss;
last_reported_rtt_ = rtt;
return changed;
}
bool SendSideCongestionController::IsSendQueueFull() const {
return pacer_->ExpectedQueueTimeMs() > PacedSender::kMaxQueueLengthMs;
}
bool SendSideCongestionController::IsNetworkDown() const {
rtc::CritScope cs(&network_state_lock_);
return network_state_ == kNetworkDown;
}
} // namespace webrtc } // namespace webrtc

View file

@ -8,16 +8,16 @@
* 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 "modules/congestion_controller/include/send_side_congestion_controller.h"
#include "logging/rtc_event_log/mock/mock_rtc_event_log.h" #include "logging/rtc_event_log/mock/mock_rtc_event_log.h"
#include "modules/bitrate_controller/include/bitrate_controller.h"
#include "modules/congestion_controller/congestion_controller_unittests_helper.h" #include "modules/congestion_controller/congestion_controller_unittests_helper.h"
#include "modules/congestion_controller/include/mock/mock_congestion_observer.h" #include "modules/congestion_controller/include/mock/mock_congestion_observer.h"
#include "modules/congestion_controller/include/send_side_congestion_controller.h"
#include "modules/pacing/mock/mock_paced_sender.h" #include "modules/pacing/mock/mock_paced_sender.h"
#include "modules/pacing/packet_router.h" #include "modules/pacing/packet_router.h"
#include "modules/remote_bitrate_estimator/include/bwe_defines.h" #include "modules/remote_bitrate_estimator/include/bwe_defines.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h" #include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
#include "rtc_base/event.h"
#include "rtc_base/socket.h" #include "rtc_base/socket.h"
#include "system_wrappers/include/clock.h" #include "system_wrappers/include/clock.h"
#include "test/field_trial.h" #include "test/field_trial.h"
@ -33,16 +33,31 @@ using testing::SaveArg;
using testing::StrictMock; using testing::StrictMock;
namespace webrtc { namespace webrtc {
namespace test {
namespace { namespace {
const webrtc::PacedPacketInfo kPacingInfo0(0, 5, 2000); const webrtc::PacedPacketInfo kPacingInfo0(0, 5, 2000);
const webrtc::PacedPacketInfo kPacingInfo1(1, 8, 4000); const webrtc::PacedPacketInfo kPacingInfo1(1, 8, 4000);
const uint32_t kInitialBitrateBps = 60000; const uint32_t kInitialBitrateBps = 60000;
const float kDefaultPacingRate = 2.5f;
class SendSideCongestionControllerForTest
: public SendSideCongestionController {
public:
SendSideCongestionControllerForTest(const Clock* clock,
Observer* observer,
RtcEventLog* event_log,
PacedSender* pacer)
: SendSideCongestionController(clock, observer, event_log, pacer) {}
~SendSideCongestionControllerForTest() {}
void Process() override {
SendSideCongestionController::Process();
SendSideCongestionController::WaitOnTasks();
}
};
} // namespace } // namespace
namespace test {
class SendSideCongestionControllerTest : public ::testing::Test { class SendSideCongestionControllerTest : public ::testing::Test {
protected: protected:
@ -52,14 +67,15 @@ class SendSideCongestionControllerTest : public ::testing::Test {
void SetUp() override { void SetUp() override {
pacer_.reset(new NiceMock<MockPacedSender>()); pacer_.reset(new NiceMock<MockPacedSender>());
controller_.reset(new SendSideCongestionController( controller_.reset(new SendSideCongestionControllerForTest(
&clock_, &observer_, &event_log_, pacer_.get())); &clock_, &observer_, &event_log_, pacer_.get()));
bandwidth_observer_ = controller_->GetBandwidthObserver(); bandwidth_observer_ = controller_->GetBandwidthObserver();
// Set the initial bitrate estimate and expect the |observer| and |pacer_| // Set the initial bitrate estimate and expect the |observer| and |pacer_|
// to be updated. // to be updated.
EXPECT_CALL(observer_, OnNetworkChanged(kInitialBitrateBps, _, _, _)); EXPECT_CALL(observer_, OnNetworkChanged(kInitialBitrateBps, _, _, _));
EXPECT_CALL(*pacer_, SetEstimatedBitrate(kInitialBitrateBps)); EXPECT_CALL(*pacer_,
SetPacingRates(kInitialBitrateBps * kDefaultPacingRate, _));
EXPECT_CALL(*pacer_, CreateProbeCluster(kInitialBitrateBps * 3)); EXPECT_CALL(*pacer_, CreateProbeCluster(kInitialBitrateBps * 3));
EXPECT_CALL(*pacer_, CreateProbeCluster(kInitialBitrateBps * 5)); EXPECT_CALL(*pacer_, CreateProbeCluster(kInitialBitrateBps * 5));
controller_->SetBweBitrates(0, kInitialBitrateBps, 5 * kInitialBitrateBps); controller_->SetBweBitrates(0, kInitialBitrateBps, 5 * kInitialBitrateBps);
@ -68,8 +84,9 @@ class SendSideCongestionControllerTest : public ::testing::Test {
// Custom setup - use an observer that tracks the target bitrate, without // Custom setup - use an observer that tracks the target bitrate, without
// prescribing on which iterations it must change (like a mock would). // prescribing on which iterations it must change (like a mock would).
void TargetBitrateTrackingSetup() { void TargetBitrateTrackingSetup() {
bandwidth_observer_ = nullptr;
pacer_.reset(new NiceMock<MockPacedSender>()); pacer_.reset(new NiceMock<MockPacedSender>());
controller_.reset(new SendSideCongestionController( controller_.reset(new SendSideCongestionControllerForTest(
&clock_, &target_bitrate_observer_, &event_log_, pacer_.get())); &clock_, &target_bitrate_observer_, &event_log_, pacer_.get()));
controller_->SetBweBitrates(0, kInitialBitrateBps, 5 * kInitialBitrateBps); controller_->SetBweBitrates(0, kInitialBitrateBps, 5 * kInitialBitrateBps);
} }
@ -137,7 +154,7 @@ class SendSideCongestionControllerTest : public ::testing::Test {
RtcpBandwidthObserver* bandwidth_observer_; RtcpBandwidthObserver* bandwidth_observer_;
PacketRouter packet_router_; PacketRouter packet_router_;
std::unique_ptr<NiceMock<MockPacedSender>> pacer_; std::unique_ptr<NiceMock<MockPacedSender>> pacer_;
std::unique_ptr<SendSideCongestionController> controller_; std::unique_ptr<SendSideCongestionControllerForTest> controller_;
rtc::Optional<uint32_t> target_bitrate_bps_; rtc::Optional<uint32_t> target_bitrate_bps_;
}; };
@ -148,13 +165,15 @@ TEST_F(SendSideCongestionControllerTest, OnNetworkChanged) {
controller_->Process(); controller_->Process();
EXPECT_CALL(observer_, OnNetworkChanged(kInitialBitrateBps * 2, _, _, _)); EXPECT_CALL(observer_, OnNetworkChanged(kInitialBitrateBps * 2, _, _, _));
EXPECT_CALL(*pacer_, SetEstimatedBitrate(kInitialBitrateBps * 2)); EXPECT_CALL(*pacer_,
SetPacingRates(kInitialBitrateBps * 2 * kDefaultPacingRate, _));
bandwidth_observer_->OnReceivedEstimatedBitrate(kInitialBitrateBps * 2); bandwidth_observer_->OnReceivedEstimatedBitrate(kInitialBitrateBps * 2);
clock_.AdvanceTimeMilliseconds(25); clock_.AdvanceTimeMilliseconds(25);
controller_->Process(); controller_->Process();
EXPECT_CALL(observer_, OnNetworkChanged(kInitialBitrateBps, _, _, _)); EXPECT_CALL(observer_, OnNetworkChanged(kInitialBitrateBps, _, _, _));
EXPECT_CALL(*pacer_, SetEstimatedBitrate(kInitialBitrateBps)); EXPECT_CALL(*pacer_,
SetPacingRates(kInitialBitrateBps * kDefaultPacingRate, _));
bandwidth_observer_->OnReceivedEstimatedBitrate(kInitialBitrateBps); bandwidth_observer_->OnReceivedEstimatedBitrate(kInitialBitrateBps);
clock_.AdvanceTimeMilliseconds(25); clock_.AdvanceTimeMilliseconds(25);
controller_->Process(); controller_->Process();
@ -162,14 +181,14 @@ TEST_F(SendSideCongestionControllerTest, OnNetworkChanged) {
TEST_F(SendSideCongestionControllerTest, OnSendQueueFull) { TEST_F(SendSideCongestionControllerTest, OnSendQueueFull) {
EXPECT_CALL(*pacer_, ExpectedQueueTimeMs()) EXPECT_CALL(*pacer_, ExpectedQueueTimeMs())
.WillOnce(Return(PacedSender::kMaxQueueLengthMs + 1)); .WillRepeatedly(Return(PacedSender::kMaxQueueLengthMs + 1));
EXPECT_CALL(observer_, OnNetworkChanged(0, _, _, _)); EXPECT_CALL(observer_, OnNetworkChanged(0, _, _, _));
controller_->Process(); controller_->Process();
// Let the pacer not be full next time the controller checks. // Let the pacer not be full next time the controller checks.
EXPECT_CALL(*pacer_, ExpectedQueueTimeMs()) EXPECT_CALL(*pacer_, ExpectedQueueTimeMs())
.WillOnce(Return(PacedSender::kMaxQueueLengthMs - 1)); .WillRepeatedly(Return(PacedSender::kMaxQueueLengthMs - 1));
EXPECT_CALL(observer_, OnNetworkChanged(kInitialBitrateBps, _, _, _)); EXPECT_CALL(observer_, OnNetworkChanged(kInitialBitrateBps, _, _, _));
controller_->Process(); controller_->Process();
@ -177,23 +196,24 @@ TEST_F(SendSideCongestionControllerTest, OnSendQueueFull) {
TEST_F(SendSideCongestionControllerTest, OnSendQueueFullAndEstimateChange) { TEST_F(SendSideCongestionControllerTest, OnSendQueueFullAndEstimateChange) {
EXPECT_CALL(*pacer_, ExpectedQueueTimeMs()) EXPECT_CALL(*pacer_, ExpectedQueueTimeMs())
.WillOnce(Return(PacedSender::kMaxQueueLengthMs + 1)); .WillRepeatedly(Return(PacedSender::kMaxQueueLengthMs + 1));
EXPECT_CALL(observer_, OnNetworkChanged(0, _, _, _)); EXPECT_CALL(observer_, OnNetworkChanged(0, _, _, _));
controller_->Process(); controller_->Process();
// Receive new estimate but let the queue still be full. // Receive new estimate but let the queue still be full.
bandwidth_observer_->OnReceivedEstimatedBitrate(kInitialBitrateBps * 2); bandwidth_observer_->OnReceivedEstimatedBitrate(kInitialBitrateBps * 2);
EXPECT_CALL(*pacer_, ExpectedQueueTimeMs()) EXPECT_CALL(*pacer_, ExpectedQueueTimeMs())
.WillOnce(Return(PacedSender::kMaxQueueLengthMs + 1)); .WillRepeatedly(Return(PacedSender::kMaxQueueLengthMs + 1));
// The send pacer should get the new estimate though. // The send pacer should get the new estimate though.
EXPECT_CALL(*pacer_, SetEstimatedBitrate(kInitialBitrateBps * 2)); EXPECT_CALL(*pacer_,
SetPacingRates(kInitialBitrateBps * 2 * kDefaultPacingRate, _));
clock_.AdvanceTimeMilliseconds(25); clock_.AdvanceTimeMilliseconds(25);
controller_->Process(); controller_->Process();
// Let the pacer not be full next time the controller checks. // Let the pacer not be full next time the controller checks.
// |OnNetworkChanged| should be called with the new estimate. // |OnNetworkChanged| should be called with the new estimate.
EXPECT_CALL(*pacer_, ExpectedQueueTimeMs()) EXPECT_CALL(*pacer_, ExpectedQueueTimeMs())
.WillOnce(Return(PacedSender::kMaxQueueLengthMs - 1)); .WillRepeatedly(Return(PacedSender::kMaxQueueLengthMs - 1));
EXPECT_CALL(observer_, OnNetworkChanged(kInitialBitrateBps * 2, _, _, _)); EXPECT_CALL(observer_, OnNetworkChanged(kInitialBitrateBps * 2, _, _, _));
clock_.AdvanceTimeMilliseconds(25); clock_.AdvanceTimeMilliseconds(25);
controller_->Process(); controller_->Process();
@ -214,7 +234,7 @@ TEST_F(SendSideCongestionControllerTest, OnNetworkRouteChanged) {
int new_bitrate = 200000; int new_bitrate = 200000;
testing::Mock::VerifyAndClearExpectations(pacer_.get()); testing::Mock::VerifyAndClearExpectations(pacer_.get());
EXPECT_CALL(observer_, OnNetworkChanged(new_bitrate, _, _, _)); EXPECT_CALL(observer_, OnNetworkChanged(new_bitrate, _, _, _));
EXPECT_CALL(*pacer_, SetEstimatedBitrate(new_bitrate)); EXPECT_CALL(*pacer_, SetPacingRates(new_bitrate * kDefaultPacingRate, _));
rtc::NetworkRoute route; rtc::NetworkRoute route;
route.local_network_id = 1; route.local_network_id = 1;
controller_->OnNetworkRouteChanged(route, new_bitrate, -1, -1); controller_->OnNetworkRouteChanged(route, new_bitrate, -1, -1);
@ -224,8 +244,10 @@ TEST_F(SendSideCongestionControllerTest, OnNetworkRouteChanged) {
EXPECT_CALL( EXPECT_CALL(
observer_, observer_,
OnNetworkChanged(congestion_controller::GetMinBitrateBps(), _, _, _)); OnNetworkChanged(congestion_controller::GetMinBitrateBps(), _, _, _));
EXPECT_CALL(*pacer_, EXPECT_CALL(
SetEstimatedBitrate(congestion_controller::GetMinBitrateBps())); *pacer_,
SetPacingRates(
congestion_controller::GetMinBitrateBps() * kDefaultPacingRate, _));
route.local_network_id = 2; route.local_network_id = 2;
controller_->OnNetworkRouteChanged(route, -1, -1, -1); controller_->OnNetworkRouteChanged(route, -1, -1, -1);
} }
@ -234,7 +256,7 @@ TEST_F(SendSideCongestionControllerTest, OldFeedback) {
int new_bitrate = 200000; int new_bitrate = 200000;
testing::Mock::VerifyAndClearExpectations(pacer_.get()); testing::Mock::VerifyAndClearExpectations(pacer_.get());
EXPECT_CALL(observer_, OnNetworkChanged(new_bitrate, _, _, _)); EXPECT_CALL(observer_, OnNetworkChanged(new_bitrate, _, _, _));
EXPECT_CALL(*pacer_, SetEstimatedBitrate(new_bitrate)); EXPECT_CALL(*pacer_, SetPacingRates(new_bitrate * kDefaultPacingRate, _));
// Send a few packets on the first network route. // Send a few packets on the first network route.
std::vector<PacketFeedback> packets; std::vector<PacketFeedback> packets;
@ -267,15 +289,17 @@ TEST_F(SendSideCongestionControllerTest, OldFeedback) {
EXPECT_CALL( EXPECT_CALL(
observer_, observer_,
OnNetworkChanged(congestion_controller::GetMinBitrateBps(), _, _, _)); OnNetworkChanged(congestion_controller::GetMinBitrateBps(), _, _, _));
EXPECT_CALL(*pacer_, EXPECT_CALL(
SetEstimatedBitrate(congestion_controller::GetMinBitrateBps())); *pacer_,
SetPacingRates(
congestion_controller::GetMinBitrateBps() * kDefaultPacingRate, _));
route.local_network_id = 2; route.local_network_id = 2;
controller_->OnNetworkRouteChanged(route, -1, -1, -1); controller_->OnNetworkRouteChanged(route, -1, -1, -1);
} }
TEST_F(SendSideCongestionControllerTest, TEST_F(SendSideCongestionControllerTest,
SignalNetworkStateAndQueueIsFullAndEstimateChange) { SignalNetworkStateAndQueueIsFullAndEstimateChange) {
// Send queue is full // Send queue is full.
EXPECT_CALL(*pacer_, ExpectedQueueTimeMs()) EXPECT_CALL(*pacer_, ExpectedQueueTimeMs())
.WillRepeatedly(Return(PacedSender::kMaxQueueLengthMs + 1)); .WillRepeatedly(Return(PacedSender::kMaxQueueLengthMs + 1));
EXPECT_CALL(observer_, OnNetworkChanged(0, _, _, _)); EXPECT_CALL(observer_, OnNetworkChanged(0, _, _, _));
@ -290,14 +314,15 @@ TEST_F(SendSideCongestionControllerTest,
controller_->Process(); controller_->Process();
// Receive new estimate but let the queue still be full. // Receive new estimate but let the queue still be full.
EXPECT_CALL(*pacer_, SetEstimatedBitrate(kInitialBitrateBps * 2)); EXPECT_CALL(*pacer_,
SetPacingRates(kInitialBitrateBps * 2 * kDefaultPacingRate, _));
bandwidth_observer_->OnReceivedEstimatedBitrate(kInitialBitrateBps * 2); bandwidth_observer_->OnReceivedEstimatedBitrate(kInitialBitrateBps * 2);
clock_.AdvanceTimeMilliseconds(25); clock_.AdvanceTimeMilliseconds(25);
controller_->Process(); controller_->Process();
// Let the pacer not be full next time the controller checks. // Let the pacer not be full next time the controller checks.
EXPECT_CALL(*pacer_, ExpectedQueueTimeMs()) EXPECT_CALL(*pacer_, ExpectedQueueTimeMs())
.WillOnce(Return(PacedSender::kMaxQueueLengthMs - 1)); .WillRepeatedly(Return(PacedSender::kMaxQueueLengthMs - 1));
EXPECT_CALL(observer_, OnNetworkChanged(kInitialBitrateBps * 2, _, _, _)); EXPECT_CALL(observer_, OnNetworkChanged(kInitialBitrateBps * 2, _, _, _));
controller_->Process(); controller_->Process();
} }
@ -323,7 +348,7 @@ TEST_F(SendSideCongestionControllerTest, GetProbingInterval) {
controller_->Process(); controller_->Process();
EXPECT_CALL(observer_, OnNetworkChanged(_, _, _, testing::Ne(0))); EXPECT_CALL(observer_, OnNetworkChanged(_, _, _, testing::Ne(0)));
EXPECT_CALL(*pacer_, SetEstimatedBitrate(_)); EXPECT_CALL(*pacer_, SetPacingRates(_, _));
bandwidth_observer_->OnReceivedEstimatedBitrate(kInitialBitrateBps * 2); bandwidth_observer_->OnReceivedEstimatedBitrate(kInitialBitrateBps * 2);
clock_.AdvanceTimeMilliseconds(25); clock_.AdvanceTimeMilliseconds(25);
controller_->Process(); controller_->Process();

View file

@ -50,6 +50,17 @@ bool SendTimeHistory::OnSentPacket(uint16_t sequence_number,
return true; return true;
} }
rtc::Optional<PacketFeedback> SendTimeHistory::GetPacket(
uint16_t sequence_number) const {
int64_t unwrapped_seq_num =
seq_num_unwrapper_.UnwrapWithoutUpdate(sequence_number);
rtc::Optional<PacketFeedback> optional_feedback;
auto it = history_.find(unwrapped_seq_num);
if (it != history_.end())
optional_feedback.emplace(it->second);
return optional_feedback;
}
bool SendTimeHistory::GetFeedback(PacketFeedback* packet_feedback, bool SendTimeHistory::GetFeedback(PacketFeedback* packet_feedback,
bool remove) { bool remove) {
RTC_DCHECK(packet_feedback); RTC_DCHECK(packet_feedback);

View file

@ -33,6 +33,9 @@ class SendTimeHistory {
// Return false if not found. // Return false if not found.
bool OnSentPacket(uint16_t sequence_number, int64_t send_time_ms); bool OnSentPacket(uint16_t sequence_number, int64_t send_time_ms);
// Retrieves packet info identified by |sequence_number|.
rtc::Optional<PacketFeedback> GetPacket(uint16_t sequence_number) const;
// Look up PacketFeedback for a sent packet, based on the sequence number, and // Look up PacketFeedback for a sent packet, based on the sequence number, and
// populate all fields except for arrival_time. The packet parameter must // populate all fields except for arrival_time. The packet parameter must
// thus be non-null and have the sequence_number field set. // thus be non-null and have the sequence_number field set.

View file

@ -52,8 +52,7 @@ TEST_F(SendTimeHistoryTest, SaveAndRestoreNetworkId) {
uint16_t sequence_number = 0; uint16_t sequence_number = 0;
int64_t now_ms = clock_.TimeInMilliseconds(); int64_t now_ms = clock_.TimeInMilliseconds();
for (int i = 1; i < 5; ++i) { for (int i = 1; i < 5; ++i) {
PacketFeedback packet(now_ms, sequence_number, 1000, i, i - 1, PacketFeedback packet(now_ms, sequence_number, 1000, i, i - 1, kPacingInfo);
kPacingInfo);
history_.AddAndRemoveOld(packet); history_.AddAndRemoveOld(packet);
history_.OnSentPacket(sequence_number, now_ms); history_.OnSentPacket(sequence_number, now_ms);
PacketFeedback restored(now_ms, sequence_number); PacketFeedback restored(now_ms, sequence_number);
@ -82,6 +81,26 @@ TEST_F(SendTimeHistoryTest, AddRemoveOne) {
EXPECT_FALSE(history_.GetFeedback(&received_packet3, true)); EXPECT_FALSE(history_.GetFeedback(&received_packet3, true));
} }
TEST_F(SendTimeHistoryTest, GetPacketReturnsSentPacket) {
const uint16_t kSeqNo = 10;
const PacedPacketInfo kPacingInfo(0, 5, 1200);
const PacketFeedback kSentPacket(0, -1, 1, kSeqNo, 123, 0, 0, kPacingInfo);
AddPacketWithSendTime(kSeqNo, 123, 1, kPacingInfo);
auto sent_packet = history_.GetPacket(kSeqNo);
EXPECT_EQ(kSentPacket, *sent_packet);
}
TEST_F(SendTimeHistoryTest, GetPacketEmptyForRemovedPacket) {
const uint16_t kSeqNo = 10;
const PacedPacketInfo kPacingInfo(0, 5, 1200);
AddPacketWithSendTime(kSeqNo, 123, 1, kPacingInfo);
auto sent_packet = history_.GetPacket(kSeqNo);
PacketFeedback received_packet(0, 0, kSeqNo, 0, kPacingInfo);
EXPECT_TRUE(history_.GetFeedback(&received_packet, true));
sent_packet = history_.GetPacket(kSeqNo);
EXPECT_FALSE(sent_packet.has_value());
}
TEST_F(SendTimeHistoryTest, PopulatesExpectedFields) { TEST_F(SendTimeHistoryTest, PopulatesExpectedFields) {
const uint16_t kSeqNo = 10; const uint16_t kSeqNo = 10;
const int64_t kSendTime = 1000; const int64_t kSendTime = 1000;

View file

@ -82,6 +82,12 @@ void TransportFeedbackAdapter::OnSentPacket(uint16_t sequence_number,
send_time_history_.OnSentPacket(sequence_number, send_time_ms); send_time_history_.OnSentPacket(sequence_number, send_time_ms);
} }
rtc::Optional<PacketFeedback> TransportFeedbackAdapter::GetPacket(
uint16_t sequence_number) const {
rtc::CritScope cs(&lock_);
return send_time_history_.GetPacket(sequence_number);
}
void TransportFeedbackAdapter::SetNetworkIds(uint16_t local_id, void TransportFeedbackAdapter::SetNetworkIds(uint16_t local_id,
uint16_t remote_id) { uint16_t remote_id) {
rtc::CritScope cs(&lock_); rtc::CritScope cs(&lock_);
@ -118,7 +124,6 @@ std::vector<PacketFeedback> TransportFeedbackAdapter::GetPacketFeedbackVector(
return packet_feedback_vector; return packet_feedback_vector;
} }
packet_feedback_vector.reserve(feedback.GetPacketStatusCount()); packet_feedback_vector.reserve(feedback.GetPacketStatusCount());
int64_t feedback_rtt = -1;
{ {
rtc::CritScope cs(&lock_); rtc::CritScope cs(&lock_);
size_t failed_lookups = 0; size_t failed_lookups = 0;
@ -148,12 +153,6 @@ std::vector<PacketFeedback> TransportFeedbackAdapter::GetPacketFeedbackVector(
++failed_lookups; ++failed_lookups;
if (packet_feedback.local_net_id == local_net_id_ && if (packet_feedback.local_net_id == local_net_id_ &&
packet_feedback.remote_net_id == remote_net_id_) { packet_feedback.remote_net_id == remote_net_id_) {
if (packet_feedback.send_time_ms >= 0) {
int64_t rtt = now_ms - packet_feedback.send_time_ms;
// max() is used to account for feedback being delayed by the
// receiver.
feedback_rtt = std::max(rtt, feedback_rtt);
}
packet_feedback_vector.push_back(packet_feedback); packet_feedback_vector.push_back(packet_feedback);
} }
@ -165,14 +164,6 @@ std::vector<PacketFeedback> TransportFeedbackAdapter::GetPacketFeedbackVector(
<< " packet" << (failed_lookups > 1 ? "s" : "") << " packet" << (failed_lookups > 1 ? "s" : "")
<< ". Send time history too small?"; << ". Send time history too small?";
} }
if (feedback_rtt > -1) {
feedback_rtts_.push_back(feedback_rtt);
const size_t kFeedbackRttWindow = 32;
if (feedback_rtts_.size() > kFeedbackRttWindow)
feedback_rtts_.pop_front();
min_feedback_rtt_.emplace(
*std::min_element(feedback_rtts_.begin(), feedback_rtts_.end()));
}
} }
return packet_feedback_vector; return packet_feedback_vector;
} }
@ -193,11 +184,6 @@ TransportFeedbackAdapter::GetTransportFeedbackVector() const {
return last_packet_feedback_vector_; return last_packet_feedback_vector_;
} }
rtc::Optional<int64_t> TransportFeedbackAdapter::GetMinFeedbackLoopRtt() const {
rtc::CritScope cs(&lock_);
return min_feedback_rtt_;
}
size_t TransportFeedbackAdapter::GetOutstandingBytes() const { size_t TransportFeedbackAdapter::GetOutstandingBytes() const {
rtc::CritScope cs(&lock_); rtc::CritScope cs(&lock_);
return send_time_history_.GetOutstandingBytes(local_net_id_, remote_net_id_); return send_time_history_.GetOutstandingBytes(local_net_id_, remote_net_id_);

View file

@ -47,7 +47,7 @@ class TransportFeedbackAdapter {
// to the CongestionController interface. // to the CongestionController interface.
void OnTransportFeedback(const rtcp::TransportFeedback& feedback); void OnTransportFeedback(const rtcp::TransportFeedback& feedback);
std::vector<PacketFeedback> GetTransportFeedbackVector() const; std::vector<PacketFeedback> GetTransportFeedbackVector() const;
rtc::Optional<int64_t> GetMinFeedbackLoopRtt() const; rtc::Optional<PacketFeedback> GetPacket(uint16_t sequence_number) const;
void SetTransportOverhead(int transport_overhead_bytes_per_packet); void SetTransportOverhead(int transport_overhead_bytes_per_packet);
@ -67,8 +67,6 @@ class TransportFeedbackAdapter {
std::vector<PacketFeedback> last_packet_feedback_vector_; std::vector<PacketFeedback> last_packet_feedback_vector_;
uint16_t local_net_id_ RTC_GUARDED_BY(&lock_); uint16_t local_net_id_ RTC_GUARDED_BY(&lock_);
uint16_t remote_net_id_ RTC_GUARDED_BY(&lock_); uint16_t remote_net_id_ RTC_GUARDED_BY(&lock_);
std::deque<int64_t> feedback_rtts_ RTC_GUARDED_BY(&lock_);
rtc::Optional<int64_t> min_feedback_rtt_ RTC_GUARDED_BY(&lock_);
rtc::CriticalSection observers_lock_; rtc::CriticalSection observers_lock_;
std::vector<PacketFeedbackObserver*> observers_ std::vector<PacketFeedbackObserver*> observers_

View file

@ -10,8 +10,6 @@ import("../../webrtc.gni")
rtc_static_library("pacing") { rtc_static_library("pacing") {
sources = [ sources = [
"alr_detector.cc",
"alr_detector.h",
"bitrate_prober.cc", "bitrate_prober.cc",
"bitrate_prober.h", "bitrate_prober.h",
"interval_budget.cc", "interval_budget.cc",
@ -58,7 +56,6 @@ if (rtc_include_tests) {
testonly = true testonly = true
sources = [ sources = [
"alr_detector_unittest.cc",
"bitrate_prober_unittest.cc", "bitrate_prober_unittest.cc",
"interval_budget_unittest.cc", "interval_budget_unittest.cc",
"paced_sender_unittest.cc", "paced_sender_unittest.cc",

View file

@ -15,7 +15,6 @@
namespace webrtc { namespace webrtc {
namespace { namespace {
constexpr int kWindowMs = 500; constexpr int kWindowMs = 500;
constexpr int kDeltaTimeMs = 2000;
} }
IntervalBudget::IntervalBudget(int initial_target_rate_kbps) IntervalBudget::IntervalBudget(int initial_target_rate_kbps)
@ -35,7 +34,6 @@ void IntervalBudget::set_target_rate_kbps(int target_rate_kbps) {
} }
void IntervalBudget::IncreaseBudget(int64_t delta_time_ms) { void IntervalBudget::IncreaseBudget(int64_t delta_time_ms) {
RTC_DCHECK_LT(delta_time_ms, kDeltaTimeMs);
int bytes = target_rate_kbps_ * delta_time_ms / 8; int bytes = target_rate_kbps_ * delta_time_ms / 8;
if (bytes_remaining_ < 0 || can_build_up_underuse_) { if (bytes_remaining_ < 0 || can_build_up_underuse_) {
// We overused last interval, compensate this interval. // We overused last interval, compensate this interval.
@ -56,6 +54,8 @@ size_t IntervalBudget::bytes_remaining() const {
} }
int IntervalBudget::budget_level_percent() const { int IntervalBudget::budget_level_percent() const {
if (max_bytes_in_budget_ == 0)
return 0;
return bytes_remaining_ * 100 / max_bytes_in_budget_; return bytes_remaining_ * 100 / max_bytes_in_budget_;
} }

View file

@ -30,12 +30,10 @@ class MockPacedSender : public PacedSender {
size_t bytes, size_t bytes,
bool retransmission)); bool retransmission));
MOCK_METHOD1(CreateProbeCluster, void(int)); MOCK_METHOD1(CreateProbeCluster, void(int));
MOCK_METHOD1(SetEstimatedBitrate, void(uint32_t)); MOCK_METHOD2(SetPacingRates, void(uint32_t, uint32_t));
MOCK_CONST_METHOD0(QueueInMs, int64_t()); MOCK_CONST_METHOD0(QueueInMs, int64_t());
MOCK_CONST_METHOD0(QueueInPackets, int()); MOCK_CONST_METHOD0(QueueInPackets, int());
MOCK_CONST_METHOD0(ExpectedQueueTimeMs, int64_t()); MOCK_CONST_METHOD0(ExpectedQueueTimeMs, int64_t());
MOCK_CONST_METHOD0(GetApplicationLimitedRegionStartTime,
rtc::Optional<int64_t>());
MOCK_METHOD0(Process, void()); MOCK_METHOD0(Process, void());
}; };

View file

@ -18,7 +18,6 @@
#include <utility> #include <utility>
#include "modules/include/module_common_types.h" #include "modules/include/module_common_types.h"
#include "modules/pacing/alr_detector.h"
#include "modules/pacing/bitrate_prober.h" #include "modules/pacing/bitrate_prober.h"
#include "modules/pacing/interval_budget.h" #include "modules/pacing/interval_budget.h"
#include "modules/utility/include/process_thread.h" #include "modules/utility/include/process_thread.h"
@ -52,7 +51,6 @@ bool IsRoundRobinPacingEnabled() {
namespace webrtc { namespace webrtc {
const int64_t PacedSender::kMaxQueueLengthMs = 2000; const int64_t PacedSender::kMaxQueueLengthMs = 2000;
const float PacedSender::kDefaultPaceMultiplier = 2.5f;
PacedSender::PacedSender(const Clock* clock, PacedSender::PacedSender(const Clock* clock,
PacketSender* packet_sender, PacketSender* packet_sender,
@ -68,21 +66,16 @@ PacedSender::PacedSender(const Clock* clock,
std::unique_ptr<PacketQueue> packets) std::unique_ptr<PacketQueue> packets)
: clock_(clock), : clock_(clock),
packet_sender_(packet_sender), packet_sender_(packet_sender),
alr_detector_(rtc::MakeUnique<AlrDetector>(event_log)),
paused_(false), paused_(false),
media_budget_(rtc::MakeUnique<IntervalBudget>(0)), media_budget_(rtc::MakeUnique<IntervalBudget>(0)),
padding_budget_(rtc::MakeUnique<IntervalBudget>(0)), padding_budget_(rtc::MakeUnique<IntervalBudget>(0)),
prober_(rtc::MakeUnique<BitrateProber>(event_log)), prober_(rtc::MakeUnique<BitrateProber>(event_log)),
probing_send_failure_(false), probing_send_failure_(false),
estimated_bitrate_bps_(0),
min_send_bitrate_kbps_(0u),
max_padding_bitrate_kbps_(0u),
pacing_bitrate_kbps_(0), pacing_bitrate_kbps_(0),
time_last_update_us_(clock->TimeInMicroseconds()), time_last_update_us_(clock->TimeInMicroseconds()),
first_sent_packet_ms_(-1), first_sent_packet_ms_(-1),
packets_(std::move(packets)), packets_(std::move(packets)),
packet_counter_(0), packet_counter_(0),
pacing_factor_(kDefaultPaceMultiplier),
queue_time_limit(kMaxQueueLengthMs), queue_time_limit(kMaxQueueLengthMs),
account_for_audio_(false) { account_for_audio_(false) {
UpdateBudgetWithElapsedTime(kMinPacketLimitMs); UpdateBudgetWithElapsedTime(kMinPacketLimitMs);
@ -103,6 +96,8 @@ void PacedSender::Pause() {
paused_ = true; paused_ = true;
packets_->SetPauseState(true, clock_->TimeInMilliseconds()); packets_->SetPauseState(true, clock_->TimeInMilliseconds());
} }
rtc::CritScope cs(&process_thread_lock_);
// Tell the process thread to call our TimeUntilNextProcess() method to get // Tell the process thread to call our TimeUntilNextProcess() method to get
// a new (longer) estimate for when to call Process(). // a new (longer) estimate for when to call Process().
if (process_thread_) if (process_thread_)
@ -117,6 +112,7 @@ void PacedSender::Resume() {
paused_ = false; paused_ = false;
packets_->SetPauseState(false, clock_->TimeInMilliseconds()); packets_->SetPauseState(false, clock_->TimeInMilliseconds());
} }
rtc::CritScope cs(&process_thread_lock_);
// Tell the process thread to call our TimeUntilNextProcess() method to // Tell the process thread to call our TimeUntilNextProcess() method to
// refresh the estimate for when to call Process(). // refresh the estimate for when to call Process().
if (process_thread_) if (process_thread_)
@ -129,29 +125,12 @@ void PacedSender::SetProbingEnabled(bool enabled) {
prober_->SetEnabled(enabled); prober_->SetEnabled(enabled);
} }
void PacedSender::SetEstimatedBitrate(uint32_t bitrate_bps) { void PacedSender::SetPacingRates(uint32_t pacing_rate_bps,
if (bitrate_bps == 0) uint32_t padding_rate_bps) {
RTC_LOG(LS_ERROR) << "PacedSender is not designed to handle 0 bitrate.";
rtc::CritScope cs(&critsect_); rtc::CritScope cs(&critsect_);
estimated_bitrate_bps_ = bitrate_bps; RTC_DCHECK(pacing_rate_bps > 0);
padding_budget_->set_target_rate_kbps( pacing_bitrate_kbps_ = pacing_rate_bps / 1000;
std::min(estimated_bitrate_bps_ / 1000, max_padding_bitrate_kbps_)); padding_budget_->set_target_rate_kbps(padding_rate_bps / 1000);
pacing_bitrate_kbps_ =
std::max(min_send_bitrate_kbps_, estimated_bitrate_bps_ / 1000) *
pacing_factor_;
alr_detector_->SetEstimatedBitrate(bitrate_bps);
}
void PacedSender::SetSendBitrateLimits(int min_send_bitrate_bps,
int padding_bitrate) {
rtc::CritScope cs(&critsect_);
min_send_bitrate_kbps_ = min_send_bitrate_bps / 1000;
pacing_bitrate_kbps_ =
std::max(min_send_bitrate_kbps_, estimated_bitrate_bps_ / 1000) *
pacing_factor_;
max_padding_bitrate_kbps_ = padding_bitrate / 1000;
padding_budget_->set_target_rate_kbps(
std::min(estimated_bitrate_bps_ / 1000, max_padding_bitrate_kbps_));
} }
void PacedSender::InsertPacket(RtpPacketSender::Priority priority, void PacedSender::InsertPacket(RtpPacketSender::Priority priority,
@ -161,8 +140,8 @@ void PacedSender::InsertPacket(RtpPacketSender::Priority priority,
size_t bytes, size_t bytes,
bool retransmission) { bool retransmission) {
rtc::CritScope cs(&critsect_); rtc::CritScope cs(&critsect_);
RTC_DCHECK(estimated_bitrate_bps_ > 0) RTC_DCHECK(pacing_bitrate_kbps_ > 0)
<< "SetEstimatedBitrate must be called before InsertPacket."; << "SetPacingRate must be called before InsertPacket.";
int64_t now_ms = clock_->TimeInMilliseconds(); int64_t now_ms = clock_->TimeInMilliseconds();
prober_->OnIncomingPacket(bytes); prober_->OnIncomingPacket(bytes);
@ -187,12 +166,6 @@ int64_t PacedSender::ExpectedQueueTimeMs() const {
pacing_bitrate_kbps_); pacing_bitrate_kbps_);
} }
rtc::Optional<int64_t> PacedSender::GetApplicationLimitedRegionStartTime()
const {
rtc::CritScope cs(&critsect_);
return alr_detector_->GetApplicationLimitedRegionStartTime();
}
size_t PacedSender::QueueSizePackets() const { size_t PacedSender::QueueSizePackets() const {
rtc::CritScope cs(&critsect_); rtc::CritScope cs(&critsect_);
return packets_->SizeInPackets(); return packets_->SizeInPackets();
@ -244,8 +217,7 @@ void PacedSender::Process() {
// do, timestamps get messed up. // do, timestamps get messed up.
if (packet_counter_ == 0) if (packet_counter_ == 0)
return; return;
size_t bytes_sent = SendPadding(1, pacing_info); SendPadding(1, pacing_info);
alr_detector_->OnBytesSent(bytes_sent, elapsed_time_ms);
return; return;
} }
@ -278,7 +250,7 @@ void PacedSender::Process() {
pacing_info = prober_->CurrentCluster(); pacing_info = prober_->CurrentCluster();
recommended_probe_size = prober_->RecommendedMinProbeSize(); recommended_probe_size = prober_->RecommendedMinProbeSize();
} }
while (!packets_->Empty()) { while (!packets_->Empty() && !paused_) {
// Since we need to release the lock in order to send, we first pop the // Since we need to release the lock in order to send, we first pop the
// element from the priority queue but keep it in storage, so that we can // element from the priority queue but keep it in storage, so that we can
// reinsert it if send fails. // reinsert it if send fails.
@ -306,8 +278,9 @@ void PacedSender::Process() {
int padding_needed = int padding_needed =
static_cast<int>(is_probing ? (recommended_probe_size - bytes_sent) static_cast<int>(is_probing ? (recommended_probe_size - bytes_sent)
: padding_budget_->bytes_remaining()); : padding_budget_->bytes_remaining());
if (padding_needed > 0) if (padding_needed > 0) {
bytes_sent += SendPadding(padding_needed, pacing_info); bytes_sent += SendPadding(padding_needed, pacing_info);
}
} }
} }
if (is_probing) { if (is_probing) {
@ -315,11 +288,11 @@ void PacedSender::Process() {
if (!probing_send_failure_) if (!probing_send_failure_)
prober_->ProbeSent(clock_->TimeInMilliseconds(), bytes_sent); prober_->ProbeSent(clock_->TimeInMilliseconds(), bytes_sent);
} }
alr_detector_->OnBytesSent(bytes_sent, elapsed_time_ms);
} }
void PacedSender::ProcessThreadAttached(ProcessThread* process_thread) { void PacedSender::ProcessThreadAttached(ProcessThread* process_thread) {
RTC_LOG(LS_INFO) << "ProcessThreadAttached 0x" << std::hex << process_thread; RTC_LOG(LS_INFO) << "ProcessThreadAttached 0x" << std::hex << process_thread;
rtc::CritScope cs(&process_thread_lock_);
process_thread_ = process_thread; process_thread_ = process_thread;
} }
@ -375,14 +348,6 @@ void PacedSender::UpdateBudgetWithBytesSent(size_t bytes_sent) {
padding_budget_->UseBudget(bytes_sent); padding_budget_->UseBudget(bytes_sent);
} }
void PacedSender::SetPacingFactor(float pacing_factor) {
rtc::CritScope cs(&critsect_);
pacing_factor_ = pacing_factor;
// Make sure new padding factor is applied immediately, otherwise we need to
// wait for the send bitrate estimate to be updated before this takes effect.
SetEstimatedBitrate(estimated_bitrate_bps_);
}
void PacedSender::SetQueueTimeLimit(int limit_ms) { void PacedSender::SetQueueTimeLimit(int limit_ms) {
rtc::CritScope cs(&critsect_); rtc::CritScope cs(&critsect_);
queue_time_limit = limit_ms; queue_time_limit = limit_ms;

View file

@ -21,7 +21,6 @@
#include "typedefs.h" // NOLINT(build/include) #include "typedefs.h" // NOLINT(build/include)
namespace webrtc { namespace webrtc {
class AlrDetector;
class BitrateProber; class BitrateProber;
class Clock; class Clock;
class ProbeClusterCreatedObserver; class ProbeClusterCreatedObserver;
@ -55,12 +54,6 @@ class PacedSender : public Pacer {
// encoding them). Bitrate sent may temporarily exceed target set by // encoding them). Bitrate sent may temporarily exceed target set by
// UpdateBitrate() so that this limit will be upheld. // UpdateBitrate() so that this limit will be upheld.
static const int64_t kMaxQueueLengthMs; static const int64_t kMaxQueueLengthMs;
// Pacing-rate relative to our target send rate.
// Multiplicative factor that is applied to the target bitrate to calculate
// the number of bytes that can be transmitted per interval.
// Increasing this factor will result in lower delays in cases of bitrate
// overshoots from the encoder.
static const float kDefaultPaceMultiplier;
PacedSender(const Clock* clock, PacedSender(const Clock* clock,
PacketSender* packet_sender, PacketSender* packet_sender,
@ -86,22 +79,14 @@ class PacedSender : public Pacer {
// effect. // effect.
void SetProbingEnabled(bool enabled); void SetProbingEnabled(bool enabled);
// Sets the estimated capacity of the network. Must be called once before // Set the bitrate used as a reference target bitrate by the application
// packets can be sent. // limited region (ALR) detector. If the sent bitrate is significantly below
// |bitrate_bps| is our estimate of what we are allowed to send on average. // the target rate, ALR state is detected.
// We will pace out bursts of packets at a bitrate of void SetAlrTargetBitrate(uint32_t bitrate_bps);
// |bitrate_bps| * kDefaultPaceMultiplier.
void SetEstimatedBitrate(uint32_t bitrate_bps) override;
// Sets the minimum send bitrate and maximum padding bitrate requested by send // Sets the pacing rates. Must be called once before packets can be sent.
// streams. void SetPacingRates(uint32_t pacing_rate_bps,
// |min_send_bitrate_bps| might be higher that the estimated available network uint32_t padding_rate_bps) override;
// bitrate and if so, the pacer will send with |min_send_bitrate_bps|.
// |max_padding_bitrate_bps| might be higher than the estimate available
// network bitrate and if so, the pacer will send padding packets to reach
// the min of the estimated available bitrate and |max_padding_bitrate_bps|.
void SetSendBitrateLimits(int min_send_bitrate_bps,
int max_padding_bitrate_bps);
// Returns true if we send the packet now, else it will add the packet // Returns true if we send the packet now, else it will add the packet
// information to the queue and call TimeToSendPacket when it's time to send. // information to the queue and call TimeToSendPacket when it's time to send.
@ -131,14 +116,6 @@ class PacedSender : public Pacer {
// packets in the queue, given the current size and bitrate, ignoring prio. // packets in the queue, given the current size and bitrate, ignoring prio.
virtual int64_t ExpectedQueueTimeMs() const; virtual int64_t ExpectedQueueTimeMs() const;
// Returns time in milliseconds when the current application-limited region
// started or empty result if the sender is currently not application-limited.
//
// Application Limited Region (ALR) refers to operating in a state where the
// traffic on network is limited due to application not having enough
// traffic to meet the current channel capacity.
virtual rtc::Optional<int64_t> GetApplicationLimitedRegionStartTime() const;
// Returns the number of milliseconds until the module want a worker thread // Returns the number of milliseconds until the module want a worker thread
// to call Process. // to call Process.
int64_t TimeUntilNextProcess() override; int64_t TimeUntilNextProcess() override;
@ -148,7 +125,6 @@ class PacedSender : public Pacer {
// Called when the prober is associated with a process thread. // Called when the prober is associated with a process thread.
void ProcessThreadAttached(ProcessThread* process_thread) override; void ProcessThreadAttached(ProcessThread* process_thread) override;
void SetPacingFactor(float pacing_factor);
void SetQueueTimeLimit(int limit_ms); void SetQueueTimeLimit(int limit_ms);
private: private:
@ -166,7 +142,6 @@ class PacedSender : public Pacer {
const Clock* const clock_; const Clock* const clock_;
PacketSender* const packet_sender_; PacketSender* const packet_sender_;
const std::unique_ptr<AlrDetector> alr_detector_ RTC_PT_GUARDED_BY(critsect_);
rtc::CriticalSection critsect_; rtc::CriticalSection critsect_;
bool paused_ RTC_GUARDED_BY(critsect_); bool paused_ RTC_GUARDED_BY(critsect_);
@ -184,9 +159,6 @@ class PacedSender : public Pacer {
bool probing_send_failure_ RTC_GUARDED_BY(critsect_); bool probing_send_failure_ RTC_GUARDED_BY(critsect_);
// Actual configured bitrates (media_budget_ may temporarily be higher in // Actual configured bitrates (media_budget_ may temporarily be higher in
// order to meet pace time constraint). // order to meet pace time constraint).
uint32_t estimated_bitrate_bps_ RTC_GUARDED_BY(critsect_);
uint32_t min_send_bitrate_kbps_ RTC_GUARDED_BY(critsect_);
uint32_t max_padding_bitrate_kbps_ RTC_GUARDED_BY(critsect_);
uint32_t pacing_bitrate_kbps_ RTC_GUARDED_BY(critsect_); uint32_t pacing_bitrate_kbps_ RTC_GUARDED_BY(critsect_);
int64_t time_last_update_us_ RTC_GUARDED_BY(critsect_); int64_t time_last_update_us_ RTC_GUARDED_BY(critsect_);
@ -194,9 +166,15 @@ class PacedSender : public Pacer {
const std::unique_ptr<PacketQueue> packets_ RTC_PT_GUARDED_BY(critsect_); const std::unique_ptr<PacketQueue> packets_ RTC_PT_GUARDED_BY(critsect_);
uint64_t packet_counter_ RTC_GUARDED_BY(critsect_); uint64_t packet_counter_ RTC_GUARDED_BY(critsect_);
ProcessThread* process_thread_ = nullptr;
float pacing_factor_ RTC_GUARDED_BY(critsect_); // Lock to avoid race when attaching process thread. This can happen due to
// the Call class setting network state on SendSideCongestionController, which
// in turn calls Pause/Resume on Pacedsender, before actually starting the
// pacer process thread. If SendSideCongestionController is running on a task
// queue separate from the thread used by Call, this causes a race.
rtc::CriticalSection process_thread_lock_;
ProcessThread* process_thread_ RTC_GUARDED_BY(process_thread_lock_) = nullptr;
int64_t queue_time_limit RTC_GUARDED_BY(critsect_); int64_t queue_time_limit RTC_GUARDED_BY(critsect_);
bool account_for_audio_ RTC_GUARDED_BY(critsect_); bool account_for_audio_ RTC_GUARDED_BY(critsect_);
}; };

View file

@ -31,6 +31,8 @@ constexpr unsigned kSecondClusterBps = 1800000;
// values. This results in probing slightly higher than the target bitrate. // values. This results in probing slightly higher than the target bitrate.
// For 1.8 Mbps, this comes to be about 120 kbps with 1200 probe packets. // For 1.8 Mbps, this comes to be about 120 kbps with 1200 probe packets.
constexpr int kBitrateProbingError = 150000; constexpr int kBitrateProbingError = 150000;
const float kPaceMultiplier = 2.5f;
} // namespace } // namespace
namespace webrtc { namespace webrtc {
@ -116,7 +118,7 @@ class PacedSenderTest : public testing::TestWithParam<std::string> {
// have to enable probing, either by creating a new PacedSender instance or // have to enable probing, either by creating a new PacedSender instance or
// by calling SetProbingEnabled(true). // by calling SetProbingEnabled(true).
send_bucket_->SetProbingEnabled(false); send_bucket_->SetProbingEnabled(false);
send_bucket_->SetEstimatedBitrate(kTargetBitrateBps); send_bucket_->SetPacingRates(kTargetBitrateBps * kPaceMultiplier, 0);
clock_.AdvanceTimeMilliseconds(send_bucket_->TimeUntilNextProcess()); clock_.AdvanceTimeMilliseconds(send_bucket_->TimeUntilNextProcess());
} }
@ -171,7 +173,7 @@ TEST_P(PacedSenderTest, QueuePacket) {
// interval. (network capacity * multiplier / (8 bits per byte * // interval. (network capacity * multiplier / (8 bits per byte *
// (packet size * #send intervals per second) // (packet size * #send intervals per second)
const size_t packets_to_send = const size_t packets_to_send =
kTargetBitrateBps * PacedSender::kDefaultPaceMultiplier / (8 * 250 * 200); kTargetBitrateBps * kPaceMultiplier / (8 * 250 * 200);
for (size_t i = 0; i < packets_to_send; ++i) { for (size_t i = 0; i < packets_to_send; ++i) {
SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
clock_.TimeInMilliseconds(), 250, false); clock_.TimeInMilliseconds(), 250, false);
@ -220,7 +222,7 @@ TEST_P(PacedSenderTest, PaceQueuedPackets) {
// interval. (network capacity * multiplier / (8 bits per byte * // interval. (network capacity * multiplier / (8 bits per byte *
// (packet size * #send intervals per second) // (packet size * #send intervals per second)
const size_t packets_to_send_per_interval = const size_t packets_to_send_per_interval =
kTargetBitrateBps * PacedSender::kDefaultPaceMultiplier / (8 * 250 * 200); kTargetBitrateBps * kPaceMultiplier / (8 * 250 * 200);
for (size_t i = 0; i < packets_to_send_per_interval; ++i) { for (size_t i = 0; i < packets_to_send_per_interval; ++i) {
SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
clock_.TimeInMilliseconds(), 250, false); clock_.TimeInMilliseconds(), 250, false);
@ -305,14 +307,14 @@ TEST_P(PacedSenderTest, Padding) {
uint32_t ssrc = 12345; uint32_t ssrc = 12345;
uint16_t sequence_number = 1234; uint16_t sequence_number = 1234;
send_bucket_->SetEstimatedBitrate(kTargetBitrateBps); send_bucket_->SetPacingRates(kTargetBitrateBps * kPaceMultiplier,
send_bucket_->SetSendBitrateLimits(kTargetBitrateBps, kTargetBitrateBps); kTargetBitrateBps);
// Due to the multiplicative factor we can send 5 packets during a send // Due to the multiplicative factor we can send 5 packets during a send
// interval. (network capacity * multiplier / (8 bits per byte * // interval. (network capacity * multiplier / (8 bits per byte *
// (packet size * #send intervals per second) // (packet size * #send intervals per second)
const size_t packets_to_send_per_interval = const size_t packets_to_send_per_interval =
kTargetBitrateBps * PacedSender::kDefaultPaceMultiplier / (8 * 250 * 200); kTargetBitrateBps * kPaceMultiplier / (8 * 250 * 200);
for (size_t i = 0; i < packets_to_send_per_interval; ++i) { for (size_t i = 0; i < packets_to_send_per_interval; ++i) {
SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
clock_.TimeInMilliseconds(), 250, false); clock_.TimeInMilliseconds(), 250, false);
@ -342,8 +344,8 @@ TEST_P(PacedSenderTest, Padding) {
} }
TEST_P(PacedSenderTest, NoPaddingBeforeNormalPacket) { TEST_P(PacedSenderTest, NoPaddingBeforeNormalPacket) {
send_bucket_->SetEstimatedBitrate(kTargetBitrateBps); send_bucket_->SetPacingRates(kTargetBitrateBps * kPaceMultiplier,
send_bucket_->SetSendBitrateLimits(kTargetBitrateBps, kTargetBitrateBps); kTargetBitrateBps);
EXPECT_CALL(callback_, TimeToSendPadding(_, _)).Times(0); EXPECT_CALL(callback_, TimeToSendPadding(_, _)).Times(0);
send_bucket_->Process(); send_bucket_->Process();
@ -370,8 +372,8 @@ TEST_P(PacedSenderTest, VerifyPaddingUpToBitrate) {
int64_t capture_time_ms = 56789; int64_t capture_time_ms = 56789;
const int kTimeStep = 5; const int kTimeStep = 5;
const int64_t kBitrateWindow = 100; const int64_t kBitrateWindow = 100;
send_bucket_->SetEstimatedBitrate(kTargetBitrateBps); send_bucket_->SetPacingRates(kTargetBitrateBps * kPaceMultiplier,
send_bucket_->SetSendBitrateLimits(kTargetBitrateBps, kTargetBitrateBps); kTargetBitrateBps);
int64_t start_time = clock_.TimeInMilliseconds(); int64_t start_time = clock_.TimeInMilliseconds();
while (clock_.TimeInMilliseconds() - start_time < kBitrateWindow) { while (clock_.TimeInMilliseconds() - start_time < kBitrateWindow) {
@ -398,11 +400,8 @@ TEST_P(PacedSenderTest, VerifyAverageBitrateVaryingMediaPayload) {
PacedSenderPadding callback; PacedSenderPadding callback;
send_bucket_.reset(new PacedSender(&clock_, &callback, nullptr)); send_bucket_.reset(new PacedSender(&clock_, &callback, nullptr));
send_bucket_->SetProbingEnabled(false); send_bucket_->SetProbingEnabled(false);
send_bucket_->SetEstimatedBitrate(kTargetBitrateBps); send_bucket_->SetPacingRates(kTargetBitrateBps * kPaceMultiplier,
kTargetBitrateBps);
send_bucket_->SetSendBitrateLimits(
0 /*allocated_bitrate_bps*/,
kTargetBitrateBps * 2 /* max_padding_bitrate_bps */);
int64_t start_time = clock_.TimeInMilliseconds(); int64_t start_time = clock_.TimeInMilliseconds();
size_t media_bytes = 0; size_t media_bytes = 0;
@ -433,7 +432,7 @@ TEST_P(PacedSenderTest, Priority) {
// interval. (network capacity * multiplier / (8 bits per byte * // interval. (network capacity * multiplier / (8 bits per byte *
// (packet size * #send intervals per second) // (packet size * #send intervals per second)
const size_t packets_to_send_per_interval = const size_t packets_to_send_per_interval =
kTargetBitrateBps * PacedSender::kDefaultPaceMultiplier / (8 * 250 * 200); kTargetBitrateBps * kPaceMultiplier / (8 * 250 * 200);
for (size_t i = 0; i < packets_to_send_per_interval; ++i) { for (size_t i = 0; i < packets_to_send_per_interval; ++i) {
SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
clock_.TimeInMilliseconds(), 250, false); clock_.TimeInMilliseconds(), 250, false);
@ -487,7 +486,7 @@ TEST_P(PacedSenderTest, RetransmissionPriority) {
// interval. (network capacity * multiplier / (8 bits per byte * // interval. (network capacity * multiplier / (8 bits per byte *
// (packet size * #send intervals per second) // (packet size * #send intervals per second)
const size_t packets_to_send_per_interval = const size_t packets_to_send_per_interval =
kTargetBitrateBps * PacedSender::kDefaultPaceMultiplier / (8 * 250 * 200); kTargetBitrateBps * kPaceMultiplier / (8 * 250 * 200);
send_bucket_->Process(); send_bucket_->Process();
EXPECT_EQ(0u, send_bucket_->QueueSizePackets()); EXPECT_EQ(0u, send_bucket_->QueueSizePackets());
@ -548,7 +547,7 @@ TEST_P(PacedSenderTest, HighPrioDoesntAffectBudget) {
// interval. (network capacity * multiplier / (8 bits per byte * // interval. (network capacity * multiplier / (8 bits per byte *
// (packet size * #send intervals per second) // (packet size * #send intervals per second)
const size_t packets_to_send_per_interval = const size_t packets_to_send_per_interval =
kTargetBitrateBps * PacedSender::kDefaultPaceMultiplier / (8 * 250 * 200); kTargetBitrateBps * kPaceMultiplier / (8 * 250 * 200);
for (size_t i = 0; i < packets_to_send_per_interval; ++i) { for (size_t i = 0; i < packets_to_send_per_interval; ++i) {
SendAndExpectPacket(PacedSender::kLowPriority, ssrc, sequence_number++, SendAndExpectPacket(PacedSender::kLowPriority, ssrc, sequence_number++,
clock_.TimeInMilliseconds(), 250, false); clock_.TimeInMilliseconds(), 250, false);
@ -582,7 +581,7 @@ TEST_P(PacedSenderTest, Pause) {
// interval. (network capacity * multiplier / (8 bits per byte * // interval. (network capacity * multiplier / (8 bits per byte *
// (packet size * #send intervals per second) // (packet size * #send intervals per second)
const size_t packets_to_send_per_interval = const size_t packets_to_send_per_interval =
kTargetBitrateBps * PacedSender::kDefaultPaceMultiplier / (8 * 250 * 200); kTargetBitrateBps * kPaceMultiplier / (8 * 250 * 200);
for (size_t i = 0; i < packets_to_send_per_interval; ++i) { for (size_t i = 0; i < packets_to_send_per_interval; ++i) {
SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
clock_.TimeInMilliseconds(), 250, false); clock_.TimeInMilliseconds(), 250, false);
@ -741,10 +740,10 @@ TEST_P(PacedSenderTest, ExpectedQueueTimeMs) {
uint16_t sequence_number = 1234; uint16_t sequence_number = 1234;
const size_t kNumPackets = 60; const size_t kNumPackets = 60;
const size_t kPacketSize = 1200; const size_t kPacketSize = 1200;
const int32_t kMaxBitrate = PacedSender::kDefaultPaceMultiplier * 30000; const int32_t kMaxBitrate = kPaceMultiplier * 30000;
EXPECT_EQ(0, send_bucket_->ExpectedQueueTimeMs()); EXPECT_EQ(0, send_bucket_->ExpectedQueueTimeMs());
send_bucket_->SetEstimatedBitrate(30000); send_bucket_->SetPacingRates(30000 * kPaceMultiplier, 0);
for (size_t i = 0; i < kNumPackets; ++i) { for (size_t i = 0; i < kNumPackets; ++i) {
SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
clock_.TimeInMilliseconds(), kPacketSize, false); clock_.TimeInMilliseconds(), kPacketSize, false);
@ -778,7 +777,7 @@ TEST_P(PacedSenderTest, QueueTimeGrowsOverTime) {
uint16_t sequence_number = 1234; uint16_t sequence_number = 1234;
EXPECT_EQ(0, send_bucket_->QueueInMs()); EXPECT_EQ(0, send_bucket_->QueueInMs());
send_bucket_->SetEstimatedBitrate(30000); send_bucket_->SetPacingRates(30000 * kPaceMultiplier, 0);
SendAndExpectPacket(PacedSender::kNormalPriority, SendAndExpectPacket(PacedSender::kNormalPriority,
ssrc, ssrc,
sequence_number, sequence_number,
@ -802,7 +801,7 @@ TEST_P(PacedSenderTest, ProbingWithInsertedPackets) {
send_bucket_.reset(new PacedSender(&clock_, &packet_sender, nullptr)); send_bucket_.reset(new PacedSender(&clock_, &packet_sender, nullptr));
send_bucket_->CreateProbeCluster(kFirstClusterBps); send_bucket_->CreateProbeCluster(kFirstClusterBps);
send_bucket_->CreateProbeCluster(kSecondClusterBps); send_bucket_->CreateProbeCluster(kSecondClusterBps);
send_bucket_->SetEstimatedBitrate(kInitialBitrateBps); send_bucket_->SetPacingRates(kInitialBitrateBps * kPaceMultiplier, 0);
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
send_bucket_->InsertPacket(PacedSender::kNormalPriority, ssrc, send_bucket_->InsertPacket(PacedSender::kNormalPriority, ssrc,
@ -847,7 +846,7 @@ TEST_P(PacedSenderTest, ProbingWithPaddingSupport) {
PacedSenderProbing packet_sender; PacedSenderProbing packet_sender;
send_bucket_.reset(new PacedSender(&clock_, &packet_sender, nullptr)); send_bucket_.reset(new PacedSender(&clock_, &packet_sender, nullptr));
send_bucket_->CreateProbeCluster(kFirstClusterBps); send_bucket_->CreateProbeCluster(kFirstClusterBps);
send_bucket_->SetEstimatedBitrate(kInitialBitrateBps); send_bucket_->SetPacingRates(kInitialBitrateBps * kPaceMultiplier, 0);
for (int i = 0; i < 3; ++i) { for (int i = 0; i < 3; ++i) {
send_bucket_->InsertPacket(PacedSender::kNormalPriority, ssrc, send_bucket_->InsertPacket(PacedSender::kNormalPriority, ssrc,
@ -935,8 +934,7 @@ TEST_P(PacedSenderTest, PaddingOveruse) {
const size_t kPacketSize = 1200; const size_t kPacketSize = 1200;
send_bucket_->Process(); send_bucket_->Process();
send_bucket_->SetEstimatedBitrate(60000); send_bucket_->SetPacingRates(60000 * kPaceMultiplier, 0);
send_bucket_->SetSendBitrateLimits(60000, 0);
SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
clock_.TimeInMilliseconds(), kPacketSize, false); clock_.TimeInMilliseconds(), kPacketSize, false);
@ -945,7 +943,7 @@ TEST_P(PacedSenderTest, PaddingOveruse) {
// Add 30kbit padding. When increasing budget, media budget will increase from // Add 30kbit padding. When increasing budget, media budget will increase from
// negative (overuse) while padding budget will increase from 0. // negative (overuse) while padding budget will increase from 0.
clock_.AdvanceTimeMilliseconds(5); clock_.AdvanceTimeMilliseconds(5);
send_bucket_->SetSendBitrateLimits(60000, 30000); send_bucket_->SetPacingRates(60000 * kPaceMultiplier, 30000);
SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++, SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
clock_.TimeInMilliseconds(), kPacketSize, false); clock_.TimeInMilliseconds(), kPacketSize, false);
@ -963,7 +961,7 @@ TEST_F(PacedSenderTest, AverageQueueTime) {
const size_t kPacketSize = 1200; const size_t kPacketSize = 1200;
const int kBitrateBps = 10 * kPacketSize * 8; // 10 packets per second. const int kBitrateBps = 10 * kPacketSize * 8; // 10 packets per second.
send_bucket_->SetEstimatedBitrate(kBitrateBps); send_bucket_->SetPacingRates(kBitrateBps * kPaceMultiplier, 0);
EXPECT_EQ(0, send_bucket_->AverageQueueTimeMs()); EXPECT_EQ(0, send_bucket_->AverageQueueTimeMs());
@ -1008,7 +1006,8 @@ TEST_P(PacedSenderTest, ProbeClusterId) {
uint16_t sequence_number = 1234; uint16_t sequence_number = 1234;
const size_t kPacketSize = 1200; const size_t kPacketSize = 1200;
send_bucket_->SetSendBitrateLimits(kTargetBitrateBps, kTargetBitrateBps); send_bucket_->SetPacingRates(kTargetBitrateBps * kPaceMultiplier,
kTargetBitrateBps);
send_bucket_->SetProbingEnabled(true); send_bucket_->SetProbingEnabled(true);
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
send_bucket_->InsertPacket(PacedSender::kNormalPriority, ssrc, send_bucket_->InsertPacket(PacedSender::kNormalPriority, ssrc,
@ -1054,7 +1053,8 @@ TEST_P(PacedSenderTest, AvoidBusyLoopOnSendFailure) {
uint16_t sequence_number = 1234; uint16_t sequence_number = 1234;
const size_t kPacketSize = kFirstClusterBps / (8000 / 10); const size_t kPacketSize = kFirstClusterBps / (8000 / 10);
send_bucket_->SetSendBitrateLimits(kTargetBitrateBps, kTargetBitrateBps); send_bucket_->SetPacingRates(kTargetBitrateBps * kPaceMultiplier,
kTargetBitrateBps);
send_bucket_->SetProbingEnabled(true); send_bucket_->SetProbingEnabled(true);
send_bucket_->InsertPacket(PacedSender::kNormalPriority, ssrc, send_bucket_->InsertPacket(PacedSender::kNormalPriority, ssrc,
sequence_number, clock_.TimeInMilliseconds(), sequence_number, clock_.TimeInMilliseconds(),

View file

@ -17,7 +17,8 @@
namespace webrtc { namespace webrtc {
class Pacer : public Module, public RtpPacketSender { class Pacer : public Module, public RtpPacketSender {
public: public:
virtual void SetEstimatedBitrate(uint32_t bitrate_bps) {} virtual void SetPacingRates(uint32_t pacing_rate_bps,
uint32_t padding_rate_bps) {}
virtual void SetEstimatedBitrateAndCongestionWindow( virtual void SetEstimatedBitrateAndCongestionWindow(
uint32_t bitrate_bps, uint32_t bitrate_bps,
bool in_probe_rtt, bool in_probe_rtt,

View file

@ -15,7 +15,6 @@
#include <vector> #include <vector>
#include "modules/include/module_common_types.h" #include "modules/include/module_common_types.h"
#include "modules/pacing/alr_detector.h"
#include "modules/pacing/bitrate_prober.h" #include "modules/pacing/bitrate_prober.h"
#include "modules/pacing/interval_budget.h" #include "modules/pacing/interval_budget.h"
#include "modules/utility/include/process_thread.h" #include "modules/utility/include/process_thread.h"

View file

@ -98,7 +98,6 @@ bool PacketRouter::TimeToSendPacket(uint32_t ssrc,
int64_t capture_timestamp, int64_t capture_timestamp,
bool retransmission, bool retransmission,
const PacedPacketInfo& pacing_info) { const PacedPacketInfo& pacing_info) {
RTC_DCHECK_RUNS_SERIALIZED(&pacer_race_);
rtc::CritScope cs(&modules_crit_); rtc::CritScope cs(&modules_crit_);
for (auto* rtp_module : rtp_send_modules_) { for (auto* rtp_module : rtp_send_modules_) {
if (!rtp_module->SendingMedia()) if (!rtp_module->SendingMedia())
@ -114,7 +113,6 @@ bool PacketRouter::TimeToSendPacket(uint32_t ssrc,
size_t PacketRouter::TimeToSendPadding(size_t bytes_to_send, size_t PacketRouter::TimeToSendPadding(size_t bytes_to_send,
const PacedPacketInfo& pacing_info) { const PacedPacketInfo& pacing_info) {
RTC_DCHECK_RUNS_SERIALIZED(&pacer_race_);
size_t total_bytes_sent = 0; size_t total_bytes_sent = 0;
rtc::CritScope cs(&modules_crit_); rtc::CritScope cs(&modules_crit_);
// Rtp modules are ordered by which stream can most benefit from padding. // Rtp modules are ordered by which stream can most benefit from padding.
@ -223,7 +221,6 @@ bool PacketRouter::SendRemb(int64_t bitrate_bps,
} }
bool PacketRouter::SendTransportFeedback(rtcp::TransportFeedback* packet) { bool PacketRouter::SendTransportFeedback(rtcp::TransportFeedback* packet) {
RTC_DCHECK_RUNS_SERIALIZED(&pacer_race_);
rtc::CritScope cs(&modules_crit_); rtc::CritScope cs(&modules_crit_);
// Prefer send modules. // Prefer send modules.
for (auto* rtp_module : rtp_send_modules_) { for (auto* rtp_module : rtp_send_modules_) {

View file

@ -91,7 +91,6 @@ class PacketRouter : public PacedSender::PacketSender,
void UnsetActiveRembModule() RTC_EXCLUSIVE_LOCKS_REQUIRED(modules_crit_); void UnsetActiveRembModule() RTC_EXCLUSIVE_LOCKS_REQUIRED(modules_crit_);
void DetermineActiveRembModule() RTC_EXCLUSIVE_LOCKS_REQUIRED(modules_crit_); void DetermineActiveRembModule() RTC_EXCLUSIVE_LOCKS_REQUIRED(modules_crit_);
rtc::RaceChecker pacer_race_;
rtc::CriticalSection modules_crit_; rtc::CriticalSection modules_crit_;
// Rtp and Rtcp modules of the rtp senders. // Rtp and Rtcp modules of the rtp senders.
std::list<RtpRtcp*> rtp_send_modules_ RTC_GUARDED_BY(modules_crit_); std::list<RtpRtcp*> rtp_send_modules_ RTC_GUARDED_BY(modules_crit_);

View file

@ -477,47 +477,47 @@ TEST_P(BweSimulation, Evaluation8) {
RunPauseResumeFlows(GetParam()); RunPauseResumeFlows(GetParam());
} }
// Following test cases begin with "GccComparison" run the // Following test cases begin with "GoogCcComparison" run the
// evaluation test cases for both GCC and other calling RMCAT. // evaluation test cases for both GoogCc and other calling RMCAT.
TEST_P(BweSimulation, GccComparison1) { TEST_P(BweSimulation, GoogCcComparison1) {
RunVariableCapacity1SingleFlow(GetParam()); RunVariableCapacity1SingleFlow(GetParam());
BweTest gcc_test(false); BweTest goog_cc_test(false);
gcc_test.RunVariableCapacity1SingleFlow(kSendSideEstimator); goog_cc_test.RunVariableCapacity1SingleFlow(kSendSideEstimator);
} }
TEST_P(BweSimulation, GccComparison2) { TEST_P(BweSimulation, GoogCcComparison2) {
const size_t kNumFlows = 2; const size_t kNumFlows = 2;
RunVariableCapacity2MultipleFlows(GetParam(), kNumFlows); RunVariableCapacity2MultipleFlows(GetParam(), kNumFlows);
BweTest gcc_test(false); BweTest goog_cc_test(false);
gcc_test.RunVariableCapacity2MultipleFlows(kSendSideEstimator, kNumFlows); goog_cc_test.RunVariableCapacity2MultipleFlows(kSendSideEstimator, kNumFlows);
} }
TEST_P(BweSimulation, GccComparison3) { TEST_P(BweSimulation, GoogCcComparison3) {
RunBidirectionalFlow(GetParam()); RunBidirectionalFlow(GetParam());
BweTest gcc_test(false); BweTest goog_cc_test(false);
gcc_test.RunBidirectionalFlow(kSendSideEstimator); goog_cc_test.RunBidirectionalFlow(kSendSideEstimator);
} }
TEST_P(BweSimulation, GccComparison4) { TEST_P(BweSimulation, GoogCcComparison4) {
RunSelfFairness(GetParam()); RunSelfFairness(GetParam());
BweTest gcc_test(false); BweTest goog_cc_test(false);
gcc_test.RunSelfFairness(GetParam()); goog_cc_test.RunSelfFairness(GetParam());
} }
TEST_P(BweSimulation, GccComparison5) { TEST_P(BweSimulation, GoogCcComparison5) {
RunRoundTripTimeFairness(GetParam()); RunRoundTripTimeFairness(GetParam());
BweTest gcc_test(false); BweTest goog_cc_test(false);
gcc_test.RunRoundTripTimeFairness(kSendSideEstimator); goog_cc_test.RunRoundTripTimeFairness(kSendSideEstimator);
} }
TEST_P(BweSimulation, GccComparison6) { TEST_P(BweSimulation, GoogCcComparison6) {
RunLongTcpFairness(GetParam()); RunLongTcpFairness(GetParam());
BweTest gcc_test(false); BweTest goog_cc_test(false);
gcc_test.RunLongTcpFairness(kSendSideEstimator); goog_cc_test.RunLongTcpFairness(kSendSideEstimator);
} }
TEST_P(BweSimulation, GccComparison7) { TEST_P(BweSimulation, GoogCcComparison7) {
const int kNumTcpFiles = 10; const int kNumTcpFiles = 10;
std::vector<int> tcp_file_sizes_bytes = std::vector<int> tcp_file_sizes_bytes =
@ -528,24 +528,24 @@ TEST_P(BweSimulation, GccComparison7) {
RunMultipleShortTcpFairness(GetParam(), tcp_file_sizes_bytes, RunMultipleShortTcpFairness(GetParam(), tcp_file_sizes_bytes,
tcp_starting_times_ms); tcp_starting_times_ms);
BweTest gcc_test(false); BweTest goog_cc_test(false);
gcc_test.RunMultipleShortTcpFairness(kSendSideEstimator, tcp_file_sizes_bytes, goog_cc_test.RunMultipleShortTcpFairness(
tcp_starting_times_ms); kSendSideEstimator, tcp_file_sizes_bytes, tcp_starting_times_ms);
} }
TEST_P(BweSimulation, GccComparison8) { TEST_P(BweSimulation, GoogCcComparison8) {
RunPauseResumeFlows(GetParam()); RunPauseResumeFlows(GetParam());
BweTest gcc_test(false); BweTest goog_cc_test(false);
gcc_test.RunPauseResumeFlows(kSendSideEstimator); goog_cc_test.RunPauseResumeFlows(kSendSideEstimator);
} }
TEST_P(BweSimulation, GccComparisonChoke) { TEST_P(BweSimulation, GoogCcComparisonChoke) {
int array[] = {1000, 500, 1000}; int array[] = {1000, 500, 1000};
std::vector<int> capacities_kbps(array, array + 3); std::vector<int> capacities_kbps(array, array + 3);
RunChoke(GetParam(), capacities_kbps); RunChoke(GetParam(), capacities_kbps);
BweTest gcc_test(false); BweTest goog_cc_test(false);
gcc_test.RunChoke(kSendSideEstimator, capacities_kbps); goog_cc_test.RunChoke(kSendSideEstimator, capacities_kbps);
} }
} // namespace bwe } // namespace bwe

View file

@ -181,7 +181,8 @@ enum BandwidthEstimatorType {
kBbrEstimator kBbrEstimator
}; };
const char* const bwe_names[] = {"Null", "NADA", "REMB", "GCC", "TCP", "BBR"}; const char* const bwe_names[] = {"Null", "NADA", "REMB",
"GoogCc", "TCP", "BBR"};
int64_t GetAbsSendTimeInMs(uint32_t abs_send_time); int64_t GetAbsSendTimeInMs(uint32_t abs_send_time);

View file

@ -32,7 +32,7 @@ SendSideBweSender::SendSideBweSender(int kbps,
&event_log_)), &event_log_)),
acknowledged_bitrate_estimator_( acknowledged_bitrate_estimator_(
rtc::MakeUnique<AcknowledgedBitrateEstimator>()), rtc::MakeUnique<AcknowledgedBitrateEstimator>()),
bwe_(new DelayBasedBwe(nullptr, clock)), bwe_(new DelayBasedBwe(nullptr)),
feedback_observer_(bitrate_controller_.get()), feedback_observer_(bitrate_controller_.get()),
clock_(clock), clock_(clock),
send_time_history_(clock_, 10000), send_time_history_(clock_, 10000),
@ -72,7 +72,7 @@ void SendSideBweSender::GiveFeedback(const FeedbackPacket& feedback) {
int64_t rtt_ms = int64_t rtt_ms =
clock_->TimeInMilliseconds() - feedback.latest_send_time_ms(); clock_->TimeInMilliseconds() - feedback.latest_send_time_ms();
bwe_->OnRttUpdate(rtt_ms, rtt_ms); bwe_->OnRttUpdate(rtt_ms);
BWE_TEST_LOGGING_PLOT(1, "RTT", clock_->TimeInMilliseconds(), rtt_ms); BWE_TEST_LOGGING_PLOT(1, "RTT", clock_->TimeInMilliseconds(), rtt_ms);
std::sort(packet_feedback_vector.begin(), packet_feedback_vector.end(), std::sort(packet_feedback_vector.begin(), packet_feedback_vector.end(),
@ -80,7 +80,8 @@ void SendSideBweSender::GiveFeedback(const FeedbackPacket& feedback) {
acknowledged_bitrate_estimator_->IncomingPacketFeedbackVector( acknowledged_bitrate_estimator_->IncomingPacketFeedbackVector(
packet_feedback_vector); packet_feedback_vector);
DelayBasedBwe::Result result = bwe_->IncomingPacketFeedbackVector( DelayBasedBwe::Result result = bwe_->IncomingPacketFeedbackVector(
packet_feedback_vector, acknowledged_bitrate_estimator_->bitrate_bps()); packet_feedback_vector, acknowledged_bitrate_estimator_->bitrate_bps(),
clock_->TimeInMilliseconds());
if (result.updated) if (result.updated)
bitrate_controller_->OnDelayBasedBweResult(result); bitrate_controller_->OnDelayBasedBweResult(result);

View file

@ -24,6 +24,9 @@
namespace webrtc { namespace webrtc {
namespace testing { namespace testing {
namespace bwe { namespace bwe {
namespace {
const float kPaceMultiplier = 2.5f;
}
void PacketSender::Pause() { void PacketSender::Pause() {
running_ = false; running_ = false;
@ -164,7 +167,7 @@ PacedVideoSender::PacedVideoSender(PacketProcessorListener* listener,
? static_cast<Pacer*>(new BbrPacedSender(&clock_, this, nullptr)) ? static_cast<Pacer*>(new BbrPacedSender(&clock_, this, nullptr))
: static_cast<Pacer*>(new PacedSender(&clock_, this, nullptr))) { : static_cast<Pacer*>(new PacedSender(&clock_, this, nullptr))) {
modules_.push_back(pacer_.get()); modules_.push_back(pacer_.get());
pacer_->SetEstimatedBitrate(source->bits_per_second()); pacer_->SetPacingRates(source->bits_per_second() * kPaceMultiplier, 0);
} }
PacedVideoSender::~PacedVideoSender() { PacedVideoSender::~PacedVideoSender() {
@ -312,7 +315,7 @@ void PacedVideoSender::OnNetworkChanged(uint32_t target_bitrate_bps,
uint8_t fraction_lost, uint8_t fraction_lost,
int64_t rtt) { int64_t rtt) {
VideoSender::OnNetworkChanged(target_bitrate_bps, fraction_lost, rtt); VideoSender::OnNetworkChanged(target_bitrate_bps, fraction_lost, rtt);
pacer_->SetEstimatedBitrate(target_bitrate_bps); pacer_->SetPacingRates(target_bitrate_bps * kPaceMultiplier, 0);
} }
void PacedVideoSender::OnNetworkChanged(uint32_t bitrate_for_encoder_bps, void PacedVideoSender::OnNetworkChanged(uint32_t bitrate_for_encoder_bps,

View file

@ -231,7 +231,6 @@ if (!build_with_chromium) {
"../modules/audio_coding:ana_debug_dump_proto", "../modules/audio_coding:ana_debug_dump_proto",
"../modules/audio_coding:audio_network_adaptor", "../modules/audio_coding:audio_network_adaptor",
"../modules/audio_coding:neteq_tools", "../modules/audio_coding:neteq_tools",
"../modules/congestion_controller:estimators",
"../modules/rtp_rtcp:rtp_rtcp_format", "../modules/rtp_rtcp:rtp_rtcp_format",
"../rtc_base:checks", "../rtc_base:checks",
"../rtc_base:rtc_base_approved", "../rtc_base:rtc_base_approved",
@ -240,6 +239,9 @@ if (!build_with_chromium) {
# TODO(kwiberg): Remove this dependency. # TODO(kwiberg): Remove this dependency.
"../api/audio_codecs:audio_codecs_api", "../api/audio_codecs:audio_codecs_api",
"../modules/congestion_controller", "../modules/congestion_controller",
"../modules/congestion_controller:delay_based_bwe",
"../modules/congestion_controller:estimators",
"../modules/congestion_controller:goog_cc",
"../modules/pacing", "../modules/pacing",
"../modules/rtp_rtcp", "../modules/rtp_rtcp",
"../system_wrappers:system_wrappers_default", "../system_wrappers:system_wrappers_default",

View file

@ -33,6 +33,7 @@
#include "modules/audio_coding/neteq/tools/resample_input_audio_file.h" #include "modules/audio_coding/neteq/tools/resample_input_audio_file.h"
#include "modules/congestion_controller/acknowledged_bitrate_estimator.h" #include "modules/congestion_controller/acknowledged_bitrate_estimator.h"
#include "modules/congestion_controller/bitrate_estimator.h" #include "modules/congestion_controller/bitrate_estimator.h"
#include "modules/congestion_controller/delay_based_bwe.h"
#include "modules/congestion_controller/include/receive_side_congestion_controller.h" #include "modules/congestion_controller/include/receive_side_congestion_controller.h"
#include "modules/congestion_controller/include/send_side_congestion_controller.h" #include "modules/congestion_controller/include/send_side_congestion_controller.h"
#include "modules/include/module_common_types.h" #include "modules/include/module_common_types.h"

View file

@ -799,7 +799,7 @@ VideoSendStreamImpl::VideoSendStreamImpl(
} }
if (alr_settings) { if (alr_settings) {
transport->send_side_cc()->EnablePeriodicAlrProbing(true); transport->send_side_cc()->EnablePeriodicAlrProbing(true);
transport->pacer()->SetPacingFactor(alr_settings->pacing_factor); transport->send_side_cc()->SetPacingFactor(alr_settings->pacing_factor);
configured_pacing_factor_ = alr_settings->pacing_factor; configured_pacing_factor_ = alr_settings->pacing_factor;
transport->pacer()->SetQueueTimeLimit(alr_settings->max_paced_queue_time); transport->pacer()->SetQueueTimeLimit(alr_settings->max_paced_queue_time);
} }