Revert "Revert "Revert "Reland "Moved congestion controller to task queue.""""
This reverts commit 65792c5a5c542201f7b9feefded505842692e6ed. Reason for revert: <INSERT REASONING HERE> Original change's description: > Revert "Revert "Reland "Moved congestion controller to task queue.""" > > This reverts commit 4e849f6925b2ac44b0957a228d7131fc391fca54. > > Reason for revert: <INSERT REASONING HERE> > > Original change's description: > > Revert "Reland "Moved congestion controller to task queue."" > > > > This reverts commit 57daeb7ac7f3d80992905b53fea500953fcfd793. > > > > Reason for revert: Cause increased congestion and deadlocks in downstream project > > > > Original change's description: > > > Reland "Moved congestion controller to task queue." > > > > > > This is a reland of 0cbcba7ea0dced1a7f353c64d6cf91d46ccb29f9. > > > > > > Original change's description: > > > > 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} > > > > > > Bug: webrtc:8415 > > > Change-Id: I1d1756a30deed5b421b1c91c1918a13b6bb455da > > > Reviewed-on: https://webrtc-review.googlesource.com/48000 > > > Reviewed-by: Stefan Holmer <stefan@webrtc.org> > > > Commit-Queue: Sebastian Jansson <srte@webrtc.org> > > > Cr-Commit-Position: refs/heads/master@{#21899} > > > > TBR=terelius@webrtc.org,stefan@webrtc.org,srte@webrtc.org > > > > # Not skipping CQ checks because original CL landed > 1 day ago. > > > > Bug: webrtc:8415 > > Change-Id: Ida8074dcac2cc28b3629228eb22846d8a8e81b83 > > Reviewed-on: https://webrtc-review.googlesource.com/52980 > > Reviewed-by: Danil Chapovalov <danilchap@webrtc.org> > > Commit-Queue: Danil Chapovalov <danilchap@webrtc.org> > > Cr-Commit-Position: refs/heads/master@{#22017} > > TBR=danilchap@webrtc.org,terelius@webrtc.org,stefan@webrtc.org,srte@webrtc.org > > Change-Id: I3393b74370c4f4d0955f50728005b2b925be169b > No-Presubmit: true > No-Tree-Checks: true > No-Try: true > Bug: webrtc:8415 > Reviewed-on: https://webrtc-review.googlesource.com/53262 > Reviewed-by: Sebastian Jansson <srte@webrtc.org> > Commit-Queue: Sebastian Jansson <srte@webrtc.org> > Cr-Commit-Position: refs/heads/master@{#22023} TBR=danilchap@webrtc.org,terelius@webrtc.org,stefan@webrtc.org,srte@webrtc.org Change-Id: Id68ad986ee51142b7be3381d0793709b4392fe2c No-Presubmit: true No-Tree-Checks: true No-Try: true Bug: webrtc:8415 Reviewed-on: https://webrtc-review.googlesource.com/53360 Reviewed-by: Sebastian Jansson <srte@webrtc.org> Commit-Queue: Sebastian Jansson <srte@webrtc.org> Cr-Commit-Position: refs/heads/master@{#22024}
This commit is contained in:

committed by
Commit Bot

