xref: /aosp_15_r20/external/openscreen/cast/streaming/bandwidth_estimator.h (revision 3f982cf4871df8771c9d4abe6e9a6f8d829b2736)
1*3f982cf4SFabien Sanglard // Copyright 2020 The Chromium Authors. All rights reserved.
2*3f982cf4SFabien Sanglard // Use of this source code is governed by a BSD-style license that can be
3*3f982cf4SFabien Sanglard // found in the LICENSE file.
4*3f982cf4SFabien Sanglard 
5*3f982cf4SFabien Sanglard #ifndef CAST_STREAMING_BANDWIDTH_ESTIMATOR_H_
6*3f982cf4SFabien Sanglard #define CAST_STREAMING_BANDWIDTH_ESTIMATOR_H_
7*3f982cf4SFabien Sanglard 
8*3f982cf4SFabien Sanglard #include <stdint.h>
9*3f982cf4SFabien Sanglard 
10*3f982cf4SFabien Sanglard #include <limits>
11*3f982cf4SFabien Sanglard 
12*3f982cf4SFabien Sanglard #include "platform/api/time.h"
13*3f982cf4SFabien Sanglard 
14*3f982cf4SFabien Sanglard namespace openscreen {
15*3f982cf4SFabien Sanglard namespace cast {
16*3f982cf4SFabien Sanglard 
17*3f982cf4SFabien Sanglard // Tracks send attempts and successful receives, and then computes a total
18*3f982cf4SFabien Sanglard // network bandwith estimate.
19*3f982cf4SFabien Sanglard //
20*3f982cf4SFabien Sanglard // Two metrics are tracked by the BandwidthEstimator, over a "recent history"
21*3f982cf4SFabien Sanglard // time window:
22*3f982cf4SFabien Sanglard //
23*3f982cf4SFabien Sanglard //   1. The number of packets sent during bursts (see SenderPacketRouter for
24*3f982cf4SFabien Sanglard //      explanation of what a "burst" is). These track when the network was
25*3f982cf4SFabien Sanglard //      actually in-use for transmission and the magnitude of each burst. When
26*3f982cf4SFabien Sanglard //      computing bandwidth, the estimator assumes the timeslices where the
27*3f982cf4SFabien Sanglard //      network was not in-use could have been used to send even more bytes at
28*3f982cf4SFabien Sanglard //      the same rate.
29*3f982cf4SFabien Sanglard //
30*3f982cf4SFabien Sanglard //   2. Successful receipt of payload bytes over time, or a lack thereof.
31*3f982cf4SFabien Sanglard //      Packets that include acknowledgements from the Receivers are providing
32*3f982cf4SFabien Sanglard //      proof of the successful receipt of payload bytes. All other packets
33*3f982cf4SFabien Sanglard //      provide proof of network connectivity over time, and are used to
34*3f982cf4SFabien Sanglard //      identify periods of time where nothing was received.
35*3f982cf4SFabien Sanglard //
36*3f982cf4SFabien Sanglard // The BandwidthEstimator assumes a simplified model for streaming over the
37*3f982cf4SFabien Sanglard // network. The model does not include any detailed knowledge about things like
38*3f982cf4SFabien Sanglard // protocol overhead, packet re-transmits, parasitic bufferring, network
39*3f982cf4SFabien Sanglard // reliability, etc. Instead, it automatically accounts for all such things by
40*3f982cf4SFabien Sanglard // looking at what's actually leaving the Senders and what's actually making it
41*3f982cf4SFabien Sanglard // to the Receivers.
42*3f982cf4SFabien Sanglard //
43*3f982cf4SFabien Sanglard // This simplified model does produce some known inaccuracies in the resulting
44*3f982cf4SFabien Sanglard // estimations. If no data has recently been transmitted (or been received),
45*3f982cf4SFabien Sanglard // estimations cannot be provided. If the transmission rate is near (or
46*3f982cf4SFabien Sanglard // exceeding) the network's capacity, the estimations will be very accurate. In
47*3f982cf4SFabien Sanglard // between those two extremes, the logic will tend to under-estimate the
48*3f982cf4SFabien Sanglard // network's capacity. However, those under-estimates will still be far larger
49*3f982cf4SFabien Sanglard // than the current transmission rate.
50*3f982cf4SFabien Sanglard //
51*3f982cf4SFabien Sanglard // Thus, these estimates can be used effectively as a control signal for
52*3f982cf4SFabien Sanglard // congestion control in upstream code modules. The logic computing the media's
53*3f982cf4SFabien Sanglard // encoding target bitrate should be adjusted in realtime using a TCP-like
54*3f982cf4SFabien Sanglard // congestion control algorithm:
55*3f982cf4SFabien Sanglard //
56*3f982cf4SFabien Sanglard //   1. When the estimated bitrate is less than the current encoding target
57*3f982cf4SFabien Sanglard //      bitrate, aggressively and immediately decrease the encoding bitrate.
58*3f982cf4SFabien Sanglard //
59*3f982cf4SFabien Sanglard //   2. When the estimated bitrate is more than the current encoding target
60*3f982cf4SFabien Sanglard //      bitrate, gradually increase the encoding bitrate (up to the maximum
61*3f982cf4SFabien Sanglard //      that is reasonable for the application).
62*3f982cf4SFabien Sanglard class BandwidthEstimator {
63*3f982cf4SFabien Sanglard  public:
64*3f982cf4SFabien Sanglard   // |max_packets_per_timeslice| and |timeslice_duration| should match the burst
65*3f982cf4SFabien Sanglard   // configuration in SenderPacketRouter. |start_time| should be a recent
66*3f982cf4SFabien Sanglard   // point-in-time before the first packet is sent.
67*3f982cf4SFabien Sanglard   BandwidthEstimator(int max_packets_per_timeslice,
68*3f982cf4SFabien Sanglard                      Clock::duration timeslice_duration,
69*3f982cf4SFabien Sanglard                      Clock::time_point start_time);
70*3f982cf4SFabien Sanglard 
71*3f982cf4SFabien Sanglard   ~BandwidthEstimator();
72*3f982cf4SFabien Sanglard 
73*3f982cf4SFabien Sanglard   // Returns the duration of the fixed, recent-history time window over which
74*3f982cf4SFabien Sanglard   // data flows are being tracked.
history_window()75*3f982cf4SFabien Sanglard   Clock::duration history_window() const { return history_window_; }
76*3f982cf4SFabien Sanglard 
77*3f982cf4SFabien Sanglard   // Records |when| burst-sending was active or inactive. For the active case,
78*3f982cf4SFabien Sanglard   // |num_packets_sent| should include all network packets sent, including
79*3f982cf4SFabien Sanglard   // non-payload packets (since both affect the modeled utilization/capacity).
80*3f982cf4SFabien Sanglard   // For the inactive case, this method should be called with zero for
81*3f982cf4SFabien Sanglard   // |num_packets_sent|.
82*3f982cf4SFabien Sanglard   void OnBurstComplete(int num_packets_sent, Clock::time_point when);
83*3f982cf4SFabien Sanglard 
84*3f982cf4SFabien Sanglard   // Records when a RTCP packet was received. It's important for Senders to call
85*3f982cf4SFabien Sanglard   // this any time a packet comes in from the Receivers, even if no payload is
86*3f982cf4SFabien Sanglard   // being acknowledged, since the time windows of "nothing successfully
87*3f982cf4SFabien Sanglard   // received" is also important information to track.
88*3f982cf4SFabien Sanglard   void OnRtcpReceived(Clock::time_point arrival_time,
89*3f982cf4SFabien Sanglard                       Clock::duration estimated_round_trip_time);
90*3f982cf4SFabien Sanglard 
91*3f982cf4SFabien Sanglard   // Records that some number of payload bytes has been acknowledged (i.e.,
92*3f982cf4SFabien Sanglard   // successfully received).
93*3f982cf4SFabien Sanglard   void OnPayloadReceived(int payload_bytes_acknowledged,
94*3f982cf4SFabien Sanglard                          Clock::time_point ack_arrival_time,
95*3f982cf4SFabien Sanglard                          Clock::duration estimated_round_trip_time);
96*3f982cf4SFabien Sanglard 
97*3f982cf4SFabien Sanglard   // Computes the current network bandwith estimate. Returns 0 if this cannot be
98*3f982cf4SFabien Sanglard   // determined due to a lack of sufficiently-recent data.
99*3f982cf4SFabien Sanglard   int ComputeNetworkBandwidth() const;
100*3f982cf4SFabien Sanglard 
101*3f982cf4SFabien Sanglard  private:
102*3f982cf4SFabien Sanglard   // FlowTracker (below) manages a ring buffer of size 256. It simplifies the
103*3f982cf4SFabien Sanglard   // index calculations to use an integer data type where all arithmetic is mod
104*3f982cf4SFabien Sanglard   // 256.
105*3f982cf4SFabien Sanglard   using index_mod_256_t = uint8_t;
106*3f982cf4SFabien Sanglard   static constexpr int kNumTimeslices =
107*3f982cf4SFabien Sanglard       static_cast<int>(std::numeric_limits<index_mod_256_t>::max()) + 1;
108*3f982cf4SFabien Sanglard 
109*3f982cf4SFabien Sanglard   // Tracks volume (e.g., the total number of payload bytes) over a fixed
110*3f982cf4SFabien Sanglard   // recent-history time window. The time window is divided up into a number of
111*3f982cf4SFabien Sanglard   // identical timeslices, each of which represents the total number of bytes
112*3f982cf4SFabien Sanglard   // that flowed during a certain period of time. The data is accumulated in
113*3f982cf4SFabien Sanglard   // ring buffer elements so that old data points drop-off as newer ones (that
114*3f982cf4SFabien Sanglard   // move the history window forward) are added.
115*3f982cf4SFabien Sanglard   class FlowTracker {
116*3f982cf4SFabien Sanglard    public:
117*3f982cf4SFabien Sanglard     FlowTracker(Clock::duration timeslice_duration,
118*3f982cf4SFabien Sanglard                 Clock::time_point begin_time);
119*3f982cf4SFabien Sanglard     ~FlowTracker();
120*3f982cf4SFabien Sanglard 
begin_time()121*3f982cf4SFabien Sanglard     Clock::time_point begin_time() const { return begin_time_; }
end_time()122*3f982cf4SFabien Sanglard     Clock::time_point end_time() const {
123*3f982cf4SFabien Sanglard       return begin_time_ + timeslice_duration_ * kNumTimeslices;
124*3f982cf4SFabien Sanglard     }
125*3f982cf4SFabien Sanglard 
126*3f982cf4SFabien Sanglard     // Advance the end of the time window being tracked such that the
127*3f982cf4SFabien Sanglard     // most-recent timeslice includes |until|. Too-old timeslices are dropped
128*3f982cf4SFabien Sanglard     // and new ones are initialized to a zero amount.
129*3f982cf4SFabien Sanglard     void AdvanceToIncludeTime(Clock::time_point until);
130*3f982cf4SFabien Sanglard 
131*3f982cf4SFabien Sanglard     // Accumulate the given |amount| into the timeslice that includes |when|.
132*3f982cf4SFabien Sanglard     void Accumulate(int32_t amount, Clock::time_point when);
133*3f982cf4SFabien Sanglard 
134*3f982cf4SFabien Sanglard     // Return the sum of all the amounts in recent history. This clamps to the
135*3f982cf4SFabien Sanglard     // valid range of int32_t, if necessary.
136*3f982cf4SFabien Sanglard     int32_t Sum() const;
137*3f982cf4SFabien Sanglard 
138*3f982cf4SFabien Sanglard    private:
139*3f982cf4SFabien Sanglard     const Clock::duration timeslice_duration_;
140*3f982cf4SFabien Sanglard 
141*3f982cf4SFabien Sanglard     // The beginning of the oldest timeslice in the recent-history time window,
142*3f982cf4SFabien Sanglard     // the one pointed to by |tail_|.
143*3f982cf4SFabien Sanglard     Clock::time_point begin_time_;
144*3f982cf4SFabien Sanglard 
145*3f982cf4SFabien Sanglard     // A ring buffer tracking the accumulated amount for each timeslice.
146*3f982cf4SFabien Sanglard     int32_t history_ring_[kNumTimeslices]{};
147*3f982cf4SFabien Sanglard 
148*3f982cf4SFabien Sanglard     // The index of the oldest timeslice in the |history_ring_|. This can also
149*3f982cf4SFabien Sanglard     // be thought of, equivalently, as the index just after the most-recent
150*3f982cf4SFabien Sanglard     // timeslice.
151*3f982cf4SFabien Sanglard     index_mod_256_t tail_ = 0;
152*3f982cf4SFabien Sanglard   };
153*3f982cf4SFabien Sanglard 
154*3f982cf4SFabien Sanglard   // The maximum number of packet sends that could possibly be attempted during
155*3f982cf4SFabien Sanglard   // the recent-history time window.
156*3f982cf4SFabien Sanglard   const int max_packets_per_history_window_;
157*3f982cf4SFabien Sanglard 
158*3f982cf4SFabien Sanglard   // The range of time being tracked.
159*3f982cf4SFabien Sanglard   const Clock::duration history_window_;
160*3f982cf4SFabien Sanglard 
161*3f982cf4SFabien Sanglard   // History tracking for send attempts, and success feeback. These timeseries
162*3f982cf4SFabien Sanglard   // are in terms of when packets have left the Senders.
163*3f982cf4SFabien Sanglard   FlowTracker burst_history_;
164*3f982cf4SFabien Sanglard   FlowTracker feedback_history_;
165*3f982cf4SFabien Sanglard };
166*3f982cf4SFabien Sanglard 
167*3f982cf4SFabien Sanglard }  // namespace cast
168*3f982cf4SFabien Sanglard }  // namespace openscreen
169*3f982cf4SFabien Sanglard 
170*3f982cf4SFabien Sanglard #endif  // CAST_STREAMING_BANDWIDTH_ESTIMATOR_H_
171