OLD | NEW |
---|---|
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 |
OLD | NEW |