mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-14 14:20:45 +01:00

Bug: webrtc:342905193 No-Try: True Change-Id: Icc968be43b8830038ea9a1f5f604307220457807 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/361021 Auto-Submit: Florent Castelli <orphis@webrtc.org> Reviewed-by: Harald Alvestrand <hta@webrtc.org> Commit-Queue: Florent Castelli <orphis@webrtc.org> Cr-Commit-Position: refs/heads/main@{#42911}
142 lines
5.2 KiB
C++
142 lines
5.2 KiB
C++
/*
|
|
* Copyright (c) 2024 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
#include "video/rate_utilization_tracker.h"
|
|
|
|
#include <algorithm>
|
|
|
|
namespace webrtc {
|
|
|
|
RateUtilizationTracker::RateUtilizationTracker(
|
|
size_t max_num_encoded_data_points,
|
|
TimeDelta max_duration)
|
|
: max_data_points_(max_num_encoded_data_points),
|
|
max_duration_(max_duration),
|
|
current_rate_(DataRate::Zero()) {
|
|
RTC_CHECK_GE(max_num_encoded_data_points, 0);
|
|
RTC_CHECK_GT(max_duration, TimeDelta::Zero());
|
|
}
|
|
|
|
void RateUtilizationTracker::OnDataRateChanged(DataRate rate, Timestamp time) {
|
|
current_rate_ = rate;
|
|
if (data_points_.empty()) {
|
|
// First entry should be contain first produced data, so just return after
|
|
// setting `current_rate_`.
|
|
return;
|
|
} else {
|
|
RateUsageUpdate& last_data_point = data_points_.back();
|
|
RTC_CHECK_GE(time, last_data_point.time);
|
|
if (last_data_point.time == time) {
|
|
last_data_point.target_rate = rate;
|
|
} else {
|
|
data_points_.push_back({.time = time,
|
|
.target_rate = rate,
|
|
.produced_data = DataSize::Zero()});
|
|
}
|
|
}
|
|
|
|
CullOldData(time);
|
|
}
|
|
|
|
void RateUtilizationTracker::OnDataProduced(DataSize size, Timestamp time) {
|
|
if (data_points_.empty()) {
|
|
data_points_.push_back(
|
|
{.time = time, .target_rate = current_rate_, .produced_data = size});
|
|
} else {
|
|
RateUsageUpdate& last_data_point = data_points_.back();
|
|
RTC_CHECK_GE(time, last_data_point.time);
|
|
if (last_data_point.time == time) {
|
|
last_data_point.produced_data += size;
|
|
} else {
|
|
data_points_.push_back(
|
|
{.time = time, .target_rate = current_rate_, .produced_data = size});
|
|
}
|
|
}
|
|
|
|
CullOldData(time);
|
|
}
|
|
|
|
std::optional<double> RateUtilizationTracker::GetRateUtilizationFactor(
|
|
Timestamp time) const {
|
|
if (data_points_.empty()) {
|
|
return std::nullopt;
|
|
}
|
|
|
|
RTC_CHECK_GE(time, data_points_.back().time);
|
|
DataSize allocated_send_data_size = DataSize::Zero();
|
|
DataSize total_produced_data = DataSize::Zero();
|
|
|
|
// Keep track of the last time data was produced - how much it was and how
|
|
// much rate budget has been allocated since then.
|
|
DataSize data_allocated_for_last_data = DataSize::Zero();
|
|
DataSize size_of_last_data = DataSize::Zero();
|
|
|
|
RTC_DCHECK(!data_points_.front().produced_data.IsZero());
|
|
for (size_t i = 0; i < data_points_.size(); ++i) {
|
|
const RateUsageUpdate& update = data_points_[i];
|
|
total_produced_data += update.produced_data;
|
|
|
|
DataSize allocated_since_previous_data_point =
|
|
i == 0 ? DataSize::Zero()
|
|
: (update.time - data_points_[i - 1].time) *
|
|
data_points_[i - 1].target_rate;
|
|
allocated_send_data_size += allocated_since_previous_data_point;
|
|
|
|
if (update.produced_data.IsZero()) {
|
|
// Just a rate update past the last seen produced data.
|
|
data_allocated_for_last_data =
|
|
std::min(size_of_last_data, data_allocated_for_last_data +
|
|
allocated_since_previous_data_point);
|
|
} else {
|
|
// A newer data point with produced data, reset accumulator for rate
|
|
// allocated past the last data point.
|
|
size_of_last_data = update.produced_data;
|
|
data_allocated_for_last_data = DataSize::Zero();
|
|
}
|
|
}
|
|
|
|
if (allocated_send_data_size.IsZero() && current_rate_.IsZero()) {
|
|
// No allocated rate across all of the data points, ignore.
|
|
return std::nullopt;
|
|
}
|
|
|
|
// Calculate the rate past the very last data point until the polling time.
|
|
const RateUsageUpdate& last_update = data_points_.back();
|
|
DataSize allocated_since_last_data_point =
|
|
(time - last_update.time) * last_update.target_rate;
|
|
|
|
// If the last produced data packet is larger than the accumulated rate
|
|
// allocation window since then, use that data point size instead (minus any
|
|
// data rate accumulated in rate updates after that data point was produced).
|
|
allocated_send_data_size +=
|
|
std::max(allocated_since_last_data_point,
|
|
size_of_last_data - data_allocated_for_last_data);
|
|
|
|
return total_produced_data.bytes<double>() / allocated_send_data_size.bytes();
|
|
}
|
|
|
|
void RateUtilizationTracker::CullOldData(Timestamp time) {
|
|
// Remove data points that are either too old, exceed the limit of number of
|
|
// data points - and make sure the first entry in the list contains actual
|
|
// data produced since we calculate send usage since that time.
|
|
|
|
// We don't allow negative times so always start window at absolute time >= 0.
|
|
const Timestamp oldest_included_time =
|
|
time.ms() > max_duration_.ms() ? time - max_duration_ : Timestamp::Zero();
|
|
|
|
while (!data_points_.empty() &&
|
|
(data_points_.front().time < oldest_included_time ||
|
|
data_points_.size() > max_data_points_ ||
|
|
data_points_.front().produced_data.IsZero())) {
|
|
data_points_.pop_front();
|
|
}
|
|
}
|
|
|
|
} // namespace webrtc
|