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

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

Issue 2117493002: Auto pause video streams based on encoder target bitrate. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Created 4 years, 5 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/base/logging.h"
18 #include "webrtc/modules/bitrate_controller/include/bitrate_controller.h" 19 #include "webrtc/modules/bitrate_controller/include/bitrate_controller.h"
20 #include "webrtc/system_wrappers/include/clock.h"
21 #include "webrtc/system_wrappers/include/metrics.h"
19 22
20 namespace webrtc { 23 namespace webrtc {
21 24
22 // Allow packets to be transmitted in up to 2 times max video bitrate if the 25 // Allow packets to be transmitted in up to 2 times max video bitrate if the
23 // bandwidth estimate allows it. 26 // bandwidth estimate allows it.
24 const int kTransmissionMaxBitrateMultiplier = 2; 27 const int kTransmissionMaxBitrateMultiplier = 2;
25 const int kDefaultBitrateBps = 300000; 28 const int kDefaultBitrateBps = 300000;
26 29
27 // Require a bitrate increase of max(10%, 20kbps) to resume paused streams. 30 // Require a bitrate increase of max(10%, 20kbps) to resume paused streams.
28 const double kToggleFactor = 0.1; 31 const double kToggleFactor = 0.1;
29 const uint32_t kMinToggleBitrateBps = 20000; 32 const uint32_t kMinToggleBitrateBps = 20000;
30 33
34 const int64_t kBweLogIntervalMs = 5000;
35
31 BitrateAllocator::BitrateAllocator(LimitObserver* limit_observer) 36 BitrateAllocator::BitrateAllocator(LimitObserver* limit_observer)
32 : limit_observer_(limit_observer), 37 : limit_observer_(limit_observer),
33 bitrate_observer_configs_(), 38 bitrate_observer_configs_(),
34 last_bitrate_bps_(kDefaultBitrateBps), 39 last_bitrate_bps_(kDefaultBitrateBps),
35 last_non_zero_bitrate_bps_(kDefaultBitrateBps), 40 last_non_zero_bitrate_bps_(kDefaultBitrateBps),
36 last_fraction_loss_(0), 41 last_fraction_loss_(0),
37 last_rtt_(0) {} 42 last_rtt_(0),
43 num_pause_events_(0),
44 clock_(Clock::GetRealTimeClock()),
45 last_bwe_log_time_(0) {}
46
47 BitrateAllocator::~BitrateAllocator() {
48 RTC_LOGGED_HISTOGRAM_COUNTS_100("WebRTC.Call.NumberOfPauseEvents",
49 num_pause_events_);
stefan-webrtc 2016/06/30 16:17:38 Good to have! Remember to add it to the uma config
mflodman 2016/07/01 09:40:15 Thanks for the reminder, I'll make sure this happe
50 }
38 51
39 void BitrateAllocator::OnNetworkChanged(uint32_t target_bitrate_bps, 52 void BitrateAllocator::OnNetworkChanged(uint32_t target_bitrate_bps,
40 uint8_t fraction_loss, 53 uint8_t fraction_loss,
41 int64_t rtt) { 54 int64_t rtt) {
42 rtc::CritScope lock(&crit_sect_); 55 rtc::CritScope lock(&crit_sect_);
43 last_bitrate_bps_ = target_bitrate_bps; 56 last_bitrate_bps_ = target_bitrate_bps;
44 last_non_zero_bitrate_bps_ = 57 last_non_zero_bitrate_bps_ =
45 target_bitrate_bps > 0 ? target_bitrate_bps : last_non_zero_bitrate_bps_; 58 target_bitrate_bps > 0 ? target_bitrate_bps : last_non_zero_bitrate_bps_;
46 last_fraction_loss_ = fraction_loss; 59 last_fraction_loss_ = fraction_loss;
47 last_rtt_ = rtt; 60 last_rtt_ = rtt;
48 61
62 // Periodically log the incoming BWE.
63 int64_t now = clock_->TimeInMilliseconds();
64 if (now > last_bwe_log_time_ + kBweLogIntervalMs) {
65 LOG(LS_INFO) << "Current BWE " << target_bitrate_bps;
66 last_bwe_log_time_ = now;
67 }
68
49 ObserverAllocation allocation = AllocateBitrates(target_bitrate_bps); 69 ObserverAllocation allocation = AllocateBitrates(target_bitrate_bps);
50 for (const auto& kv : allocation) { 70
51 kv.first->OnBitrateUpdated(kv.second, last_fraction_loss_, last_rtt_); 71 for (auto& config : bitrate_observer_configs_) {
72 uint32_t allocated_bitrate = allocation[config.observer];
73 uint32_t protection_bitrate = config.observer->OnBitrateUpdated(
74 allocated_bitrate, last_fraction_loss_, last_rtt_);
75
76 if (allocated_bitrate == 0 && config.allocated_bitrate_bps > 0) {
77 if (target_bitrate_bps > 0)
78 ++num_pause_events_;
79 uint32_t predicted_protection =
stefan-webrtc 2016/06/30 16:17:38 _bps Add a comment describing that this assumes t
mflodman 2016/07/01 09:40:15 Done.
80 (1.0 - config.media_ratio) * config.min_bitrate_bps;
81 LOG(LS_INFO) << "Pausing observer " << config.observer
82 << " with configured min bitrate " << config.min_bitrate_bps
83 << " and current estimate of " << target_bitrate_bps
stefan-webrtc 2016/06/30 16:17:38 Should you log the allocation here too?
mflodman 2016/07/01 09:40:15 Good point, added.
stefan-webrtc 2016/07/01 10:42:49 Can't see that it was added?
mflodman 2016/07/01 10:52:28 Sorry, bad reply from me. The allocation will be 0
84 << " and protection bitrate " << predicted_protection;
85 } else if (allocated_bitrate > 0 && config.allocated_bitrate_bps == 0) {
86 if (target_bitrate_bps > 0)
87 ++num_pause_events_;
88 LOG(LS_INFO) << "Resuming observer " << config.observer
89 << " with configured min bitrate " << config.min_bitrate_bps
90 << " and current allocation " << allocated_bitrate
91 << " and protection bitrate " << protection_bitrate;
92 }
93
94 // Only update the media ratio if the observer got an allocation.
95 if (allocated_bitrate > 0) {
96 config.media_ratio = (allocated_bitrate - protection_bitrate) /
stefan-webrtc 2016/06/30 16:17:38 Use a helper variable media_bitrate = allocated_bi
mflodman 2016/07/01 09:40:15 Done.
97 static_cast<double>(allocated_bitrate);
98 }
99 config.allocated_bitrate_bps = allocated_bitrate;
52 } 100 }
53 last_allocation_ = allocation;
54 } 101 }
55 102
56 void BitrateAllocator::AddObserver(BitrateAllocatorObserver* observer, 103 void BitrateAllocator::AddObserver(BitrateAllocatorObserver* observer,
57 uint32_t min_bitrate_bps, 104 uint32_t min_bitrate_bps,
58 uint32_t max_bitrate_bps, 105 uint32_t max_bitrate_bps,
59 uint32_t pad_up_bitrate_bps, 106 uint32_t pad_up_bitrate_bps,
60 bool enforce_min_bitrate) { 107 bool enforce_min_bitrate) {
61 rtc::CritScope lock(&crit_sect_); 108 rtc::CritScope lock(&crit_sect_);
62 auto it = FindObserverConfig(observer); 109 auto it = FindObserverConfig(observer);
63 110
64 // Update settings if the observer already exists, create a new one otherwise. 111 // Update settings if the observer already exists, create a new one otherwise.
65 if (it != bitrate_observer_configs_.end()) { 112 if (it != bitrate_observer_configs_.end()) {
66 it->min_bitrate_bps = min_bitrate_bps; 113 it->min_bitrate_bps = min_bitrate_bps;
67 it->max_bitrate_bps = max_bitrate_bps; 114 it->max_bitrate_bps = max_bitrate_bps;
68 it->pad_up_bitrate_bps = pad_up_bitrate_bps; 115 it->pad_up_bitrate_bps = pad_up_bitrate_bps;
69 it->enforce_min_bitrate = enforce_min_bitrate; 116 it->enforce_min_bitrate = enforce_min_bitrate;
70 } else { 117 } else {
71 bitrate_observer_configs_.push_back( 118 bitrate_observer_configs_.push_back(
72 ObserverConfig(observer, min_bitrate_bps, max_bitrate_bps, 119 ObserverConfig(observer, min_bitrate_bps, max_bitrate_bps,
73 pad_up_bitrate_bps, enforce_min_bitrate)); 120 pad_up_bitrate_bps, enforce_min_bitrate));
74 } 121 }
75 122
76 ObserverAllocation allocation; 123 ObserverAllocation allocation;
77 if (last_bitrate_bps_ > 0) { 124 if (last_bitrate_bps_ > 0) {
78 // Calculate a new allocation and update all observers. 125 // Calculate a new allocation and update all observers.
79 allocation = AllocateBitrates(last_bitrate_bps_); 126 allocation = AllocateBitrates(last_bitrate_bps_);
80 for (const auto& kv : allocation) 127 for (auto& config : bitrate_observer_configs_) {
81 kv.first->OnBitrateUpdated(kv.second, last_fraction_loss_, last_rtt_); 128 uint32_t allocated_bitrate = allocation[config.observer];
129 config.observer->OnBitrateUpdated(
130 allocated_bitrate, last_fraction_loss_, last_rtt_);
131 config.allocated_bitrate_bps = allocated_bitrate;
stefan-webrtc 2016/06/30 16:17:38 Is there no need to update the media ratio here? I
mflodman 2016/07/01 09:40:15 That is a good question and I assumed it would be
stefan-webrtc 2016/07/01 10:42:49 Thanks. Better to do it and avoid others asking th
132 }
82 } else { 133 } else {
83 // Currently, an encoder is not allowed to produce frames. 134 // Currently, an encoder is not allowed to produce frames.
84 // But we still have to return the initial config bitrate + let the 135 // But we still have to return the initial config bitrate + let the
85 // observer know that it can not produce frames. 136 // observer know that it can not produce frames.
86 allocation = AllocateBitrates(last_non_zero_bitrate_bps_); 137 allocation = AllocateBitrates(last_non_zero_bitrate_bps_);
87 observer->OnBitrateUpdated(0, last_fraction_loss_, last_rtt_); 138 observer->OnBitrateUpdated(0, last_fraction_loss_, last_rtt_);
88 } 139 }
89 UpdateAllocationLimits(); 140 UpdateAllocationLimits();
90
91 last_allocation_ = allocation;
92 } 141 }
93 142
94 void BitrateAllocator::UpdateAllocationLimits() { 143 void BitrateAllocator::UpdateAllocationLimits() {
95 uint32_t total_requested_padding_bitrate = 0; 144 uint32_t total_requested_padding_bitrate = 0;
96 uint32_t total_requested_min_bitrate = 0; 145 uint32_t total_requested_min_bitrate = 0;
97 146
98 { 147 {
99 rtc::CritScope lock(&crit_sect_); 148 rtc::CritScope lock(&crit_sect_);
100 for (const auto& config : bitrate_observer_configs_) { 149 for (const auto& config : bitrate_observer_configs_) {
101 if (config.enforce_min_bitrate) { 150 if (config.enforce_min_bitrate) {
(...skipping 13 matching lines...) Expand all
115 auto it = FindObserverConfig(observer); 164 auto it = FindObserverConfig(observer);
116 if (it != bitrate_observer_configs_.end()) { 165 if (it != bitrate_observer_configs_.end()) {
117 bitrate_observer_configs_.erase(it); 166 bitrate_observer_configs_.erase(it);
118 } 167 }
119 } 168 }
120 UpdateAllocationLimits(); 169 UpdateAllocationLimits();
121 } 170 }
122 171
123 int BitrateAllocator::GetStartBitrate(BitrateAllocatorObserver* observer) { 172 int BitrateAllocator::GetStartBitrate(BitrateAllocatorObserver* observer) {
124 rtc::CritScope lock(&crit_sect_); 173 rtc::CritScope lock(&crit_sect_);
125 const auto& it = last_allocation_.find(observer); 174 const auto& it = FindObserverConfig(observer);
126 if (it != last_allocation_.end()) 175 if (it == bitrate_observer_configs_.end()) {
127 return it->second; 176 // This observer hasn't been added yet, just give it its fair share.
stefan-webrtc 2016/06/30 16:17:38 Not clear to me why this can happen? Is it correct
mflodman 2016/07/01 09:40:15 AS of now it is, the encoder is configured before
stefan-webrtc 2016/07/01 10:42:49 Acknowledged.
128 177 return last_non_zero_bitrate_bps_ /
129 // This is a new observer that has not yet been started. Assume that if it is 178 static_cast<int>((bitrate_observer_configs_.size() + 1));
130 // added, all observers would split the available bitrate evenly. 179 } else if (it->allocated_bitrate_bps == -1) {
131 return last_non_zero_bitrate_bps_ / 180 // This observer hasn't received an allocation yet, so do the same.
132 static_cast<int>((bitrate_observer_configs_.size() + 1)); 181 return last_non_zero_bitrate_bps_ /
182 static_cast<int>(bitrate_observer_configs_.size());
183 } else {
184 // This observer already has an allocation.
185 return it->allocated_bitrate_bps;
186 }
133 } 187 }
134 188
135 BitrateAllocator::ObserverConfigList::iterator 189 BitrateAllocator::ObserverConfigs::iterator
136 BitrateAllocator::FindObserverConfig( 190 BitrateAllocator::FindObserverConfig(
137 const BitrateAllocatorObserver* observer) { 191 const BitrateAllocatorObserver* observer) {
138 for (auto it = bitrate_observer_configs_.begin(); 192 for (auto it = bitrate_observer_configs_.begin();
139 it != bitrate_observer_configs_.end(); ++it) { 193 it != bitrate_observer_configs_.end(); ++it) {
140 if (it->observer == observer) 194 if (it->observer == observer)
141 return it; 195 return it;
142 } 196 }
143 return bitrate_observer_configs_.end(); 197 return bitrate_observer_configs_.end();
144 } 198 }
145 199
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
195 remaining_bitrate -= allocated_bitrate; 249 remaining_bitrate -= allocated_bitrate;
196 } 250 }
197 251
198 // Allocate bitrate to all previously active streams. 252 // Allocate bitrate to all previously active streams.
199 if (remaining_bitrate > 0) { 253 if (remaining_bitrate > 0) {
200 for (const auto& observer_config : bitrate_observer_configs_) { 254 for (const auto& observer_config : bitrate_observer_configs_) {
201 if (observer_config.enforce_min_bitrate || 255 if (observer_config.enforce_min_bitrate ||
202 LastAllocatedBitrate(observer_config) == 0) 256 LastAllocatedBitrate(observer_config) == 0)
203 continue; 257 continue;
204 258
205 if (remaining_bitrate >= observer_config.min_bitrate_bps) { 259 uint32_t required_bitrate = MinBitrateWithHysteresis(observer_config);
206 allocation[observer_config.observer] = observer_config.min_bitrate_bps; 260 if (remaining_bitrate >= required_bitrate) {
207 remaining_bitrate -= observer_config.min_bitrate_bps; 261 allocation[observer_config.observer] = required_bitrate;
262 remaining_bitrate -= required_bitrate;
208 } 263 }
209 } 264 }
210 } 265 }
211 266
212 // Allocate bitrate to previously paused streams. 267 // Allocate bitrate to previously paused streams.
213 if (remaining_bitrate > 0) { 268 if (remaining_bitrate > 0) {
214 for (const auto& observer_config : bitrate_observer_configs_) { 269 for (const auto& observer_config : bitrate_observer_configs_) {
215 if (LastAllocatedBitrate(observer_config) != 0) 270 if (LastAllocatedBitrate(observer_config) != 0)
216 continue; 271 continue;
217 272
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
256 bitrate -= observer_config.max_bitrate_bps; 311 bitrate -= observer_config.max_bitrate_bps;
257 } 312 }
258 DistributeBitrateEvenly(bitrate, true, kTransmissionMaxBitrateMultiplier, 313 DistributeBitrateEvenly(bitrate, true, kTransmissionMaxBitrateMultiplier,
259 &allocation); 314 &allocation);
260 return allocation; 315 return allocation;
261 } 316 }
262 317
263 uint32_t BitrateAllocator::LastAllocatedBitrate( 318 uint32_t BitrateAllocator::LastAllocatedBitrate(
264 const ObserverConfig& observer_config) { 319 const ObserverConfig& observer_config) {
265 320
266 const auto& it = last_allocation_.find(observer_config.observer);
267 if (it != last_allocation_.end())
268 return it->second;
269
270 // Return the configured minimum bitrate for newly added observers, to avoid 321 // Return the configured minimum bitrate for newly added observers, to avoid
271 // requiring an extra high bitrate for the observer to get an allocated 322 // requiring an extra high bitrate for the observer to get an allocated
272 // bitrate. 323 // bitrate.
273 return observer_config.min_bitrate_bps; 324 return observer_config.allocated_bitrate_bps == -1 ?
325 observer_config.min_bitrate_bps : observer_config.allocated_bitrate_bps;
274 } 326 }
275 327
276 uint32_t BitrateAllocator::MinBitrateWithHysteresis( 328 uint32_t BitrateAllocator::MinBitrateWithHysteresis(
277 const ObserverConfig& observer_config) { 329 const ObserverConfig& observer_config) {
278 uint32_t min_bitrate = observer_config.min_bitrate_bps; 330 uint32_t min_bitrate = observer_config.min_bitrate_bps;
279 if (LastAllocatedBitrate(observer_config) == 0) { 331 if (LastAllocatedBitrate(observer_config) == 0) {
280 min_bitrate += std::max(static_cast<uint32_t>(kToggleFactor * min_bitrate), 332 min_bitrate += std::max(static_cast<uint32_t>(kToggleFactor * min_bitrate),
281 kMinToggleBitrateBps); 333 kMinToggleBitrateBps);
282 } 334 }
335 // Account for protection bitrate used by this observer in the previous
336 // allocation.
337 // Note: the ratio will only be updated when the stream is active, meaning a
338 // paused stream won't get any ratio updates. This might lead to waiting a bit
339 // longer than necessary if the network condition improves, but this is to
340 // avoid too much toggling.
stefan-webrtc 2016/06/30 16:17:38 I wonder if this should be moved up to where the r
mflodman 2016/07/01 09:40:15 As of now I prefer it this way to have it separate
stefan-webrtc 2016/07/01 10:42:49 Acknowledged.
341 if (observer_config.media_ratio > 0.0 && observer_config.media_ratio < 1.0)
342 min_bitrate += min_bitrate * (1.0 - observer_config.media_ratio);
343
283 return min_bitrate; 344 return min_bitrate;
284 } 345 }
285 346
286 void BitrateAllocator::DistributeBitrateEvenly(uint32_t bitrate, 347 void BitrateAllocator::DistributeBitrateEvenly(uint32_t bitrate,
287 bool include_zero_allocations, 348 bool include_zero_allocations,
288 int max_multiplier, 349 int max_multiplier,
289 ObserverAllocation* allocation) { 350 ObserverAllocation* allocation) {
290 RTC_DCHECK_EQ(allocation->size(), bitrate_observer_configs_.size()); 351 RTC_DCHECK_EQ(allocation->size(), bitrate_observer_configs_.size());
291 352
292 ObserverSortingMap list_max_bitrates; 353 ObserverSortingMap list_max_bitrates;
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
325 uint32_t extra_bitrate_per_observer = (bitrate - sum_min_bitrates) / 386 uint32_t extra_bitrate_per_observer = (bitrate - sum_min_bitrates) /
326 static_cast<uint32_t>(bitrate_observer_configs_.size()); 387 static_cast<uint32_t>(bitrate_observer_configs_.size());
327 for (const auto& observer_config : bitrate_observer_configs_) { 388 for (const auto& observer_config : bitrate_observer_configs_) {
328 if (observer_config.min_bitrate_bps + extra_bitrate_per_observer < 389 if (observer_config.min_bitrate_bps + extra_bitrate_per_observer <
329 MinBitrateWithHysteresis(observer_config)) 390 MinBitrateWithHysteresis(observer_config))
330 return false; 391 return false;
331 } 392 }
332 return true; 393 return true;
333 } 394 }
334 } // namespace webrtc 395 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698