• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2016 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/goog_cc/delay_based_bwe.h"
12 
13 #include <algorithm>
14 #include <cstdint>
15 #include <cstdio>
16 #include <memory>
17 #include <string>
18 #include <utility>
19 
20 #include "absl/strings/match.h"
21 #include "api/rtc_event_log/rtc_event.h"
22 #include "api/rtc_event_log/rtc_event_log.h"
23 #include "logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h"
24 #include "modules/congestion_controller/goog_cc/trendline_estimator.h"
25 #include "modules/remote_bitrate_estimator/test/bwe_test_logging.h"
26 #include "rtc_base/checks.h"
27 #include "rtc_base/logging.h"
28 #include "system_wrappers/include/metrics.h"
29 
30 namespace webrtc {
31 namespace {
32 constexpr TimeDelta kStreamTimeOut = TimeDelta::Seconds(2);
33 constexpr int kTimestampGroupLengthMs = 5;
34 constexpr int kAbsSendTimeFraction = 18;
35 constexpr int kAbsSendTimeInterArrivalUpshift = 8;
36 constexpr int kInterArrivalShift =
37     kAbsSendTimeFraction + kAbsSendTimeInterArrivalUpshift;
38 constexpr int kTimestampGroupTicks =
39     (kTimestampGroupLengthMs << kInterArrivalShift) / 1000;
40 constexpr double kTimestampToMs =
41     1000.0 / static_cast<double>(1 << kInterArrivalShift);
42 
43 // This ssrc is used to fulfill the current API but will be removed
44 // after the API has been changed.
45 constexpr uint32_t kFixedSsrc = 0;
46 }  // namespace
47 
48 constexpr char BweIgnoreSmallPacketsSettings::kKey[];
49 constexpr char BweSeparateAudioPacketsSettings::kKey[];
50 
BweIgnoreSmallPacketsSettings(const WebRtcKeyValueConfig * key_value_config)51 BweIgnoreSmallPacketsSettings::BweIgnoreSmallPacketsSettings(
52     const WebRtcKeyValueConfig* key_value_config) {
53   Parser()->Parse(
54       key_value_config->Lookup(BweIgnoreSmallPacketsSettings::kKey));
55 }
56 
57 std::unique_ptr<StructParametersParser>
Parser()58 BweIgnoreSmallPacketsSettings::Parser() {
59   return StructParametersParser::Create("smoothing", &smoothing_factor,     //
60                                         "fraction_large", &fraction_large,  //
61                                         "large", &large_threshold,          //
62                                         "small", &small_threshold);
63 }
64 
BweSeparateAudioPacketsSettings(const WebRtcKeyValueConfig * key_value_config)65 BweSeparateAudioPacketsSettings::BweSeparateAudioPacketsSettings(
66     const WebRtcKeyValueConfig* key_value_config) {
67   Parser()->Parse(
68       key_value_config->Lookup(BweSeparateAudioPacketsSettings::kKey));
69 }
70 
71 std::unique_ptr<StructParametersParser>
Parser()72 BweSeparateAudioPacketsSettings::Parser() {
73   return StructParametersParser::Create(      //
74       "enabled", &enabled,                    //
75       "packet_threshold", &packet_threshold,  //
76       "time_threshold", &time_threshold);
77 }
78 
Result()79 DelayBasedBwe::Result::Result()
80     : updated(false),
81       probe(false),
82       target_bitrate(DataRate::Zero()),
83       recovered_from_overuse(false),
84       backoff_in_alr(false) {}
85 
Result(bool probe,DataRate target_bitrate)86 DelayBasedBwe::Result::Result(bool probe, DataRate target_bitrate)
87     : updated(true),
88       probe(probe),
89       target_bitrate(target_bitrate),
90       recovered_from_overuse(false),
91       backoff_in_alr(false) {}
92 
DelayBasedBwe(const WebRtcKeyValueConfig * key_value_config,RtcEventLog * event_log,NetworkStatePredictor * network_state_predictor)93 DelayBasedBwe::DelayBasedBwe(const WebRtcKeyValueConfig* key_value_config,
94                              RtcEventLog* event_log,
95                              NetworkStatePredictor* network_state_predictor)
96     : event_log_(event_log),
97       key_value_config_(key_value_config),
98       ignore_small_(key_value_config),
99       fraction_large_packets_(0.5),
100       separate_audio_(key_value_config),
101       audio_packets_since_last_video_(0),
102       last_video_packet_recv_time_(Timestamp::MinusInfinity()),
103       network_state_predictor_(network_state_predictor),
104       video_inter_arrival_(),
105       video_delay_detector_(
106           new TrendlineEstimator(key_value_config_, network_state_predictor_)),
107       audio_inter_arrival_(),
108       audio_delay_detector_(
109           new TrendlineEstimator(key_value_config_, network_state_predictor_)),
110       active_delay_detector_(video_delay_detector_.get()),
111       last_seen_packet_(Timestamp::MinusInfinity()),
112       uma_recorded_(false),
113       rate_control_(key_value_config, /*send_side=*/true),
114       prev_bitrate_(DataRate::Zero()),
115       has_once_detected_overuse_(false),
116       prev_state_(BandwidthUsage::kBwNormal),
117       alr_limited_backoff_enabled_(absl::StartsWith(
118           key_value_config->Lookup("WebRTC-Bwe-AlrLimitedBackoff"),
119           "Enabled")) {
120   RTC_LOG(LS_INFO) << "Initialized DelayBasedBwe with small packet filtering "
121                    << ignore_small_.Parser()->Encode()
122                    << ", separate audio overuse detection"
123                    << separate_audio_.Parser()->Encode()
124                    << " and alr limited backoff "
125                    << (alr_limited_backoff_enabled_ ? "enabled" : "disabled");
126 }
127 
~DelayBasedBwe()128 DelayBasedBwe::~DelayBasedBwe() {}
129 
IncomingPacketFeedbackVector(const TransportPacketsFeedback & msg,absl::optional<DataRate> acked_bitrate,absl::optional<DataRate> probe_bitrate,absl::optional<NetworkStateEstimate> network_estimate,bool in_alr)130 DelayBasedBwe::Result DelayBasedBwe::IncomingPacketFeedbackVector(
131     const TransportPacketsFeedback& msg,
132     absl::optional<DataRate> acked_bitrate,
133     absl::optional<DataRate> probe_bitrate,
134     absl::optional<NetworkStateEstimate> network_estimate,
135     bool in_alr) {
136   RTC_DCHECK_RUNS_SERIALIZED(&network_race_);
137 
138   auto packet_feedback_vector = msg.SortedByReceiveTime();
139   // TODO(holmer): An empty feedback vector here likely means that
140   // all acks were too late and that the send time history had
141   // timed out. We should reduce the rate when this occurs.
142   if (packet_feedback_vector.empty()) {
143     RTC_LOG(LS_WARNING) << "Very late feedback received.";
144     return DelayBasedBwe::Result();
145   }
146 
147   if (!uma_recorded_) {
148     RTC_HISTOGRAM_ENUMERATION(kBweTypeHistogram,
149                               BweNames::kSendSideTransportSeqNum,
150                               BweNames::kBweNamesMax);
151     uma_recorded_ = true;
152   }
153   bool delayed_feedback = true;
154   bool recovered_from_overuse = false;
155   BandwidthUsage prev_detector_state = active_delay_detector_->State();
156   for (const auto& packet_feedback : packet_feedback_vector) {
157     delayed_feedback = false;
158     IncomingPacketFeedback(packet_feedback, msg.feedback_time);
159     if (prev_detector_state == BandwidthUsage::kBwUnderusing &&
160         active_delay_detector_->State() == BandwidthUsage::kBwNormal) {
161       recovered_from_overuse = true;
162     }
163     prev_detector_state = active_delay_detector_->State();
164   }
165 
166   if (delayed_feedback) {
167     // TODO(bugs.webrtc.org/10125): Design a better mechanism to safe-guard
168     // against building very large network queues.
169     return Result();
170   }
171   rate_control_.SetInApplicationLimitedRegion(in_alr);
172   rate_control_.SetNetworkStateEstimate(network_estimate);
173   return MaybeUpdateEstimate(acked_bitrate, probe_bitrate,
174                              std::move(network_estimate),
175                              recovered_from_overuse, in_alr, msg.feedback_time);
176 }
177 
IncomingPacketFeedback(const PacketResult & packet_feedback,Timestamp at_time)178 void DelayBasedBwe::IncomingPacketFeedback(const PacketResult& packet_feedback,
179                                            Timestamp at_time) {
180   // Reset if the stream has timed out.
181   if (last_seen_packet_.IsInfinite() ||
182       at_time - last_seen_packet_ > kStreamTimeOut) {
183     video_inter_arrival_.reset(
184         new InterArrival(kTimestampGroupTicks, kTimestampToMs, true));
185     video_delay_detector_.reset(
186         new TrendlineEstimator(key_value_config_, network_state_predictor_));
187     audio_inter_arrival_.reset(
188         new InterArrival(kTimestampGroupTicks, kTimestampToMs, true));
189     audio_delay_detector_.reset(
190         new TrendlineEstimator(key_value_config_, network_state_predictor_));
191     active_delay_detector_ = video_delay_detector_.get();
192   }
193   last_seen_packet_ = at_time;
194 
195   // Ignore "small" packets if many/most packets in the call are "large". The
196   // packet size may have a significant effect on the propagation delay,
197   // especially at low bandwidths. Variations in packet size will then show up
198   // as noise in the delay measurement. By default, we include all packets.
199   DataSize packet_size = packet_feedback.sent_packet.size;
200   if (!ignore_small_.small_threshold.IsZero()) {
201     double is_large =
202         static_cast<double>(packet_size >= ignore_small_.large_threshold);
203     fraction_large_packets_ +=
204         ignore_small_.smoothing_factor * (is_large - fraction_large_packets_);
205     if (packet_size <= ignore_small_.small_threshold &&
206         fraction_large_packets_ >= ignore_small_.fraction_large) {
207       return;
208     }
209   }
210 
211   // As an alternative to ignoring small packets, we can separate audio and
212   // video packets for overuse detection.
213   InterArrival* inter_arrival_for_packet = video_inter_arrival_.get();
214   DelayIncreaseDetectorInterface* delay_detector_for_packet =
215       video_delay_detector_.get();
216   if (separate_audio_.enabled) {
217     if (packet_feedback.sent_packet.audio) {
218       inter_arrival_for_packet = audio_inter_arrival_.get();
219       delay_detector_for_packet = audio_delay_detector_.get();
220       audio_packets_since_last_video_++;
221       if (audio_packets_since_last_video_ > separate_audio_.packet_threshold &&
222           packet_feedback.receive_time - last_video_packet_recv_time_ >
223               separate_audio_.time_threshold) {
224         active_delay_detector_ = audio_delay_detector_.get();
225       }
226     } else {
227       audio_packets_since_last_video_ = 0;
228       last_video_packet_recv_time_ =
229           std::max(last_video_packet_recv_time_, packet_feedback.receive_time);
230       active_delay_detector_ = video_delay_detector_.get();
231     }
232   }
233 
234   uint32_t send_time_24bits =
235       static_cast<uint32_t>(
236           ((static_cast<uint64_t>(packet_feedback.sent_packet.send_time.ms())
237             << kAbsSendTimeFraction) +
238            500) /
239           1000) &
240       0x00FFFFFF;
241   // Shift up send time to use the full 32 bits that inter_arrival works with,
242   // so wrapping works properly.
243   uint32_t timestamp = send_time_24bits << kAbsSendTimeInterArrivalUpshift;
244 
245   uint32_t timestamp_delta = 0;
246   int64_t recv_delta_ms = 0;
247   int size_delta = 0;
248   bool calculated_deltas = inter_arrival_for_packet->ComputeDeltas(
249       timestamp, packet_feedback.receive_time.ms(), at_time.ms(),
250       packet_size.bytes(), &timestamp_delta, &recv_delta_ms, &size_delta);
251   double send_delta_ms = (1000.0 * timestamp_delta) / (1 << kInterArrivalShift);
252   delay_detector_for_packet->Update(recv_delta_ms, send_delta_ms,
253                                     packet_feedback.sent_packet.send_time.ms(),
254                                     packet_feedback.receive_time.ms(),
255                                     packet_size.bytes(), calculated_deltas);
256 }
257 
TriggerOveruse(Timestamp at_time,absl::optional<DataRate> link_capacity)258 DataRate DelayBasedBwe::TriggerOveruse(Timestamp at_time,
259                                        absl::optional<DataRate> link_capacity) {
260   RateControlInput input(BandwidthUsage::kBwOverusing, link_capacity);
261   return rate_control_.Update(&input, at_time);
262 }
263 
MaybeUpdateEstimate(absl::optional<DataRate> acked_bitrate,absl::optional<DataRate> probe_bitrate,absl::optional<NetworkStateEstimate> state_estimate,bool recovered_from_overuse,bool in_alr,Timestamp at_time)264 DelayBasedBwe::Result DelayBasedBwe::MaybeUpdateEstimate(
265     absl::optional<DataRate> acked_bitrate,
266     absl::optional<DataRate> probe_bitrate,
267     absl::optional<NetworkStateEstimate> state_estimate,
268     bool recovered_from_overuse,
269     bool in_alr,
270     Timestamp at_time) {
271   Result result;
272 
273   // Currently overusing the bandwidth.
274   if (active_delay_detector_->State() == BandwidthUsage::kBwOverusing) {
275     if (has_once_detected_overuse_ && in_alr && alr_limited_backoff_enabled_) {
276       if (rate_control_.TimeToReduceFurther(at_time, prev_bitrate_)) {
277         result.updated =
278             UpdateEstimate(at_time, prev_bitrate_, &result.target_bitrate);
279         result.backoff_in_alr = true;
280       }
281     } else if (acked_bitrate &&
282                rate_control_.TimeToReduceFurther(at_time, *acked_bitrate)) {
283       result.updated =
284           UpdateEstimate(at_time, acked_bitrate, &result.target_bitrate);
285     } else if (!acked_bitrate && rate_control_.ValidEstimate() &&
286                rate_control_.InitialTimeToReduceFurther(at_time)) {
287       // Overusing before we have a measured acknowledged bitrate. Reduce send
288       // rate by 50% every 200 ms.
289       // TODO(tschumim): Improve this and/or the acknowledged bitrate estimator
290       // so that we (almost) always have a bitrate estimate.
291       rate_control_.SetEstimate(rate_control_.LatestEstimate() / 2, at_time);
292       result.updated = true;
293       result.probe = false;
294       result.target_bitrate = rate_control_.LatestEstimate();
295     }
296     has_once_detected_overuse_ = true;
297   } else {
298     if (probe_bitrate) {
299       result.probe = true;
300       result.updated = true;
301       result.target_bitrate = *probe_bitrate;
302       rate_control_.SetEstimate(*probe_bitrate, at_time);
303     } else {
304       result.updated =
305           UpdateEstimate(at_time, acked_bitrate, &result.target_bitrate);
306       result.recovered_from_overuse = recovered_from_overuse;
307     }
308   }
309   BandwidthUsage detector_state = active_delay_detector_->State();
310   if ((result.updated && prev_bitrate_ != result.target_bitrate) ||
311       detector_state != prev_state_) {
312     DataRate bitrate = result.updated ? result.target_bitrate : prev_bitrate_;
313 
314     BWE_TEST_LOGGING_PLOT(1, "target_bitrate_bps", at_time.ms(), bitrate.bps());
315 
316     if (event_log_) {
317       event_log_->Log(std::make_unique<RtcEventBweUpdateDelayBased>(
318           bitrate.bps(), detector_state));
319     }
320 
321     prev_bitrate_ = bitrate;
322     prev_state_ = detector_state;
323   }
324   return result;
325 }
326 
UpdateEstimate(Timestamp at_time,absl::optional<DataRate> acked_bitrate,DataRate * target_rate)327 bool DelayBasedBwe::UpdateEstimate(Timestamp at_time,
328                                    absl::optional<DataRate> acked_bitrate,
329                                    DataRate* target_rate) {
330   const RateControlInput input(active_delay_detector_->State(), acked_bitrate);
331   *target_rate = rate_control_.Update(&input, at_time);
332   return rate_control_.ValidEstimate();
333 }
334 
OnRttUpdate(TimeDelta avg_rtt)335 void DelayBasedBwe::OnRttUpdate(TimeDelta avg_rtt) {
336   rate_control_.SetRtt(avg_rtt);
337 }
338 
LatestEstimate(std::vector<uint32_t> * ssrcs,DataRate * bitrate) const339 bool DelayBasedBwe::LatestEstimate(std::vector<uint32_t>* ssrcs,
340                                    DataRate* bitrate) const {
341   // Currently accessed from both the process thread (see
342   // ModuleRtpRtcpImpl::Process()) and the configuration thread (see
343   // Call::GetStats()). Should in the future only be accessed from a single
344   // thread.
345   RTC_DCHECK(ssrcs);
346   RTC_DCHECK(bitrate);
347   if (!rate_control_.ValidEstimate())
348     return false;
349 
350   *ssrcs = {kFixedSsrc};
351   *bitrate = rate_control_.LatestEstimate();
352   return true;
353 }
354 
SetStartBitrate(DataRate start_bitrate)355 void DelayBasedBwe::SetStartBitrate(DataRate start_bitrate) {
356   RTC_LOG(LS_INFO) << "BWE Setting start bitrate to: "
357                    << ToString(start_bitrate);
358   rate_control_.SetStartBitrate(start_bitrate);
359 }
360 
SetMinBitrate(DataRate min_bitrate)361 void DelayBasedBwe::SetMinBitrate(DataRate min_bitrate) {
362   // Called from both the configuration thread and the network thread. Shouldn't
363   // be called from the network thread in the future.
364   rate_control_.SetMinBitrate(min_bitrate);
365 }
366 
GetExpectedBwePeriod() const367 TimeDelta DelayBasedBwe::GetExpectedBwePeriod() const {
368   return rate_control_.GetExpectedBandwidthPeriod();
369 }
370 
SetAlrLimitedBackoffExperiment(bool enabled)371 void DelayBasedBwe::SetAlrLimitedBackoffExperiment(bool enabled) {
372   alr_limited_backoff_enabled_ = enabled;
373 }
374 
375 }  // namespace webrtc
376