Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(441)

Side by Side Diff: webrtc/call/bitrate_allocator.cc

Issue 2035383002: Implementing auto pausing of video streams. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 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 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 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 * 9 *
10 */ 10 */
11 11
12 #include "webrtc/call/bitrate_allocator.h" 12 #include "webrtc/call/bitrate_allocator.h"
13 13
14 #include <algorithm> 14 #include <algorithm>
15 #include <utility> 15 #include <utility>
16 16
17 #include "webrtc/base/checks.h" 17 #include "webrtc/base/checks.h"
18 #include "webrtc/modules/bitrate_controller/include/bitrate_controller.h" 18 #include "webrtc/modules/bitrate_controller/include/bitrate_controller.h"
19 19
20 namespace webrtc { 20 namespace webrtc {
21 21
22 // Allow packets to be transmitted in up to 2 times max video bitrate if the 22 // Allow packets to be transmitted in up to 2 times max video bitrate if the
23 // bandwidth estimate allows it. 23 // bandwidth estimate allows it.
24 const int kTransmissionMaxBitrateMultiplier = 2; 24 const int kTransmissionMaxBitrateMultiplier = 2;
25 const int kDefaultBitrateBps = 300000; 25 const int kDefaultBitrateBps = 300000;
26 26
27 // Require a bitrate increase of max(10%, 20kbps) to resume paused streams.
28 const double kToggleFactor = 0.1;
29 const uint32_t kMinToggleBitrateBps = 20000;
30
27 BitrateAllocator::BitrateAllocator() 31 BitrateAllocator::BitrateAllocator()
28 : bitrate_observer_configs_(), 32 : bitrate_observer_configs_(),
29 enforce_min_bitrate_(true),
30 last_bitrate_bps_(kDefaultBitrateBps), 33 last_bitrate_bps_(kDefaultBitrateBps),
31 last_non_zero_bitrate_bps_(kDefaultBitrateBps), 34 last_non_zero_bitrate_bps_(kDefaultBitrateBps),
32 last_fraction_loss_(0), 35 last_fraction_loss_(0),
33 last_rtt_(0) {} 36 last_rtt_(0) {}
34 37
35 uint32_t BitrateAllocator::OnNetworkChanged(uint32_t bitrate, 38 uint32_t BitrateAllocator::OnNetworkChanged(uint32_t target_bitrate_bps,
36 uint8_t fraction_loss, 39 uint8_t fraction_loss,
37 int64_t rtt) { 40 int64_t rtt) {
38 rtc::CritScope lock(&crit_sect_); 41 rtc::CritScope lock(&crit_sect_);
39 last_bitrate_bps_ = bitrate; 42 last_bitrate_bps_ = target_bitrate_bps;
40 last_non_zero_bitrate_bps_ = 43 last_non_zero_bitrate_bps_ =
41 bitrate > 0 ? bitrate : last_non_zero_bitrate_bps_; 44 target_bitrate_bps > 0 ? target_bitrate_bps : last_non_zero_bitrate_bps_;
42 last_fraction_loss_ = fraction_loss; 45 last_fraction_loss_ = fraction_loss;
43 last_rtt_ = rtt; 46 last_rtt_ = rtt;
44 47
45 uint32_t allocated_bitrate_bps = 0; 48 uint32_t allocated_bitrate_bps = 0;
46 ObserverAllocation allocation = AllocateBitrates(bitrate); 49 ObserverAllocation allocation = AllocateBitrates(target_bitrate_bps);
47 for (const auto& kv : allocation) { 50 for (const auto& kv : allocation) {
48 kv.first->OnBitrateUpdated(kv.second, last_fraction_loss_, last_rtt_); 51 kv.first->OnBitrateUpdated(kv.second, last_fraction_loss_, last_rtt_);
49 allocated_bitrate_bps += kv.second; 52 allocated_bitrate_bps += kv.second;
50 } 53 }
54 last_allocation_ = allocation;
51 return allocated_bitrate_bps; 55 return allocated_bitrate_bps;
52 } 56 }
53 57
54 int BitrateAllocator::AddObserver(BitrateAllocatorObserver* observer, 58 int BitrateAllocator::AddObserver(BitrateAllocatorObserver* observer,
55 uint32_t min_bitrate_bps, 59 uint32_t min_bitrate_bps,
56 uint32_t max_bitrate_bps, 60 uint32_t max_bitrate_bps,
57 bool enforce_min_bitrate) { 61 bool enforce_min_bitrate) {
58 rtc::CritScope lock(&crit_sect_); 62 rtc::CritScope lock(&crit_sect_);
59 // TODO(mflodman): Enforce this per observer.
60 EnforceMinBitrate(enforce_min_bitrate);
61
62 auto it = FindObserverConfig(observer); 63 auto it = FindObserverConfig(observer);
63 64
64 // Allow the max bitrate to be exceeded for FEC and retransmissions. 65 // Update settings if the observer already exists, create a new one otherwise.
65 // TODO(holmer): We have to get rid of this hack as it makes it difficult to
66 // properly allocate bitrate. The allocator should instead distribute any
67 // extra bitrate after all streams have maxed out.
68 max_bitrate_bps *= kTransmissionMaxBitrateMultiplier;
69 if (it != bitrate_observer_configs_.end()) { 66 if (it != bitrate_observer_configs_.end()) {
70 // Update current configuration.
71 it->min_bitrate_bps = min_bitrate_bps; 67 it->min_bitrate_bps = min_bitrate_bps;
72 it->max_bitrate_bps = max_bitrate_bps; 68 it->max_bitrate_bps = max_bitrate_bps;
69 it->enforce_min_bitrate = enforce_min_bitrate;
73 } else { 70 } else {
74 // Add new settings.
75 bitrate_observer_configs_.push_back(ObserverConfig( 71 bitrate_observer_configs_.push_back(ObserverConfig(
76 observer, min_bitrate_bps, max_bitrate_bps, enforce_min_bitrate)); 72 observer, min_bitrate_bps, max_bitrate_bps, enforce_min_bitrate));
77 } 73 }
78 74
79 int new_observer_bitrate_bps = 0; 75 ObserverAllocation allocation;
80 if (last_bitrate_bps_ > 0) { // We have a bitrate to allocate. 76 if (last_bitrate_bps_ > 0) {
81 ObserverAllocation allocation = AllocateBitrates(last_bitrate_bps_); 77 // Calculate a new allocation and update all observers.
82 for (auto& kv : allocation) { 78 allocation = AllocateBitrates(last_bitrate_bps_);
83 // Update all observers with the new allocation. 79 for (const auto& kv : allocation)
84 kv.first->OnBitrateUpdated(kv.second, last_fraction_loss_, last_rtt_); 80 kv.first->OnBitrateUpdated(kv.second, last_fraction_loss_, last_rtt_);
85 if (kv.first == observer)
86 new_observer_bitrate_bps = kv.second;
87 }
88 } else { 81 } else {
89 // Currently, an encoder is not allowed to produce frames. 82 // Currently, an encoder is not allowed to produce frames.
90 // But we still have to return the initial config bitrate + let the 83 // But we still have to return the initial config bitrate + let the
91 // observer know that it can not produce frames. 84 // observer know that it can not produce frames.
92 ObserverAllocation allocation = 85 allocation = AllocateBitrates(last_non_zero_bitrate_bps_);
93 AllocateBitrates(last_non_zero_bitrate_bps_);
94 observer->OnBitrateUpdated(0, last_fraction_loss_, last_rtt_); 86 observer->OnBitrateUpdated(0, last_fraction_loss_, last_rtt_);
95 new_observer_bitrate_bps = allocation[observer];
96 } 87 }
97 return new_observer_bitrate_bps; 88 last_allocation_ = allocation;
89 return allocation[observer];
98 } 90 }
99 91
100 void BitrateAllocator::RemoveObserver(BitrateAllocatorObserver* observer) { 92 void BitrateAllocator::RemoveObserver(BitrateAllocatorObserver* observer) {
101 rtc::CritScope lock(&crit_sect_); 93 rtc::CritScope lock(&crit_sect_);
102 auto it = FindObserverConfig(observer); 94 auto it = FindObserverConfig(observer);
103 if (it != bitrate_observer_configs_.end()) { 95 if (it != bitrate_observer_configs_.end()) {
104 bitrate_observer_configs_.erase(it); 96 bitrate_observer_configs_.erase(it);
105 } 97 }
106 } 98 }
107 99
108 void BitrateAllocator::EnforceMinBitrate(bool enforce_min_bitrate) {
109 enforce_min_bitrate_ = enforce_min_bitrate;
110 }
111
112 BitrateAllocator::ObserverConfigList::iterator 100 BitrateAllocator::ObserverConfigList::iterator
113 BitrateAllocator::FindObserverConfig( 101 BitrateAllocator::FindObserverConfig(
114 const BitrateAllocatorObserver* observer) { 102 const BitrateAllocatorObserver* observer) {
115 for (auto it = bitrate_observer_configs_.begin(); 103 for (auto it = bitrate_observer_configs_.begin();
116 it != bitrate_observer_configs_.end(); ++it) { 104 it != bitrate_observer_configs_.end(); ++it) {
117 if (it->observer == observer) 105 if (it->observer == observer)
118 return it; 106 return it;
119 } 107 }
120 return bitrate_observer_configs_.end(); 108 return bitrate_observer_configs_.end();
121 } 109 }
122 110
123 BitrateAllocator::ObserverAllocation BitrateAllocator::AllocateBitrates( 111 BitrateAllocator::ObserverAllocation BitrateAllocator::AllocateBitrates(
124 uint32_t bitrate) { 112 uint32_t bitrate) {
113
pbos-webrtc 2016/06/06 15:26:28 remove
mflodman 2016/06/09 13:23:12 Done.
125 if (bitrate_observer_configs_.empty()) 114 if (bitrate_observer_configs_.empty())
126 return ObserverAllocation(); 115 return ObserverAllocation();
127 116
128 if (bitrate == 0) 117 if (bitrate == 0)
129 return ZeroRateAllocation(); 118 return ZeroRateAllocation();
130 119
131 uint32_t sum_min_bitrates = 0; 120 uint32_t sum_min_bitrates = 0;
pbos-webrtc 2016/06/06 15:26:28 _bps
mflodman 2016/06/09 13:23:12 See my previous reply and question, ignore the sim
132 for (const auto& observer_config : bitrate_observer_configs_) 121 uint32_t sum_max_bitrates = 0;
122 for (const auto& observer_config : bitrate_observer_configs_) {
133 sum_min_bitrates += observer_config.min_bitrate_bps; 123 sum_min_bitrates += observer_config.min_bitrate_bps;
134 if (bitrate <= sum_min_bitrates) 124 sum_max_bitrates += observer_config.max_bitrate_bps;
125 }
126
127 // Not enough for all observers to get an allocation, allocate according to:
128 // enforced min bitrate -> allocated bitrate previous round -> restart paused
129 // streams.
130 if (ShouldDoLowRateAllocation(bitrate, sum_min_bitrates))
stefan-webrtc 2016/06/08 10:18:31 Should we call this something like EnoughBitrateFo
mflodman 2016/06/09 13:23:12 That is a good suggestion.
stefan-webrtc 2016/06/09 13:51:25 Probably should be inverted so that the check is:
135 return LowRateAllocation(bitrate); 131 return LowRateAllocation(bitrate);
136 132
137 return NormalRateAllocation(bitrate, sum_min_bitrates); 133 // All observers will get their min bitrate plus an even share of the rest.
138 } 134 if (bitrate <= sum_max_bitrates)
135 return NormalRateAllocation(bitrate, sum_min_bitrates);
139 136
140 BitrateAllocator::ObserverAllocation BitrateAllocator::NormalRateAllocation( 137 // All observers will get up to kTransmissionMaxBitrateMultiplier x max.
141 uint32_t bitrate, 138 return MaxRateAllocation(bitrate, sum_max_bitrates);
142 uint32_t sum_min_bitrates) {
143 uint32_t num_remaining_observers =
144 static_cast<uint32_t>(bitrate_observer_configs_.size());
145 RTC_DCHECK_GT(num_remaining_observers, 0u);
146
147 uint32_t bitrate_per_observer =
148 (bitrate - sum_min_bitrates) / num_remaining_observers;
149 // Use map to sort list based on max bitrate.
150 ObserverSortingMap list_max_bitrates;
151 for (const auto& config : bitrate_observer_configs_) {
152 list_max_bitrates.insert(std::pair<uint32_t, const ObserverConfig*>(
153 config.max_bitrate_bps, &config));
154 }
155
156 ObserverAllocation allocation;
157 ObserverSortingMap::iterator max_it = list_max_bitrates.begin();
158 while (max_it != list_max_bitrates.end()) {
159 num_remaining_observers--;
160 uint32_t observer_allowance =
161 max_it->second->min_bitrate_bps + bitrate_per_observer;
162 if (max_it->first < observer_allowance) {
163 // We have more than enough for this observer.
164 // Carry the remainder forward.
165 uint32_t remainder = observer_allowance - max_it->first;
166 if (num_remaining_observers != 0)
167 bitrate_per_observer += remainder / num_remaining_observers;
168 allocation[max_it->second->observer] = max_it->first;
169 } else {
170 allocation[max_it->second->observer] = observer_allowance;
171 }
172 list_max_bitrates.erase(max_it);
173 // Prepare next iteration.
174 max_it = list_max_bitrates.begin();
175 }
176 return allocation;
177 } 139 }
178 140
179 BitrateAllocator::ObserverAllocation BitrateAllocator::ZeroRateAllocation() { 141 BitrateAllocator::ObserverAllocation BitrateAllocator::ZeroRateAllocation() {
180 ObserverAllocation allocation; 142 ObserverAllocation allocation;
181 // Zero bitrate to all observers.
182 for (const auto& observer_config : bitrate_observer_configs_) 143 for (const auto& observer_config : bitrate_observer_configs_)
183 allocation[observer_config.observer] = 0; 144 allocation[observer_config.observer] = 0;
184 return allocation; 145 return allocation;
185 } 146 }
186 147
187 BitrateAllocator::ObserverAllocation BitrateAllocator::LowRateAllocation( 148 BitrateAllocator::ObserverAllocation BitrateAllocator::LowRateAllocation(
188 uint32_t bitrate) { 149 uint32_t bitrate) {
189 ObserverAllocation allocation; 150 ObserverAllocation allocation;
190 if (enforce_min_bitrate_) { 151
191 // Min bitrate to all observers. 152 // Start by allocating bitrate to observers enforcing a min bitrate, hence
192 for (const auto& observer_config : bitrate_observer_configs_) 153 // remaining_bitrate might turn negative.
193 allocation[observer_config.observer] = observer_config.min_bitrate_bps; 154 int64_t remaining_bitrate = bitrate;
pbos-webrtc 2016/06/06 15:26:28 _bps
194 } else { 155 for (const auto& observer_config : bitrate_observer_configs_) {
195 // Allocate up to |min_bitrate_bps| to one observer at a time, until 156 int32_t allocated_bitrate = 0;
pbos-webrtc 2016/06/06 15:26:28 _bps
196 // |bitrate| is depleted. 157 if (observer_config.enforce_min_bitrate)
197 uint32_t remainder = bitrate; 158 allocated_bitrate = observer_config.min_bitrate_bps;
159
160 allocation[observer_config.observer] = allocated_bitrate;
161 remaining_bitrate -= allocated_bitrate;
162 }
163
164 // Allocate bitrate to all previously active streams.
165 if (remaining_bitrate > 0) {
198 for (const auto& observer_config : bitrate_observer_configs_) { 166 for (const auto& observer_config : bitrate_observer_configs_) {
199 uint32_t allocated_bitrate = 167 if (observer_config.enforce_min_bitrate ||
200 std::min(remainder, observer_config.min_bitrate_bps); 168 LastAllocatedBitrate(observer_config) == 0)
201 allocation[observer_config.observer] = allocated_bitrate; 169 continue;
202 remainder -= allocated_bitrate; 170
171 if (remaining_bitrate >= observer_config.min_bitrate_bps) {
172 allocation[observer_config.observer] = observer_config.min_bitrate_bps;
173 remaining_bitrate -= observer_config.min_bitrate_bps;
174 }
203 } 175 }
204 } 176 }
177
178 // Allocate bitrate to previously paused streams.
stefan-webrtc 2016/06/08 10:18:31 remove extra space after Allocate
mflodman 2016/06/09 13:23:12 Done.
179 if (remaining_bitrate > 0) {
180 for (const auto& observer_config : bitrate_observer_configs_) {
181 if (LastAllocatedBitrate(observer_config) != 0)
182 continue;
183
184 // Add a hysteresis to avoid toggling.
stefan-webrtc 2016/06/08 10:18:31 Maybe this comment should go into MinBitrateForObs
mflodman 2016/06/09 13:23:12 Yes, I'll rename to this suggestion.
185 uint32_t required_bitrate = MinBitrateForObserver(observer_config);
186 if (remaining_bitrate >= required_bitrate) {
187 allocation[observer_config.observer] = required_bitrate;
188 remaining_bitrate -= required_bitrate;
189 }
190 }
191 }
192
193 // Split a possible remainder evenly on all streams with an allocation.
194 if (remaining_bitrate > 0)
195 DistributeBitrateEvenly(remaining_bitrate, 1, &allocation);
196
197 RTC_DCHECK_EQ(allocation.size(), bitrate_observer_configs_.size());
205 return allocation; 198 return allocation;
206 } 199 }
200
201 BitrateAllocator::ObserverAllocation BitrateAllocator::NormalRateAllocation(
202 uint32_t bitrate,
pbos-webrtc 2016/06/06 15:26:28 _bps here and everywhere
203 uint32_t sum_min_bitrates) {
204
205 ObserverAllocation allocation;
206 for (const auto& observer_config : bitrate_observer_configs_) {
207 // Adding at least 1bps simplifies the implementation of
208 // DistributeBitrateEvenly.
stefan-webrtc 2016/06/08 10:18:31 Why?
mflodman 2016/06/09 13:23:12 Bc DistributeBitrateEvenly only adds bitrate to ob
stefan-webrtc 2016/06/09 13:51:25 Thanks! Should you also update the comment now?
mflodman 2016/06/09 13:57:37 Done.
209 allocation[observer_config.observer] =
210 std::max(observer_config.min_bitrate_bps, 1u);
211 }
212
213 bitrate -= sum_min_bitrates;
214 if (bitrate > 0)
215 DistributeBitrateEvenly(bitrate, 1, &allocation);
216
217 return allocation;
218 }
219
220 BitrateAllocator::ObserverAllocation BitrateAllocator::MaxRateAllocation(
221 uint32_t bitrate, uint32_t sum_max_bitrates) {
222 ObserverAllocation allocation;
223
224 ObserverSortingMap list_max_bitrates;
stefan-webrtc 2016/06/08 10:18:31 Not used.
mflodman 2016/06/09 13:23:12 Thanks, leftovers after I created DistributeBitrat
225 for (const auto& observer_config : bitrate_observer_configs_) {
226 allocation[observer_config.observer] = observer_config.max_bitrate_bps;
227 bitrate -= observer_config.max_bitrate_bps;
228 }
229 DistributeBitrateEvenly(bitrate, kTransmissionMaxBitrateMultiplier,
230 &allocation);
231 return allocation;
232 }
233
234 uint32_t BitrateAllocator::LastAllocatedBitrate(
235 const ObserverConfig& observer_config) {
236
237 const auto& it = last_allocation_.find(observer_config.observer);
238 if (it != last_allocation_.end())
239 return it->second;
240
241 // Return the configured minimum bitrate for newly added observers, to avoid
242 // requiring an extra high bitrate for the observer to get an allocated
243 // bitrate.
244 return observer_config.min_bitrate_bps;
245 }
246
247 uint32_t BitrateAllocator::MinBitrateForObserver(
248 const ObserverConfig& observer_config) {
249 uint32_t min_bitrate = observer_config.min_bitrate_bps;
250 if (LastAllocatedBitrate(observer_config) == 0) {
251 min_bitrate += std::max(static_cast<uint32_t>(kToggleFactor * min_bitrate),
252 kMinToggleBitrateBps);
253 }
254 return min_bitrate;
255 }
256
257 void BitrateAllocator::DistributeBitrateEvenly(uint32_t bitrate,
258 int max_multiplier,
259 ObserverAllocation* allocation) {
260 RTC_DCHECK_EQ(allocation->size(), bitrate_observer_configs_.size());
261
262 ObserverSortingMap list_max_bitrates;
263 for (const auto& observer_config : bitrate_observer_configs_) {
264 if (allocation->at(observer_config.observer) != 0) {
265 list_max_bitrates.insert(std::pair<uint32_t, const ObserverConfig*>(
266 observer_config.max_bitrate_bps, &observer_config));
267 }
268 }
269 auto it = list_max_bitrates.begin();
270 while (it != list_max_bitrates.end()) {
271 RTC_DCHECK_GT(bitrate, 0u);
272 uint32_t extra_allocation = bitrate / list_max_bitrates.size();
273 uint32_t total_allocation =
274 extra_allocation + allocation->at(it->second->observer);
275 bitrate -= extra_allocation;
276 if (total_allocation > max_multiplier * it->first) {
277 // There is more than we can fit for this observer, carry over to the
278 // remaining observers.
279 bitrate += total_allocation - max_multiplier * it->first;
280 total_allocation = max_multiplier * it->first;
281 }
282 // Finally, update the allocation for this observer.
283 allocation->at(it->second->observer) = total_allocation;
284 it = list_max_bitrates.erase(it);
285 }
286 }
287
288 bool BitrateAllocator::ShouldDoLowRateAllocation(uint32_t bitrate,
289 uint32_t sum_min_bitrates) {
290 if (bitrate < sum_min_bitrates)
291 return true;
292
293 uint32_t extra_bitrate_per_observer =
294 (bitrate - sum_min_bitrates) / bitrate_observer_configs_.size();
295 for (const auto& observer_config : bitrate_observer_configs_) {
296 if (observer_config.min_bitrate_bps + extra_bitrate_per_observer <
297 MinBitrateForObserver(observer_config))
298 return true;
299 }
300 return false;
301 }
207 } // namespace webrtc 302 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698