blob: 0326a4430ff2c25254e68dd56721f32bceb2d0a6 [file] [log] [blame]
vasilvv8ab2fda2024-09-12 08:48:43 -07001// Copyright 2024 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "quiche/quic/moqt/moqt_bitrate_adjuster.h"
6
7#include <algorithm>
8#include <cstdint>
9
10#include "quiche/quic/core/quic_bandwidth.h"
11#include "quiche/quic/core/quic_time.h"
12#include "quiche/common/platform/api/quiche_logging.h"
13#include "quiche/web_transport/web_transport.h"
14
15namespace moqt {
16
17namespace {
18
19using ::quic::QuicBandwidth;
20using ::quic::QuicTime;
21using ::quic::QuicTimeDelta;
22
23// Whenever adjusting bitrate down, it is set to `kTargetBitrateMultiplier *
24// bw`, where `bw` is typically windowed max bandwidth reported by BBR. The
25// current value selected is a bit arbitrary; ideally, we would adjust down to
26// the application data goodput (i.e. goodput excluding all of the framing
27// overhead), but that would either require us knowing how to compute the
28// framing overhead correctly, or implementing our own application-level goodput
29// monitoring.
30constexpr float kTargetBitrateMultiplier = 0.9f;
31
32// Avoid re-adjusting bitrate within N RTTs after adjusting it. Here, on a
33// typical 20ms connection, 40 RTTs is 800ms. Cap the limit at 3000ms.
34constexpr float kMinTimeBetweenAdjustmentsInRtts = 40;
35constexpr QuicTimeDelta kMaxTimeBetweenAdjustments =
36 QuicTimeDelta::FromSeconds(3);
37
38} // namespace
39
40void MoqtBitrateAdjuster::OnObjectAckReceived(
41 uint64_t /*group_id*/, uint64_t /*object_id*/,
42 QuicTimeDelta delta_from_deadline) {
43 if (delta_from_deadline < QuicTimeDelta::Zero()) {
44 // While adjusting down upon the first sign of packets getting late might
45 // seem aggressive, note that:
46 // - By the time user occurs, this is already a user-visible issue (so, in
47 // some sense, this isn't aggressive enough).
48 // - The adjustment won't happen if we're already bellow `k * max_bw`, so
49 // if the delays are due to other factors like bufferbloat, the measured
50 // bandwidth will likely not result in a downwards adjustment.
51 AttemptAdjustingDown();
52 }
53}
54
55void MoqtBitrateAdjuster::AttemptAdjustingDown() {
56 webtransport::SessionStats stats = session_->GetSessionStats();
57
58 // Wait for a while after doing an adjustment. There are non-trivial costs to
59 // switching, so we should rate limit adjustments.
60 QuicTimeDelta adjustment_delay =
61 QuicTimeDelta(stats.smoothed_rtt * kMinTimeBetweenAdjustmentsInRtts);
62 adjustment_delay = std::min(adjustment_delay, kMaxTimeBetweenAdjustments);
63 QuicTime now = clock_->ApproximateNow();
64 if (now - last_adjustment_time_ < adjustment_delay) {
65 return;
66 }
67
68 // Only adjust downwards.
69 QuicBandwidth target_bandwidth =
70 kTargetBitrateMultiplier *
71 QuicBandwidth::FromBitsPerSecond(stats.estimated_send_rate_bps);
72 QuicBandwidth current_bandwidth = adjustable_->GetCurrentBitrate();
73 if (current_bandwidth <= target_bandwidth) {
74 return;
75 }
76
77 QUICHE_DLOG(INFO) << "Adjusting the bitrate from " << current_bandwidth
78 << " to " << target_bandwidth;
79 bool success = adjustable_->AdjustBitrate(target_bandwidth);
80 if (success) {
81 last_adjustment_time_ = now;
82 }
83}
84
85void MoqtBitrateAdjuster::OnObjectAckSupportKnown(bool supported) {
86 QUICHE_DLOG_IF(WARNING, !supported)
87 << "OBJECT_ACK not supported; bitrate adjustments will not work.";
88}
89
90} // namespace moqt