blob: ad7125a5a15f5a1cb24b35847b58737a6261d5b2 [file] [log] [blame]
Erik Språngc5922572024-07-04 15:28:521/*
2 * Copyright (c) 2024 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 "video/rate_utilization_tracker.h"
12
13#include <algorithm>
14
15namespace webrtc {
16
17RateUtilizationTracker::RateUtilizationTracker(
18 size_t max_num_encoded_data_points,
19 TimeDelta max_duration)
20 : max_data_points_(max_num_encoded_data_points),
21 max_duration_(max_duration),
22 current_rate_(DataRate::Zero()) {
23 RTC_CHECK_GE(max_num_encoded_data_points, 0);
24 RTC_CHECK_GT(max_duration, TimeDelta::Zero());
25}
26
27void RateUtilizationTracker::OnDataRateChanged(DataRate rate, Timestamp time) {
28 current_rate_ = rate;
29 if (data_points_.empty()) {
30 // First entry should be contain first produced data, so just return after
31 // setting `current_rate_`.
32 return;
33 } else {
34 RateUsageUpdate& last_data_point = data_points_.back();
35 RTC_CHECK_GE(time, last_data_point.time);
36 if (last_data_point.time == time) {
37 last_data_point.target_rate = rate;
38 } else {
39 data_points_.push_back({.time = time,
40 .target_rate = rate,
41 .produced_data = DataSize::Zero()});
42 }
43 }
44
45 CullOldData(time);
46}
47
48void RateUtilizationTracker::OnDataProduced(DataSize size, Timestamp time) {
49 if (data_points_.empty()) {
50 data_points_.push_back(
51 {.time = time, .target_rate = current_rate_, .produced_data = size});
52 } else {
53 RateUsageUpdate& last_data_point = data_points_.back();
54 RTC_CHECK_GE(time, last_data_point.time);
55 if (last_data_point.time == time) {
56 last_data_point.produced_data += size;
57 } else {
58 data_points_.push_back(
59 {.time = time, .target_rate = current_rate_, .produced_data = size});
60 }
61 }
62
63 CullOldData(time);
64}
65
Florent Castelli8037fc62024-08-29 13:00:4066std::optional<double> RateUtilizationTracker::GetRateUtilizationFactor(
Erik Språngc5922572024-07-04 15:28:5267 Timestamp time) const {
68 if (data_points_.empty()) {
Florent Castelli8037fc62024-08-29 13:00:4069 return std::nullopt;
Erik Språngc5922572024-07-04 15:28:5270 }
71
72 RTC_CHECK_GE(time, data_points_.back().time);
73 DataSize allocated_send_data_size = DataSize::Zero();
74 DataSize total_produced_data = DataSize::Zero();
75
76 // Keep track of the last time data was produced - how much it was and how
77 // much rate budget has been allocated since then.
78 DataSize data_allocated_for_last_data = DataSize::Zero();
79 DataSize size_of_last_data = DataSize::Zero();
80
81 RTC_DCHECK(!data_points_.front().produced_data.IsZero());
82 for (size_t i = 0; i < data_points_.size(); ++i) {
83 const RateUsageUpdate& update = data_points_[i];
84 total_produced_data += update.produced_data;
85
86 DataSize allocated_since_previous_data_point =
87 i == 0 ? DataSize::Zero()
88 : (update.time - data_points_[i - 1].time) *
89 data_points_[i - 1].target_rate;
90 allocated_send_data_size += allocated_since_previous_data_point;
91
92 if (update.produced_data.IsZero()) {
93 // Just a rate update past the last seen produced data.
Erik Språng8ac4a462024-07-08 15:54:1394 data_allocated_for_last_data =
95 std::min(size_of_last_data, data_allocated_for_last_data +
96 allocated_since_previous_data_point);
Erik Språngc5922572024-07-04 15:28:5297 } else {
98 // A newer data point with produced data, reset accumulator for rate
99 // allocated past the last data point.
100 size_of_last_data = update.produced_data;
101 data_allocated_for_last_data = DataSize::Zero();
102 }
103 }
104
105 if (allocated_send_data_size.IsZero() && current_rate_.IsZero()) {
106 // No allocated rate across all of the data points, ignore.
Florent Castelli8037fc62024-08-29 13:00:40107 return std::nullopt;
Erik Språngc5922572024-07-04 15:28:52108 }
109
110 // Calculate the rate past the very last data point until the polling time.
111 const RateUsageUpdate& last_update = data_points_.back();
112 DataSize allocated_since_last_data_point =
113 (time - last_update.time) * last_update.target_rate;
114
115 // If the last produced data packet is larger than the accumulated rate
116 // allocation window since then, use that data point size instead (minus any
117 // data rate accumulated in rate updates after that data point was produced).
118 allocated_send_data_size +=
119 std::max(allocated_since_last_data_point,
120 size_of_last_data - data_allocated_for_last_data);
121
122 return total_produced_data.bytes<double>() / allocated_send_data_size.bytes();
123}
124
125void RateUtilizationTracker::CullOldData(Timestamp time) {
126 // Remove data points that are either too old, exceed the limit of number of
127 // data points - and make sure the first entry in the list contains actual
128 // data produced since we calculate send usage since that time.
129
130 // We don't allow negative times so always start window at absolute time >= 0.
131 const Timestamp oldest_included_time =
132 time.ms() > max_duration_.ms() ? time - max_duration_ : Timestamp::Zero();
133
134 while (!data_points_.empty() &&
135 (data_points_.front().time < oldest_included_time ||
136 data_points_.size() > max_data_points_ ||
137 data_points_.front().produced_data.IsZero())) {
138 data_points_.pop_front();
139 }
140}
141
142} // namespace webrtc