parent
65792c5a5c
commit
ea86bb74fc
@ -46,8 +46,7 @@ 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) {
|
||||||
send_side_cc_.SetSendBitrateLimits(min_send_bitrate_bps,
|
pacer_.SetSendBitrateLimits(min_send_bitrate_bps, max_padding_bitrate_bps);
|
||||||
max_padding_bitrate_bps);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RtpTransportControllerSend::SetKeepAliveConfig(
|
void RtpTransportControllerSend::SetKeepAliveConfig(
|
||||||
|
@ -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, 0, sequence_number[0]));
|
report_blocks.push_back(CreateReportBlock(1, 2, 1, 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, 0, 1, 255), bitrate_observer_.last_fraction_loss_);
|
EXPECT_EQ(WeightedLoss(20, 1, 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;
|
||||||
|
@ -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_(0),
|
: lost_packets_since_last_loss_update_Q8_(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,7 +125,6 @@ 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),
|
||||||
@ -207,28 +206,24 @@ void SendSideBandwidthEstimation::UpdateDelayBasedEstimate(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SendSideBandwidthEstimation::UpdateReceiverBlock(uint8_t fraction_loss,
|
void SendSideBandwidthEstimation::UpdateReceiverBlock(uint8_t fraction_loss,
|
||||||
int64_t rtt_ms,
|
int64_t rtt,
|
||||||
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_ += packets_lost;
|
lost_packets_since_last_loss_update_Q8_ += num_lost_packets_Q8;
|
||||||
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.
|
||||||
@ -236,22 +231,21 @@ void SendSideBandwidthEstimation::UpdatePacketsLost(int packets_lost,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
has_decreased_since_last_fraction_loss_ = false;
|
has_decreased_since_last_fraction_loss_ = false;
|
||||||
int64_t lost_q8 = lost_packets_since_last_loss_update_ << 8;
|
last_fraction_loss_ = lost_packets_since_last_loss_update_Q8_ /
|
||||||
int64_t expected = expected_packets_since_last_loss_update_;
|
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);
|
||||||
}
|
}
|
||||||
UpdateUmaStatsPacketsLost(now_ms, packets_lost);
|
UpdateUmaStats(now_ms, rtt, (fraction_loss * number_of_packets) >> 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendSideBandwidthEstimation::UpdateUmaStatsPacketsLost(int64_t now_ms,
|
void SendSideBandwidthEstimation::UpdateUmaStats(int64_t now_ms,
|
||||||
int packets_lost) {
|
int64_t rtt,
|
||||||
|
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] &&
|
||||||
@ -262,12 +256,14 @@ void SendSideBandwidthEstimation::UpdateUmaStatsPacketsLost(int64_t now_ms,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (IsInStartPhase(now_ms)) {
|
if (IsInStartPhase(now_ms)) {
|
||||||
initially_lost_packets_ += packets_lost;
|
initially_lost_packets_ += lost_packets;
|
||||||
} 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 &&
|
||||||
@ -280,19 +276,6 @@ void SendSideBandwidthEstimation::UpdateUmaStatsPacketsLost(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
|
||||||
@ -374,7 +357,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_ = 0;
|
lost_packets_since_last_loss_update_Q8_ = 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;
|
||||||
}
|
}
|
||||||
|
@ -42,18 +42,10 @@ 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_ms,
|
int64_t rtt,
|
||||||
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);
|
||||||
@ -66,7 +58,7 @@ class SendSideBandwidthEstimation {
|
|||||||
|
|
||||||
bool IsInStartPhase(int64_t now_ms) const;
|
bool IsInStartPhase(int64_t now_ms) const;
|
||||||
|
|
||||||
void UpdateUmaStatsPacketsLost(int64_t now_ms, int packets_lost);
|
void UpdateUmaStats(int64_t now_ms, int64_t rtt, int lost_packets);
|
||||||
|
|
||||||
// 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
|
||||||
@ -80,7 +72,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_;
|
int lost_packets_since_last_loss_update_Q8_;
|
||||||
int expected_packets_since_last_loss_update_;
|
int expected_packets_since_last_loss_update_;
|
||||||
|
|
||||||
uint32_t current_bitrate_bps_;
|
uint32_t current_bitrate_bps_;
|
||||||
@ -103,7 +95,6 @@ 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_;
|
||||||
|
@ -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",
|
||||||
"pacer_controller.cc",
|
"probe_controller.cc",
|
||||||
"pacer_controller.h",
|
"probe_controller.h",
|
||||||
"receive_side_congestion_controller.cc",
|
"receive_side_congestion_controller.cc",
|
||||||
"send_side_congestion_controller.cc",
|
"send_side_congestion_controller.cc",
|
||||||
]
|
]
|
||||||
@ -37,14 +37,13 @@ rtc_static_library("congestion_controller") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
deps = [
|
deps = [
|
||||||
":goog_cc",
|
":delay_based_bwe",
|
||||||
|
":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",
|
||||||
@ -53,7 +52,6 @@ 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) {
|
||||||
@ -71,57 +69,14 @@ rtc_static_library("transport_feedback") {
|
|||||||
]
|
]
|
||||||
|
|
||||||
deps = [
|
deps = [
|
||||||
"..:module_api",
|
"../../modules: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 = [
|
||||||
@ -155,7 +110,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",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -190,16 +145,25 @@ 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",
|
||||||
":goog_cc_unittests",
|
":delay_based_bwe",
|
||||||
|
":estimators",
|
||||||
":mock_congestion_controller",
|
":mock_congestion_controller",
|
||||||
":transport_feedback",
|
":transport_feedback",
|
||||||
"../../logging:mocks",
|
"../../logging:mocks",
|
||||||
@ -210,51 +174,12 @@ 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).
|
||||||
|
@ -27,8 +27,6 @@ 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)) {}
|
||||||
|
@ -27,7 +27,6 @@ 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);
|
||||||
|
@ -85,8 +85,9 @@ DelayBasedBwe::Result::Result(bool probe, uint32_t target_bitrate_bps)
|
|||||||
|
|
||||||
DelayBasedBwe::Result::~Result() {}
|
DelayBasedBwe::Result::~Result() {}
|
||||||
|
|
||||||
DelayBasedBwe::DelayBasedBwe(RtcEventLog* event_log)
|
DelayBasedBwe::DelayBasedBwe(RtcEventLog* event_log, const Clock* clock)
|
||||||
: 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),
|
||||||
@ -113,8 +114,7 @@ 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, at_time_ms);
|
IncomingPacketFeedback(packet_feedback);
|
||||||
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,8 +157,7 @@ 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();
|
||||||
}
|
}
|
||||||
@ -181,9 +180,8 @@ DelayBasedBwe::Result DelayBasedBwe::OnLongFeedbackDelay(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DelayBasedBwe::IncomingPacketFeedback(
|
void DelayBasedBwe::IncomingPacketFeedback(
|
||||||
const PacketFeedback& packet_feedback,
|
const PacketFeedback& packet_feedback) {
|
||||||
int64_t at_time_ms) {
|
int64_t now_ms = clock_->TimeInMilliseconds();
|
||||||
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) {
|
||||||
@ -225,10 +223,9 @@ 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 = at_time_ms;
|
int64_t now_ms = clock_->TimeInMilliseconds();
|
||||||
|
|
||||||
rtc::Optional<int> probe_bitrate_bps =
|
rtc::Optional<int> probe_bitrate_bps =
|
||||||
probe_bitrate_estimator_.FetchAndResetLastEstimatedBitrateBps();
|
probe_bitrate_estimator_.FetchAndResetLastEstimatedBitrateBps();
|
||||||
@ -292,7 +289,7 @@ bool DelayBasedBwe::UpdateEstimate(int64_t now_ms,
|
|||||||
return rate_control_.ValidEstimate();
|
return rate_control_.ValidEstimate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DelayBasedBwe::OnRttUpdate(int64_t avg_rtt_ms) {
|
void DelayBasedBwe::OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_ms) {
|
||||||
rate_control_.SetRtt(avg_rtt_ms);
|
rate_control_.SetRtt(avg_rtt_ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,14 +42,13 @@ class DelayBasedBwe {
|
|||||||
bool recovered_from_overuse;
|
bool recovered_from_overuse;
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit DelayBasedBwe(RtcEventLog* event_log);
|
DelayBasedBwe(RtcEventLog* event_log, const Clock* clock);
|
||||||
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);
|
||||||
int64_t at_time_ms);
|
void OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_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);
|
||||||
@ -57,12 +56,10 @@ 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,
|
||||||
@ -71,6 +68,7 @@ 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_;
|
||||||
|
@ -24,13 +24,12 @@ 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(
|
bitrate_estimator_->IncomingPacketFeedbackVector(packet_feedback_vector,
|
||||||
packet_feedback_vector, rtc::nullopt, kDummyTimestamp);
|
rtc::nullopt);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DelayBasedBweTest, NoCrashOnlyLostFeedback) {
|
TEST_F(DelayBasedBweTest, NoCrashOnlyLostFeedback) {
|
||||||
@ -41,8 +40,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(
|
bitrate_estimator_->IncomingPacketFeedbackVector(packet_feedback_vector,
|
||||||
packet_feedback_vector, rtc::nullopt, kDummyTimestamp);
|
rtc::nullopt);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DelayBasedBweTest, ProbeDetection) {
|
TEST_F(DelayBasedBweTest, ProbeDetection) {
|
||||||
|
@ -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)),
|
bitrate_estimator_(new DelayBasedBwe(nullptr, &clock_)),
|
||||||
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,8 +187,7 @@ 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},
|
||||||
@ -223,8 +222,7 @@ 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},
|
||||||
|
@ -1,425 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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>()),
|
|
||||||
pacing_factor_(kDefaultPaceMultiplier),
|
|
||||||
min_pacing_rate_(DataRate::Zero()),
|
|
||||||
max_padding_rate_(DataRate::Zero()),
|
|
||||||
in_cwnd_experiment_(CwndExperimentEnabled()),
|
|
||||||
accepted_queue_ms_(kDefaultAcceptedQueueMs) {
|
|
||||||
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) {
|
|
||||||
probe_controller_->EnablePeriodicAlrProbing(msg.requests_alr_probing);
|
|
||||||
|
|
||||||
bool pacing_changed = false;
|
|
||||||
if (msg.pacing_factor && *msg.pacing_factor != pacing_factor_) {
|
|
||||||
pacing_factor_ = *msg.pacing_factor;
|
|
||||||
pacing_changed = true;
|
|
||||||
}
|
|
||||||
if (msg.min_pacing_rate && *msg.min_pacing_rate != min_pacing_rate_) {
|
|
||||||
min_pacing_rate_ = *msg.min_pacing_rate;
|
|
||||||
pacing_changed = true;
|
|
||||||
}
|
|
||||||
if (msg.max_padding_rate && *msg.max_padding_rate != max_padding_rate_) {
|
|
||||||
max_padding_rate_ = *msg.max_padding_rate;
|
|
||||||
pacing_changed = true;
|
|
||||||
}
|
|
||||||
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(min_pacing_rate_, last_estimate_->bandwidth) * pacing_factor_;
|
|
||||||
DataRate padding_rate =
|
|
||||||
std::min(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
|
|
@ -1,92 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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;
|
|
||||||
|
|
||||||
double pacing_factor_;
|
|
||||||
DataRate min_pacing_rate_;
|
|
||||||
DataRate max_padding_rate_;
|
|
||||||
|
|
||||||
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_
|
|
@ -1,32 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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_
|
|
@ -11,26 +11,19 @@
|
|||||||
#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/network_control/include/network_control.h"
|
#include "modules/congestion_controller/delay_based_bwe.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/task_queue.h"
|
|
||||||
|
|
||||||
namespace rtc {
|
namespace rtc {
|
||||||
struct SentPacket;
|
struct SentPacket;
|
||||||
@ -38,23 +31,16 @@ 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
|
||||||
@ -100,7 +86,10 @@ 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);
|
||||||
|
|
||||||
virtual RtcpBandwidthObserver* GetBandwidthObserver();
|
// Deprecated: Use GetBandwidthObserver instead.
|
||||||
|
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;
|
||||||
@ -113,11 +102,6 @@ class SendSideCongestionController : public CallStatsObserver,
|
|||||||
|
|
||||||
virtual void OnSentPacket(const rtc::SentPacket& sent_packet);
|
virtual void OnSentPacket(const rtc::SentPacket& sent_packet);
|
||||||
|
|
||||||
// Implements RtcpBandwidthObserver
|
|
||||||
void OnReceivedEstimatedBitrate(uint32_t bitrate) override;
|
|
||||||
void OnReceivedRtcpReceiverReport(const ReportBlockList& report_blocks,
|
|
||||||
int64_t rtt,
|
|
||||||
int64_t now_ms) override;
|
|
||||||
// Implements CallStatsObserver.
|
// Implements CallStatsObserver.
|
||||||
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;
|
||||||
|
|
||||||
@ -133,64 +117,52 @@ 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;
|
||||||
|
|
||||||
// Sets the minimum send bitrate and maximum padding bitrate requested by send
|
|
||||||
// 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:
|
private:
|
||||||
SendSideCongestionController(
|
void MaybeTriggerOnNetworkChanged();
|
||||||
const Clock* clock,
|
|
||||||
RtcEventLog* event_log,
|
|
||||||
PacedSender* pacer,
|
|
||||||
NetworkControllerFactoryInterface::uptr controller_factory);
|
|
||||||
|
|
||||||
void UpdateStreamsConfig();
|
|
||||||
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_;
|
||||||
const std::unique_ptr<PacerController> pacer_controller_;
|
uint32_t last_reported_bitrate_bps_ RTC_GUARDED_BY(network_state_lock_);
|
||||||
const std::unique_ptr<send_side_cc_internal::ControlHandler> control_handler;
|
uint8_t last_reported_fraction_loss_ RTC_GUARDED_BY(network_state_lock_);
|
||||||
const std::unique_ptr<NetworkControllerInterface> controller_;
|
int64_t last_reported_rtt_ RTC_GUARDED_BY(network_state_lock_);
|
||||||
|
NetworkState network_state_ RTC_GUARDED_BY(network_state_lock_);
|
||||||
TimeDelta process_interval_;
|
bool pause_pacer_ RTC_GUARDED_BY(network_state_lock_);
|
||||||
int64_t last_process_update_ms_ = 0;
|
// Duplicate the pacer paused state to avoid grabbing a lock when
|
||||||
|
// pausing the pacer. This can be removed when we move this class
|
||||||
std::map<uint32_t, RTCPReportBlock> last_report_blocks_;
|
// over to the task queue.
|
||||||
Timestamp last_report_block_time_;
|
bool pacer_paused_;
|
||||||
|
rtc::CriticalSection bwe_lock_;
|
||||||
StreamsConfig streams_config_;
|
int min_bitrate_bps_ RTC_GUARDED_BY(bwe_lock_);
|
||||||
|
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_;
|
||||||
std::atomic<size_t> transport_overhead_bytes_per_packet_;
|
size_t transport_overhead_bytes_per_packet_ RTC_GUARDED_BY(bwe_lock_);
|
||||||
std::atomic<bool> network_available_;
|
|
||||||
|
|
||||||
rtc::RaceChecker worker_race_;
|
rtc::RaceChecker worker_race_;
|
||||||
|
|
||||||
// Note that moving ownership of the task queue makes it neccessary to make
|
bool pacer_pushback_experiment_ = false;
|
||||||
// sure that there is no outstanding tasks on it using destructed objects.
|
float encoding_rate_ = 1.0;
|
||||||
// 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_
|
||||||
|
@ -1,40 +0,0 @@
|
|||||||
# 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",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,89 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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_
|
|
@ -1,172 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 {
|
|
||||||
StreamsConfig();
|
|
||||||
StreamsConfig(const StreamsConfig&);
|
|
||||||
~StreamsConfig();
|
|
||||||
Timestamp at_time;
|
|
||||||
bool requests_alr_probing = false;
|
|
||||||
rtc::Optional<double> pacing_factor;
|
|
||||||
rtc::Optional<DataRate> min_pacing_rate;
|
|
||||||
rtc::Optional<DataRate> max_padding_rate;
|
|
||||||
};
|
|
||||||
|
|
||||||
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 {
|
|
||||||
PacketResult();
|
|
||||||
PacketResult(const PacketResult&);
|
|
||||||
~PacketResult();
|
|
||||||
|
|
||||||
rtc::Optional<SentPacket> sent_packet;
|
|
||||||
Timestamp receive_time;
|
|
||||||
};
|
|
||||||
|
|
||||||
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_
|
|
@ -1,353 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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_
|
|
@ -1,63 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 {
|
|
||||||
|
|
||||||
StreamsConfig::StreamsConfig() = default;
|
|
||||||
StreamsConfig::StreamsConfig(const StreamsConfig&) = default;
|
|
||||||
StreamsConfig::~StreamsConfig() = default;
|
|
||||||
|
|
||||||
PacketResult::PacketResult() = default;
|
|
||||||
PacketResult::PacketResult(const PacketResult& other) = default;
|
|
||||||
PacketResult::~PacketResult() = default;
|
|
||||||
|
|
||||||
TransportPacketsFeedback::TransportPacketsFeedback() = default;
|
|
||||||
TransportPacketsFeedback::TransportPacketsFeedback(
|
|
||||||
const TransportPacketsFeedback& other) = default;
|
|
||||||
TransportPacketsFeedback::~TransportPacketsFeedback() = default;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
::std::ostream& operator<<(::std::ostream& os,
|
|
||||||
const ProbeClusterConfig& config) {
|
|
||||||
return os << "ProbeClusterConfig(...)";
|
|
||||||
}
|
|
||||||
|
|
||||||
::std::ostream& operator<<(::std::ostream& os, const PacerConfig& config) {
|
|
||||||
return os << "PacerConfig(...)";
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace webrtc
|
|
@ -1,101 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
@ -1,307 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
@ -1,83 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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
|
|
@ -1,53 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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_
|
|
@ -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 =
|
int payload_size_bits = rtc::dchecked_cast<int>(
|
||||||
rtc::dchecked_cast<int>(packet_feedback.payload_size * 8);
|
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) {
|
||||||
|
@ -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 <limits>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
|
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
|
||||||
|
|
||||||
|
@ -10,8 +10,8 @@
|
|||||||
|
|
||||||
#include "modules/congestion_controller/probe_bitrate_estimator.h"
|
#include "modules/congestion_controller/probe_bitrate_estimator.h"
|
||||||
|
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#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"
|
||||||
|
@ -21,12 +21,6 @@
|
|||||||
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;
|
||||||
@ -75,20 +69,19 @@ constexpr char kBweRapidRecoveryExperiment[] =
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
ProbeController::ProbeController(NetworkControllerObserver* observer)
|
ProbeController::ProbeController(PacedSender* pacer, const Clock* clock)
|
||||||
: observer_(observer), enable_periodic_alr_probing_(false) {
|
: pacer_(pacer), clock_(clock), enable_periodic_alr_probing_(false) {
|
||||||
Reset(0);
|
Reset();
|
||||||
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) {
|
||||||
int64_t at_time_ms) {
|
rtc::CritScope cs(&critsect_);
|
||||||
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) {
|
||||||
@ -102,8 +95,8 @@ void ProbeController::SetBitrates(int64_t min_bitrate_bps,
|
|||||||
|
|
||||||
switch (state_) {
|
switch (state_) {
|
||||||
case State::kInit:
|
case State::kInit:
|
||||||
if (network_available_)
|
if (network_state_ == kNetworkUp)
|
||||||
InitiateExponentialProbing(at_time_ms);
|
InitiateExponentialProbing();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case State::kWaitingForProbingResult:
|
case State::kWaitingForProbingResult:
|
||||||
@ -126,32 +119,33 @@ 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(at_time_ms, {max_bitrate_bps}, false);
|
InitiateProbing(clock_->TimeInMilliseconds(), {max_bitrate_bps}, false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProbeController::OnNetworkAvailability(NetworkAvailability msg) {
|
void ProbeController::OnNetworkStateChanged(NetworkState network_state) {
|
||||||
network_available_ = msg.network_available;
|
rtc::CritScope cs(&critsect_);
|
||||||
if (network_available_ && state_ == State::kInit && start_bitrate_bps_ > 0)
|
network_state_ = network_state;
|
||||||
InitiateExponentialProbing(msg.at_time.ms());
|
if (network_state_ == kNetworkUp && state_ == State::kInit)
|
||||||
|
InitiateExponentialProbing();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProbeController::InitiateExponentialProbing(int64_t at_time_ms) {
|
void ProbeController::InitiateExponentialProbing() {
|
||||||
RTC_DCHECK(network_available_);
|
RTC_DCHECK(network_state_ == kNetworkUp);
|
||||||
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(at_time_ms, {3 * start_bitrate_bps_, 6 * start_bitrate_bps_},
|
InitiateProbing(clock_->TimeInMilliseconds(),
|
||||||
true);
|
{3 * start_bitrate_bps_, 6 * start_bitrate_bps_}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProbeController::SetEstimatedBitrate(int64_t bitrate_bps,
|
void ProbeController::SetEstimatedBitrate(int64_t bitrate_bps) {
|
||||||
int64_t at_time_ms) {
|
rtc::CritScope cs(&critsect_);
|
||||||
int64_t now_ms = at_time_ms;
|
int64_t now_ms = clock_->TimeInMilliseconds();
|
||||||
|
|
||||||
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_) {
|
||||||
@ -185,36 +179,36 @@ 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(int64_t at_time_ms) {
|
void ProbeController::RequestProbe() {
|
||||||
|
int64_t now_ms = clock_->TimeInMilliseconds();
|
||||||
|
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 = alr_start_time_ms_.has_value();
|
bool in_alr = pacer_->GetApplicationLimitedRegionStartTime().has_value();
|
||||||
bool alr_ended_recently =
|
bool alr_ended_recently =
|
||||||
(alr_end_time_ms_.has_value() &&
|
(alr_end_time_ms_.has_value() &&
|
||||||
at_time_ms - alr_end_time_ms_.value() < kAlrEndedTimeoutMs);
|
now_ms - alr_end_time_ms_.value() < kAlrEndedTimeoutMs);
|
||||||
if (in_alr || alr_ended_recently || in_rapid_recovery_experiment_) {
|
if (in_alr || alr_ended_recently || in_rapid_recovery_experiment_) {
|
||||||
if (state_ == State::kProbingComplete) {
|
if (state_ == State::kProbingComplete) {
|
||||||
uint32_t suggested_probe_bps =
|
uint32_t suggested_probe_bps =
|
||||||
kProbeFractionAfterDrop * bitrate_before_last_large_drop_bps_;
|
kProbeFractionAfterDrop * bitrate_before_last_large_drop_bps_;
|
||||||
uint32_t min_expected_probe_result_bps =
|
uint32_t min_expected_probe_result_bps =
|
||||||
(1 - kProbeUncertainty) * suggested_probe_bps;
|
(1 - kProbeUncertainty) * suggested_probe_bps;
|
||||||
int64_t time_since_drop_ms = at_time_ms - time_of_last_large_drop_ms_;
|
int64_t time_since_drop_ms = now_ms - time_of_last_large_drop_ms_;
|
||||||
int64_t time_since_probe_ms = at_time_ms - last_bwe_drop_probing_time_ms_;
|
int64_t time_since_probe_ms = now_ms - last_bwe_drop_probing_time_ms_;
|
||||||
if (min_expected_probe_result_bps > estimated_bitrate_bps_ &&
|
if (min_expected_probe_result_bps > estimated_bitrate_bps_ &&
|
||||||
time_since_drop_ms < kBitrateDropTimeoutMs &&
|
time_since_drop_ms < kBitrateDropTimeoutMs &&
|
||||||
time_since_probe_ms > kMinTimeBetweenAlrProbesMs) {
|
time_since_probe_ms > kMinTimeBetweenAlrProbesMs) {
|
||||||
@ -222,23 +216,24 @@ void ProbeController::RequestProbe(int64_t at_time_ms) {
|
|||||||
// Track how often we probe in response to bandwidth drop in ALR.
|
// Track how often we probe in response to bandwidth drop in ALR.
|
||||||
RTC_HISTOGRAM_COUNTS_10000(
|
RTC_HISTOGRAM_COUNTS_10000(
|
||||||
"WebRTC.BWE.BweDropProbingIntervalInS",
|
"WebRTC.BWE.BweDropProbingIntervalInS",
|
||||||
(at_time_ms - last_bwe_drop_probing_time_ms_) / 1000);
|
(now_ms - last_bwe_drop_probing_time_ms_) / 1000);
|
||||||
InitiateProbing(at_time_ms, {suggested_probe_bps}, false);
|
InitiateProbing(now_ms, {suggested_probe_bps}, false);
|
||||||
last_bwe_drop_probing_time_ms_ = at_time_ms;
|
last_bwe_drop_probing_time_ms_ = now_ms;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProbeController::Reset(int64_t at_time_ms) {
|
void ProbeController::Reset() {
|
||||||
network_available_ = true;
|
rtc::CritScope cs(&critsect_);
|
||||||
|
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 = at_time_ms;
|
int64_t now_ms = clock_->TimeInMilliseconds();
|
||||||
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;
|
||||||
@ -246,8 +241,10 @@ void ProbeController::Reset(int64_t at_time_ms) {
|
|||||||
bitrate_before_last_large_drop_bps_ = 0;
|
bitrate_before_last_large_drop_bps_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProbeController::Process(int64_t at_time_ms) {
|
void ProbeController::Process() {
|
||||||
int64_t now_ms = at_time_ms;
|
rtc::CritScope cs(&critsect_);
|
||||||
|
|
||||||
|
int64_t now_ms = clock_->TimeInMilliseconds();
|
||||||
|
|
||||||
if (now_ms - time_last_probing_initiated_ms_ >
|
if (now_ms - time_last_probing_initiated_ms_ >
|
||||||
kMaxWaitingTimeForProbingResultMs) {
|
kMaxWaitingTimeForProbingResultMs) {
|
||||||
@ -264,9 +261,11 @@ void ProbeController::Process(int64_t at_time_ms) {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Probe bandwidth periodically when in ALR state.
|
// Probe bandwidth periodically when in ALR state.
|
||||||
if (alr_start_time_ms_ && estimated_bitrate_bps_ > 0) {
|
rtc::Optional<int64_t> alr_start_time =
|
||||||
|
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_ms_, time_last_probing_initiated_ms_) +
|
std::max(*alr_start_time, 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);
|
||||||
@ -286,13 +285,7 @@ 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) {
|
||||||
|
@ -11,12 +11,11 @@
|
|||||||
#ifndef MODULES_CONGESTION_CONTROLLER_PROBE_CONTROLLER_H_
|
#ifndef MODULES_CONGESTION_CONTROLLER_PROBE_CONTROLLER_H_
|
||||||
#define MODULES_CONGESTION_CONTROLLER_PROBE_CONTROLLER_H_
|
#define MODULES_CONGESTION_CONTROLLER_PROBE_CONTROLLER_H_
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
|
|
||||||
#include "api/optional.h"
|
#include "common_types.h" // NOLINT(build/include)
|
||||||
#include "modules/congestion_controller/network_control/include/network_control.h"
|
#include "modules/pacing/paced_sender.h"
|
||||||
|
#include "rtc_base/criticalsection.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
@ -27,30 +26,27 @@ class Clock;
|
|||||||
// bitrate is adjusted by an application.
|
// bitrate is adjusted by an application.
|
||||||
class ProbeController {
|
class ProbeController {
|
||||||
public:
|
public:
|
||||||
explicit ProbeController(NetworkControllerObserver* observer);
|
ProbeController(PacedSender* pacer, const Clock* clock);
|
||||||
~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 OnNetworkAvailability(NetworkAvailability msg);
|
void OnNetworkStateChanged(NetworkState state);
|
||||||
|
|
||||||
void SetEstimatedBitrate(int64_t bitrate_bps, int64_t at_time_ms);
|
void SetEstimatedBitrate(int64_t bitrate_bps);
|
||||||
|
|
||||||
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(int64_t at_time_ms);
|
void RequestProbe();
|
||||||
|
|
||||||
// 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(int64_t at_time_ms);
|
void Reset();
|
||||||
|
|
||||||
void Process(int64_t at_time_ms);
|
void Process();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class State {
|
enum class State {
|
||||||
@ -62,32 +58,33 @@ class ProbeController {
|
|||||||
kProbingComplete,
|
kProbingComplete,
|
||||||
};
|
};
|
||||||
|
|
||||||
void InitiateExponentialProbing(int64_t at_time_ms);
|
void InitiateExponentialProbing() RTC_EXCLUSIVE_LOCKS_REQUIRED(critsect_);
|
||||||
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_);
|
||||||
|
|
||||||
NetworkControllerObserver* const observer_;
|
rtc::CriticalSection critsect_;
|
||||||
|
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 network_available_;
|
bool in_rapid_recovery_experiment_ RTC_GUARDED_BY(critsect_);
|
||||||
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_;
|
bool mid_call_probing_waiting_for_result_ RTC_GUARDED_BY(&critsect_);
|
||||||
int64_t mid_call_probing_bitrate_bps_;
|
int64_t mid_call_probing_bitrate_bps_ RTC_GUARDED_BY(&critsect_);
|
||||||
int64_t mid_call_probing_succcess_threshold_;
|
int64_t mid_call_probing_succcess_threshold_ RTC_GUARDED_BY(&critsect_);
|
||||||
|
|
||||||
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(ProbeController);
|
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(ProbeController);
|
||||||
};
|
};
|
||||||
|
@ -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,13 +18,9 @@
|
|||||||
|
|
||||||
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 {
|
||||||
|
|
||||||
@ -40,252 +36,234 @@ 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(&cluster_handler_));
|
probe_controller_.reset(new ProbeController(&pacer_, &clock_));
|
||||||
}
|
}
|
||||||
~ProbeControllerTest() override {}
|
~ProbeControllerTest() override {}
|
||||||
|
|
||||||
void SetNetworkAvailable(bool available) {
|
|
||||||
NetworkAvailability msg;
|
|
||||||
msg.at_time = Timestamp::ms(NowMs());
|
|
||||||
msg.network_available = available;
|
|
||||||
probe_controller_->OnNetworkAvailability(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t NowMs() { return clock_.TimeInMilliseconds(); }
|
|
||||||
|
|
||||||
SimulatedClock clock_;
|
SimulatedClock clock_;
|
||||||
NiceMock<MockNetworkControllerObserver> cluster_handler_;
|
NiceMock<MockPacedSender> pacer_;
|
||||||
std::unique_ptr<ProbeController> probe_controller_;
|
std::unique_ptr<ProbeController> probe_controller_;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(ProbeControllerTest, InitiatesProbingAtStart) {
|
TEST_F(ProbeControllerTest, InitiatesProbingAtStart) {
|
||||||
EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(AtLeast(2));
|
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(AtLeast(2));
|
||||||
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||||
kMaxBitrateBps, NowMs());
|
kMaxBitrateBps);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ProbeControllerTest, ProbeOnlyWhenNetworkIsUp) {
|
TEST_F(ProbeControllerTest, ProbeOnlyWhenNetworkIsUp) {
|
||||||
SetNetworkAvailable(false);
|
probe_controller_->OnNetworkStateChanged(kNetworkDown);
|
||||||
EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(0);
|
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(0);
|
||||||
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||||
kMaxBitrateBps, NowMs());
|
kMaxBitrateBps);
|
||||||
|
|
||||||
testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
|
testing::Mock::VerifyAndClearExpectations(&pacer_);
|
||||||
EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(AtLeast(2));
|
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(AtLeast(2));
|
||||||
SetNetworkAvailable(true);
|
probe_controller_->OnNetworkStateChanged(kNetworkUp);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ProbeControllerTest, InitiatesProbingOnMaxBitrateIncrease) {
|
TEST_F(ProbeControllerTest, InitiatesProbingOnMaxBitrateIncrease) {
|
||||||
EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(AtLeast(2));
|
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(AtLeast(2));
|
||||||
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||||
kMaxBitrateBps, NowMs());
|
kMaxBitrateBps);
|
||||||
// Long enough to time out exponential probing.
|
// Long enough to time out exponential probing.
|
||||||
clock_.AdvanceTimeMilliseconds(kExponentialProbingTimeoutMs);
|
clock_.AdvanceTimeMilliseconds(kExponentialProbingTimeoutMs);
|
||||||
probe_controller_->SetEstimatedBitrate(kStartBitrateBps, NowMs());
|
probe_controller_->SetEstimatedBitrate(kStartBitrateBps);
|
||||||
probe_controller_->Process(NowMs());
|
probe_controller_->Process();
|
||||||
|
|
||||||
EXPECT_CALL(cluster_handler_,
|
EXPECT_CALL(pacer_, CreateProbeCluster(kMaxBitrateBps + 100));
|
||||||
OnProbeClusterConfig(DataRateEqBps(kMaxBitrateBps + 100)));
|
|
||||||
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||||
kMaxBitrateBps + 100, NowMs());
|
kMaxBitrateBps + 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ProbeControllerTest, InitiatesProbingOnMaxBitrateIncreaseAtMaxBitrate) {
|
TEST_F(ProbeControllerTest, InitiatesProbingOnMaxBitrateIncreaseAtMaxBitrate) {
|
||||||
EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(AtLeast(2));
|
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(AtLeast(2));
|
||||||
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||||
kMaxBitrateBps, NowMs());
|
kMaxBitrateBps);
|
||||||
// Long enough to time out exponential probing.
|
// Long enough to time out exponential probing.
|
||||||
clock_.AdvanceTimeMilliseconds(kExponentialProbingTimeoutMs);
|
clock_.AdvanceTimeMilliseconds(kExponentialProbingTimeoutMs);
|
||||||
probe_controller_->SetEstimatedBitrate(kStartBitrateBps, NowMs());
|
probe_controller_->SetEstimatedBitrate(kStartBitrateBps);
|
||||||
probe_controller_->Process(NowMs());
|
probe_controller_->Process();
|
||||||
|
|
||||||
probe_controller_->SetEstimatedBitrate(kMaxBitrateBps, NowMs());
|
probe_controller_->SetEstimatedBitrate(kMaxBitrateBps);
|
||||||
EXPECT_CALL(cluster_handler_,
|
EXPECT_CALL(pacer_, CreateProbeCluster(kMaxBitrateBps + 100));
|
||||||
OnProbeClusterConfig(DataRateEqBps(kMaxBitrateBps + 100)));
|
|
||||||
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||||
kMaxBitrateBps + 100, NowMs());
|
kMaxBitrateBps + 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ProbeControllerTest, TestExponentialProbing) {
|
TEST_F(ProbeControllerTest, TestExponentialProbing) {
|
||||||
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||||
kMaxBitrateBps, NowMs());
|
kMaxBitrateBps);
|
||||||
|
|
||||||
// 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(cluster_handler_, OnProbeClusterConfig(_)).Times(0);
|
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(0);
|
||||||
probe_controller_->SetEstimatedBitrate(1000, NowMs());
|
probe_controller_->SetEstimatedBitrate(1000);
|
||||||
testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
|
testing::Mock::VerifyAndClearExpectations(&pacer_);
|
||||||
|
|
||||||
EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(DataRateEqBps(2 * 1800)));
|
EXPECT_CALL(pacer_, CreateProbeCluster(2 * 1800));
|
||||||
probe_controller_->SetEstimatedBitrate(1800, NowMs());
|
probe_controller_->SetEstimatedBitrate(1800);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ProbeControllerTest, TestExponentialProbingTimeout) {
|
TEST_F(ProbeControllerTest, TestExponentialProbingTimeout) {
|
||||||
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||||
kMaxBitrateBps, NowMs());
|
kMaxBitrateBps);
|
||||||
|
|
||||||
// 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(NowMs());
|
probe_controller_->Process();
|
||||||
|
|
||||||
EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(0);
|
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(0);
|
||||||
probe_controller_->SetEstimatedBitrate(1800, NowMs());
|
probe_controller_->SetEstimatedBitrate(1800);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ProbeControllerTest, RequestProbeInAlr) {
|
TEST_F(ProbeControllerTest, RequestProbeInAlr) {
|
||||||
EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(2);
|
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(2);
|
||||||
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||||
kMaxBitrateBps, NowMs());
|
kMaxBitrateBps);
|
||||||
probe_controller_->SetEstimatedBitrate(500, NowMs());
|
probe_controller_->SetEstimatedBitrate(500);
|
||||||
testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
|
testing::Mock::VerifyAndClearExpectations(&pacer_);
|
||||||
EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(DataRateEqBps(0.85 * 500)))
|
EXPECT_CALL(pacer_, CreateProbeCluster(0.85 * 500)).Times(1);
|
||||||
.Times(1);
|
EXPECT_CALL(pacer_, GetApplicationLimitedRegionStartTime())
|
||||||
probe_controller_->SetAlrStartTimeMs(clock_.TimeInMilliseconds());
|
.WillRepeatedly(Return(clock_.TimeInMilliseconds()));
|
||||||
clock_.AdvanceTimeMilliseconds(kAlrProbeInterval + 1);
|
clock_.AdvanceTimeMilliseconds(kAlrProbeInterval + 1);
|
||||||
probe_controller_->Process(NowMs());
|
probe_controller_->Process();
|
||||||
probe_controller_->SetEstimatedBitrate(250, NowMs());
|
probe_controller_->SetEstimatedBitrate(250);
|
||||||
probe_controller_->RequestProbe(NowMs());
|
probe_controller_->RequestProbe();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ProbeControllerTest, RequestProbeWhenAlrEndedRecently) {
|
TEST_F(ProbeControllerTest, RequestProbeWhenAlrEndedRecently) {
|
||||||
EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(2);
|
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(2);
|
||||||
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||||
kMaxBitrateBps, NowMs());
|
kMaxBitrateBps);
|
||||||
probe_controller_->SetEstimatedBitrate(500, NowMs());
|
probe_controller_->SetEstimatedBitrate(500);
|
||||||
testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
|
testing::Mock::VerifyAndClearExpectations(&pacer_);
|
||||||
EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(DataRateEqBps(0.85 * 500)))
|
EXPECT_CALL(pacer_, CreateProbeCluster(0.85 * 500)).Times(1);
|
||||||
.Times(1);
|
EXPECT_CALL(pacer_, GetApplicationLimitedRegionStartTime())
|
||||||
probe_controller_->SetAlrStartTimeMs(rtc::nullopt);
|
.WillRepeatedly(Return(rtc::nullopt));
|
||||||
clock_.AdvanceTimeMilliseconds(kAlrProbeInterval + 1);
|
clock_.AdvanceTimeMilliseconds(kAlrProbeInterval + 1);
|
||||||
probe_controller_->Process(NowMs());
|
probe_controller_->Process();
|
||||||
probe_controller_->SetEstimatedBitrate(250, NowMs());
|
probe_controller_->SetEstimatedBitrate(250);
|
||||||
probe_controller_->SetAlrEndedTimeMs(clock_.TimeInMilliseconds());
|
probe_controller_->SetAlrEndedTimeMs(clock_.TimeInMilliseconds());
|
||||||
clock_.AdvanceTimeMilliseconds(kAlrEndedTimeoutMs - 1);
|
clock_.AdvanceTimeMilliseconds(kAlrEndedTimeoutMs - 1);
|
||||||
probe_controller_->RequestProbe(NowMs());
|
probe_controller_->RequestProbe();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ProbeControllerTest, RequestProbeWhenAlrNotEndedRecently) {
|
TEST_F(ProbeControllerTest, RequestProbeWhenAlrNotEndedRecently) {
|
||||||
EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(2);
|
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(2);
|
||||||
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||||
kMaxBitrateBps, NowMs());
|
kMaxBitrateBps);
|
||||||
probe_controller_->SetEstimatedBitrate(500, NowMs());
|
probe_controller_->SetEstimatedBitrate(500);
|
||||||
testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
|
testing::Mock::VerifyAndClearExpectations(&pacer_);
|
||||||
EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(0);
|
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(0);
|
||||||
probe_controller_->SetAlrStartTimeMs(rtc::nullopt);
|
EXPECT_CALL(pacer_, GetApplicationLimitedRegionStartTime())
|
||||||
|
.WillRepeatedly(Return(rtc::nullopt));
|
||||||
clock_.AdvanceTimeMilliseconds(kAlrProbeInterval + 1);
|
clock_.AdvanceTimeMilliseconds(kAlrProbeInterval + 1);
|
||||||
probe_controller_->Process(NowMs());
|
probe_controller_->Process();
|
||||||
probe_controller_->SetEstimatedBitrate(250, NowMs());
|
probe_controller_->SetEstimatedBitrate(250);
|
||||||
probe_controller_->SetAlrEndedTimeMs(clock_.TimeInMilliseconds());
|
probe_controller_->SetAlrEndedTimeMs(clock_.TimeInMilliseconds());
|
||||||
clock_.AdvanceTimeMilliseconds(kAlrEndedTimeoutMs + 1);
|
clock_.AdvanceTimeMilliseconds(kAlrEndedTimeoutMs + 1);
|
||||||
probe_controller_->RequestProbe(NowMs());
|
probe_controller_->RequestProbe();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ProbeControllerTest, RequestProbeWhenBweDropNotRecent) {
|
TEST_F(ProbeControllerTest, RequestProbeWhenBweDropNotRecent) {
|
||||||
EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(2);
|
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(2);
|
||||||
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||||
kMaxBitrateBps, NowMs());
|
kMaxBitrateBps);
|
||||||
probe_controller_->SetEstimatedBitrate(500, NowMs());
|
probe_controller_->SetEstimatedBitrate(500);
|
||||||
testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
|
testing::Mock::VerifyAndClearExpectations(&pacer_);
|
||||||
EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(0);
|
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(0);
|
||||||
probe_controller_->SetAlrStartTimeMs(clock_.TimeInMilliseconds());
|
EXPECT_CALL(pacer_, GetApplicationLimitedRegionStartTime())
|
||||||
|
.WillRepeatedly(Return(clock_.TimeInMilliseconds()));
|
||||||
clock_.AdvanceTimeMilliseconds(kAlrProbeInterval + 1);
|
clock_.AdvanceTimeMilliseconds(kAlrProbeInterval + 1);
|
||||||
probe_controller_->Process(NowMs());
|
probe_controller_->Process();
|
||||||
probe_controller_->SetEstimatedBitrate(250, NowMs());
|
probe_controller_->SetEstimatedBitrate(250);
|
||||||
clock_.AdvanceTimeMilliseconds(kBitrateDropTimeoutMs + 1);
|
clock_.AdvanceTimeMilliseconds(kBitrateDropTimeoutMs + 1);
|
||||||
probe_controller_->RequestProbe(NowMs());
|
probe_controller_->RequestProbe();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ProbeControllerTest, PeriodicProbing) {
|
TEST_F(ProbeControllerTest, PeriodicProbing) {
|
||||||
EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(2);
|
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(2);
|
||||||
probe_controller_->EnablePeriodicAlrProbing(true);
|
probe_controller_->EnablePeriodicAlrProbing(true);
|
||||||
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||||
kMaxBitrateBps, NowMs());
|
kMaxBitrateBps);
|
||||||
probe_controller_->SetEstimatedBitrate(500, NowMs());
|
probe_controller_->SetEstimatedBitrate(500);
|
||||||
testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
|
testing::Mock::VerifyAndClearExpectations(&pacer_);
|
||||||
|
|
||||||
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(cluster_handler_, OnProbeClusterConfig(DataRateEqBps(1000)))
|
EXPECT_CALL(pacer_, CreateProbeCluster(1000)).Times(1);
|
||||||
.Times(1);
|
EXPECT_CALL(pacer_, GetApplicationLimitedRegionStartTime())
|
||||||
probe_controller_->SetAlrStartTimeMs(start_time);
|
.WillRepeatedly(Return(start_time));
|
||||||
clock_.AdvanceTimeMilliseconds(5000);
|
clock_.AdvanceTimeMilliseconds(5000);
|
||||||
probe_controller_->Process(NowMs());
|
probe_controller_->Process();
|
||||||
probe_controller_->SetEstimatedBitrate(500, NowMs());
|
probe_controller_->SetEstimatedBitrate(500);
|
||||||
testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
|
testing::Mock::VerifyAndClearExpectations(&pacer_);
|
||||||
|
|
||||||
// The following probe should be sent at 10s into ALR.
|
// The following probe should be sent at 10s into ALR.
|
||||||
EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(0);
|
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(0);
|
||||||
probe_controller_->SetAlrStartTimeMs(start_time);
|
EXPECT_CALL(pacer_, GetApplicationLimitedRegionStartTime())
|
||||||
|
.WillRepeatedly(Return(start_time));
|
||||||
clock_.AdvanceTimeMilliseconds(4000);
|
clock_.AdvanceTimeMilliseconds(4000);
|
||||||
probe_controller_->Process(NowMs());
|
probe_controller_->Process();
|
||||||
probe_controller_->SetEstimatedBitrate(500, NowMs());
|
probe_controller_->SetEstimatedBitrate(500);
|
||||||
testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
|
testing::Mock::VerifyAndClearExpectations(&pacer_);
|
||||||
|
|
||||||
EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(1);
|
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(1);
|
||||||
probe_controller_->SetAlrStartTimeMs(start_time);
|
EXPECT_CALL(pacer_, GetApplicationLimitedRegionStartTime())
|
||||||
|
.WillRepeatedly(Return(start_time));
|
||||||
clock_.AdvanceTimeMilliseconds(1000);
|
clock_.AdvanceTimeMilliseconds(1000);
|
||||||
probe_controller_->Process(NowMs());
|
probe_controller_->Process();
|
||||||
probe_controller_->SetEstimatedBitrate(500, NowMs());
|
probe_controller_->SetEstimatedBitrate(500);
|
||||||
testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
|
testing::Mock::VerifyAndClearExpectations(&pacer_);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ProbeControllerTest, PeriodicProbingAfterReset) {
|
TEST_F(ProbeControllerTest, PeriodicProbingAfterReset) {
|
||||||
NiceMock<MockNetworkControllerObserver> local_handler;
|
testing::StrictMock<MockPacedSender> local_pacer;
|
||||||
probe_controller_.reset(new ProbeController(&local_handler));
|
probe_controller_.reset(new ProbeController(&local_pacer, &clock_));
|
||||||
int64_t alr_start_time = clock_.TimeInMilliseconds();
|
int64_t alr_start_time = clock_.TimeInMilliseconds();
|
||||||
|
EXPECT_CALL(local_pacer, GetApplicationLimitedRegionStartTime())
|
||||||
|
.WillRepeatedly(Return(alr_start_time));
|
||||||
|
|
||||||
probe_controller_->SetAlrStartTimeMs(alr_start_time);
|
EXPECT_CALL(local_pacer, CreateProbeCluster(_)).Times(2);
|
||||||
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, NowMs());
|
kMaxBitrateBps);
|
||||||
probe_controller_->Reset(NowMs());
|
probe_controller_->Reset();
|
||||||
|
|
||||||
clock_.AdvanceTimeMilliseconds(10000);
|
clock_.AdvanceTimeMilliseconds(10000);
|
||||||
probe_controller_->Process(NowMs());
|
probe_controller_->Process();
|
||||||
|
|
||||||
EXPECT_CALL(local_handler, OnProbeClusterConfig(_)).Times(2);
|
EXPECT_CALL(local_pacer, CreateProbeCluster(_)).Times(2);
|
||||||
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
probe_controller_->SetBitrates(kMinBitrateBps, kStartBitrateBps,
|
||||||
kMaxBitrateBps, NowMs());
|
kMaxBitrateBps);
|
||||||
|
|
||||||
// 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_handler,
|
EXPECT_CALL(local_pacer, CreateProbeCluster(kStartBitrateBps*2));
|
||||||
OnProbeClusterConfig(DataRateEqBps(kStartBitrateBps * 2)));
|
probe_controller_->Process();
|
||||||
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, NowMs());
|
100 * kMbpsMultiplier);
|
||||||
|
|
||||||
// Verify that probe bitrate is capped at the specified max bitrate.
|
// Verify that probe bitrate is capped at the specified max bitrate
|
||||||
EXPECT_CALL(cluster_handler_,
|
EXPECT_CALL(pacer_, CreateProbeCluster(100 * kMbpsMultiplier));
|
||||||
OnProbeClusterConfig(DataRateEqBps(100 * kMbpsMultiplier)));
|
probe_controller_->SetEstimatedBitrate(60 * kMbpsMultiplier);
|
||||||
probe_controller_->SetEstimatedBitrate(60 * kMbpsMultiplier, NowMs());
|
testing::Mock::VerifyAndClearExpectations(&pacer_);
|
||||||
testing::Mock::VerifyAndClearExpectations(&cluster_handler_);
|
|
||||||
|
|
||||||
// Verify that repeated probes aren't sent.
|
// Verify that repeated probes aren't sent.
|
||||||
EXPECT_CALL(cluster_handler_, OnProbeClusterConfig(_)).Times(0);
|
EXPECT_CALL(pacer_, CreateProbeCluster(_)).Times(0);
|
||||||
probe_controller_->SetEstimatedBitrate(100 * kMbpsMultiplier, NowMs());
|
probe_controller_->SetEstimatedBitrate(100 * kMbpsMultiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace test
|
} // namespace test
|
||||||
|
@ -11,331 +11,142 @@
|
|||||||
#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 <functional>
|
#include <cstdio>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "modules/congestion_controller/include/goog_cc_factory.h"
|
|
||||||
#include "modules/congestion_controller/network_control/include/network_types.h"
|
#include "modules/bitrate_controller/include/bitrate_controller.h"
|
||||||
#include "modules/congestion_controller/network_control/include/network_units.h"
|
#include "modules/congestion_controller/acknowledged_bitrate_estimator.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;
|
||||||
|
|
||||||
const char kPacerPushbackExperiment[] = "WebRTC-PacerPushbackExperiment";
|
// Makes sure that the bitrate and the min, max values are in valid range.
|
||||||
|
static void ClampBitrates(int* bitrate_bps,
|
||||||
bool IsPacerPushbackExperimentEnabled() {
|
int* min_bitrate_bps,
|
||||||
return webrtc::field_trial::IsEnabled(kPacerPushbackExperiment) ||
|
int* max_bitrate_bps) {
|
||||||
(!webrtc::field_trial::IsDisabled(kPacerPushbackExperiment) &&
|
// TODO(holmer): We should make sure the default bitrates are set to 10 kbps,
|
||||||
webrtc::runtime_enabled_features::IsFeatureEnabled(
|
// and that we don't try to set the min bitrate to 0 from any applications.
|
||||||
webrtc::runtime_enabled_features::kDualStreamModeFeatureName));
|
// 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkControllerFactoryInterface::uptr ControllerFactory(
|
std::vector<webrtc::PacketFeedback> ReceivedPacketFeedbackVector(
|
||||||
RtcEventLog* event_log) {
|
const std::vector<webrtc::PacketFeedback>& input) {
|
||||||
return rtc::MakeUnique<GoogCcNetworkControllerFactory>(event_log);
|
std::vector<PacketFeedback> received_packet_feedback_vector;
|
||||||
|
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(std::vector<webrtc::PacketFeedback>* input) {
|
void SortPacketFeedbackVector(
|
||||||
|
std::vector<webrtc::PacketFeedback>* const input) {
|
||||||
|
RTC_DCHECK(input);
|
||||||
std::sort(input->begin(), input->end(), PacketFeedbackComparator());
|
std::sort(input->begin(), input->end(), PacketFeedbackComparator());
|
||||||
}
|
}
|
||||||
|
|
||||||
PacketResult NetworkPacketFeedbackFromRtpPacketFeedback(
|
bool IsPacerPushbackExperimentEnabled() {
|
||||||
const webrtc::PacketFeedback& pf) {
|
return webrtc::field_trial::IsEnabled(kPacerPushbackExperiment) || (
|
||||||
PacketResult feedback;
|
!webrtc::field_trial::IsDisabled(kPacerPushbackExperiment) &&
|
||||||
if (pf.arrival_time_ms == webrtc::PacketFeedback::kNotReceived)
|
webrtc::runtime_enabled_features::IsFeatureEnabled(
|
||||||
feedback.receive_time = Timestamp::Infinity();
|
webrtc::runtime_enabled_features::kDualStreamModeFeatureName));
|
||||||
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_),
|
||||||
pacer_controller_(MakeUnique<PacerController>(pacer_)),
|
last_reported_bitrate_bps_(0),
|
||||||
control_handler(MakeUnique<send_side_cc_internal::ControlHandler>(
|
last_reported_fraction_loss_(0),
|
||||||
pacer_controller_.get(),
|
last_reported_rtt_(0),
|
||||||
clock_)),
|
network_state_(kNetworkUp),
|
||||||
controller_(controller_factory->Create(control_handler.get())),
|
pause_pacer_(false),
|
||||||
process_interval_(controller_factory->GetProcessInterval()),
|
pacer_paused_(false),
|
||||||
|
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),
|
||||||
network_available_(true),
|
pacer_pushback_experiment_(IsPacerPushbackExperimentEnabled()) {
|
||||||
task_queue_(MakeUnique<rtc::TaskQueue>("SendSideCCQueue")) {}
|
delay_based_bwe_->SetMinBitrate(min_bitrate_bps_);
|
||||||
|
if (in_cwnd_experiment_ &&
|
||||||
SendSideCongestionController::~SendSideCongestionController() {
|
!ReadCwndExperimentParameter(&accepted_queue_ms_)) {
|
||||||
// Must be destructed before any objects used by calls on the task queue.
|
RTC_LOG(LS_WARNING) << "Failed to parse parameters for CwndExperiment "
|
||||||
task_queue_.reset();
|
"from field trial string. Experiment disabled.";
|
||||||
|
in_cwnd_experiment_ = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SendSideCongestionController::~SendSideCongestionController() {}
|
||||||
|
|
||||||
void SendSideCongestionController::RegisterPacketFeedbackObserver(
|
void SendSideCongestionController::RegisterPacketFeedbackObserver(
|
||||||
PacketFeedbackObserver* observer) {
|
PacketFeedbackObserver* observer) {
|
||||||
transport_feedback_adapter_.RegisterPacketFeedbackObserver(observer);
|
transport_feedback_adapter_.RegisterPacketFeedbackObserver(observer);
|
||||||
@ -347,84 +158,92 @@ void SendSideCongestionController::DeRegisterPacketFeedbackObserver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SendSideCongestionController::RegisterNetworkObserver(Observer* observer) {
|
void SendSideCongestionController::RegisterNetworkObserver(Observer* observer) {
|
||||||
WaitOnTask([this, observer]() {
|
rtc::CritScope cs(&observer_lock_);
|
||||||
control_handler->RegisterNetworkObserver(observer);
|
RTC_DCHECK(observer_ == nullptr);
|
||||||
});
|
observer_ = observer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendSideCongestionController::DeRegisterNetworkObserver(
|
void SendSideCongestionController::DeRegisterNetworkObserver(
|
||||||
Observer* observer) {
|
Observer* observer) {
|
||||||
WaitOnTask([this, observer]() {
|
rtc::CritScope cs(&observer_lock_);
|
||||||
control_handler->DeRegisterNetworkObserver(observer);
|
RTC_DCHECK_EQ(observer_, 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) {
|
||||||
TargetRateConstraints msg = ConvertConstraints(
|
ClampBitrates(&start_bitrate_bps, &min_bitrate_bps, &max_bitrate_bps);
|
||||||
min_bitrate_bps, max_bitrate_bps, start_bitrate_bps, clock_);
|
bitrate_controller_->SetBitrates(start_bitrate_bps, min_bitrate_bps,
|
||||||
WaitOnTask([this, msg]() { controller_->OnTargetRateConstraints(msg); });
|
max_bitrate_bps);
|
||||||
|
|
||||||
|
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 start_bitrate_bps,
|
int 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);
|
||||||
|
}
|
||||||
|
|
||||||
NetworkRouteChange msg;
|
probe_controller_->Reset();
|
||||||
msg.at_time = Timestamp::ms(clock_->TimeInMilliseconds());
|
probe_controller_->SetBitrates(min_bitrate_bps, bitrate_bps, max_bitrate_bps);
|
||||||
msg.constraints = ConvertConstraints(min_bitrate_bps, max_bitrate_bps,
|
|
||||||
start_bitrate_bps, clock_);
|
MaybeTriggerOnNetworkChanged();
|
||||||
WaitOnTask([this, msg]() {
|
}
|
||||||
controller_->OnNetworkRouteChange(msg);
|
|
||||||
pacer_controller_->OnNetworkRouteChange(msg);
|
BitrateController* SendSideCongestionController::GetBitrateController() const {
|
||||||
});
|
return bitrate_controller_.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SendSideCongestionController::AvailableBandwidth(
|
bool SendSideCongestionController::AvailableBandwidth(
|
||||||
uint32_t* bandwidth) const {
|
uint32_t* bandwidth) const {
|
||||||
// TODO(srte): Remove this interface and push information about bandwidth
|
return bitrate_controller_->AvailableBandwidth(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()
|
||||||
return this;
|
const {
|
||||||
|
return bitrate_controller_.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
RateLimiter* SendSideCongestionController::GetRetransmissionRateLimiter() {
|
RateLimiter* SendSideCongestionController::GetRetransmissionRateLimiter() {
|
||||||
return control_handler->retransmission_rate_limiter();
|
return retransmission_rate_limiter_.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendSideCongestionController::EnablePeriodicAlrProbing(bool enable) {
|
void SendSideCongestionController::EnablePeriodicAlrProbing(bool enable) {
|
||||||
WaitOnTask([this, enable]() {
|
probe_controller_->EnablePeriodicAlrProbing(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 {
|
||||||
// TODO(srte): This should be made less synchronous. Now it grabs a lock in
|
return IsNetworkDown() ? 0 : pacer_->QueueInMs();
|
||||||
// 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 {
|
||||||
@ -439,19 +258,18 @@ 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;
|
{
|
||||||
msg.at_time = Timestamp::ms(clock_->TimeInMilliseconds());
|
rtc::CritScope cs(&network_state_lock_);
|
||||||
msg.network_available = state == kNetworkUp;
|
pause_pacer_ = state == kNetworkDown;
|
||||||
network_available_ = msg.network_available;
|
network_state_ = state;
|
||||||
WaitOnTask([this, msg]() {
|
}
|
||||||
controller_->OnNetworkAvailability(msg);
|
probe_controller_->OnNetworkStateChanged(state);
|
||||||
pacer_controller_->OnNetworkAvailability(msg);
|
MaybeTriggerOnNetworkChanged();
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -463,52 +281,38 @@ 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);
|
||||||
MaybeUpdateOutstandingData();
|
if (in_cwnd_experiment_)
|
||||||
auto packet = transport_feedback_adapter_.GetPacket(sent_packet.packet_id);
|
LimitOutstandingBytes(transport_feedback_adapter_.GetOutstandingBytes());
|
||||||
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) {
|
||||||
int64_t now_ms = clock_->TimeInMilliseconds();
|
rtc::CritScope cs(&bwe_lock_);
|
||||||
RoundTripTimeUpdate report;
|
delay_based_bwe_->OnRttUpdate(avg_rtt_ms, max_rtt_ms);
|
||||||
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() {
|
||||||
const int kMaxProcessInterval = 60 * 1000;
|
return bitrate_controller_->TimeUntilNextProcess();
|
||||||
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() {
|
||||||
int64_t now_ms = clock_->TimeInMilliseconds();
|
bool pause_pacer;
|
||||||
last_process_update_ms_ = now_ms;
|
// TODO(holmer): Once this class is running on a task queue we should
|
||||||
|
// replace this with a task instead.
|
||||||
{
|
{
|
||||||
ProcessInterval msg;
|
rtc::CritScope lock(&network_state_lock_);
|
||||||
msg.at_time = Timestamp::ms(now_ms);
|
pause_pacer = pause_pacer_;
|
||||||
task_queue_->PostTask(
|
|
||||||
[this, msg]() { controller_->OnProcessInterval(msg); });
|
|
||||||
}
|
}
|
||||||
if (control_handler->pacer_configured()) {
|
if (pause_pacer && !pacer_paused_) {
|
||||||
PacerQueueUpdate msg;
|
pacer_->Pause();
|
||||||
msg.expected_queue_time = TimeDelta::ms(pacer_->ExpectedQueueTimeMs());
|
pacer_paused_ = true;
|
||||||
task_queue_->PostTask(
|
} else if (!pause_pacer && pacer_paused_) {
|
||||||
[this, msg]() { control_handler->OnPacerQueueUpdate(msg); });
|
pacer_->Resume();
|
||||||
|
pacer_paused_ = false;
|
||||||
}
|
}
|
||||||
|
bitrate_controller_->Process();
|
||||||
|
probe_controller_->Process();
|
||||||
|
MaybeTriggerOnNetworkChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendSideCongestionController::AddPacket(
|
void SendSideCongestionController::AddPacket(
|
||||||
@ -517,6 +321,7 @@ 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,
|
||||||
@ -526,35 +331,61 @@ 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);
|
||||||
MaybeUpdateOutstandingData();
|
std::vector<PacketFeedback> feedback_vector = ReceivedPacketFeedbackVector(
|
||||||
|
transport_feedback_adapter_.GetTransportFeedbackVector());
|
||||||
std::vector<PacketFeedback> feedback_vector =
|
|
||||||
transport_feedback_adapter_.GetTransportFeedbackVector();
|
|
||||||
SortPacketFeedbackVector(&feedback_vector);
|
SortPacketFeedbackVector(&feedback_vector);
|
||||||
|
|
||||||
if (!feedback_vector.empty()) {
|
bool currently_in_alr =
|
||||||
TransportPacketsFeedback msg;
|
pacer_->GetApplicationLimitedRegionStartTime().has_value();
|
||||||
msg.packet_feedbacks = PacketResultsFromRtpFeedbackVector(feedback_vector);
|
if (was_in_alr_ && !currently_in_alr) {
|
||||||
msg.feedback_time = Timestamp::ms(feedback_time_ms);
|
int64_t now_ms = rtc::TimeMillis();
|
||||||
msg.prior_in_flight = prior_in_flight;
|
acknowledged_bitrate_estimator_->SetAlrEndedTimeMs(now_ms);
|
||||||
msg.data_in_flight =
|
probe_controller_->SetAlrEndedTimeMs(now_ms);
|
||||||
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::MaybeUpdateOutstandingData() {
|
void SendSideCongestionController::LimitOutstandingBytes(
|
||||||
OutstandingData msg;
|
size_t num_outstanding_bytes) {
|
||||||
msg.in_flight_data =
|
RTC_DCHECK(in_cwnd_experiment_);
|
||||||
DataSize::bytes(transport_feedback_adapter_.GetOutstandingBytes());
|
rtc::CritScope lock(&network_state_lock_);
|
||||||
task_queue_->PostTask(
|
rtc::Optional<int64_t> min_rtt_ms =
|
||||||
[this, msg]() { pacer_controller_->OnOutstandingData(msg); });
|
transport_feedback_adapter_.GetMinFeedbackLoopRtt();
|
||||||
|
// 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>
|
||||||
@ -563,99 +394,81 @@ SendSideCongestionController::GetTransportFeedbackVector() const {
|
|||||||
return transport_feedback_adapter_.GetTransportFeedbackVector();
|
return transport_feedback_adapter_.GetTransportFeedbackVector();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendSideCongestionController::WaitOnTasks() {
|
void SendSideCongestionController::MaybeTriggerOnNetworkChanged() {
|
||||||
rtc::Event event(false, false);
|
uint32_t bitrate_bps;
|
||||||
task_queue_->PostTask([&event]() { event.Set(); });
|
uint8_t fraction_loss;
|
||||||
event.Wait(rtc::Event::kForever);
|
int64_t rtt;
|
||||||
}
|
bool estimate_changed = bitrate_controller_->GetNetworkParameters(
|
||||||
|
&bitrate_bps, &fraction_loss, &rtt);
|
||||||
void SendSideCongestionController::WaitOnTask(std::function<void()> closure) {
|
if (estimate_changed) {
|
||||||
rtc::Event done(false, false);
|
pacer_->SetEstimatedBitrate(bitrate_bps);
|
||||||
task_queue_->PostTask(rtc::NewClosure(closure, [&done] { done.Set(); }));
|
probe_controller_->SetEstimatedBitrate(bitrate_bps);
|
||||||
done.Wait(rtc::Event::kForever);
|
retransmission_rate_limiter_->SetMaxRate(bitrate_bps);
|
||||||
}
|
|
||||||
|
|
||||||
void SendSideCongestionController::SetSendBitrateLimits(
|
|
||||||
int64_t min_send_bitrate_bps,
|
|
||||||
int64_t max_padding_bitrate_bps) {
|
|
||||||
WaitOnTask([this, min_send_bitrate_bps, max_padding_bitrate_bps]() {
|
|
||||||
streams_config_.min_pacing_rate = DataRate::bps(min_send_bitrate_bps);
|
|
||||||
streams_config_.max_padding_rate = DataRate::bps(max_padding_bitrate_bps);
|
|
||||||
UpdateStreamsConfig();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void SendSideCongestionController::SetPacingFactor(float pacing_factor) {
|
|
||||||
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 (packets_received_delta < 1)
|
if (!pacer_pushback_experiment_) {
|
||||||
return;
|
bitrate_bps = IsNetworkDown() || IsSendQueueFull() ? 0 : bitrate_bps;
|
||||||
Timestamp now = Timestamp::ms(now_ms);
|
} else {
|
||||||
TransportLossReport msg;
|
if (IsNetworkDown()) {
|
||||||
msg.packets_lost_delta = total_packets_lost_delta;
|
bitrate_bps = 0;
|
||||||
msg.packets_received_delta = packets_received_delta;
|
} else {
|
||||||
msg.receive_time = now;
|
int64_t queue_length_ms = pacer_->ExpectedQueueTimeMs();
|
||||||
msg.start_time = last_report_block_time_;
|
|
||||||
msg.end_time = now;
|
if (queue_length_ms == 0) {
|
||||||
task_queue_->PostTask(
|
encoding_rate_ = 1.0;
|
||||||
[this, msg]() { controller_->OnTransportLossReport(msg); });
|
} else if (queue_length_ms > 50) {
|
||||||
last_report_block_time_ = now;
|
float encoding_rate = 1.0 - queue_length_ms / 1000.0;
|
||||||
|
encoding_rate_ = std::min(encoding_rate_, encoding_rate);
|
||||||
|
encoding_rate_ = std::max(encoding_rate_, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
bitrate_bps *= encoding_rate_;
|
||||||
|
bitrate_bps = bitrate_bps < 50000 ? 0 : bitrate_bps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasNetworkParametersToReportChanged(bitrate_bps, fraction_loss, rtt)) {
|
||||||
|
int64_t probing_interval_ms;
|
||||||
|
{
|
||||||
|
rtc::CritScope cs(&bwe_lock_);
|
||||||
|
probing_interval_ms = delay_based_bwe_->GetExpectedBwePeriodMs();
|
||||||
|
}
|
||||||
|
{
|
||||||
|
rtc::CritScope cs(&observer_lock_);
|
||||||
|
if (observer_) {
|
||||||
|
observer_->OnNetworkChanged(bitrate_bps, fraction_loss, rtt,
|
||||||
|
probing_interval_ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
@ -8,10 +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/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"
|
||||||
@ -32,31 +33,16 @@ 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:
|
||||||
@ -66,15 +52,14 @@ class SendSideCongestionControllerTest : public ::testing::Test {
|
|||||||
|
|
||||||
void SetUp() override {
|
void SetUp() override {
|
||||||
pacer_.reset(new NiceMock<MockPacedSender>());
|
pacer_.reset(new NiceMock<MockPacedSender>());
|
||||||
controller_.reset(new SendSideCongestionControllerForTest(
|
controller_.reset(new SendSideCongestionController(
|
||||||
&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_,
|
EXPECT_CALL(*pacer_, SetEstimatedBitrate(kInitialBitrateBps));
|
||||||
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);
|
||||||
@ -83,9 +68,8 @@ 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 SendSideCongestionControllerForTest(
|
controller_.reset(new SendSideCongestionController(
|
||||||
&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);
|
||||||
}
|
}
|
||||||
@ -153,7 +137,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<SendSideCongestionControllerForTest> controller_;
|
std::unique_ptr<SendSideCongestionController> controller_;
|
||||||
|
|
||||||
rtc::Optional<uint32_t> target_bitrate_bps_;
|
rtc::Optional<uint32_t> target_bitrate_bps_;
|
||||||
};
|
};
|
||||||
@ -164,15 +148,13 @@ TEST_F(SendSideCongestionControllerTest, OnNetworkChanged) {
|
|||||||
controller_->Process();
|
controller_->Process();
|
||||||
|
|
||||||
EXPECT_CALL(observer_, OnNetworkChanged(kInitialBitrateBps * 2, _, _, _));
|
EXPECT_CALL(observer_, OnNetworkChanged(kInitialBitrateBps * 2, _, _, _));
|
||||||
EXPECT_CALL(*pacer_,
|
EXPECT_CALL(*pacer_, SetEstimatedBitrate(kInitialBitrateBps * 2));
|
||||||
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_,
|
EXPECT_CALL(*pacer_, SetEstimatedBitrate(kInitialBitrateBps));
|
||||||
SetPacingRates(kInitialBitrateBps * kDefaultPacingRate, _));
|
|
||||||
bandwidth_observer_->OnReceivedEstimatedBitrate(kInitialBitrateBps);
|
bandwidth_observer_->OnReceivedEstimatedBitrate(kInitialBitrateBps);
|
||||||
clock_.AdvanceTimeMilliseconds(25);
|
clock_.AdvanceTimeMilliseconds(25);
|
||||||
controller_->Process();
|
controller_->Process();
|
||||||
@ -180,14 +162,14 @@ TEST_F(SendSideCongestionControllerTest, OnNetworkChanged) {
|
|||||||
|
|
||||||
TEST_F(SendSideCongestionControllerTest, OnSendQueueFull) {
|
TEST_F(SendSideCongestionControllerTest, OnSendQueueFull) {
|
||||||
EXPECT_CALL(*pacer_, ExpectedQueueTimeMs())
|
EXPECT_CALL(*pacer_, ExpectedQueueTimeMs())
|
||||||
.WillRepeatedly(Return(PacedSender::kMaxQueueLengthMs + 1));
|
.WillOnce(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())
|
||||||
.WillRepeatedly(Return(PacedSender::kMaxQueueLengthMs - 1));
|
.WillOnce(Return(PacedSender::kMaxQueueLengthMs - 1));
|
||||||
|
|
||||||
EXPECT_CALL(observer_, OnNetworkChanged(kInitialBitrateBps, _, _, _));
|
EXPECT_CALL(observer_, OnNetworkChanged(kInitialBitrateBps, _, _, _));
|
||||||
controller_->Process();
|
controller_->Process();
|
||||||
@ -195,24 +177,23 @@ TEST_F(SendSideCongestionControllerTest, OnSendQueueFull) {
|
|||||||
|
|
||||||
TEST_F(SendSideCongestionControllerTest, OnSendQueueFullAndEstimateChange) {
|
TEST_F(SendSideCongestionControllerTest, OnSendQueueFullAndEstimateChange) {
|
||||||
EXPECT_CALL(*pacer_, ExpectedQueueTimeMs())
|
EXPECT_CALL(*pacer_, ExpectedQueueTimeMs())
|
||||||
.WillRepeatedly(Return(PacedSender::kMaxQueueLengthMs + 1));
|
.WillOnce(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())
|
||||||
.WillRepeatedly(Return(PacedSender::kMaxQueueLengthMs + 1));
|
.WillOnce(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_,
|
EXPECT_CALL(*pacer_, SetEstimatedBitrate(kInitialBitrateBps * 2));
|
||||||
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())
|
||||||
.WillRepeatedly(Return(PacedSender::kMaxQueueLengthMs - 1));
|
.WillOnce(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();
|
||||||
@ -233,7 +214,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_, SetPacingRates(new_bitrate * kDefaultPacingRate, _));
|
EXPECT_CALL(*pacer_, SetEstimatedBitrate(new_bitrate));
|
||||||
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);
|
||||||
@ -243,10 +224,8 @@ TEST_F(SendSideCongestionControllerTest, OnNetworkRouteChanged) {
|
|||||||
EXPECT_CALL(
|
EXPECT_CALL(
|
||||||
observer_,
|
observer_,
|
||||||
OnNetworkChanged(congestion_controller::GetMinBitrateBps(), _, _, _));
|
OnNetworkChanged(congestion_controller::GetMinBitrateBps(), _, _, _));
|
||||||
EXPECT_CALL(
|
EXPECT_CALL(*pacer_,
|
||||||
*pacer_,
|
SetEstimatedBitrate(congestion_controller::GetMinBitrateBps()));
|
||||||
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);
|
||||||
}
|
}
|
||||||
@ -255,7 +234,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_, SetPacingRates(new_bitrate * kDefaultPacingRate, _));
|
EXPECT_CALL(*pacer_, SetEstimatedBitrate(new_bitrate));
|
||||||
|
|
||||||
// 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;
|
||||||
@ -288,17 +267,15 @@ TEST_F(SendSideCongestionControllerTest, OldFeedback) {
|
|||||||
EXPECT_CALL(
|
EXPECT_CALL(
|
||||||
observer_,
|
observer_,
|
||||||
OnNetworkChanged(congestion_controller::GetMinBitrateBps(), _, _, _));
|
OnNetworkChanged(congestion_controller::GetMinBitrateBps(), _, _, _));
|
||||||
EXPECT_CALL(
|
EXPECT_CALL(*pacer_,
|
||||||
*pacer_,
|
SetEstimatedBitrate(congestion_controller::GetMinBitrateBps()));
|
||||||
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, _, _, _));
|
||||||
@ -313,15 +290,14 @@ 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_,
|
EXPECT_CALL(*pacer_, SetEstimatedBitrate(kInitialBitrateBps * 2));
|
||||||
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())
|
||||||
.WillRepeatedly(Return(PacedSender::kMaxQueueLengthMs - 1));
|
.WillOnce(Return(PacedSender::kMaxQueueLengthMs - 1));
|
||||||
EXPECT_CALL(observer_, OnNetworkChanged(kInitialBitrateBps * 2, _, _, _));
|
EXPECT_CALL(observer_, OnNetworkChanged(kInitialBitrateBps * 2, _, _, _));
|
||||||
controller_->Process();
|
controller_->Process();
|
||||||
}
|
}
|
||||||
@ -347,7 +323,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_, SetPacingRates(_, _));
|
EXPECT_CALL(*pacer_, SetEstimatedBitrate(_));
|
||||||
bandwidth_observer_->OnReceivedEstimatedBitrate(kInitialBitrateBps * 2);
|
bandwidth_observer_->OnReceivedEstimatedBitrate(kInitialBitrateBps * 2);
|
||||||
clock_.AdvanceTimeMilliseconds(25);
|
clock_.AdvanceTimeMilliseconds(25);
|
||||||
controller_->Process();
|
controller_->Process();
|
||||||
|
@ -50,17 +50,6 @@ 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);
|
||||||
|
@ -33,9 +33,6 @@ 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.
|
||||||
|
@ -52,7 +52,8 @@ 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, kPacingInfo);
|
PacketFeedback packet(now_ms, sequence_number, 1000, i, i - 1,
|
||||||
|
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);
|
||||||
@ -81,26 +82,6 @@ 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;
|
||||||
|
@ -82,12 +82,6 @@ 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_);
|
||||||
@ -124,6 +118,7 @@ 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;
|
||||||
@ -153,6 +148,12 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,6 +165,14 @@ 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;
|
||||||
}
|
}
|
||||||
@ -184,6 +193,11 @@ 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_);
|
||||||
|
@ -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<PacketFeedback> GetPacket(uint16_t sequence_number) const;
|
rtc::Optional<int64_t> GetMinFeedbackLoopRtt() const;
|
||||||
|
|
||||||
void SetTransportOverhead(int transport_overhead_bytes_per_packet);
|
void SetTransportOverhead(int transport_overhead_bytes_per_packet);
|
||||||
|
|
||||||
@ -67,6 +67,8 @@ 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_
|
||||||
|
@ -10,6 +10,8 @@ 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,6 +60,7 @@ 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",
|
||||||
|
@ -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/congestion_controller/alr_detector.h"
|
#include "modules/pacing/alr_detector.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstdio>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
#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,16 +52,7 @@ AlrDetector::AlrDetector(RtcEventLog* event_log)
|
|||||||
|
|
||||||
AlrDetector::~AlrDetector() {}
|
AlrDetector::~AlrDetector() {}
|
||||||
|
|
||||||
void AlrDetector::OnBytesSent(size_t bytes_sent, int64_t send_time_ms) {
|
void AlrDetector::OnBytesSent(size_t bytes_sent, int64_t delta_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;
|
@ -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_CONGESTION_CONTROLLER_ALR_DETECTOR_H_
|
#ifndef MODULES_PACING_ALR_DETECTOR_H_
|
||||||
#define MODULES_CONGESTION_CONTROLLER_ALR_DETECTOR_H_
|
#define MODULES_PACING_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 send_time_ms);
|
void OnBytesSent(size_t bytes_sent, int64_t delta_time_ms);
|
||||||
|
|
||||||
// Set current estimated bandwidth.
|
// Set current estimated bandwidth.
|
||||||
void SetEstimatedBitrate(int bitrate_bps);
|
void SetEstimatedBitrate(int bitrate_bps);
|
||||||
@ -61,8 +61,6 @@ 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_;
|
||||||
|
|
||||||
@ -71,4 +69,4 @@ class AlrDetector {
|
|||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|
||||||
#endif // MODULES_CONGESTION_CONTROLLER_ALR_DETECTOR_H_
|
#endif // MODULES_PACING_ALR_DETECTOR_H_
|
@ -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/congestion_controller/alr_detector.h"
|
#include "modules/pacing/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,9 +25,8 @@ namespace webrtc {
|
|||||||
namespace {
|
namespace {
|
||||||
class SimulateOutgoingTrafficIn {
|
class SimulateOutgoingTrafficIn {
|
||||||
public:
|
public:
|
||||||
explicit SimulateOutgoingTrafficIn(AlrDetector* alr_detector,
|
explicit SimulateOutgoingTrafficIn(AlrDetector* alr_detector)
|
||||||
int64_t* timestamp_ms)
|
: alr_detector_(alr_detector) {
|
||||||
: alr_detector_(alr_detector), timestamp_ms_(timestamp_ms) {
|
|
||||||
RTC_CHECK(alr_detector_);
|
RTC_CHECK(alr_detector_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,21 +48,18 @@ 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),
|
||||||
*timestamp_ms_);
|
kTimeStepMs);
|
||||||
}
|
}
|
||||||
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),
|
||||||
*timestamp_ms_);
|
kTimeStepMs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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_;
|
||||||
};
|
};
|
||||||
@ -77,7 +73,6 @@ 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) {
|
||||||
@ -85,19 +80,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_, ×tamp_ms_)
|
SimulateOutgoingTrafficIn(&alr_detector_)
|
||||||
.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_, ×tamp_ms_)
|
SimulateOutgoingTrafficIn(&alr_detector_)
|
||||||
.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_, ×tamp_ms_)
|
SimulateOutgoingTrafficIn(&alr_detector_)
|
||||||
.ForTimeMs(4000)
|
.ForTimeMs(4000)
|
||||||
.AtPercentOfEstimatedBitrate(100);
|
.AtPercentOfEstimatedBitrate(100);
|
||||||
EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime());
|
EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime());
|
||||||
@ -108,19 +103,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_, ×tamp_ms_)
|
SimulateOutgoingTrafficIn(&alr_detector_)
|
||||||
.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_, ×tamp_ms_)
|
SimulateOutgoingTrafficIn(&alr_detector_)
|
||||||
.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_, ×tamp_ms_)
|
SimulateOutgoingTrafficIn(&alr_detector_)
|
||||||
.ForTimeMs(3000)
|
.ForTimeMs(3000)
|
||||||
.AtPercentOfEstimatedBitrate(100);
|
.AtPercentOfEstimatedBitrate(100);
|
||||||
EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime());
|
EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime());
|
||||||
@ -131,7 +126,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_, ×tamp_ms_)
|
SimulateOutgoingTrafficIn(&alr_detector_)
|
||||||
.ForTimeMs(1000)
|
.ForTimeMs(1000)
|
||||||
.AtPercentOfEstimatedBitrate(20);
|
.AtPercentOfEstimatedBitrate(20);
|
||||||
EXPECT_TRUE(alr_detector_.GetApplicationLimitedRegionStartTime());
|
EXPECT_TRUE(alr_detector_.GetApplicationLimitedRegionStartTime());
|
||||||
@ -142,7 +137,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_, ×tamp_ms_)
|
SimulateOutgoingTrafficIn(&alr_detector_)
|
||||||
.ForTimeMs(1000)
|
.ForTimeMs(1000)
|
||||||
.AtPercentOfEstimatedBitrate(50);
|
.AtPercentOfEstimatedBitrate(50);
|
||||||
EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime());
|
EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime());
|
@ -15,6 +15,7 @@
|
|||||||
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)
|
||||||
@ -34,6 +35,7 @@ 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.
|
||||||
@ -54,8 +56,6 @@ 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_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,10 +30,12 @@ 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_METHOD2(SetPacingRates, void(uint32_t, uint32_t));
|
MOCK_METHOD1(SetEstimatedBitrate, void(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());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#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/pacing/packet_queue.h"
|
#include "modules/pacing/packet_queue.h"
|
||||||
@ -53,6 +54,7 @@ bool IsRoundRobinPacingEnabled() {
|
|||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
const int64_t PacedSender::kMaxQueueLengthMs = 2000;
|
const int64_t PacedSender::kMaxQueueLengthMs = 2000;
|
||||||
|
const float PacedSender::kDefaultPaceMultiplier = 2.5f;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
std::unique_ptr<PacketQueueInterface> CreatePacketQueue(const Clock* clock,
|
std::unique_ptr<PacketQueueInterface> CreatePacketQueue(const Clock* clock,
|
||||||
@ -79,16 +81,21 @@ PacedSender::PacedSender(const Clock* clock,
|
|||||||
std::unique_ptr<PacketQueueInterface> packets)
|
std::unique_ptr<PacketQueueInterface> 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);
|
||||||
@ -109,7 +116,6 @@ 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_)
|
||||||
@ -124,7 +130,6 @@ 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_)
|
||||||
@ -137,12 +142,29 @@ void PacedSender::SetProbingEnabled(bool enabled) {
|
|||||||
prober_->SetEnabled(enabled);
|
prober_->SetEnabled(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PacedSender::SetPacingRates(uint32_t pacing_rate_bps,
|
void PacedSender::SetEstimatedBitrate(uint32_t bitrate_bps) {
|
||||||
uint32_t padding_rate_bps) {
|
if (bitrate_bps == 0)
|
||||||
|
RTC_LOG(LS_ERROR) << "PacedSender is not designed to handle 0 bitrate.";
|
||||||
rtc::CritScope cs(&critsect_);
|
rtc::CritScope cs(&critsect_);
|
||||||
RTC_DCHECK(pacing_rate_bps > 0);
|
estimated_bitrate_bps_ = bitrate_bps;
|
||||||
pacing_bitrate_kbps_ = pacing_rate_bps / 1000;
|
padding_budget_->set_target_rate_kbps(
|
||||||
padding_budget_->set_target_rate_kbps(padding_rate_bps / 1000);
|
std::min(estimated_bitrate_bps_ / 1000, max_padding_bitrate_kbps_));
|
||||||
|
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,
|
||||||
@ -152,8 +174,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(pacing_bitrate_kbps_ > 0)
|
RTC_DCHECK(estimated_bitrate_bps_ > 0)
|
||||||
<< "SetPacingRate must be called before InsertPacket.";
|
<< "SetEstimatedBitrate must be called before InsertPacket.";
|
||||||
|
|
||||||
int64_t now_ms = clock_->TimeInMilliseconds();
|
int64_t now_ms = clock_->TimeInMilliseconds();
|
||||||
prober_->OnIncomingPacket(bytes);
|
prober_->OnIncomingPacket(bytes);
|
||||||
@ -178,6 +200,12 @@ 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();
|
||||||
@ -229,7 +257,8 @@ void PacedSender::Process() {
|
|||||||
// do, timestamps get messed up.
|
// do, timestamps get messed up.
|
||||||
if (packet_counter_ == 0)
|
if (packet_counter_ == 0)
|
||||||
return;
|
return;
|
||||||
SendPadding(1, pacing_info);
|
size_t bytes_sent = SendPadding(1, pacing_info);
|
||||||
|
alr_detector_->OnBytesSent(bytes_sent, elapsed_time_ms);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,7 +291,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() && !paused_) {
|
while (!packets_->Empty()) {
|
||||||
// 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.
|
||||||
@ -290,9 +319,8 @@ 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) {
|
||||||
@ -300,11 +328,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -360,6 +388,14 @@ 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;
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#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;
|
||||||
@ -54,6 +55,12 @@ 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,
|
||||||
@ -79,9 +86,22 @@ class PacedSender : public Pacer {
|
|||||||
// effect.
|
// effect.
|
||||||
void SetProbingEnabled(bool enabled);
|
void SetProbingEnabled(bool enabled);
|
||||||
|
|
||||||
// Sets the pacing rates. Must be called once before packets can be sent.
|
// Sets the estimated capacity of the network. Must be called once before
|
||||||
void SetPacingRates(uint32_t pacing_rate_bps,
|
// packets can be sent.
|
||||||
uint32_t padding_rate_bps) override;
|
// |bitrate_bps| is our estimate of what we are allowed to send on average.
|
||||||
|
// We will pace out bursts of packets at a bitrate of
|
||||||
|
// |bitrate_bps| * kDefaultPaceMultiplier.
|
||||||
|
void SetEstimatedBitrate(uint32_t bitrate_bps) override;
|
||||||
|
|
||||||
|
// Sets the minimum send bitrate and maximum padding bitrate requested by send
|
||||||
|
// 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(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.
|
||||||
@ -111,6 +131,14 @@ 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;
|
||||||
@ -120,6 +148,7 @@ 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:
|
||||||
@ -137,6 +166,7 @@ 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_);
|
||||||
@ -154,6 +184,9 @@ 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_);
|
||||||
@ -162,15 +195,9 @@ class PacedSender : public Pacer {
|
|||||||
const std::unique_ptr<PacketQueueInterface> packets_
|
const std::unique_ptr<PacketQueueInterface> packets_
|
||||||
RTC_PT_GUARDED_BY(critsect_);
|
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;
|
||||||
|
|
||||||
// Lock to avoid race when attaching process thread. This can happen due to
|
float pacing_factor_ RTC_GUARDED_BY(critsect_);
|
||||||
// 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_);
|
||||||
};
|
};
|
||||||
|
@ -31,8 +31,6 @@ 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 {
|
||||||
@ -118,7 +116,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_->SetPacingRates(kTargetBitrateBps * kPaceMultiplier, 0);
|
send_bucket_->SetEstimatedBitrate(kTargetBitrateBps);
|
||||||
|
|
||||||
clock_.AdvanceTimeMilliseconds(send_bucket_->TimeUntilNextProcess());
|
clock_.AdvanceTimeMilliseconds(send_bucket_->TimeUntilNextProcess());
|
||||||
}
|
}
|
||||||
@ -173,7 +171,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 * kPaceMultiplier / (8 * 250 * 200);
|
kTargetBitrateBps * PacedSender::kDefaultPaceMultiplier / (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);
|
||||||
@ -222,7 +220,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 * kPaceMultiplier / (8 * 250 * 200);
|
kTargetBitrateBps * PacedSender::kDefaultPaceMultiplier / (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);
|
||||||
@ -307,14 +305,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_->SetPacingRates(kTargetBitrateBps * kPaceMultiplier,
|
send_bucket_->SetEstimatedBitrate(kTargetBitrateBps);
|
||||||
kTargetBitrateBps);
|
send_bucket_->SetSendBitrateLimits(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 * kPaceMultiplier / (8 * 250 * 200);
|
kTargetBitrateBps * PacedSender::kDefaultPaceMultiplier / (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);
|
||||||
@ -344,8 +342,8 @@ TEST_P(PacedSenderTest, Padding) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(PacedSenderTest, NoPaddingBeforeNormalPacket) {
|
TEST_P(PacedSenderTest, NoPaddingBeforeNormalPacket) {
|
||||||
send_bucket_->SetPacingRates(kTargetBitrateBps * kPaceMultiplier,
|
send_bucket_->SetEstimatedBitrate(kTargetBitrateBps);
|
||||||
kTargetBitrateBps);
|
send_bucket_->SetSendBitrateLimits(kTargetBitrateBps, kTargetBitrateBps);
|
||||||
|
|
||||||
EXPECT_CALL(callback_, TimeToSendPadding(_, _)).Times(0);
|
EXPECT_CALL(callback_, TimeToSendPadding(_, _)).Times(0);
|
||||||
send_bucket_->Process();
|
send_bucket_->Process();
|
||||||
@ -372,8 +370,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_->SetPacingRates(kTargetBitrateBps * kPaceMultiplier,
|
send_bucket_->SetEstimatedBitrate(kTargetBitrateBps);
|
||||||
kTargetBitrateBps);
|
send_bucket_->SetSendBitrateLimits(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) {
|
||||||
@ -400,8 +398,11 @@ 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_->SetPacingRates(kTargetBitrateBps * kPaceMultiplier,
|
send_bucket_->SetEstimatedBitrate(kTargetBitrateBps);
|
||||||
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;
|
||||||
@ -432,7 +433,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 * kPaceMultiplier / (8 * 250 * 200);
|
kTargetBitrateBps * PacedSender::kDefaultPaceMultiplier / (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);
|
||||||
@ -486,7 +487,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 * kPaceMultiplier / (8 * 250 * 200);
|
kTargetBitrateBps * PacedSender::kDefaultPaceMultiplier / (8 * 250 * 200);
|
||||||
send_bucket_->Process();
|
send_bucket_->Process();
|
||||||
EXPECT_EQ(0u, send_bucket_->QueueSizePackets());
|
EXPECT_EQ(0u, send_bucket_->QueueSizePackets());
|
||||||
|
|
||||||
@ -547,7 +548,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 * kPaceMultiplier / (8 * 250 * 200);
|
kTargetBitrateBps * PacedSender::kDefaultPaceMultiplier / (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);
|
||||||
@ -581,7 +582,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 * kPaceMultiplier / (8 * 250 * 200);
|
kTargetBitrateBps * PacedSender::kDefaultPaceMultiplier / (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);
|
||||||
@ -740,10 +741,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 = kPaceMultiplier * 30000;
|
const int32_t kMaxBitrate = PacedSender::kDefaultPaceMultiplier * 30000;
|
||||||
EXPECT_EQ(0, send_bucket_->ExpectedQueueTimeMs());
|
EXPECT_EQ(0, send_bucket_->ExpectedQueueTimeMs());
|
||||||
|
|
||||||
send_bucket_->SetPacingRates(30000 * kPaceMultiplier, 0);
|
send_bucket_->SetEstimatedBitrate(30000);
|
||||||
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);
|
||||||
@ -777,7 +778,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_->SetPacingRates(30000 * kPaceMultiplier, 0);
|
send_bucket_->SetEstimatedBitrate(30000);
|
||||||
SendAndExpectPacket(PacedSender::kNormalPriority,
|
SendAndExpectPacket(PacedSender::kNormalPriority,
|
||||||
ssrc,
|
ssrc,
|
||||||
sequence_number,
|
sequence_number,
|
||||||
@ -801,7 +802,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_->SetPacingRates(kInitialBitrateBps * kPaceMultiplier, 0);
|
send_bucket_->SetEstimatedBitrate(kInitialBitrateBps);
|
||||||
|
|
||||||
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,
|
||||||
@ -846,7 +847,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_->SetPacingRates(kInitialBitrateBps * kPaceMultiplier, 0);
|
send_bucket_->SetEstimatedBitrate(kInitialBitrateBps);
|
||||||
|
|
||||||
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,
|
||||||
@ -934,7 +935,8 @@ TEST_P(PacedSenderTest, PaddingOveruse) {
|
|||||||
const size_t kPacketSize = 1200;
|
const size_t kPacketSize = 1200;
|
||||||
|
|
||||||
send_bucket_->Process();
|
send_bucket_->Process();
|
||||||
send_bucket_->SetPacingRates(60000 * kPaceMultiplier, 0);
|
send_bucket_->SetEstimatedBitrate(60000);
|
||||||
|
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);
|
||||||
@ -943,7 +945,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_->SetPacingRates(60000 * kPaceMultiplier, 30000);
|
send_bucket_->SetSendBitrateLimits(60000, 30000);
|
||||||
|
|
||||||
SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
|
SendAndExpectPacket(PacedSender::kNormalPriority, ssrc, sequence_number++,
|
||||||
clock_.TimeInMilliseconds(), kPacketSize, false);
|
clock_.TimeInMilliseconds(), kPacketSize, false);
|
||||||
@ -961,7 +963,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_->SetPacingRates(kBitrateBps * kPaceMultiplier, 0);
|
send_bucket_->SetEstimatedBitrate(kBitrateBps);
|
||||||
|
|
||||||
EXPECT_EQ(0, send_bucket_->AverageQueueTimeMs());
|
EXPECT_EQ(0, send_bucket_->AverageQueueTimeMs());
|
||||||
|
|
||||||
@ -1006,8 +1008,7 @@ 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_->SetPacingRates(kTargetBitrateBps * kPaceMultiplier,
|
send_bucket_->SetSendBitrateLimits(kTargetBitrateBps, kTargetBitrateBps);
|
||||||
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,
|
||||||
@ -1053,8 +1054,7 @@ 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_->SetPacingRates(kTargetBitrateBps * kPaceMultiplier,
|
send_bucket_->SetSendBitrateLimits(kTargetBitrateBps, kTargetBitrateBps);
|
||||||
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(),
|
||||||
|
@ -17,8 +17,7 @@
|
|||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
class Pacer : public Module, public RtpPacketSender {
|
class Pacer : public Module, public RtpPacketSender {
|
||||||
public:
|
public:
|
||||||
virtual void SetPacingRates(uint32_t pacing_rate_bps,
|
virtual void SetEstimatedBitrate(uint32_t bitrate_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,
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#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"
|
||||||
|
@ -98,6 +98,7 @@ 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())
|
||||||
@ -113,6 +114,7 @@ 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.
|
||||||
@ -221,6 +223,7 @@ 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_) {
|
||||||
|
@ -91,6 +91,7 @@ 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_);
|
||||||
|
@ -477,47 +477,47 @@ TEST_P(BweSimulation, Evaluation8) {
|
|||||||
RunPauseResumeFlows(GetParam());
|
RunPauseResumeFlows(GetParam());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Following test cases begin with "GoogCcComparison" run the
|
// Following test cases begin with "GccComparison" run the
|
||||||
// evaluation test cases for both GoogCc and other calling RMCAT.
|
// evaluation test cases for both GCC and other calling RMCAT.
|
||||||
|
|
||||||
TEST_P(BweSimulation, GoogCcComparison1) {
|
TEST_P(BweSimulation, GccComparison1) {
|
||||||
RunVariableCapacity1SingleFlow(GetParam());
|
RunVariableCapacity1SingleFlow(GetParam());
|
||||||
BweTest goog_cc_test(false);
|
BweTest gcc_test(false);
|
||||||
goog_cc_test.RunVariableCapacity1SingleFlow(kSendSideEstimator);
|
gcc_test.RunVariableCapacity1SingleFlow(kSendSideEstimator);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(BweSimulation, GoogCcComparison2) {
|
TEST_P(BweSimulation, GccComparison2) {
|
||||||
const size_t kNumFlows = 2;
|
const size_t kNumFlows = 2;
|
||||||
RunVariableCapacity2MultipleFlows(GetParam(), kNumFlows);
|
RunVariableCapacity2MultipleFlows(GetParam(), kNumFlows);
|
||||||
BweTest goog_cc_test(false);
|
BweTest gcc_test(false);
|
||||||
goog_cc_test.RunVariableCapacity2MultipleFlows(kSendSideEstimator, kNumFlows);
|
gcc_test.RunVariableCapacity2MultipleFlows(kSendSideEstimator, kNumFlows);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(BweSimulation, GoogCcComparison3) {
|
TEST_P(BweSimulation, GccComparison3) {
|
||||||
RunBidirectionalFlow(GetParam());
|
RunBidirectionalFlow(GetParam());
|
||||||
BweTest goog_cc_test(false);
|
BweTest gcc_test(false);
|
||||||
goog_cc_test.RunBidirectionalFlow(kSendSideEstimator);
|
gcc_test.RunBidirectionalFlow(kSendSideEstimator);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(BweSimulation, GoogCcComparison4) {
|
TEST_P(BweSimulation, GccComparison4) {
|
||||||
RunSelfFairness(GetParam());
|
RunSelfFairness(GetParam());
|
||||||
BweTest goog_cc_test(false);
|
BweTest gcc_test(false);
|
||||||
goog_cc_test.RunSelfFairness(GetParam());
|
gcc_test.RunSelfFairness(GetParam());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(BweSimulation, GoogCcComparison5) {
|
TEST_P(BweSimulation, GccComparison5) {
|
||||||
RunRoundTripTimeFairness(GetParam());
|
RunRoundTripTimeFairness(GetParam());
|
||||||
BweTest goog_cc_test(false);
|
BweTest gcc_test(false);
|
||||||
goog_cc_test.RunRoundTripTimeFairness(kSendSideEstimator);
|
gcc_test.RunRoundTripTimeFairness(kSendSideEstimator);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(BweSimulation, GoogCcComparison6) {
|
TEST_P(BweSimulation, GccComparison6) {
|
||||||
RunLongTcpFairness(GetParam());
|
RunLongTcpFairness(GetParam());
|
||||||
BweTest goog_cc_test(false);
|
BweTest gcc_test(false);
|
||||||
goog_cc_test.RunLongTcpFairness(kSendSideEstimator);
|
gcc_test.RunLongTcpFairness(kSendSideEstimator);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(BweSimulation, GoogCcComparison7) {
|
TEST_P(BweSimulation, GccComparison7) {
|
||||||
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, GoogCcComparison7) {
|
|||||||
RunMultipleShortTcpFairness(GetParam(), tcp_file_sizes_bytes,
|
RunMultipleShortTcpFairness(GetParam(), tcp_file_sizes_bytes,
|
||||||
tcp_starting_times_ms);
|
tcp_starting_times_ms);
|
||||||
|
|
||||||
BweTest goog_cc_test(false);
|
BweTest gcc_test(false);
|
||||||
goog_cc_test.RunMultipleShortTcpFairness(
|
gcc_test.RunMultipleShortTcpFairness(kSendSideEstimator, tcp_file_sizes_bytes,
|
||||||
kSendSideEstimator, tcp_file_sizes_bytes, tcp_starting_times_ms);
|
tcp_starting_times_ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(BweSimulation, GoogCcComparison8) {
|
TEST_P(BweSimulation, GccComparison8) {
|
||||||
RunPauseResumeFlows(GetParam());
|
RunPauseResumeFlows(GetParam());
|
||||||
BweTest goog_cc_test(false);
|
BweTest gcc_test(false);
|
||||||
goog_cc_test.RunPauseResumeFlows(kSendSideEstimator);
|
gcc_test.RunPauseResumeFlows(kSendSideEstimator);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_P(BweSimulation, GoogCcComparisonChoke) {
|
TEST_P(BweSimulation, GccComparisonChoke) {
|
||||||
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 goog_cc_test(false);
|
BweTest gcc_test(false);
|
||||||
goog_cc_test.RunChoke(kSendSideEstimator, capacities_kbps);
|
gcc_test.RunChoke(kSendSideEstimator, capacities_kbps);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace bwe
|
} // namespace bwe
|
||||||
|
@ -181,8 +181,7 @@ enum BandwidthEstimatorType {
|
|||||||
kBbrEstimator
|
kBbrEstimator
|
||||||
};
|
};
|
||||||
|
|
||||||
const char* const bwe_names[] = {"Null", "NADA", "REMB",
|
const char* const bwe_names[] = {"Null", "NADA", "REMB", "GCC", "TCP", "BBR"};
|
||||||
"GoogCc", "TCP", "BBR"};
|
|
||||||
|
|
||||||
int64_t GetAbsSendTimeInMs(uint32_t abs_send_time);
|
int64_t GetAbsSendTimeInMs(uint32_t abs_send_time);
|
||||||
|
|
||||||
|
@ -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)),
|
bwe_(new DelayBasedBwe(nullptr, clock)),
|
||||||
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);
|
bwe_->OnRttUpdate(rtt_ms, 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,8 +80,7 @@ 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);
|
||||||
|
|
||||||
|
@ -24,9 +24,6 @@
|
|||||||
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;
|
||||||
@ -167,7 +164,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_->SetPacingRates(source->bits_per_second() * kPaceMultiplier, 0);
|
pacer_->SetEstimatedBitrate(source->bits_per_second());
|
||||||
}
|
}
|
||||||
|
|
||||||
PacedVideoSender::~PacedVideoSender() {
|
PacedVideoSender::~PacedVideoSender() {
|
||||||
@ -315,7 +312,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_->SetPacingRates(target_bitrate_bps * kPaceMultiplier, 0);
|
pacer_->SetEstimatedBitrate(target_bitrate_bps);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PacedVideoSender::OnNetworkChanged(uint32_t bitrate_for_encoder_bps,
|
void PacedVideoSender::OnNetworkChanged(uint32_t bitrate_for_encoder_bps,
|
||||||
|
@ -231,6 +231,7 @@ 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",
|
||||||
@ -239,8 +240,6 @@ 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/pacing",
|
"../modules/pacing",
|
||||||
"../modules/rtp_rtcp",
|
"../modules/rtp_rtcp",
|
||||||
"../system_wrappers:system_wrappers_default",
|
"../system_wrappers:system_wrappers_default",
|
||||||
|
@ -33,7 +33,6 @@
|
|||||||
#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"
|
||||||
|
@ -839,7 +839,7 @@ VideoSendStreamImpl::VideoSendStreamImpl(
|
|||||||
}
|
}
|
||||||
if (alr_settings) {
|
if (alr_settings) {
|
||||||
transport->send_side_cc()->EnablePeriodicAlrProbing(true);
|
transport->send_side_cc()->EnablePeriodicAlrProbing(true);
|
||||||
transport->send_side_cc()->SetPacingFactor(alr_settings->pacing_factor);
|
transport->pacer()->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);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user