blob: 989f70cb0d2295afef265b051c174d465bf87698 [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),
perkjfea93092016-05-14 00:58:48 -070059 last_non_zero_bitrate_bps_(kDefaultBitrateBps),
Stefan Holmere5904162015-03-26 11:11:06 +010060 last_fraction_loss_(0),
mflodman48a4beb2016-07-01 13:03:59 +020061 last_rtt_(0),
Sebastian Jansson13e59032018-11-21 19:13:07 +010062 last_bwe_period_ms_(1000),
mflodman48a4beb2016-07-01 13:03:59 +020063 num_pause_events_(0),
philipel5ef2bc12017-02-21 07:28:31 -080064 last_bwe_log_time_(0),
Ying Wanga646d302018-03-02 17:04:11 +010065 transmission_max_bitrate_multiplier_(
Jonas Olsson0182a032019-07-09 12:31:20 +020066 GetTransmissionMaxBitrateMultiplier()) {
perkj26091b12016-09-01 01:17:40 -070067 sequenced_checker_.Detach();
68}
mflodman48a4beb2016-07-01 13:03:59 +020069
70BitrateAllocator::~BitrateAllocator() {
asapersson1d02d3e2016-09-09 22:40:25 -070071 RTC_HISTOGRAM_COUNTS_100("WebRTC.Call.NumberOfPauseEvents",
72 num_pause_events_);
mflodman48a4beb2016-07-01 13:03:59 +020073}
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000074
Sebastian Jansson2701bc92018-12-11 15:02:47 +010075void BitrateAllocator::UpdateStartRate(uint32_t start_rate_bps) {
Sebastian Janssonb55015e2019-04-09 13:44:04 +020076 RTC_DCHECK_RUN_ON(&sequenced_checker_);
Sebastian Jansson2701bc92018-12-11 15:02:47 +010077 last_non_zero_bitrate_bps_ = start_rate_bps;
78}
79
Niels Möller74e5f802018-04-25 14:03:46 +020080// static
Ying Wanga646d302018-03-02 17:04:11 +010081uint8_t BitrateAllocator::GetTransmissionMaxBitrateMultiplier() {
82 uint64_t multiplier = strtoul(webrtc::field_trial::FindFullName(
83 "WebRTC-TransmissionMaxBitrateMultiplier")
84 .c_str(),
85 nullptr, 10);
86 if (multiplier > 0 && multiplier <= kTransmissionMaxBitrateMultiplier) {
Ying Wang012b7e72018-03-05 15:44:23 +010087 RTC_LOG(LS_INFO) << "TransmissionMaxBitrateMultiplier is set to "
88 << multiplier;
Ying Wanga646d302018-03-02 17:04:11 +010089 return static_cast<uint8_t>(multiplier);
90 }
91 return kTransmissionMaxBitrateMultiplier;
92}
93
Sebastian Jansson40de3cc2019-09-19 14:54:43 +020094void BitrateAllocator::OnNetworkEstimateChanged(TargetTransferRate msg) {
Sebastian Janssonb55015e2019-04-09 13:44:04 +020095 RTC_DCHECK_RUN_ON(&sequenced_checker_);
Sebastian Jansson40de3cc2019-09-19 14:54:43 +020096 last_target_bps_ = msg.target_rate.bps();
Sebastian Jansson40de3cc2019-09-19 14:54:43 +020097 last_stable_target_bps_ = msg.stable_target_rate.bps();
perkjfea93092016-05-14 00:58:48 -070098 last_non_zero_bitrate_bps_ =
Sebastian Jansson40de3cc2019-09-19 14:54:43 +020099 last_target_bps_ > 0 ? last_target_bps_ : last_non_zero_bitrate_bps_;
100
101 int loss_ratio_255 = msg.network_estimate.loss_rate_ratio * 255;
102 last_fraction_loss_ =
103 rtc::dchecked_cast<uint8_t>(rtc::SafeClamp(loss_ratio_255, 0, 255));
104 last_rtt_ = msg.network_estimate.round_trip_time.ms();
105 last_bwe_period_ms_ = msg.network_estimate.bwe_period.ms();
mflodman2ebe5b12016-05-13 01:43:51 -0700106
mflodman48a4beb2016-07-01 13:03:59 +0200107 // Periodically log the incoming BWE.
Sebastian Jansson40de3cc2019-09-19 14:54:43 +0200108 int64_t now = msg.at_time.ms();
mflodman48a4beb2016-07-01 13:03:59 +0200109 if (now > last_bwe_log_time_ + kBweLogIntervalMs) {
Sebastian Jansson40de3cc2019-09-19 14:54:43 +0200110 RTC_LOG(LS_INFO) << "Current BWE " << last_target_bps_;
mflodman48a4beb2016-07-01 13:03:59 +0200111 last_bwe_log_time_ = now;
sprang2f48d942015-11-05 04:25:49 -0800112 }
mflodman48a4beb2016-07-01 13:03:59 +0200113
Sebastian Jansson40de3cc2019-09-19 14:54:43 +0200114 ObserverAllocation allocation = AllocateBitrates(last_target_bps_);
Florent Castelli4e615d52019-08-22 16:09:06 +0200115 ObserverAllocation stable_bitrate_allocation =
Sebastian Jansson40de3cc2019-09-19 14:54:43 +0200116 AllocateBitrates(last_stable_target_bps_);
mflodman48a4beb2016-07-01 13:03:59 +0200117
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200118 for (auto& config : allocatable_tracks_) {
mflodman48a4beb2016-07-01 13:03:59 +0200119 uint32_t allocated_bitrate = allocation[config.observer];
Florent Castelli4e615d52019-08-22 16:09:06 +0200120 uint32_t allocated_stable_target_rate =
121 stable_bitrate_allocation[config.observer];
Sebastian Jansson13e59032018-11-21 19:13:07 +0100122 BitrateAllocationUpdate update;
123 update.target_bitrate = DataRate::bps(allocated_bitrate);
Florent Castelli4e615d52019-08-22 16:09:06 +0200124 update.stable_target_bitrate = DataRate::bps(allocated_stable_target_rate);
Sebastian Jansson13e59032018-11-21 19:13:07 +0100125 update.packet_loss_ratio = last_fraction_loss_ / 256.0;
126 update.round_trip_time = TimeDelta::ms(last_rtt_);
127 update.bwe_period = TimeDelta::ms(last_bwe_period_ms_);
128 uint32_t protection_bitrate = config.observer->OnBitrateUpdated(update);
mflodman48a4beb2016-07-01 13:03:59 +0200129
130 if (allocated_bitrate == 0 && config.allocated_bitrate_bps > 0) {
Sebastian Jansson40de3cc2019-09-19 14:54:43 +0200131 if (last_target_bps_ > 0)
mflodman48a4beb2016-07-01 13:03:59 +0200132 ++num_pause_events_;
133 // The protection bitrate is an estimate based on the ratio between media
134 // and protection used before this observer was muted.
135 uint32_t predicted_protection_bps =
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200136 (1.0 - config.media_ratio) * config.config.min_bitrate_bps;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100137 RTC_LOG(LS_INFO) << "Pausing observer " << config.observer
138 << " with configured min bitrate "
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200139 << config.config.min_bitrate_bps
Sebastian Jansson40de3cc2019-09-19 14:54:43 +0200140 << " and current estimate of " << last_target_bps_
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200141 << " and protection bitrate "
Mirko Bonadei675513b2017-11-09 11:09:25 +0100142 << predicted_protection_bps;
mflodman48a4beb2016-07-01 13:03:59 +0200143 } else if (allocated_bitrate > 0 && config.allocated_bitrate_bps == 0) {
Sebastian Jansson40de3cc2019-09-19 14:54:43 +0200144 if (last_target_bps_ > 0)
mflodman48a4beb2016-07-01 13:03:59 +0200145 ++num_pause_events_;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100146 RTC_LOG(LS_INFO) << "Resuming observer " << config.observer
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200147 << ", configured min bitrate "
148 << config.config.min_bitrate_bps
Mirko Bonadei675513b2017-11-09 11:09:25 +0100149 << ", current allocation " << allocated_bitrate
150 << " and protection bitrate " << protection_bitrate;
mflodman48a4beb2016-07-01 13:03:59 +0200151 }
152
153 // Only update the media ratio if the observer got an allocation.
154 if (allocated_bitrate > 0)
155 config.media_ratio = MediaRatio(allocated_bitrate, protection_bitrate);
156 config.allocated_bitrate_bps = allocated_bitrate;
157 }
philipel5ef2bc12017-02-21 07:28:31 -0800158 UpdateAllocationLimits();
Stefan Holmere5904162015-03-26 11:11:06 +0100159}
160
perkj57c21f92016-06-17 07:27:16 -0700161void BitrateAllocator::AddObserver(BitrateAllocatorObserver* observer,
Sebastian Jansson24ad7202018-04-19 08:25:12 +0200162 MediaStreamAllocationConfig config) {
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200163 RTC_DCHECK_RUN_ON(&sequenced_checker_);
Sebastian Jansson24ad7202018-04-19 08:25:12 +0200164 RTC_DCHECK_GT(config.bitrate_priority, 0);
165 RTC_DCHECK(std::isnormal(config.bitrate_priority));
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200166 auto it = absl::c_find_if(
167 allocatable_tracks_,
168 [observer](const auto& config) { return config.observer == observer; });
mflodman101f2502016-06-09 17:21:19 +0200169 // Update settings if the observer already exists, create a new one otherwise.
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200170 if (it != allocatable_tracks_.end()) {
171 it->config = config;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000172 } else {
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200173 allocatable_tracks_.push_back(AllocatableTrack(observer, config));
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000174 }
Stefan Holmere5904162015-03-26 11:11:06 +0100175
Sebastian Jansson89c94b92018-11-20 17:16:36 +0100176 if (last_target_bps_ > 0) {
mflodman101f2502016-06-09 17:21:19 +0200177 // Calculate a new allocation and update all observers.
Sebastian Jansson89c94b92018-11-20 17:16:36 +0100178
179 ObserverAllocation allocation = AllocateBitrates(last_target_bps_);
Florent Castelli4e615d52019-08-22 16:09:06 +0200180 ObserverAllocation stable_bitrate_allocation =
181 AllocateBitrates(last_stable_target_bps_);
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200182 for (auto& config : allocatable_tracks_) {
mflodman48a4beb2016-07-01 13:03:59 +0200183 uint32_t allocated_bitrate = allocation[config.observer];
Florent Castelli4e615d52019-08-22 16:09:06 +0200184 uint32_t allocated_stable_bitrate =
185 stable_bitrate_allocation[config.observer];
Sebastian Jansson13e59032018-11-21 19:13:07 +0100186 BitrateAllocationUpdate update;
187 update.target_bitrate = DataRate::bps(allocated_bitrate);
Florent Castelli4e615d52019-08-22 16:09:06 +0200188 update.stable_target_bitrate = DataRate::bps(allocated_stable_bitrate);
Sebastian Jansson13e59032018-11-21 19:13:07 +0100189 update.packet_loss_ratio = last_fraction_loss_ / 256.0;
190 update.round_trip_time = TimeDelta::ms(last_rtt_);
191 update.bwe_period = TimeDelta::ms(last_bwe_period_ms_);
192 uint32_t protection_bitrate = config.observer->OnBitrateUpdated(update);
mflodman48a4beb2016-07-01 13:03:59 +0200193 config.allocated_bitrate_bps = allocated_bitrate;
194 if (allocated_bitrate > 0)
195 config.media_ratio = MediaRatio(allocated_bitrate, protection_bitrate);
196 }
perkjfea93092016-05-14 00:58:48 -0700197 } else {
198 // Currently, an encoder is not allowed to produce frames.
199 // But we still have to return the initial config bitrate + let the
200 // observer know that it can not produce frames.
Sebastian Jansson13e59032018-11-21 19:13:07 +0100201
202 BitrateAllocationUpdate update;
203 update.target_bitrate = DataRate::Zero();
Florent Castelli4e615d52019-08-22 16:09:06 +0200204 update.stable_target_bitrate = DataRate::Zero();
Sebastian Jansson13e59032018-11-21 19:13:07 +0100205 update.packet_loss_ratio = last_fraction_loss_ / 256.0;
206 update.round_trip_time = TimeDelta::ms(last_rtt_);
207 update.bwe_period = TimeDelta::ms(last_bwe_period_ms_);
208 observer->OnBitrateUpdated(update);
Stefan Holmere5904162015-03-26 11:11:06 +0100209 }
perkj71ee44c2016-06-15 00:47:53 -0700210 UpdateAllocationLimits();
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000211}
212
perkj71ee44c2016-06-15 00:47:53 -0700213void BitrateAllocator::UpdateAllocationLimits() {
Sebastian Jansson93b1ea22019-09-18 18:31:52 +0200214 BitrateAllocationLimits limits;
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200215 for (const auto& config : allocatable_tracks_) {
216 uint32_t stream_padding = config.config.pad_up_bitrate_bps;
217 if (config.config.enforce_min_bitrate) {
Sebastian Jansson93b1ea22019-09-18 18:31:52 +0200218 limits.min_allocatable_rate +=
219 DataRate::bps(config.config.min_bitrate_bps);
philipel5ef2bc12017-02-21 07:28:31 -0800220 } else if (config.allocated_bitrate_bps == 0) {
221 stream_padding =
srte1eb051c2017-11-29 11:23:59 +0100222 std::max(config.MinBitrateWithHysteresis(), stream_padding);
perkj71ee44c2016-06-15 00:47:53 -0700223 }
Sebastian Jansson93b1ea22019-09-18 18:31:52 +0200224 limits.max_padding_rate += DataRate::bps(stream_padding);
225 limits.max_allocatable_rate += DataRate::bps(config.config.max_bitrate_bps);
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000226 }
perkj71ee44c2016-06-15 00:47:53 -0700227
Sebastian Jansson93b1ea22019-09-18 18:31:52 +0200228 if (limits.min_allocatable_rate == current_limits_.min_allocatable_rate &&
229 limits.max_allocatable_rate == current_limits_.max_allocatable_rate &&
230 limits.max_padding_rate == current_limits_.max_padding_rate) {
philipel5ef2bc12017-02-21 07:28:31 -0800231 return;
232 }
Sebastian Jansson93b1ea22019-09-18 18:31:52 +0200233 current_limits_ = limits;
philipel5ef2bc12017-02-21 07:28:31 -0800234
Mirko Bonadei675513b2017-11-09 11:09:25 +0100235 RTC_LOG(LS_INFO) << "UpdateAllocationLimits : total_requested_min_bitrate: "
Sebastian Jansson93b1ea22019-09-18 18:31:52 +0200236 << ToString(limits.min_allocatable_rate)
237 << ", total_requested_padding_bitrate: "
238 << ToString(limits.max_padding_rate)
239 << ", total_requested_max_bitrate: "
240 << ToString(limits.max_allocatable_rate);
241
242 limit_observer_->OnAllocationLimitsChanged(limits);
perkj71ee44c2016-06-15 00:47:53 -0700243}
244
245void BitrateAllocator::RemoveObserver(BitrateAllocatorObserver* observer) {
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200246 RTC_DCHECK_RUN_ON(&sequenced_checker_);
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200247 for (auto it = allocatable_tracks_.begin(); it != allocatable_tracks_.end();
248 ++it) {
249 if (it->observer == observer) {
250 allocatable_tracks_.erase(it);
251 break;
252 }
perkj71ee44c2016-06-15 00:47:53 -0700253 }
perkj26091b12016-09-01 01:17:40 -0700254
perkj71ee44c2016-06-15 00:47:53 -0700255 UpdateAllocationLimits();
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000256}
257
Sebastian Jansson44a262a2018-10-24 16:07:20 +0200258int BitrateAllocator::GetStartBitrate(
259 BitrateAllocatorObserver* observer) const {
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200260 RTC_DCHECK_RUN_ON(&sequenced_checker_);
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200261 auto it = absl::c_find_if(
262 allocatable_tracks_,
263 [observer](const auto& config) { return config.observer == observer; });
264 if (it == allocatable_tracks_.end()) {
mflodman48a4beb2016-07-01 13:03:59 +0200265 // This observer hasn't been added yet, just give it its fair share.
266 return last_non_zero_bitrate_bps_ /
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200267 static_cast<int>((allocatable_tracks_.size() + 1));
mflodman48a4beb2016-07-01 13:03:59 +0200268 } else if (it->allocated_bitrate_bps == -1) {
269 // This observer hasn't received an allocation yet, so do the same.
270 return last_non_zero_bitrate_bps_ /
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200271 static_cast<int>(allocatable_tracks_.size());
mflodman48a4beb2016-07-01 13:03:59 +0200272 } else {
273 // This observer already has an allocation.
274 return it->allocated_bitrate_bps;
275 }
perkj57c21f92016-06-17 07:27:16 -0700276}
277
perkjfea93092016-05-14 00:58:48 -0700278BitrateAllocator::ObserverAllocation BitrateAllocator::AllocateBitrates(
Sebastian Jansson44a262a2018-10-24 16:07:20 +0200279 uint32_t bitrate) const {
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200280 if (allocatable_tracks_.empty())
mflodman2ebe5b12016-05-13 01:43:51 -0700281 return ObserverAllocation();
282
perkjfea93092016-05-14 00:58:48 -0700283 if (bitrate == 0)
mflodman2ebe5b12016-05-13 01:43:51 -0700284 return ZeroRateAllocation();
285
286 uint32_t sum_min_bitrates = 0;
mflodman101f2502016-06-09 17:21:19 +0200287 uint32_t sum_max_bitrates = 0;
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200288 for (const auto& observer_config : allocatable_tracks_) {
289 sum_min_bitrates += observer_config.config.min_bitrate_bps;
290 sum_max_bitrates += observer_config.config.max_bitrate_bps;
mflodman101f2502016-06-09 17:21:19 +0200291 }
292
293 // Not enough for all observers to get an allocation, allocate according to:
294 // enforced min bitrate -> allocated bitrate previous round -> restart paused
295 // streams.
296 if (!EnoughBitrateForAllObservers(bitrate, sum_min_bitrates))
perkjfea93092016-05-14 00:58:48 -0700297 return LowRateAllocation(bitrate);
mflodman2ebe5b12016-05-13 01:43:51 -0700298
Seth Hampsonfe73d6a2017-11-14 10:49:06 -0800299 // All observers will get their min bitrate plus a share of the rest. This
300 // share is allocated to each observer based on its bitrate_priority.
mflodman101f2502016-06-09 17:21:19 +0200301 if (bitrate <= sum_max_bitrates)
302 return NormalRateAllocation(bitrate, sum_min_bitrates);
mflodman2ebe5b12016-05-13 01:43:51 -0700303
Ying Wanga646d302018-03-02 17:04:11 +0100304 // All observers will get up to transmission_max_bitrate_multiplier_ x max.
mflodman101f2502016-06-09 17:21:19 +0200305 return MaxRateAllocation(bitrate, sum_max_bitrates);
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000306}
307
Sebastian Jansson44a262a2018-10-24 16:07:20 +0200308BitrateAllocator::ObserverAllocation BitrateAllocator::ZeroRateAllocation()
309 const {
mflodman2ebe5b12016-05-13 01:43:51 -0700310 ObserverAllocation allocation;
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200311 for (const auto& observer_config : allocatable_tracks_)
mflodman2ebe5b12016-05-13 01:43:51 -0700312 allocation[observer_config.observer] = 0;
perkjec81bcd2016-05-11 06:01:13 -0700313 return allocation;
314}
315
mflodman2ebe5b12016-05-13 01:43:51 -0700316BitrateAllocator::ObserverAllocation BitrateAllocator::LowRateAllocation(
Sebastian Jansson44a262a2018-10-24 16:07:20 +0200317 uint32_t bitrate) const {
mflodman2ebe5b12016-05-13 01:43:51 -0700318 ObserverAllocation allocation;
mflodman101f2502016-06-09 17:21:19 +0200319 // Start by allocating bitrate to observers enforcing a min bitrate, hence
320 // remaining_bitrate might turn negative.
321 int64_t remaining_bitrate = bitrate;
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200322 for (const auto& observer_config : allocatable_tracks_) {
mflodman101f2502016-06-09 17:21:19 +0200323 int32_t allocated_bitrate = 0;
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200324 if (observer_config.config.enforce_min_bitrate)
325 allocated_bitrate = observer_config.config.min_bitrate_bps;
mflodman101f2502016-06-09 17:21:19 +0200326
327 allocation[observer_config.observer] = allocated_bitrate;
328 remaining_bitrate -= allocated_bitrate;
329 }
330
331 // Allocate bitrate to all previously active streams.
332 if (remaining_bitrate > 0) {
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200333 for (const auto& observer_config : allocatable_tracks_) {
334 if (observer_config.config.enforce_min_bitrate ||
srte1eb051c2017-11-29 11:23:59 +0100335 observer_config.LastAllocatedBitrate() == 0)
mflodman101f2502016-06-09 17:21:19 +0200336 continue;
337
srte1eb051c2017-11-29 11:23:59 +0100338 uint32_t required_bitrate = observer_config.MinBitrateWithHysteresis();
mflodman48a4beb2016-07-01 13:03:59 +0200339 if (remaining_bitrate >= required_bitrate) {
340 allocation[observer_config.observer] = required_bitrate;
341 remaining_bitrate -= required_bitrate;
mflodman101f2502016-06-09 17:21:19 +0200342 }
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000343 }
344 }
mflodman101f2502016-06-09 17:21:19 +0200345
346 // Allocate bitrate to previously paused streams.
347 if (remaining_bitrate > 0) {
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200348 for (const auto& observer_config : allocatable_tracks_) {
srte1eb051c2017-11-29 11:23:59 +0100349 if (observer_config.LastAllocatedBitrate() != 0)
mflodman101f2502016-06-09 17:21:19 +0200350 continue;
351
352 // Add a hysteresis to avoid toggling.
srte1eb051c2017-11-29 11:23:59 +0100353 uint32_t required_bitrate = observer_config.MinBitrateWithHysteresis();
mflodman101f2502016-06-09 17:21:19 +0200354 if (remaining_bitrate >= required_bitrate) {
355 allocation[observer_config.observer] = required_bitrate;
356 remaining_bitrate -= required_bitrate;
357 }
358 }
359 }
360
361 // Split a possible remainder evenly on all streams with an allocation.
362 if (remaining_bitrate > 0)
363 DistributeBitrateEvenly(remaining_bitrate, false, 1, &allocation);
364
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200365 RTC_DCHECK_EQ(allocation.size(), allocatable_tracks_.size());
Stefan Holmere5904162015-03-26 11:11:06 +0100366 return allocation;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000367}
mflodman101f2502016-06-09 17:21:19 +0200368
Seth Hampsonfe73d6a2017-11-14 10:49:06 -0800369// Allocates the bitrate based on the bitrate priority of each observer. This
370// bitrate priority defines the priority for bitrate to be allocated to that
371// observer in relation to other observers. For example with two observers, if
372// observer 1 had a bitrate_priority = 1.0, and observer 2 has a
373// bitrate_priority = 2.0, the expected behavior is that observer 2 will be
374// allocated twice the bitrate as observer 1 above the each observer's
375// min_bitrate_bps values, until one of the observers hits its max_bitrate_bps.
mflodman101f2502016-06-09 17:21:19 +0200376BitrateAllocator::ObserverAllocation BitrateAllocator::NormalRateAllocation(
377 uint32_t bitrate,
Sebastian Jansson44a262a2018-10-24 16:07:20 +0200378 uint32_t sum_min_bitrates) const {
mflodman101f2502016-06-09 17:21:19 +0200379 ObserverAllocation allocation;
Seth Hampsonfe73d6a2017-11-14 10:49:06 -0800380 ObserverAllocation observers_capacities;
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200381 for (const auto& observer_config : allocatable_tracks_) {
382 allocation[observer_config.observer] =
383 observer_config.config.min_bitrate_bps;
Seth Hampsonfe73d6a2017-11-14 10:49:06 -0800384 observers_capacities[observer_config.observer] =
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200385 observer_config.config.max_bitrate_bps -
386 observer_config.config.min_bitrate_bps;
Seth Hampsonfe73d6a2017-11-14 10:49:06 -0800387 }
mflodman101f2502016-06-09 17:21:19 +0200388
389 bitrate -= sum_min_bitrates;
Sebastian Jansson464a5572019-02-12 13:32:32 +0100390
391 // TODO(srte): Implement fair sharing between prioritized streams, currently
392 // they are treated on a first come first serve basis.
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200393 for (const auto& observer_config : allocatable_tracks_) {
394 int64_t priority_margin = observer_config.config.priority_bitrate_bps -
Sebastian Jansson464a5572019-02-12 13:32:32 +0100395 allocation[observer_config.observer];
396 if (priority_margin > 0 && bitrate > 0) {
397 int64_t extra_bitrate = std::min<int64_t>(priority_margin, bitrate);
398 allocation[observer_config.observer] +=
399 rtc::dchecked_cast<int>(extra_bitrate);
400 observers_capacities[observer_config.observer] -= extra_bitrate;
401 bitrate -= extra_bitrate;
402 }
403 }
404
Seth Hampsonfe73d6a2017-11-14 10:49:06 -0800405 // From the remaining bitrate, allocate a proportional amount to each observer
406 // above the min bitrate already allocated.
mflodman101f2502016-06-09 17:21:19 +0200407 if (bitrate > 0)
Seth Hampsonfe73d6a2017-11-14 10:49:06 -0800408 DistributeBitrateRelatively(bitrate, observers_capacities, &allocation);
mflodman101f2502016-06-09 17:21:19 +0200409
410 return allocation;
411}
412
413BitrateAllocator::ObserverAllocation BitrateAllocator::MaxRateAllocation(
perkj26091b12016-09-01 01:17:40 -0700414 uint32_t bitrate,
Sebastian Jansson44a262a2018-10-24 16:07:20 +0200415 uint32_t sum_max_bitrates) const {
mflodman101f2502016-06-09 17:21:19 +0200416 ObserverAllocation allocation;
417
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200418 for (const auto& observer_config : allocatable_tracks_) {
419 allocation[observer_config.observer] =
420 observer_config.config.max_bitrate_bps;
421 bitrate -= observer_config.config.max_bitrate_bps;
mflodman101f2502016-06-09 17:21:19 +0200422 }
Ying Wanga646d302018-03-02 17:04:11 +0100423 DistributeBitrateEvenly(bitrate, true, transmission_max_bitrate_multiplier_,
mflodman101f2502016-06-09 17:21:19 +0200424 &allocation);
425 return allocation;
426}
427
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200428uint32_t BitrateAllocator::AllocatableTrack::LastAllocatedBitrate() const {
mflodman101f2502016-06-09 17:21:19 +0200429 // Return the configured minimum bitrate for newly added observers, to avoid
430 // requiring an extra high bitrate for the observer to get an allocated
431 // bitrate.
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200432 return allocated_bitrate_bps == -1 ? config.min_bitrate_bps
433 : allocated_bitrate_bps;
mflodman101f2502016-06-09 17:21:19 +0200434}
435
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200436uint32_t BitrateAllocator::AllocatableTrack::MinBitrateWithHysteresis() const {
437 uint32_t min_bitrate = config.min_bitrate_bps;
srte1eb051c2017-11-29 11:23:59 +0100438 if (LastAllocatedBitrate() == 0) {
mflodman101f2502016-06-09 17:21:19 +0200439 min_bitrate += std::max(static_cast<uint32_t>(kToggleFactor * min_bitrate),
440 kMinToggleBitrateBps);
441 }
mflodman48a4beb2016-07-01 13:03:59 +0200442 // Account for protection bitrate used by this observer in the previous
443 // allocation.
444 // Note: the ratio will only be updated when the stream is active, meaning a
445 // paused stream won't get any ratio updates. This might lead to waiting a bit
446 // longer than necessary if the network condition improves, but this is to
447 // avoid too much toggling.
srte1eb051c2017-11-29 11:23:59 +0100448 if (media_ratio > 0.0 && media_ratio < 1.0)
449 min_bitrate += min_bitrate * (1.0 - media_ratio);
mflodman48a4beb2016-07-01 13:03:59 +0200450
mflodman101f2502016-06-09 17:21:19 +0200451 return min_bitrate;
452}
453
Sebastian Jansson44a262a2018-10-24 16:07:20 +0200454void BitrateAllocator::DistributeBitrateEvenly(
455 uint32_t bitrate,
456 bool include_zero_allocations,
457 int max_multiplier,
458 ObserverAllocation* allocation) const {
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200459 RTC_DCHECK_EQ(allocation->size(), allocatable_tracks_.size());
mflodman101f2502016-06-09 17:21:19 +0200460
461 ObserverSortingMap list_max_bitrates;
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200462 for (const auto& observer_config : allocatable_tracks_) {
mflodman101f2502016-06-09 17:21:19 +0200463 if (include_zero_allocations ||
464 allocation->at(observer_config.observer) != 0) {
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200465 list_max_bitrates.insert(std::pair<uint32_t, const AllocatableTrack*>(
466 observer_config.config.max_bitrate_bps, &observer_config));
mflodman101f2502016-06-09 17:21:19 +0200467 }
468 }
469 auto it = list_max_bitrates.begin();
470 while (it != list_max_bitrates.end()) {
kwibergaf476c72016-11-28 15:21:39 -0800471 RTC_DCHECK_GT(bitrate, 0);
mflodman101f2502016-06-09 17:21:19 +0200472 uint32_t extra_allocation =
473 bitrate / static_cast<uint32_t>(list_max_bitrates.size());
474 uint32_t total_allocation =
475 extra_allocation + allocation->at(it->second->observer);
476 bitrate -= extra_allocation;
477 if (total_allocation > max_multiplier * it->first) {
478 // There is more than we can fit for this observer, carry over to the
479 // remaining observers.
480 bitrate += total_allocation - max_multiplier * it->first;
481 total_allocation = max_multiplier * it->first;
482 }
483 // Finally, update the allocation for this observer.
484 allocation->at(it->second->observer) = total_allocation;
485 it = list_max_bitrates.erase(it);
486 }
487}
488
Sebastian Jansson44a262a2018-10-24 16:07:20 +0200489bool BitrateAllocator::EnoughBitrateForAllObservers(
490 uint32_t bitrate,
491 uint32_t sum_min_bitrates) const {
mflodman101f2502016-06-09 17:21:19 +0200492 if (bitrate < sum_min_bitrates)
493 return false;
494
perkj26091b12016-09-01 01:17:40 -0700495 uint32_t extra_bitrate_per_observer =
496 (bitrate - sum_min_bitrates) /
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200497 static_cast<uint32_t>(allocatable_tracks_.size());
498 for (const auto& observer_config : allocatable_tracks_) {
499 if (observer_config.config.min_bitrate_bps + extra_bitrate_per_observer <
srte1eb051c2017-11-29 11:23:59 +0100500 observer_config.MinBitrateWithHysteresis()) {
mflodman101f2502016-06-09 17:21:19 +0200501 return false;
philipel5ef2bc12017-02-21 07:28:31 -0800502 }
mflodman101f2502016-06-09 17:21:19 +0200503 }
504 return true;
505}
Seth Hampsonfe73d6a2017-11-14 10:49:06 -0800506
507void BitrateAllocator::DistributeBitrateRelatively(
508 uint32_t remaining_bitrate,
509 const ObserverAllocation& observers_capacities,
Sebastian Jansson44a262a2018-10-24 16:07:20 +0200510 ObserverAllocation* allocation) const {
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200511 RTC_DCHECK_EQ(allocation->size(), allocatable_tracks_.size());
512 RTC_DCHECK_EQ(observers_capacities.size(), allocatable_tracks_.size());
Seth Hampsonfe73d6a2017-11-14 10:49:06 -0800513
514 struct PriorityRateObserverConfig {
515 PriorityRateObserverConfig(BitrateAllocatorObserver* allocation_key,
516 uint32_t capacity_bps,
517 double bitrate_priority)
518 : allocation_key(allocation_key),
519 capacity_bps(capacity_bps),
520 bitrate_priority(bitrate_priority) {}
521
522 BitrateAllocatorObserver* allocation_key;
523 // The amount of bitrate bps that can be allocated to this observer.
524 uint32_t capacity_bps;
525 double bitrate_priority;
526
527 // We want to sort by which observers will be allocated their full capacity
528 // first. By dividing each observer's capacity by its bitrate priority we
529 // are "normalizing" the capacity of an observer by the rate it will be
530 // filled. This is because the amount allocated is based upon bitrate
531 // priority. We allocate twice as much bitrate to an observer with twice the
532 // bitrate priority of another.
533 bool operator<(const PriorityRateObserverConfig& other) const {
534 return capacity_bps / bitrate_priority <
535 other.capacity_bps / other.bitrate_priority;
536 }
537 };
538
539 double bitrate_priority_sum = 0;
540 std::vector<PriorityRateObserverConfig> priority_rate_observers;
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200541 for (const auto& observer_config : allocatable_tracks_) {
Seth Hampsonfe73d6a2017-11-14 10:49:06 -0800542 uint32_t capacity_bps = observers_capacities.at(observer_config.observer);
Sebastian Jansson4d461ba2019-09-17 20:53:26 +0200543 priority_rate_observers.emplace_back(
544 observer_config.observer, capacity_bps,
545 observer_config.config.bitrate_priority);
546 bitrate_priority_sum += observer_config.config.bitrate_priority;
Seth Hampsonfe73d6a2017-11-14 10:49:06 -0800547 }
548
549 // Iterate in the order observers can be allocated their full capacity.
550 std::sort(priority_rate_observers.begin(), priority_rate_observers.end());
551 size_t i;
552 for (i = 0; i < priority_rate_observers.size(); ++i) {
553 const auto& priority_rate_observer = priority_rate_observers[i];
554 // We allocate the full capacity to an observer only if its relative
555 // portion from the remaining bitrate is sufficient to allocate its full
556 // capacity. This means we aren't greedily allocating the full capacity, but
557 // that it is only done when there is also enough bitrate to allocate the
558 // proportional amounts to all other observers.
559 double observer_share =
560 priority_rate_observer.bitrate_priority / bitrate_priority_sum;
561 double allocation_bps = observer_share * remaining_bitrate;
562 bool enough_bitrate = allocation_bps >= priority_rate_observer.capacity_bps;
563 if (!enough_bitrate)
564 break;
565 allocation->at(priority_rate_observer.allocation_key) +=
566 priority_rate_observer.capacity_bps;
567 remaining_bitrate -= priority_rate_observer.capacity_bps;
568 bitrate_priority_sum -= priority_rate_observer.bitrate_priority;
569 }
570
571 // From the remaining bitrate, allocate the proportional amounts to the
572 // observers that aren't allocated their max capacity.
573 for (; i < priority_rate_observers.size(); ++i) {
574 const auto& priority_rate_observer = priority_rate_observers[i];
575 double fraction_allocated =
576 priority_rate_observer.bitrate_priority / bitrate_priority_sum;
577 allocation->at(priority_rate_observer.allocation_key) +=
578 fraction_allocated * remaining_bitrate;
579 }
580}
581
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000582} // namespace webrtc