blob: 5362ceec5fa7c3145d5b47cdd8be44e4fa2b99cc [file] [log] [blame]
stefan@webrtc.org792f1a12015-03-04 12:24:26 +00001/*
2 * Copyright (c) 2015 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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020012#include "call/bitrate_allocator.h"
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000013
14#include <algorithm>
Seth Hampsonfe73d6a2017-11-14 10:49:06 -080015#include <cmath>
Alex Narest78609d52017-10-20 10:37:47 +020016#include <memory>
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000017#include <utility>
18
Sebastian Jansson4d461ba2019-09-17 20:53:26 +020019#include "absl/algorithm/container.h"
Sebastian Jansson6736df12018-11-21 19:18:39 +010020#include "api/units/data_rate.h"
21#include "api/units/time_delta.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "rtc_base/checks.h"
23#include "rtc_base/logging.h"
Sebastian Jansson40de3cc2019-09-19 14:54:43 +020024#include "rtc_base/numerics/safe_minmax.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "system_wrappers/include/clock.h"
Ying Wanga646d302018-03-02 17:04:11 +010026#include "system_wrappers/include/field_trial.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020027#include "system_wrappers/include/metrics.h"
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000028
29namespace webrtc {
30
Rasmus Brandt681de202019-02-04 15:09:34 +010031namespace {
32
Stefan Holmere5904162015-03-26 11:11:06 +010033// Allow packets to be transmitted in up to 2 times max video bitrate if the
34// bandwidth estimate allows it.
Ying Wanga646d302018-03-02 17:04:11 +010035const uint8_t kTransmissionMaxBitrateMultiplier = 2;
Stefan Holmere5904162015-03-26 11:11:06 +010036const int kDefaultBitrateBps = 300000;
37
mflodman101f2502016-06-09 17:21:19 +020038// Require a bitrate increase of max(10%, 20kbps) to resume paused streams.
39const double kToggleFactor = 0.1;
40const uint32_t kMinToggleBitrateBps = 20000;
41
mflodman48a4beb2016-07-01 13:03:59 +020042const int64_t kBweLogIntervalMs = 5000;
43
mflodman48a4beb2016-07-01 13:03:59 +020044double MediaRatio(uint32_t allocated_bitrate, uint32_t protection_bitrate) {
kwibergaf476c72016-11-28 15:21:39 -080045 RTC_DCHECK_GT(allocated_bitrate, 0);
mflodman48a4beb2016-07-01 13:03:59 +020046 if (protection_bitrate == 0)
47 return 1.0;
48
49 uint32_t media_bitrate = allocated_bitrate - protection_bitrate;
50 return media_bitrate / static_cast<double>(allocated_bitrate);
51}
Rasmus Brandt681de202019-02-04 15:09:34 +010052
mflodman48a4beb2016-07-01 13:03:59 +020053} // namespace
54
Sebastian Jansson40de3cc2019-09-19 14:54:43 +020055BitrateAllocator::BitrateAllocator(LimitObserver* limit_observer)
perkj71ee44c2016-06-15 00:47:53 -070056 : limit_observer_(limit_observer),
Sebastian Jansson89c94b92018-11-20 17:16:36 +010057 last_target_bps_(0),
Florent Castelli4e615d52019-08-22 16:09:06 +020058 last_stable_target_bps_(0),
59 last_bandwidth_bps_(0),
perkjfea93092016-05-14 00:58:48 -070060 last_non_zero_bitrate_bps_(kDefaultBitrateBps),
Stefan Holmere5904162015-03-26 11:11:06 +010061 last_fraction_loss_(0),
mflodman48a4beb2016-07-01 13:03:59 +020062 last_rtt_(0),
Sebastian Jansson13e59032018-11-21 19:13:07 +010063 last_bwe_period_ms_(1000),
mflodman48a4beb2016-07-01 13:03:59 +020064 num_pause_events_(0),
philipel5ef2bc12017-02-21 07:28:31 -080065 last_bwe_log_time_(0),
Ying Wanga646d302018-03-02 17:04:11 +010066 transmission_max_bitrate_multiplier_(
Jonas Olsson0182a032019-07-09 12:31:20 +020067 GetTransmissionMaxBitrateMultiplier()) {
perkj26091b12016-09-01 01:17:40 -070068 sequenced_checker_.Detach();
69}
mflodman48a4beb2016-07-01 13:03:59 +020070
71BitrateAllocator::~BitrateAllocator() {
asapersson1d02d3e2016-09-09 22:40:25 -070072 RTC_HISTOGRAM_COUNTS_100("WebRTC.Call.NumberOfPauseEvents",
73 num_pause_events_);
mflodman48a4beb2016-07-01 13:03:59 +020074}
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000075
Sebastian Jansson2701bc92018-12-11 15:02:47 +010076void BitrateAllocator::UpdateStartRate(uint32_t start_rate_bps) {
Sebastian Janssonb55015e2019-04-09 13:44:04 +020077 RTC_DCHECK_RUN_ON(&sequenced_checker_);
Sebastian Jansson2701bc92018-12-11 15:02:47 +010078 last_non_zero_bitrate_bps_ = start_rate_bps;
79}
80
Niels Möller74e5f802018-04-25 14:03:46 +020081// static
Ying Wanga646d302018-03-02 17:04:11 +010082uint8_t BitrateAllocator::GetTransmissionMaxBitrateMultiplier() {
83 uint64_t multiplier = strtoul(webrtc::field_trial::FindFullName(
84 "WebRTC-TransmissionMaxBitrateMultiplier")
85 .c_str(),
86 nullptr, 10);
87 if (multiplier > 0 && multiplier <= kTransmissionMaxBitrateMultiplier) {
Ying Wang012b7e72018-03-05 15:44:23 +010088 RTC_LOG(LS_INFO) << "TransmissionMaxBitrateMultiplier is set to "
89 << multiplier;
Ying Wanga646d302018-03-02 17:04:11 +010090 return static_cast<uint8_t>(multiplier);
91 }
92 return kTransmissionMaxBitrateMultiplier;
93}
94
Sebastian Jansson40de3cc2019-09-19 14:54:43 +020095void BitrateAllocator::OnNetworkEstimateChanged(TargetTransferRate msg) {
Sebastian Janssonb55015e2019-04-09 13:44:04 +020096 RTC_DCHECK_RUN_ON(&sequenced_checker_);
Sebastian Jansson40de3cc2019-09-19 14:54:43 +020097 last_target_bps_ = msg.target_rate.bps();
98 last_bandwidth_bps_ = msg.network_estimate.bandwidth.bps();
99 last_stable_target_bps_ = msg.stable_target_rate.bps();
perkjfea93092016-05-14 00:58:48 -0700100 last_non_zero_bitrate_bps_ =
Sebastian Jansson40de3cc2019-09-19 14:54:43 +0200101 last_target_bps_ > 0 ? last_target_bps_ : last_non_zero_bitrate_bps_;
102
103 int loss_ratio_255 = msg.network_estimate.loss_rate_ratio * 255;
104 last_fraction_loss_ =
105 rtc::dchecked_cast<uint8_t>(rtc::SafeClamp(loss_ratio_255, 0, 255));
106 last_rtt_ = msg.network_estimate.round_trip_time.ms();
107 last_bwe_period_ms_ = msg.network_estimate.bwe_period.ms();
mflodman2ebe5b12016-05-13 01:43:51 -0700108
mflodman48a4beb2016-07-01 13:03:59 +0200109 // Periodically log the incoming BWE.
Sebastian Jansson40de3cc2019-09-19 14:54:43 +0200110 int64_t now = msg.at_time.ms();
mflodman48a4beb2016-07-01 13:03:59 +0200111 if (now > last_bwe_log_time_ + kBweLogIntervalMs) {
Sebastian Jansson40de3cc2019-09-19 14:54:43 +0200112 RTC_LOG(LS_INFO) << "Current BWE " << last_target_bps_;
mflodman48a4beb2016-07-01 13:03:59 +0200113 last_bwe_log_time_ = now;
sprang2f48d942015-11-05 04:25:49 -0800114 }
mflodman48a4beb2016-07-01 13:03:59 +0200115
Sebastian Jansson40de3cc2019-09-19 14:54:43 +0200116 ObserverAllocation allocation = AllocateBitrates(last_target_bps_);
117 ObserverAllocation bandwidth_allocation =
118 AllocateBitrates(last_bandwidth_bps_);
Florent Castelli4e615d52019-08-22 16:09:06 +0200119 ObserverAllocation stable_bitrate_allocation =
Sebastian Jansson40de3cc2019-09-19 14:54:43 +0200120 AllocateBitrates(last_stable_target_bps_);
mflodman48a4beb2016-07-01 13:03:59 +0200121
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200122 for (auto& config : allocatable_tracks_) {
mflodman48a4beb2016-07-01 13:03:59 +0200123 uint32_t allocated_bitrate = allocation[config.observer];
Sebastian Jansson89c94b92018-11-20 17:16:36 +0100124 uint32_t allocated_bandwidth = bandwidth_allocation[config.observer];
Florent Castelli4e615d52019-08-22 16:09:06 +0200125 uint32_t allocated_stable_target_rate =
126 stable_bitrate_allocation[config.observer];
Sebastian Jansson13e59032018-11-21 19:13:07 +0100127 BitrateAllocationUpdate update;
128 update.target_bitrate = DataRate::bps(allocated_bitrate);
Florent Castelli4e615d52019-08-22 16:09:06 +0200129 update.stable_target_bitrate = DataRate::bps(allocated_stable_target_rate);
Sebastian Jansson13e59032018-11-21 19:13:07 +0100130 update.link_capacity = DataRate::bps(allocated_bandwidth);
131 update.packet_loss_ratio = last_fraction_loss_ / 256.0;
132 update.round_trip_time = TimeDelta::ms(last_rtt_);
133 update.bwe_period = TimeDelta::ms(last_bwe_period_ms_);
134 uint32_t protection_bitrate = config.observer->OnBitrateUpdated(update);
mflodman48a4beb2016-07-01 13:03:59 +0200135
136 if (allocated_bitrate == 0 && config.allocated_bitrate_bps > 0) {
Sebastian Jansson40de3cc2019-09-19 14:54:43 +0200137 if (last_target_bps_ > 0)
mflodman48a4beb2016-07-01 13:03:59 +0200138 ++num_pause_events_;
139 // The protection bitrate is an estimate based on the ratio between media
140 // and protection used before this observer was muted.
141 uint32_t predicted_protection_bps =
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200142 (1.0 - config.media_ratio) * config.config.min_bitrate_bps;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100143 RTC_LOG(LS_INFO) << "Pausing observer " << config.observer
144 << " with configured min bitrate "
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200145 << config.config.min_bitrate_bps
Sebastian Jansson40de3cc2019-09-19 14:54:43 +0200146 << " and current estimate of " << last_target_bps_
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200147 << " and protection bitrate "
Mirko Bonadei675513b2017-11-09 11:09:25 +0100148 << predicted_protection_bps;
mflodman48a4beb2016-07-01 13:03:59 +0200149 } else if (allocated_bitrate > 0 && config.allocated_bitrate_bps == 0) {
Sebastian Jansson40de3cc2019-09-19 14:54:43 +0200150 if (last_target_bps_ > 0)
mflodman48a4beb2016-07-01 13:03:59 +0200151 ++num_pause_events_;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100152 RTC_LOG(LS_INFO) << "Resuming observer " << config.observer
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200153 << ", configured min bitrate "
154 << config.config.min_bitrate_bps
Mirko Bonadei675513b2017-11-09 11:09:25 +0100155 << ", current allocation " << allocated_bitrate
156 << " and protection bitrate " << protection_bitrate;
mflodman48a4beb2016-07-01 13:03:59 +0200157 }
158
159 // Only update the media ratio if the observer got an allocation.
160 if (allocated_bitrate > 0)
161 config.media_ratio = MediaRatio(allocated_bitrate, protection_bitrate);
162 config.allocated_bitrate_bps = allocated_bitrate;
163 }
philipel5ef2bc12017-02-21 07:28:31 -0800164 UpdateAllocationLimits();
Stefan Holmere5904162015-03-26 11:11:06 +0100165}
166
perkj57c21f92016-06-17 07:27:16 -0700167void BitrateAllocator::AddObserver(BitrateAllocatorObserver* observer,
Sebastian Jansson24ad7202018-04-19 08:25:12 +0200168 MediaStreamAllocationConfig config) {
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200169 RTC_DCHECK_RUN_ON(&sequenced_checker_);
Sebastian Jansson24ad7202018-04-19 08:25:12 +0200170 RTC_DCHECK_GT(config.bitrate_priority, 0);
171 RTC_DCHECK(std::isnormal(config.bitrate_priority));
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200172 auto it = absl::c_find_if(
173 allocatable_tracks_,
174 [observer](const auto& config) { return config.observer == observer; });
mflodman101f2502016-06-09 17:21:19 +0200175 // Update settings if the observer already exists, create a new one otherwise.
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200176 if (it != allocatable_tracks_.end()) {
177 it->config = config;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000178 } else {
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200179 allocatable_tracks_.push_back(AllocatableTrack(observer, config));
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000180 }
Stefan Holmere5904162015-03-26 11:11:06 +0100181
Sebastian Jansson89c94b92018-11-20 17:16:36 +0100182 if (last_target_bps_ > 0) {
mflodman101f2502016-06-09 17:21:19 +0200183 // Calculate a new allocation and update all observers.
Sebastian Jansson89c94b92018-11-20 17:16:36 +0100184
185 ObserverAllocation allocation = AllocateBitrates(last_target_bps_);
186 ObserverAllocation bandwidth_allocation =
Florent Castelli4e615d52019-08-22 16:09:06 +0200187 AllocateBitrates(last_bandwidth_bps_);
188 ObserverAllocation stable_bitrate_allocation =
189 AllocateBitrates(last_stable_target_bps_);
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200190 for (auto& config : allocatable_tracks_) {
mflodman48a4beb2016-07-01 13:03:59 +0200191 uint32_t allocated_bitrate = allocation[config.observer];
Florent Castelli4e615d52019-08-22 16:09:06 +0200192 uint32_t allocated_stable_bitrate =
193 stable_bitrate_allocation[config.observer];
Sebastian Jansson89c94b92018-11-20 17:16:36 +0100194 uint32_t bandwidth = bandwidth_allocation[config.observer];
Sebastian Jansson13e59032018-11-21 19:13:07 +0100195 BitrateAllocationUpdate update;
196 update.target_bitrate = DataRate::bps(allocated_bitrate);
Florent Castelli4e615d52019-08-22 16:09:06 +0200197 update.stable_target_bitrate = DataRate::bps(allocated_stable_bitrate);
Sebastian Jansson13e59032018-11-21 19:13:07 +0100198 update.link_capacity = DataRate::bps(bandwidth);
199 update.packet_loss_ratio = last_fraction_loss_ / 256.0;
200 update.round_trip_time = TimeDelta::ms(last_rtt_);
201 update.bwe_period = TimeDelta::ms(last_bwe_period_ms_);
202 uint32_t protection_bitrate = config.observer->OnBitrateUpdated(update);
mflodman48a4beb2016-07-01 13:03:59 +0200203 config.allocated_bitrate_bps = allocated_bitrate;
204 if (allocated_bitrate > 0)
205 config.media_ratio = MediaRatio(allocated_bitrate, protection_bitrate);
206 }
perkjfea93092016-05-14 00:58:48 -0700207 } else {
208 // Currently, an encoder is not allowed to produce frames.
209 // But we still have to return the initial config bitrate + let the
210 // observer know that it can not produce frames.
Sebastian Jansson13e59032018-11-21 19:13:07 +0100211
212 BitrateAllocationUpdate update;
213 update.target_bitrate = DataRate::Zero();
Florent Castelli4e615d52019-08-22 16:09:06 +0200214 update.stable_target_bitrate = DataRate::Zero();
Sebastian Jansson13e59032018-11-21 19:13:07 +0100215 update.link_capacity = DataRate::Zero();
216 update.packet_loss_ratio = last_fraction_loss_ / 256.0;
217 update.round_trip_time = TimeDelta::ms(last_rtt_);
218 update.bwe_period = TimeDelta::ms(last_bwe_period_ms_);
219 observer->OnBitrateUpdated(update);
Stefan Holmere5904162015-03-26 11:11:06 +0100220 }
perkj71ee44c2016-06-15 00:47:53 -0700221 UpdateAllocationLimits();
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000222}
223
perkj71ee44c2016-06-15 00:47:53 -0700224void BitrateAllocator::UpdateAllocationLimits() {
Sebastian Jansson93b1ea22019-09-18 18:31:52 +0200225 BitrateAllocationLimits limits;
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200226 for (const auto& config : allocatable_tracks_) {
227 uint32_t stream_padding = config.config.pad_up_bitrate_bps;
228 if (config.config.enforce_min_bitrate) {
Sebastian Jansson93b1ea22019-09-18 18:31:52 +0200229 limits.min_allocatable_rate +=
230 DataRate::bps(config.config.min_bitrate_bps);
philipel5ef2bc12017-02-21 07:28:31 -0800231 } else if (config.allocated_bitrate_bps == 0) {
232 stream_padding =
srte1eb051c2017-11-29 11:23:59 +0100233 std::max(config.MinBitrateWithHysteresis(), stream_padding);
perkj71ee44c2016-06-15 00:47:53 -0700234 }
Sebastian Jansson93b1ea22019-09-18 18:31:52 +0200235 limits.max_padding_rate += DataRate::bps(stream_padding);
236 limits.max_allocatable_rate += DataRate::bps(config.config.max_bitrate_bps);
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000237 }
perkj71ee44c2016-06-15 00:47:53 -0700238
Sebastian Jansson93b1ea22019-09-18 18:31:52 +0200239 if (limits.min_allocatable_rate == current_limits_.min_allocatable_rate &&
240 limits.max_allocatable_rate == current_limits_.max_allocatable_rate &&
241 limits.max_padding_rate == current_limits_.max_padding_rate) {
philipel5ef2bc12017-02-21 07:28:31 -0800242 return;
243 }
Sebastian Jansson93b1ea22019-09-18 18:31:52 +0200244 current_limits_ = limits;
philipel5ef2bc12017-02-21 07:28:31 -0800245
Mirko Bonadei675513b2017-11-09 11:09:25 +0100246 RTC_LOG(LS_INFO) << "UpdateAllocationLimits : total_requested_min_bitrate: "
Sebastian Jansson93b1ea22019-09-18 18:31:52 +0200247 << ToString(limits.min_allocatable_rate)
248 << ", total_requested_padding_bitrate: "
249 << ToString(limits.max_padding_rate)
250 << ", total_requested_max_bitrate: "
251 << ToString(limits.max_allocatable_rate);
252
253 limit_observer_->OnAllocationLimitsChanged(limits);
perkj71ee44c2016-06-15 00:47:53 -0700254}
255
256void BitrateAllocator::RemoveObserver(BitrateAllocatorObserver* observer) {
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200257 RTC_DCHECK_RUN_ON(&sequenced_checker_);
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200258 for (auto it = allocatable_tracks_.begin(); it != allocatable_tracks_.end();
259 ++it) {
260 if (it->observer == observer) {
261 allocatable_tracks_.erase(it);
262 break;
263 }
perkj71ee44c2016-06-15 00:47:53 -0700264 }
perkj26091b12016-09-01 01:17:40 -0700265
perkj71ee44c2016-06-15 00:47:53 -0700266 UpdateAllocationLimits();
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000267}
268
Sebastian Jansson44a262a2018-10-24 16:07:20 +0200269int BitrateAllocator::GetStartBitrate(
270 BitrateAllocatorObserver* observer) const {
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200271 RTC_DCHECK_RUN_ON(&sequenced_checker_);
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200272 auto it = absl::c_find_if(
273 allocatable_tracks_,
274 [observer](const auto& config) { return config.observer == observer; });
275 if (it == allocatable_tracks_.end()) {
mflodman48a4beb2016-07-01 13:03:59 +0200276 // This observer hasn't been added yet, just give it its fair share.
277 return last_non_zero_bitrate_bps_ /
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200278 static_cast<int>((allocatable_tracks_.size() + 1));
mflodman48a4beb2016-07-01 13:03:59 +0200279 } else if (it->allocated_bitrate_bps == -1) {
280 // This observer hasn't received an allocation yet, so do the same.
281 return last_non_zero_bitrate_bps_ /
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200282 static_cast<int>(allocatable_tracks_.size());
mflodman48a4beb2016-07-01 13:03:59 +0200283 } else {
284 // This observer already has an allocation.
285 return it->allocated_bitrate_bps;
286 }
perkj57c21f92016-06-17 07:27:16 -0700287}
288
perkjfea93092016-05-14 00:58:48 -0700289BitrateAllocator::ObserverAllocation BitrateAllocator::AllocateBitrates(
Sebastian Jansson44a262a2018-10-24 16:07:20 +0200290 uint32_t bitrate) const {
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200291 if (allocatable_tracks_.empty())
mflodman2ebe5b12016-05-13 01:43:51 -0700292 return ObserverAllocation();
293
perkjfea93092016-05-14 00:58:48 -0700294 if (bitrate == 0)
mflodman2ebe5b12016-05-13 01:43:51 -0700295 return ZeroRateAllocation();
296
297 uint32_t sum_min_bitrates = 0;
mflodman101f2502016-06-09 17:21:19 +0200298 uint32_t sum_max_bitrates = 0;
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200299 for (const auto& observer_config : allocatable_tracks_) {
300 sum_min_bitrates += observer_config.config.min_bitrate_bps;
301 sum_max_bitrates += observer_config.config.max_bitrate_bps;
mflodman101f2502016-06-09 17:21:19 +0200302 }
303
304 // Not enough for all observers to get an allocation, allocate according to:
305 // enforced min bitrate -> allocated bitrate previous round -> restart paused
306 // streams.
307 if (!EnoughBitrateForAllObservers(bitrate, sum_min_bitrates))
perkjfea93092016-05-14 00:58:48 -0700308 return LowRateAllocation(bitrate);
mflodman2ebe5b12016-05-13 01:43:51 -0700309
Seth Hampsonfe73d6a2017-11-14 10:49:06 -0800310 // All observers will get their min bitrate plus a share of the rest. This
311 // share is allocated to each observer based on its bitrate_priority.
mflodman101f2502016-06-09 17:21:19 +0200312 if (bitrate <= sum_max_bitrates)
313 return NormalRateAllocation(bitrate, sum_min_bitrates);
mflodman2ebe5b12016-05-13 01:43:51 -0700314
Ying Wanga646d302018-03-02 17:04:11 +0100315 // All observers will get up to transmission_max_bitrate_multiplier_ x max.
mflodman101f2502016-06-09 17:21:19 +0200316 return MaxRateAllocation(bitrate, sum_max_bitrates);
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000317}
318
Sebastian Jansson44a262a2018-10-24 16:07:20 +0200319BitrateAllocator::ObserverAllocation BitrateAllocator::ZeroRateAllocation()
320 const {
mflodman2ebe5b12016-05-13 01:43:51 -0700321 ObserverAllocation allocation;
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200322 for (const auto& observer_config : allocatable_tracks_)
mflodman2ebe5b12016-05-13 01:43:51 -0700323 allocation[observer_config.observer] = 0;
perkjec81bcd2016-05-11 06:01:13 -0700324 return allocation;
325}
326
mflodman2ebe5b12016-05-13 01:43:51 -0700327BitrateAllocator::ObserverAllocation BitrateAllocator::LowRateAllocation(
Sebastian Jansson44a262a2018-10-24 16:07:20 +0200328 uint32_t bitrate) const {
mflodman2ebe5b12016-05-13 01:43:51 -0700329 ObserverAllocation allocation;
mflodman101f2502016-06-09 17:21:19 +0200330 // Start by allocating bitrate to observers enforcing a min bitrate, hence
331 // remaining_bitrate might turn negative.
332 int64_t remaining_bitrate = bitrate;
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200333 for (const auto& observer_config : allocatable_tracks_) {
mflodman101f2502016-06-09 17:21:19 +0200334 int32_t allocated_bitrate = 0;
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200335 if (observer_config.config.enforce_min_bitrate)
336 allocated_bitrate = observer_config.config.min_bitrate_bps;
mflodman101f2502016-06-09 17:21:19 +0200337
338 allocation[observer_config.observer] = allocated_bitrate;
339 remaining_bitrate -= allocated_bitrate;
340 }
341
342 // Allocate bitrate to all previously active streams.
343 if (remaining_bitrate > 0) {
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200344 for (const auto& observer_config : allocatable_tracks_) {
345 if (observer_config.config.enforce_min_bitrate ||
srte1eb051c2017-11-29 11:23:59 +0100346 observer_config.LastAllocatedBitrate() == 0)
mflodman101f2502016-06-09 17:21:19 +0200347 continue;
348
srte1eb051c2017-11-29 11:23:59 +0100349 uint32_t required_bitrate = observer_config.MinBitrateWithHysteresis();
mflodman48a4beb2016-07-01 13:03:59 +0200350 if (remaining_bitrate >= required_bitrate) {
351 allocation[observer_config.observer] = required_bitrate;
352 remaining_bitrate -= required_bitrate;
mflodman101f2502016-06-09 17:21:19 +0200353 }
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000354 }
355 }
mflodman101f2502016-06-09 17:21:19 +0200356
357 // Allocate bitrate to previously paused streams.
358 if (remaining_bitrate > 0) {
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200359 for (const auto& observer_config : allocatable_tracks_) {
srte1eb051c2017-11-29 11:23:59 +0100360 if (observer_config.LastAllocatedBitrate() != 0)
mflodman101f2502016-06-09 17:21:19 +0200361 continue;
362
363 // Add a hysteresis to avoid toggling.
srte1eb051c2017-11-29 11:23:59 +0100364 uint32_t required_bitrate = observer_config.MinBitrateWithHysteresis();
mflodman101f2502016-06-09 17:21:19 +0200365 if (remaining_bitrate >= required_bitrate) {
366 allocation[observer_config.observer] = required_bitrate;
367 remaining_bitrate -= required_bitrate;
368 }
369 }
370 }
371
372 // Split a possible remainder evenly on all streams with an allocation.
373 if (remaining_bitrate > 0)
374 DistributeBitrateEvenly(remaining_bitrate, false, 1, &allocation);
375
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200376 RTC_DCHECK_EQ(allocation.size(), allocatable_tracks_.size());
Stefan Holmere5904162015-03-26 11:11:06 +0100377 return allocation;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000378}
mflodman101f2502016-06-09 17:21:19 +0200379
Seth Hampsonfe73d6a2017-11-14 10:49:06 -0800380// Allocates the bitrate based on the bitrate priority of each observer. This
381// bitrate priority defines the priority for bitrate to be allocated to that
382// observer in relation to other observers. For example with two observers, if
383// observer 1 had a bitrate_priority = 1.0, and observer 2 has a
384// bitrate_priority = 2.0, the expected behavior is that observer 2 will be
385// allocated twice the bitrate as observer 1 above the each observer's
386// min_bitrate_bps values, until one of the observers hits its max_bitrate_bps.
mflodman101f2502016-06-09 17:21:19 +0200387BitrateAllocator::ObserverAllocation BitrateAllocator::NormalRateAllocation(
388 uint32_t bitrate,
Sebastian Jansson44a262a2018-10-24 16:07:20 +0200389 uint32_t sum_min_bitrates) const {
mflodman101f2502016-06-09 17:21:19 +0200390 ObserverAllocation allocation;
Seth Hampsonfe73d6a2017-11-14 10:49:06 -0800391 ObserverAllocation observers_capacities;
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200392 for (const auto& observer_config : allocatable_tracks_) {
393 allocation[observer_config.observer] =
394 observer_config.config.min_bitrate_bps;
Seth Hampsonfe73d6a2017-11-14 10:49:06 -0800395 observers_capacities[observer_config.observer] =
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200396 observer_config.config.max_bitrate_bps -
397 observer_config.config.min_bitrate_bps;
Seth Hampsonfe73d6a2017-11-14 10:49:06 -0800398 }
mflodman101f2502016-06-09 17:21:19 +0200399
400 bitrate -= sum_min_bitrates;
Sebastian Jansson464a5572019-02-12 13:32:32 +0100401
402 // TODO(srte): Implement fair sharing between prioritized streams, currently
403 // they are treated on a first come first serve basis.
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200404 for (const auto& observer_config : allocatable_tracks_) {
405 int64_t priority_margin = observer_config.config.priority_bitrate_bps -
Sebastian Jansson464a5572019-02-12 13:32:32 +0100406 allocation[observer_config.observer];
407 if (priority_margin > 0 && bitrate > 0) {
408 int64_t extra_bitrate = std::min<int64_t>(priority_margin, bitrate);
409 allocation[observer_config.observer] +=
410 rtc::dchecked_cast<int>(extra_bitrate);
411 observers_capacities[observer_config.observer] -= extra_bitrate;
412 bitrate -= extra_bitrate;
413 }
414 }
415
Seth Hampsonfe73d6a2017-11-14 10:49:06 -0800416 // From the remaining bitrate, allocate a proportional amount to each observer
417 // above the min bitrate already allocated.
mflodman101f2502016-06-09 17:21:19 +0200418 if (bitrate > 0)
Seth Hampsonfe73d6a2017-11-14 10:49:06 -0800419 DistributeBitrateRelatively(bitrate, observers_capacities, &allocation);
mflodman101f2502016-06-09 17:21:19 +0200420
421 return allocation;
422}
423
424BitrateAllocator::ObserverAllocation BitrateAllocator::MaxRateAllocation(
perkj26091b12016-09-01 01:17:40 -0700425 uint32_t bitrate,
Sebastian Jansson44a262a2018-10-24 16:07:20 +0200426 uint32_t sum_max_bitrates) const {
mflodman101f2502016-06-09 17:21:19 +0200427 ObserverAllocation allocation;
428
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200429 for (const auto& observer_config : allocatable_tracks_) {
430 allocation[observer_config.observer] =
431 observer_config.config.max_bitrate_bps;
432 bitrate -= observer_config.config.max_bitrate_bps;
mflodman101f2502016-06-09 17:21:19 +0200433 }
Ying Wanga646d302018-03-02 17:04:11 +0100434 DistributeBitrateEvenly(bitrate, true, transmission_max_bitrate_multiplier_,
mflodman101f2502016-06-09 17:21:19 +0200435 &allocation);
436 return allocation;
437}
438
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200439uint32_t BitrateAllocator::AllocatableTrack::LastAllocatedBitrate() const {
mflodman101f2502016-06-09 17:21:19 +0200440 // Return the configured minimum bitrate for newly added observers, to avoid
441 // requiring an extra high bitrate for the observer to get an allocated
442 // bitrate.
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200443 return allocated_bitrate_bps == -1 ? config.min_bitrate_bps
444 : allocated_bitrate_bps;
mflodman101f2502016-06-09 17:21:19 +0200445}
446
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200447uint32_t BitrateAllocator::AllocatableTrack::MinBitrateWithHysteresis() const {
448 uint32_t min_bitrate = config.min_bitrate_bps;
srte1eb051c2017-11-29 11:23:59 +0100449 if (LastAllocatedBitrate() == 0) {
mflodman101f2502016-06-09 17:21:19 +0200450 min_bitrate += std::max(static_cast<uint32_t>(kToggleFactor * min_bitrate),
451 kMinToggleBitrateBps);
452 }
mflodman48a4beb2016-07-01 13:03:59 +0200453 // Account for protection bitrate used by this observer in the previous
454 // allocation.
455 // Note: the ratio will only be updated when the stream is active, meaning a
456 // paused stream won't get any ratio updates. This might lead to waiting a bit
457 // longer than necessary if the network condition improves, but this is to
458 // avoid too much toggling.
srte1eb051c2017-11-29 11:23:59 +0100459 if (media_ratio > 0.0 && media_ratio < 1.0)
460 min_bitrate += min_bitrate * (1.0 - media_ratio);
mflodman48a4beb2016-07-01 13:03:59 +0200461
mflodman101f2502016-06-09 17:21:19 +0200462 return min_bitrate;
463}
464
Sebastian Jansson44a262a2018-10-24 16:07:20 +0200465void BitrateAllocator::DistributeBitrateEvenly(
466 uint32_t bitrate,
467 bool include_zero_allocations,
468 int max_multiplier,
469 ObserverAllocation* allocation) const {
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200470 RTC_DCHECK_EQ(allocation->size(), allocatable_tracks_.size());
mflodman101f2502016-06-09 17:21:19 +0200471
472 ObserverSortingMap list_max_bitrates;
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200473 for (const auto& observer_config : allocatable_tracks_) {
mflodman101f2502016-06-09 17:21:19 +0200474 if (include_zero_allocations ||
475 allocation->at(observer_config.observer) != 0) {
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200476 list_max_bitrates.insert(std::pair<uint32_t, const AllocatableTrack*>(
477 observer_config.config.max_bitrate_bps, &observer_config));
mflodman101f2502016-06-09 17:21:19 +0200478 }
479 }
480 auto it = list_max_bitrates.begin();
481 while (it != list_max_bitrates.end()) {
kwibergaf476c72016-11-28 15:21:39 -0800482 RTC_DCHECK_GT(bitrate, 0);
mflodman101f2502016-06-09 17:21:19 +0200483 uint32_t extra_allocation =
484 bitrate / static_cast<uint32_t>(list_max_bitrates.size());
485 uint32_t total_allocation =
486 extra_allocation + allocation->at(it->second->observer);
487 bitrate -= extra_allocation;
488 if (total_allocation > max_multiplier * it->first) {
489 // There is more than we can fit for this observer, carry over to the
490 // remaining observers.
491 bitrate += total_allocation - max_multiplier * it->first;
492 total_allocation = max_multiplier * it->first;
493 }
494 // Finally, update the allocation for this observer.
495 allocation->at(it->second->observer) = total_allocation;
496 it = list_max_bitrates.erase(it);
497 }
498}
499
Sebastian Jansson44a262a2018-10-24 16:07:20 +0200500bool BitrateAllocator::EnoughBitrateForAllObservers(
501 uint32_t bitrate,
502 uint32_t sum_min_bitrates) const {
mflodman101f2502016-06-09 17:21:19 +0200503 if (bitrate < sum_min_bitrates)
504 return false;
505
perkj26091b12016-09-01 01:17:40 -0700506 uint32_t extra_bitrate_per_observer =
507 (bitrate - sum_min_bitrates) /
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200508 static_cast<uint32_t>(allocatable_tracks_.size());
509 for (const auto& observer_config : allocatable_tracks_) {
510 if (observer_config.config.min_bitrate_bps + extra_bitrate_per_observer <
srte1eb051c2017-11-29 11:23:59 +0100511 observer_config.MinBitrateWithHysteresis()) {
mflodman101f2502016-06-09 17:21:19 +0200512 return false;
philipel5ef2bc12017-02-21 07:28:31 -0800513 }
mflodman101f2502016-06-09 17:21:19 +0200514 }
515 return true;
516}
Seth Hampsonfe73d6a2017-11-14 10:49:06 -0800517
518void BitrateAllocator::DistributeBitrateRelatively(
519 uint32_t remaining_bitrate,
520 const ObserverAllocation& observers_capacities,
Sebastian Jansson44a262a2018-10-24 16:07:20 +0200521 ObserverAllocation* allocation) const {
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200522 RTC_DCHECK_EQ(allocation->size(), allocatable_tracks_.size());
523 RTC_DCHECK_EQ(observers_capacities.size(), allocatable_tracks_.size());
Seth Hampsonfe73d6a2017-11-14 10:49:06 -0800524
525 struct PriorityRateObserverConfig {
526 PriorityRateObserverConfig(BitrateAllocatorObserver* allocation_key,
527 uint32_t capacity_bps,
528 double bitrate_priority)
529 : allocation_key(allocation_key),
530 capacity_bps(capacity_bps),
531 bitrate_priority(bitrate_priority) {}
532
533 BitrateAllocatorObserver* allocation_key;
534 // The amount of bitrate bps that can be allocated to this observer.
535 uint32_t capacity_bps;
536 double bitrate_priority;
537
538 // We want to sort by which observers will be allocated their full capacity
539 // first. By dividing each observer's capacity by its bitrate priority we
540 // are "normalizing" the capacity of an observer by the rate it will be
541 // filled. This is because the amount allocated is based upon bitrate
542 // priority. We allocate twice as much bitrate to an observer with twice the
543 // bitrate priority of another.
544 bool operator<(const PriorityRateObserverConfig& other) const {
545 return capacity_bps / bitrate_priority <
546 other.capacity_bps / other.bitrate_priority;
547 }
548 };
549
550 double bitrate_priority_sum = 0;
551 std::vector<PriorityRateObserverConfig> priority_rate_observers;
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200552 for (const auto& observer_config : allocatable_tracks_) {
Seth Hampsonfe73d6a2017-11-14 10:49:06 -0800553 uint32_t capacity_bps = observers_capacities.at(observer_config.observer);
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200554 priority_rate_observers.emplace_back(
555 observer_config.observer, capacity_bps,
556 observer_config.config.bitrate_priority);
557 bitrate_priority_sum += observer_config.config.bitrate_priority;
Seth Hampsonfe73d6a2017-11-14 10:49:06 -0800558 }
559
560 // Iterate in the order observers can be allocated their full capacity.
561 std::sort(priority_rate_observers.begin(), priority_rate_observers.end());
562 size_t i;
563 for (i = 0; i < priority_rate_observers.size(); ++i) {
564 const auto& priority_rate_observer = priority_rate_observers[i];
565 // We allocate the full capacity to an observer only if its relative
566 // portion from the remaining bitrate is sufficient to allocate its full
567 // capacity. This means we aren't greedily allocating the full capacity, but
568 // that it is only done when there is also enough bitrate to allocate the
569 // proportional amounts to all other observers.
570 double observer_share =
571 priority_rate_observer.bitrate_priority / bitrate_priority_sum;
572 double allocation_bps = observer_share * remaining_bitrate;
573 bool enough_bitrate = allocation_bps >= priority_rate_observer.capacity_bps;
574 if (!enough_bitrate)
575 break;
576 allocation->at(priority_rate_observer.allocation_key) +=
577 priority_rate_observer.capacity_bps;
578 remaining_bitrate -= priority_rate_observer.capacity_bps;
579 bitrate_priority_sum -= priority_rate_observer.bitrate_priority;
580 }
581
582 // From the remaining bitrate, allocate the proportional amounts to the
583 // observers that aren't allocated their max capacity.
584 for (; i < priority_rate_observers.size(); ++i) {
585 const auto& priority_rate_observer = priority_rate_observers[i];
586 double fraction_allocated =
587 priority_rate_observer.bitrate_priority / bitrate_priority_sum;
588 allocation->at(priority_rate_observer.allocation_key) +=
589 fraction_allocated * remaining_bitrate;
590 }
591}
592
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000593} // namespace webrtc