blob: e4b1ad49fa03dcb331506f674ab57bfa99f97e08 [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
mflodman0e7e2592015-11-12 21:02:42 -080012#include "webrtc/call/bitrate_allocator.h"
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000013
14#include <algorithm>
15#include <utility>
16
mflodman2ebe5b12016-05-13 01:43:51 -070017#include "webrtc/base/checks.h"
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000018#include "webrtc/modules/bitrate_controller/include/bitrate_controller.h"
19
20namespace webrtc {
21
Stefan Holmere5904162015-03-26 11:11:06 +010022// Allow packets to be transmitted in up to 2 times max video bitrate if the
23// bandwidth estimate allows it.
24const int kTransmissionMaxBitrateMultiplier = 2;
25const int kDefaultBitrateBps = 300000;
26
mflodman101f2502016-06-09 17:21:19 +020027// Require a bitrate increase of max(10%, 20kbps) to resume paused streams.
28const double kToggleFactor = 0.1;
29const uint32_t kMinToggleBitrateBps = 20000;
30
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000031BitrateAllocator::BitrateAllocator()
mflodman2ebe5b12016-05-13 01:43:51 -070032 : bitrate_observer_configs_(),
Stefan Holmere5904162015-03-26 11:11:06 +010033 last_bitrate_bps_(kDefaultBitrateBps),
perkjfea93092016-05-14 00:58:48 -070034 last_non_zero_bitrate_bps_(kDefaultBitrateBps),
Stefan Holmere5904162015-03-26 11:11:06 +010035 last_fraction_loss_(0),
sprang2f48d942015-11-05 04:25:49 -080036 last_rtt_(0) {}
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000037
mflodman101f2502016-06-09 17:21:19 +020038uint32_t BitrateAllocator::OnNetworkChanged(uint32_t target_bitrate_bps,
sprang2f48d942015-11-05 04:25:49 -080039 uint8_t fraction_loss,
40 int64_t rtt) {
tommi63cb4342016-01-20 02:32:54 -080041 rtc::CritScope lock(&crit_sect_);
mflodman101f2502016-06-09 17:21:19 +020042 last_bitrate_bps_ = target_bitrate_bps;
perkjfea93092016-05-14 00:58:48 -070043 last_non_zero_bitrate_bps_ =
mflodman101f2502016-06-09 17:21:19 +020044 target_bitrate_bps > 0 ? target_bitrate_bps : last_non_zero_bitrate_bps_;
Stefan Holmere5904162015-03-26 11:11:06 +010045 last_fraction_loss_ = fraction_loss;
46 last_rtt_ = rtt;
mflodman2ebe5b12016-05-13 01:43:51 -070047
sprang2f48d942015-11-05 04:25:49 -080048 uint32_t allocated_bitrate_bps = 0;
mflodman101f2502016-06-09 17:21:19 +020049 ObserverAllocation allocation = AllocateBitrates(target_bitrate_bps);
sprang2f48d942015-11-05 04:25:49 -080050 for (const auto& kv : allocation) {
mflodman86aabb22016-03-11 15:44:32 +010051 kv.first->OnBitrateUpdated(kv.second, last_fraction_loss_, last_rtt_);
sprang2f48d942015-11-05 04:25:49 -080052 allocated_bitrate_bps += kv.second;
53 }
mflodman101f2502016-06-09 17:21:19 +020054 last_allocation_ = allocation;
sprang2f48d942015-11-05 04:25:49 -080055 return allocated_bitrate_bps;
Stefan Holmere5904162015-03-26 11:11:06 +010056}
57
mflodman86aabb22016-03-11 15:44:32 +010058int BitrateAllocator::AddObserver(BitrateAllocatorObserver* observer,
59 uint32_t min_bitrate_bps,
mflodman2ebe5b12016-05-13 01:43:51 -070060 uint32_t max_bitrate_bps,
61 bool enforce_min_bitrate) {
tommi63cb4342016-01-20 02:32:54 -080062 rtc::CritScope lock(&crit_sect_);
mflodman2ebe5b12016-05-13 01:43:51 -070063 auto it = FindObserverConfig(observer);
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000064
mflodman101f2502016-06-09 17:21:19 +020065 // Update settings if the observer already exists, create a new one otherwise.
mflodman2ebe5b12016-05-13 01:43:51 -070066 if (it != bitrate_observer_configs_.end()) {
mflodman2ebe5b12016-05-13 01:43:51 -070067 it->min_bitrate_bps = min_bitrate_bps;
68 it->max_bitrate_bps = max_bitrate_bps;
mflodman101f2502016-06-09 17:21:19 +020069 it->enforce_min_bitrate = enforce_min_bitrate;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000070 } else {
mflodman2ebe5b12016-05-13 01:43:51 -070071 bitrate_observer_configs_.push_back(ObserverConfig(
72 observer, min_bitrate_bps, max_bitrate_bps, enforce_min_bitrate));
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000073 }
Stefan Holmere5904162015-03-26 11:11:06 +010074
mflodman101f2502016-06-09 17:21:19 +020075 ObserverAllocation allocation;
76 if (last_bitrate_bps_ > 0) {
77 // Calculate a new allocation and update all observers.
78 allocation = AllocateBitrates(last_bitrate_bps_);
79 for (const auto& kv : allocation)
perkjfea93092016-05-14 00:58:48 -070080 kv.first->OnBitrateUpdated(kv.second, last_fraction_loss_, last_rtt_);
perkjfea93092016-05-14 00:58:48 -070081 } else {
82 // Currently, an encoder is not allowed to produce frames.
83 // But we still have to return the initial config bitrate + let the
84 // observer know that it can not produce frames.
mflodman101f2502016-06-09 17:21:19 +020085 allocation = AllocateBitrates(last_non_zero_bitrate_bps_);
perkjfea93092016-05-14 00:58:48 -070086 observer->OnBitrateUpdated(0, last_fraction_loss_, last_rtt_);
Stefan Holmere5904162015-03-26 11:11:06 +010087 }
mflodman101f2502016-06-09 17:21:19 +020088 last_allocation_ = allocation;
89 return allocation[observer];
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000090}
91
mflodman86aabb22016-03-11 15:44:32 +010092void BitrateAllocator::RemoveObserver(BitrateAllocatorObserver* observer) {
tommi63cb4342016-01-20 02:32:54 -080093 rtc::CritScope lock(&crit_sect_);
mflodman2ebe5b12016-05-13 01:43:51 -070094 auto it = FindObserverConfig(observer);
95 if (it != bitrate_observer_configs_.end()) {
96 bitrate_observer_configs_.erase(it);
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000097 }
98}
99
mflodman2ebe5b12016-05-13 01:43:51 -0700100BitrateAllocator::ObserverConfigList::iterator
101BitrateAllocator::FindObserverConfig(
102 const BitrateAllocatorObserver* observer) {
103 for (auto it = bitrate_observer_configs_.begin();
104 it != bitrate_observer_configs_.end(); ++it) {
105 if (it->observer == observer)
106 return it;
107 }
108 return bitrate_observer_configs_.end();
109}
110
perkjfea93092016-05-14 00:58:48 -0700111BitrateAllocator::ObserverAllocation BitrateAllocator::AllocateBitrates(
112 uint32_t bitrate) {
mflodman2ebe5b12016-05-13 01:43:51 -0700113 if (bitrate_observer_configs_.empty())
114 return ObserverAllocation();
115
perkjfea93092016-05-14 00:58:48 -0700116 if (bitrate == 0)
mflodman2ebe5b12016-05-13 01:43:51 -0700117 return ZeroRateAllocation();
118
119 uint32_t sum_min_bitrates = 0;
mflodman101f2502016-06-09 17:21:19 +0200120 uint32_t sum_max_bitrates = 0;
121 for (const auto& observer_config : bitrate_observer_configs_) {
mflodman2ebe5b12016-05-13 01:43:51 -0700122 sum_min_bitrates += observer_config.min_bitrate_bps;
mflodman101f2502016-06-09 17:21:19 +0200123 sum_max_bitrates += observer_config.max_bitrate_bps;
124 }
125
126 // Not enough for all observers to get an allocation, allocate according to:
127 // enforced min bitrate -> allocated bitrate previous round -> restart paused
128 // streams.
129 if (!EnoughBitrateForAllObservers(bitrate, sum_min_bitrates))
perkjfea93092016-05-14 00:58:48 -0700130 return LowRateAllocation(bitrate);
mflodman2ebe5b12016-05-13 01:43:51 -0700131
mflodman101f2502016-06-09 17:21:19 +0200132 // All observers will get their min bitrate plus an even share of the rest.
133 if (bitrate <= sum_max_bitrates)
134 return NormalRateAllocation(bitrate, sum_min_bitrates);
mflodman2ebe5b12016-05-13 01:43:51 -0700135
mflodman101f2502016-06-09 17:21:19 +0200136 // All observers will get up to kTransmissionMaxBitrateMultiplier x max.
137 return MaxRateAllocation(bitrate, sum_max_bitrates);
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000138}
139
mflodman2ebe5b12016-05-13 01:43:51 -0700140BitrateAllocator::ObserverAllocation BitrateAllocator::ZeroRateAllocation() {
141 ObserverAllocation allocation;
mflodman2ebe5b12016-05-13 01:43:51 -0700142 for (const auto& observer_config : bitrate_observer_configs_)
143 allocation[observer_config.observer] = 0;
perkjec81bcd2016-05-11 06:01:13 -0700144 return allocation;
145}
146
mflodman2ebe5b12016-05-13 01:43:51 -0700147BitrateAllocator::ObserverAllocation BitrateAllocator::LowRateAllocation(
Stefan Holmere5904162015-03-26 11:11:06 +0100148 uint32_t bitrate) {
mflodman2ebe5b12016-05-13 01:43:51 -0700149 ObserverAllocation allocation;
mflodman101f2502016-06-09 17:21:19 +0200150
151 // Start by allocating bitrate to observers enforcing a min bitrate, hence
152 // remaining_bitrate might turn negative.
153 int64_t remaining_bitrate = bitrate;
154 for (const auto& observer_config : bitrate_observer_configs_) {
155 int32_t allocated_bitrate = 0;
156 if (observer_config.enforce_min_bitrate)
157 allocated_bitrate = observer_config.min_bitrate_bps;
158
159 allocation[observer_config.observer] = allocated_bitrate;
160 remaining_bitrate -= allocated_bitrate;
161 }
162
163 // Allocate bitrate to all previously active streams.
164 if (remaining_bitrate > 0) {
mflodman2ebe5b12016-05-13 01:43:51 -0700165 for (const auto& observer_config : bitrate_observer_configs_) {
mflodman101f2502016-06-09 17:21:19 +0200166 if (observer_config.enforce_min_bitrate ||
167 LastAllocatedBitrate(observer_config) == 0)
168 continue;
169
170 if (remaining_bitrate >= observer_config.min_bitrate_bps) {
171 allocation[observer_config.observer] = observer_config.min_bitrate_bps;
172 remaining_bitrate -= observer_config.min_bitrate_bps;
173 }
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000174 }
175 }
mflodman101f2502016-06-09 17:21:19 +0200176
177 // Allocate bitrate to previously paused streams.
178 if (remaining_bitrate > 0) {
179 for (const auto& observer_config : bitrate_observer_configs_) {
180 if (LastAllocatedBitrate(observer_config) != 0)
181 continue;
182
183 // Add a hysteresis to avoid toggling.
184 uint32_t required_bitrate = MinBitrateWithHysteresis(observer_config);
185 if (remaining_bitrate >= required_bitrate) {
186 allocation[observer_config.observer] = required_bitrate;
187 remaining_bitrate -= required_bitrate;
188 }
189 }
190 }
191
192 // Split a possible remainder evenly on all streams with an allocation.
193 if (remaining_bitrate > 0)
194 DistributeBitrateEvenly(remaining_bitrate, false, 1, &allocation);
195
196 RTC_DCHECK_EQ(allocation.size(), bitrate_observer_configs_.size());
Stefan Holmere5904162015-03-26 11:11:06 +0100197 return allocation;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000198}
mflodman101f2502016-06-09 17:21:19 +0200199
200BitrateAllocator::ObserverAllocation BitrateAllocator::NormalRateAllocation(
201 uint32_t bitrate,
202 uint32_t sum_min_bitrates) {
203
204 ObserverAllocation allocation;
205 for (const auto& observer_config : bitrate_observer_configs_)
206 allocation[observer_config.observer] = observer_config.min_bitrate_bps;
207
208 bitrate -= sum_min_bitrates;
209 if (bitrate > 0)
210 DistributeBitrateEvenly(bitrate, true, 1, &allocation);
211
212 return allocation;
213}
214
215BitrateAllocator::ObserverAllocation BitrateAllocator::MaxRateAllocation(
216 uint32_t bitrate, uint32_t sum_max_bitrates) {
217 ObserverAllocation allocation;
218
219 for (const auto& observer_config : bitrate_observer_configs_) {
220 allocation[observer_config.observer] = observer_config.max_bitrate_bps;
221 bitrate -= observer_config.max_bitrate_bps;
222 }
223 DistributeBitrateEvenly(bitrate, true, kTransmissionMaxBitrateMultiplier,
224 &allocation);
225 return allocation;
226}
227
228uint32_t BitrateAllocator::LastAllocatedBitrate(
229 const ObserverConfig& observer_config) {
230
231 const auto& it = last_allocation_.find(observer_config.observer);
232 if (it != last_allocation_.end())
233 return it->second;
234
235 // Return the configured minimum bitrate for newly added observers, to avoid
236 // requiring an extra high bitrate for the observer to get an allocated
237 // bitrate.
238 return observer_config.min_bitrate_bps;
239}
240
241uint32_t BitrateAllocator::MinBitrateWithHysteresis(
242 const ObserverConfig& observer_config) {
243 uint32_t min_bitrate = observer_config.min_bitrate_bps;
244 if (LastAllocatedBitrate(observer_config) == 0) {
245 min_bitrate += std::max(static_cast<uint32_t>(kToggleFactor * min_bitrate),
246 kMinToggleBitrateBps);
247 }
248 return min_bitrate;
249}
250
251void BitrateAllocator::DistributeBitrateEvenly(uint32_t bitrate,
252 bool include_zero_allocations,
253 int max_multiplier,
254 ObserverAllocation* allocation) {
255 RTC_DCHECK_EQ(allocation->size(), bitrate_observer_configs_.size());
256
257 ObserverSortingMap list_max_bitrates;
258 for (const auto& observer_config : bitrate_observer_configs_) {
259 if (include_zero_allocations ||
260 allocation->at(observer_config.observer) != 0) {
261 list_max_bitrates.insert(std::pair<uint32_t, const ObserverConfig*>(
262 observer_config.max_bitrate_bps, &observer_config));
263 }
264 }
265 auto it = list_max_bitrates.begin();
266 while (it != list_max_bitrates.end()) {
267 RTC_DCHECK_GT(bitrate, 0u);
268 uint32_t extra_allocation =
269 bitrate / static_cast<uint32_t>(list_max_bitrates.size());
270 uint32_t total_allocation =
271 extra_allocation + allocation->at(it->second->observer);
272 bitrate -= extra_allocation;
273 if (total_allocation > max_multiplier * it->first) {
274 // There is more than we can fit for this observer, carry over to the
275 // remaining observers.
276 bitrate += total_allocation - max_multiplier * it->first;
277 total_allocation = max_multiplier * it->first;
278 }
279 // Finally, update the allocation for this observer.
280 allocation->at(it->second->observer) = total_allocation;
281 it = list_max_bitrates.erase(it);
282 }
283}
284
285bool BitrateAllocator::EnoughBitrateForAllObservers(uint32_t bitrate,
286 uint32_t sum_min_bitrates) {
287 if (bitrate < sum_min_bitrates)
288 return false;
289
290 uint32_t extra_bitrate_per_observer = (bitrate - sum_min_bitrates) /
291 static_cast<uint32_t>(bitrate_observer_configs_.size());
292 for (const auto& observer_config : bitrate_observer_configs_) {
293 if (observer_config.min_bitrate_bps + extra_bitrate_per_observer <
294 MinBitrateWithHysteresis(observer_config))
295 return false;
296 }
297 return true;
298}
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000299} // namespace webrtc