blob: da22691f5ceaf3c73880216e39a42d340b4cadff [file] [log] [blame]
Sebastian Jansson74c066c2018-10-15 14:31:24 +02001/*
2 * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "modules/congestion_controller/rtp/control_handler.h"
12
13#include "rtc_base/checks.h"
14#include "rtc_base/logging.h"
15#include "rtc_base/numerics/safe_minmax.h"
16#include "system_wrappers/include/field_trial.h"
17
18namespace webrtc {
19namespace {
20
21// When PacerPushbackExperiment is enabled, build-up in the pacer due to
22// the congestion window and/or data spikes reduces encoder allocations.
23const char kPacerPushbackExperiment[] = "WebRTC-PacerPushbackExperiment";
24
25bool IsPacerPushbackExperimentEnabled() {
26 return field_trial::IsEnabled(kPacerPushbackExperiment);
27}
28} // namespace
29CongestionControlHandler::CongestionControlHandler(
30 NetworkChangedObserver* observer,
31 PacedSender* pacer)
32 : observer_(observer),
33 pacer_(pacer),
34 pacer_pushback_experiment_(IsPacerPushbackExperimentEnabled()) {
35 sequenced_checker_.Detach();
36}
37
38CongestionControlHandler::~CongestionControlHandler() {}
39
40void CongestionControlHandler::PostUpdates(NetworkControlUpdate update) {
41 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
42 if (update.congestion_window) {
43 if (update.congestion_window->IsFinite())
44 pacer_->SetCongestionWindow(update.congestion_window->bytes());
45 else
46 pacer_->SetCongestionWindow(PacedSender::kNoCongestionWindow);
47 }
48 if (update.pacer_config) {
49 pacer_->SetPacingRates(update.pacer_config->data_rate().bps(),
50 update.pacer_config->pad_rate().bps());
51 }
52 for (const auto& probe : update.probe_cluster_configs) {
53 int64_t bitrate_bps = probe.target_data_rate.bps();
54 pacer_->CreateProbeCluster(bitrate_bps);
55 }
56 if (update.target_rate) {
57 current_target_rate_msg_ = *update.target_rate;
58 OnNetworkInvalidation();
59 }
60}
61
62void CongestionControlHandler::OnNetworkAvailability(NetworkAvailability msg) {
63 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
64 if (network_available_ != msg.network_available) {
65 network_available_ = msg.network_available;
66 pacer_->UpdateOutstandingData(0);
67 SetPacerState(!msg.network_available);
68 OnNetworkInvalidation();
69 }
70}
71
72void CongestionControlHandler::OnOutstandingData(DataSize in_flight_data) {
73 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
74 pacer_->UpdateOutstandingData(in_flight_data.bytes());
75 OnNetworkInvalidation();
76}
77
78void CongestionControlHandler::OnPacerQueueUpdate(
79 TimeDelta expected_queue_time) {
80 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
81 pacer_expected_queue_ms_ = expected_queue_time.ms();
82 OnNetworkInvalidation();
83}
84
85void CongestionControlHandler::SetPacerState(bool paused) {
86 if (paused && !pacer_paused_)
87 pacer_->Pause();
88 else if (!paused && pacer_paused_)
89 pacer_->Resume();
90 pacer_paused_ = paused;
91}
92
93void CongestionControlHandler::OnNetworkInvalidation() {
94 if (!current_target_rate_msg_.has_value())
95 return;
96
97 uint32_t target_bitrate_bps = current_target_rate_msg_->target_rate.bps();
98 int64_t rtt_ms =
99 current_target_rate_msg_->network_estimate.round_trip_time.ms();
100 float loss_rate_ratio =
101 current_target_rate_msg_->network_estimate.loss_rate_ratio;
102
103 int loss_ratio_255 = loss_rate_ratio * 255;
104 uint8_t fraction_loss =
105 rtc::dchecked_cast<uint8_t>(rtc::SafeClamp(loss_ratio_255, 0, 255));
106
107 int64_t probing_interval_ms =
108 current_target_rate_msg_->network_estimate.bwe_period.ms();
109
110 if (!network_available_) {
111 target_bitrate_bps = 0;
112 } else if (!pacer_pushback_experiment_) {
113 target_bitrate_bps = IsSendQueueFull() ? 0 : target_bitrate_bps;
114 } else {
115 int64_t queue_length_ms = pacer_expected_queue_ms_;
116
117 if (queue_length_ms == 0) {
118 encoding_rate_ratio_ = 1.0;
119 } else if (queue_length_ms > 50) {
120 double encoding_ratio = 1.0 - queue_length_ms / 1000.0;
121 encoding_rate_ratio_ = std::min(encoding_rate_ratio_, encoding_ratio);
122 encoding_rate_ratio_ = std::max(encoding_rate_ratio_, 0.0);
123 }
124
125 target_bitrate_bps *= encoding_rate_ratio_;
126 target_bitrate_bps = target_bitrate_bps < 50000 ? 0 : target_bitrate_bps;
127 }
128 if (HasNetworkParametersToReportChanged(target_bitrate_bps, fraction_loss,
129 rtt_ms)) {
130 observer_->OnNetworkChanged(target_bitrate_bps, fraction_loss, rtt_ms,
131 probing_interval_ms);
132 }
133}
134bool CongestionControlHandler::HasNetworkParametersToReportChanged(
135 int64_t target_bitrate_bps,
136 uint8_t fraction_loss,
137 int64_t rtt_ms) {
138 bool changed = last_reported_target_bitrate_bps_ != target_bitrate_bps ||
139 (target_bitrate_bps > 0 &&
140 (last_reported_fraction_loss_ != fraction_loss ||
141 last_reported_rtt_ms_ != rtt_ms));
142 if (changed &&
143 (last_reported_target_bitrate_bps_ == 0 || target_bitrate_bps == 0)) {
144 RTC_LOG(LS_INFO) << "Bitrate estimate state changed, BWE: "
145 << target_bitrate_bps << " bps.";
146 }
147 last_reported_target_bitrate_bps_ = target_bitrate_bps;
148 last_reported_fraction_loss_ = fraction_loss;
149 last_reported_rtt_ms_ = rtt_ms;
150 return changed;
151}
152
153bool CongestionControlHandler::IsSendQueueFull() const {
154 return pacer_expected_queue_ms_ > PacedSender::kMaxQueueLengthMs;
155}
156
157absl::optional<TargetTransferRate>
158CongestionControlHandler::last_transfer_rate() {
159 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequenced_checker_);
160 return current_target_rate_msg_;
161}
162
163} // namespace webrtc