bitrate_allocator.cc (31707B)
1 /* 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 12 #include "call/bitrate_allocator.h" 13 14 #include <algorithm> 15 #include <cmath> 16 #include <cstddef> 17 #include <cstdint> 18 #include <map> 19 #include <optional> 20 #include <string> 21 #include <vector> 22 23 #include "absl/algorithm/container.h" 24 #include "api/call/bitrate_allocation.h" 25 #include "api/field_trials_view.h" 26 #include "api/sequence_checker.h" 27 #include "api/transport/network_types.h" 28 #include "api/units/data_rate.h" 29 #include "api/units/time_delta.h" 30 #include "rtc_base/checks.h" 31 #include "rtc_base/experiments/field_trial_parser.h" 32 #include "rtc_base/logging.h" 33 #include "rtc_base/numerics/safe_conversions.h" 34 #include "rtc_base/numerics/safe_minmax.h" 35 #include "system_wrappers/include/metrics.h" 36 37 namespace webrtc { 38 39 namespace { 40 using bitrate_allocator_impl::AllocatableTrack; 41 42 // Allow packets to be transmitted in up to 2 times max video bitrate if the 43 // bandwidth estimate allows it. 44 const uint8_t kTransmissionMaxBitrateMultiplier = 2; 45 const int kDefaultBitrateBps = 300000; 46 47 // Require a bitrate increase of max(10%, 20kbps) to resume paused streams. 48 const double kToggleFactor = 0.1; 49 const uint32_t kMinToggleBitrateBps = 20000; 50 51 const int64_t kBweLogIntervalMs = 5000; 52 53 double MediaRatio(uint32_t allocated_bitrate, uint32_t protection_bitrate) { 54 RTC_DCHECK_GT(allocated_bitrate, 0); 55 if (protection_bitrate == 0) 56 return 1.0; 57 58 uint32_t media_bitrate = allocated_bitrate - protection_bitrate; 59 return media_bitrate / static_cast<double>(allocated_bitrate); 60 } 61 62 bool EnoughBitrateForAllObservers( 63 const std::vector<AllocatableTrack>& allocatable_tracks, 64 uint32_t bitrate, 65 uint32_t sum_min_bitrates) { 66 if (bitrate < sum_min_bitrates) 67 return false; 68 69 uint32_t extra_bitrate_per_observer = 70 (bitrate - sum_min_bitrates) / 71 static_cast<uint32_t>(allocatable_tracks.size()); 72 for (const auto& observer_config : allocatable_tracks) { 73 if (observer_config.config.min_bitrate_bps + extra_bitrate_per_observer < 74 observer_config.MinBitrateWithHysteresis()) { 75 return false; 76 } 77 } 78 return true; 79 } 80 81 // Splits `bitrate` evenly to observers already in `allocation`. 82 // `include_zero_allocations` decides if zero allocations should be part of 83 // the distribution or not. The allowed max bitrate is `max_multiplier` x 84 // observer max bitrate. 85 void DistributeBitrateEvenly( 86 const std::vector<AllocatableTrack>& allocatable_tracks, 87 uint32_t bitrate, 88 bool include_zero_allocations, 89 int max_multiplier, 90 std::map<BitrateAllocatorObserver*, int>* allocation) { 91 RTC_DCHECK_EQ(allocation->size(), allocatable_tracks.size()); 92 93 std::multimap<uint32_t, const AllocatableTrack*> list_max_bitrates; 94 for (const auto& observer_config : allocatable_tracks) { 95 if (include_zero_allocations || 96 allocation->at(observer_config.observer) != 0) { 97 list_max_bitrates.insert( 98 {observer_config.config.max_bitrate_bps, &observer_config}); 99 } 100 } 101 auto it = list_max_bitrates.begin(); 102 while (it != list_max_bitrates.end()) { 103 RTC_DCHECK_GT(bitrate, 0); 104 uint32_t extra_allocation = 105 bitrate / static_cast<uint32_t>(list_max_bitrates.size()); 106 uint32_t total_allocation = 107 extra_allocation + allocation->at(it->second->observer); 108 bitrate -= extra_allocation; 109 if (total_allocation > max_multiplier * it->first) { 110 // There is more than we can fit for this observer, carry over to the 111 // remaining observers. 112 bitrate += total_allocation - max_multiplier * it->first; 113 total_allocation = max_multiplier * it->first; 114 } 115 // Finally, update the allocation for this observer. 116 allocation->at(it->second->observer) = total_allocation; 117 it = list_max_bitrates.erase(it); 118 } 119 } 120 121 // From the available `bitrate`, each observer will be allocated a 122 // proportional amount based upon its bitrate priority. If that amount is 123 // more than the observer's capacity, it will be allocated its capacity, and 124 // the excess bitrate is still allocated proportionally to other observers. 125 // Allocating the proportional amount means an observer with twice the 126 // bitrate_priority of another will be allocated twice the bitrate. 127 void DistributeBitrateRelatively( 128 const std::vector<AllocatableTrack>& allocatable_tracks, 129 uint32_t remaining_bitrate, 130 const std::map<BitrateAllocatorObserver*, int>& observers_capacities, 131 std::map<BitrateAllocatorObserver*, int>* allocation) { 132 RTC_DCHECK_EQ(allocation->size(), allocatable_tracks.size()); 133 RTC_DCHECK_EQ(observers_capacities.size(), allocatable_tracks.size()); 134 135 struct PriorityRateObserverConfig { 136 BitrateAllocatorObserver* allocation_key; 137 // The amount of bitrate bps that can be allocated to this observer. 138 int capacity_bps; 139 double bitrate_priority; 140 }; 141 142 double bitrate_priority_sum = 0; 143 std::vector<PriorityRateObserverConfig> priority_rate_observers; 144 for (const auto& observer_config : allocatable_tracks) { 145 priority_rate_observers.push_back(PriorityRateObserverConfig{ 146 .allocation_key = observer_config.observer, 147 .capacity_bps = observers_capacities.at(observer_config.observer), 148 .bitrate_priority = observer_config.config.bitrate_priority}); 149 bitrate_priority_sum += observer_config.config.bitrate_priority; 150 } 151 152 // Iterate in the order observers can be allocated their full capacity. 153 154 // We want to sort by which observers will be allocated their full capacity 155 // first. By dividing each observer's capacity by its bitrate priority we 156 // are "normalizing" the capacity of an observer by the rate it will be 157 // filled. This is because the amount allocated is based upon bitrate 158 // priority. We allocate twice as much bitrate to an observer with twice the 159 // bitrate priority of another. 160 absl::c_sort(priority_rate_observers, [](const auto& a, const auto& b) { 161 return a.capacity_bps / a.bitrate_priority < 162 b.capacity_bps / b.bitrate_priority; 163 }); 164 size_t i; 165 for (i = 0; i < priority_rate_observers.size(); ++i) { 166 const auto& priority_rate_observer = priority_rate_observers[i]; 167 // We allocate the full capacity to an observer only if its relative 168 // portion from the remaining bitrate is sufficient to allocate its full 169 // capacity. This means we aren't greedily allocating the full capacity, but 170 // that it is only done when there is also enough bitrate to allocate the 171 // proportional amounts to all other observers. 172 double observer_share = 173 priority_rate_observer.bitrate_priority / bitrate_priority_sum; 174 double allocation_bps = observer_share * remaining_bitrate; 175 bool enough_bitrate = allocation_bps >= priority_rate_observer.capacity_bps; 176 if (!enough_bitrate) 177 break; 178 allocation->at(priority_rate_observer.allocation_key) += 179 priority_rate_observer.capacity_bps; 180 remaining_bitrate -= priority_rate_observer.capacity_bps; 181 bitrate_priority_sum -= priority_rate_observer.bitrate_priority; 182 } 183 184 // From the remaining bitrate, allocate the proportional amounts to the 185 // observers that aren't allocated their max capacity. 186 for (; i < priority_rate_observers.size(); ++i) { 187 const auto& priority_rate_observer = priority_rate_observers[i]; 188 double fraction_allocated = 189 priority_rate_observer.bitrate_priority / bitrate_priority_sum; 190 allocation->at(priority_rate_observer.allocation_key) += 191 fraction_allocated * remaining_bitrate; 192 } 193 } 194 195 // Allocates bitrate to observers when there isn't enough to allocate the 196 // minimum to all observers. 197 std::map<BitrateAllocatorObserver*, int> LowRateAllocation( 198 const std::vector<AllocatableTrack>& allocatable_tracks, 199 uint32_t bitrate) { 200 std::map<BitrateAllocatorObserver*, int> allocation; 201 // Start by allocating bitrate to observers enforcing a min bitrate, hence 202 // remaining_bitrate might turn negative. 203 int64_t remaining_bitrate = bitrate; 204 for (const auto& observer_config : allocatable_tracks) { 205 int32_t allocated_bitrate = 0; 206 if (observer_config.config.enforce_min_bitrate) 207 allocated_bitrate = observer_config.config.min_bitrate_bps; 208 209 allocation[observer_config.observer] = allocated_bitrate; 210 remaining_bitrate -= allocated_bitrate; 211 } 212 213 // Allocate bitrate to all previously active streams. 214 if (remaining_bitrate > 0) { 215 for (const auto& observer_config : allocatable_tracks) { 216 if (observer_config.config.enforce_min_bitrate || 217 observer_config.LastAllocatedBitrate() == 0) 218 continue; 219 220 uint32_t required_bitrate = observer_config.MinBitrateWithHysteresis(); 221 if (remaining_bitrate >= required_bitrate) { 222 allocation[observer_config.observer] = required_bitrate; 223 remaining_bitrate -= required_bitrate; 224 } 225 } 226 } 227 228 // Allocate bitrate to previously paused streams. 229 if (remaining_bitrate > 0) { 230 for (const auto& observer_config : allocatable_tracks) { 231 if (observer_config.LastAllocatedBitrate() != 0) 232 continue; 233 234 // Add a hysteresis to avoid toggling. 235 uint32_t required_bitrate = observer_config.MinBitrateWithHysteresis(); 236 if (remaining_bitrate >= required_bitrate) { 237 allocation[observer_config.observer] = required_bitrate; 238 remaining_bitrate -= required_bitrate; 239 } 240 } 241 } 242 243 // Split a possible remainder evenly on all streams with an allocation. 244 if (remaining_bitrate > 0) 245 DistributeBitrateEvenly(allocatable_tracks, remaining_bitrate, false, 1, 246 &allocation); 247 248 RTC_DCHECK_EQ(allocation.size(), allocatable_tracks.size()); 249 return allocation; 250 } 251 252 // Allocates bitrate to all observers when the available bandwidth is enough 253 // to allocate the minimum to all observers but not enough to allocate the 254 // max bitrate of each observer. 255 256 // Allocates the bitrate based on the bitrate priority of each observer. This 257 // bitrate priority defines the priority for bitrate to be allocated to that 258 // observer in relation to other observers. For example with two observers, if 259 // observer 1 had a bitrate_priority = 1.0, and observer 2 has a 260 // bitrate_priority = 2.0, the expected behavior is that observer 2 will be 261 // allocated twice the bitrate as observer 1 above the each observer's 262 // min_bitrate_bps values, until one of the observers hits its max_bitrate_bps. 263 std::map<BitrateAllocatorObserver*, int> NormalRateAllocation( 264 const std::vector<AllocatableTrack>& allocatable_tracks, 265 uint32_t bitrate, 266 uint32_t sum_min_bitrates) { 267 std::map<BitrateAllocatorObserver*, int> allocation; 268 std::map<BitrateAllocatorObserver*, int> observers_capacities; 269 for (const auto& observer_config : allocatable_tracks) { 270 allocation[observer_config.observer] = 271 observer_config.config.min_bitrate_bps; 272 observers_capacities[observer_config.observer] = 273 observer_config.config.max_bitrate_bps - 274 observer_config.config.min_bitrate_bps; 275 } 276 277 bitrate -= sum_min_bitrates; 278 279 // TODO(srte): Implement fair sharing between prioritized streams, currently 280 // they are treated on a first come first serve basis. 281 for (const auto& observer_config : allocatable_tracks) { 282 int64_t priority_margin = observer_config.config.priority_bitrate_bps - 283 allocation[observer_config.observer]; 284 if (priority_margin > 0 && bitrate > 0) { 285 int64_t extra_bitrate = std::min<int64_t>(priority_margin, bitrate); 286 allocation[observer_config.observer] += dchecked_cast<int>(extra_bitrate); 287 observers_capacities[observer_config.observer] -= extra_bitrate; 288 bitrate -= extra_bitrate; 289 } 290 } 291 292 // From the remaining bitrate, allocate a proportional amount to each observer 293 // above the min bitrate already allocated. 294 if (bitrate > 0) 295 DistributeBitrateRelatively(allocatable_tracks, bitrate, 296 observers_capacities, &allocation); 297 298 return allocation; 299 } 300 301 // Allocates bitrate to observers when there is enough available bandwidth 302 // for all observers to be allocated their max bitrate. 303 std::map<BitrateAllocatorObserver*, int> MaxRateAllocation( 304 const std::vector<AllocatableTrack>& allocatable_tracks, 305 uint32_t bitrate, 306 uint32_t /* sum_max_bitrates */) { 307 std::map<BitrateAllocatorObserver*, int> allocation; 308 309 for (const auto& observer_config : allocatable_tracks) { 310 allocation[observer_config.observer] = 311 observer_config.config.max_bitrate_bps; 312 bitrate -= observer_config.config.max_bitrate_bps; 313 } 314 DistributeBitrateEvenly(allocatable_tracks, bitrate, true, 315 kTransmissionMaxBitrateMultiplier, &allocation); 316 return allocation; 317 } 318 319 // Allocates zero bitrate to all observers. 320 std::map<BitrateAllocatorObserver*, int> ZeroRateAllocation( 321 const std::vector<AllocatableTrack>& allocatable_tracks) { 322 std::map<BitrateAllocatorObserver*, int> allocation; 323 for (const auto& observer_config : allocatable_tracks) 324 allocation[observer_config.observer] = 0; 325 return allocation; 326 } 327 328 // Returns new allocation if modified, std::nullopt otherwise. 329 std::optional<std::map<BitrateAllocatorObserver*, int>> MaybeApplySurplus( 330 const std::map<BitrateAllocatorObserver*, int>& allocation, 331 const std::vector<AllocatableTrack>& allocatable_tracks, 332 DataRate bitrate, 333 DataRate upper_elastic_limit) { 334 if (upper_elastic_limit.IsZero()) 335 return std::nullopt; 336 337 // In this first pass looping over all `allocatable_tracks`, we aggregates 338 // - `surplus`: sum of unused rates for all kCanContribute* tracks, 339 // - `sum_demand`: sum of `bitrate_priority` for all tracks that can consume 340 // more bitrate to allow proportional sharing of surplus later, 341 // - `sum_allocated`: sum of allocated bitrates for all tracks, which might 342 // be larger than `bitrate` e.g. when min_bitrate_bps are enforced. 343 DataRate surplus = DataRate::Zero(); 344 double sum_demand = 0.0; 345 DataRate sum_allocated = DataRate::Zero(); 346 347 for (const auto& observer_config : allocatable_tracks) { 348 const auto it = allocation.find(observer_config.observer); 349 if (it == allocation.end()) { 350 // No allocation for this track. 351 continue; 352 } 353 const DataRate allocated = DataRate::BitsPerSec(it->second); 354 sum_allocated += allocated; 355 if (const std::optional<TrackRateElasticity> elasticity = 356 observer_config.config.rate_elasticity) { 357 bool inactive_can_contribute_and_consume = false; 358 if (elasticity == TrackRateElasticity::kCanContributeUnusedRate || 359 elasticity == TrackRateElasticity::kCanContributeAndConsume) { 360 if (const std::optional<DataRate> used = 361 observer_config.observer->GetUsedRate()) { 362 if (*used < allocated) { 363 surplus += allocated - *used; 364 if (elasticity == TrackRateElasticity::kCanContributeAndConsume && 365 *used < allocated / 2) { 366 inactive_can_contribute_and_consume = true; 367 } 368 } 369 } 370 } 371 if (!inactive_can_contribute_and_consume && 372 (elasticity == TrackRateElasticity::kCanConsumeExtraRate || 373 elasticity == TrackRateElasticity::kCanContributeAndConsume)) { 374 sum_demand += observer_config.config.bitrate_priority; 375 } 376 } 377 } 378 379 // `sum_allocated` can exceed `bitrate` if sum minBitrates exceeds 380 // estimated rate. The real `surplus` should cover the difference. 381 DataRate overshoot = 382 (sum_allocated >= bitrate) ? (sum_allocated - bitrate) : DataRate::Zero(); 383 if (sum_demand < 0.0001 || overshoot > surplus) { 384 // No demand for extra bitrate or no available surplus. 385 return std::nullopt; 386 } 387 surplus -= overshoot; 388 389 auto new_allocation = allocation; 390 // We loop over all allocatable_tracks again, and proportionally assign 391 // `surplus` to each track according to `bitrate_priority`. 392 for (const auto& observer_config : allocatable_tracks) { 393 auto it = new_allocation.find(observer_config.observer); 394 if (it == new_allocation.end()) { 395 // No allocation for this track. 396 continue; 397 } 398 std::optional<TrackRateElasticity> elasticity = 399 observer_config.config.rate_elasticity; 400 if (elasticity == TrackRateElasticity::kCanConsumeExtraRate || 401 elasticity == TrackRateElasticity::kCanContributeAndConsume) { 402 DataRate allocated = DataRate::BitsPerSec(it->second); 403 if (allocated < upper_elastic_limit) { 404 allocated += 405 surplus * (observer_config.config.bitrate_priority / sum_demand); 406 if (allocated > upper_elastic_limit) 407 allocated = upper_elastic_limit; 408 } 409 DataRate max_bitrate = 410 DataRate::BitsPerSec(observer_config.config.max_bitrate_bps); 411 if (allocated > max_bitrate) { 412 allocated = max_bitrate; 413 } 414 // Save new allocated rate back to `new_allocation`. 415 it->second = allocated.bps(); 416 } 417 } 418 return new_allocation; 419 } 420 421 std::map<BitrateAllocatorObserver*, int> AllocateBitrates( 422 const std::vector<AllocatableTrack>& allocatable_tracks, 423 uint32_t bitrate, 424 DataRate upper_elastic_limit) { 425 if (allocatable_tracks.empty()) 426 return std::map<BitrateAllocatorObserver*, int>(); 427 428 if (bitrate == 0) 429 return ZeroRateAllocation(allocatable_tracks); 430 431 uint32_t sum_min_bitrates = 0; 432 uint32_t sum_max_bitrates = 0; 433 for (const auto& observer_config : allocatable_tracks) { 434 sum_min_bitrates += observer_config.config.min_bitrate_bps; 435 sum_max_bitrates += observer_config.config.max_bitrate_bps; 436 } 437 438 // Not enough for all observers to get an allocation, allocate according to: 439 // enforced min bitrate -> allocated bitrate previous round -> restart paused 440 // streams. 441 if (!EnoughBitrateForAllObservers(allocatable_tracks, bitrate, 442 sum_min_bitrates)) 443 return LowRateAllocation(allocatable_tracks, bitrate); 444 445 // All observers will get their min bitrate plus a share of the rest. This 446 // share is allocated to each observer based on its bitrate_priority. 447 if (bitrate <= sum_max_bitrates) { 448 auto allocation = 449 NormalRateAllocation(allocatable_tracks, bitrate, sum_min_bitrates); 450 return MaybeApplySurplus(allocation, allocatable_tracks, 451 DataRate::BitsPerSec(bitrate), upper_elastic_limit) 452 .value_or(allocation); 453 } 454 455 // All observers will get up to transmission_max_bitrate_multiplier_ x max. 456 return MaxRateAllocation(allocatable_tracks, bitrate, sum_max_bitrates); 457 } 458 459 } // namespace 460 461 BitrateAllocator::BitrateAllocator(LimitObserver* limit_observer, 462 DataRate upper_elastic_rate_limit) 463 : limit_observer_(limit_observer), 464 last_target_bps_(0), 465 last_non_zero_bitrate_bps_(kDefaultBitrateBps), 466 last_fraction_loss_(0), 467 last_rtt_(0), 468 last_bwe_period_ms_(1000), 469 num_pause_events_(0), 470 last_bwe_log_time_(0), 471 upper_elastic_rate_limit_(upper_elastic_rate_limit) { 472 sequenced_checker_.Detach(); 473 } 474 475 BitrateAllocator::~BitrateAllocator() { 476 RTC_HISTOGRAM_COUNTS_100("WebRTC.Call.NumberOfPauseEvents", 477 num_pause_events_); 478 } 479 480 void BitrateAllocator::UpdateStartRate(uint32_t start_rate_bps) { 481 RTC_DCHECK_RUN_ON(&sequenced_checker_); 482 last_non_zero_bitrate_bps_ = start_rate_bps; 483 } 484 485 void BitrateAllocator::OnNetworkEstimateChanged(TargetTransferRate msg) { 486 RTC_DCHECK_RUN_ON(&sequenced_checker_); 487 last_target_bps_ = msg.target_rate.bps(); 488 last_non_zero_bitrate_bps_ = 489 last_target_bps_ > 0 ? last_target_bps_ : last_non_zero_bitrate_bps_; 490 491 int loss_ratio_255 = msg.network_estimate.loss_rate_ratio * 255; 492 last_fraction_loss_ = 493 dchecked_cast<uint8_t>(SafeClamp(loss_ratio_255, 0, 255)); 494 last_rtt_ = msg.network_estimate.round_trip_time.ms(); 495 last_bwe_period_ms_ = msg.network_estimate.bwe_period.ms(); 496 497 // Periodically log the incoming BWE. 498 int64_t now = msg.at_time.ms(); 499 if (now > last_bwe_log_time_ + kBweLogIntervalMs) { 500 RTC_LOG(LS_INFO) << "Current BWE " << last_target_bps_; 501 last_bwe_log_time_ = now; 502 } 503 504 auto allocation = AllocateBitrates(allocatable_tracks_, last_target_bps_, 505 upper_elastic_rate_limit_); 506 507 for (auto& track : allocatable_tracks_) { 508 uint32_t allocated_bitrate = allocation[track.observer]; 509 BitrateAllocationUpdate update; 510 update.target_bitrate = DataRate::BitsPerSec(allocated_bitrate); 511 update.packet_loss_ratio = last_fraction_loss_ / 256.0; 512 update.round_trip_time = TimeDelta::Millis(last_rtt_); 513 update.bwe_period = TimeDelta::Millis(last_bwe_period_ms_); 514 update.cwnd_reduce_ratio = msg.cwnd_reduce_ratio; 515 uint32_t protection_bitrate = track.observer->OnBitrateUpdated(update); 516 517 if (allocated_bitrate == 0 && track.allocated_bitrate_bps > 0) { 518 if (last_target_bps_ > 0) 519 ++num_pause_events_; 520 // The protection bitrate is an estimate based on the ratio between media 521 // and protection used before this observer was muted. 522 uint32_t predicted_protection_bps = 523 (1.0 - track.media_ratio) * track.config.min_bitrate_bps; 524 RTC_LOG(LS_INFO) << "Pausing observer " << track.observer 525 << " with configured min bitrate " 526 << track.config.min_bitrate_bps 527 << " and current estimate of " << last_target_bps_ 528 << " and protection bitrate " 529 << predicted_protection_bps; 530 } else if (allocated_bitrate > 0 && track.allocated_bitrate_bps == 0) { 531 if (last_target_bps_ > 0) 532 ++num_pause_events_; 533 RTC_LOG(LS_INFO) << "Resuming observer " << track.observer 534 << ", configured min bitrate " 535 << track.config.min_bitrate_bps 536 << ", current allocation " << allocated_bitrate 537 << " and protection bitrate " << protection_bitrate; 538 } 539 540 // Only update the media ratio if the observer got an allocation. 541 if (allocated_bitrate > 0) 542 track.media_ratio = MediaRatio(allocated_bitrate, protection_bitrate); 543 track.allocated_bitrate_bps = allocated_bitrate; 544 track.last_used_bitrate = track.observer->GetUsedRate(); 545 } 546 UpdateAllocationLimits(); 547 } 548 549 void BitrateAllocator::AddObserver(BitrateAllocatorObserver* observer, 550 MediaStreamAllocationConfig config) { 551 RTC_DCHECK_RUN_ON(&sequenced_checker_); 552 RTC_DCHECK_GT(config.bitrate_priority, 0); 553 RTC_DCHECK(std::isnormal(config.bitrate_priority)); 554 auto it = absl::c_find_if( 555 allocatable_tracks_, 556 [observer](const auto& config) { return config.observer == observer; }); 557 // Update settings if the observer already exists, create a new one otherwise. 558 if (it != allocatable_tracks_.end()) { 559 it->config = config; 560 } else { 561 allocatable_tracks_.push_back(AllocatableTrack(observer, config)); 562 } 563 564 if (last_target_bps_ > 0) { 565 // Calculate a new allocation and update all observers. 566 567 auto allocation = AllocateBitrates(allocatable_tracks_, last_target_bps_, 568 upper_elastic_rate_limit_); 569 for (auto& track : allocatable_tracks_) { 570 uint32_t allocated_bitrate = allocation[track.observer]; 571 BitrateAllocationUpdate update; 572 update.target_bitrate = DataRate::BitsPerSec(allocated_bitrate); 573 update.packet_loss_ratio = last_fraction_loss_ / 256.0; 574 update.round_trip_time = TimeDelta::Millis(last_rtt_); 575 update.bwe_period = TimeDelta::Millis(last_bwe_period_ms_); 576 uint32_t protection_bitrate = track.observer->OnBitrateUpdated(update); 577 track.allocated_bitrate_bps = allocated_bitrate; 578 track.last_used_bitrate = track.observer->GetUsedRate(); 579 if (allocated_bitrate > 0) 580 track.media_ratio = MediaRatio(allocated_bitrate, protection_bitrate); 581 } 582 } else { 583 // Currently, an encoder is not allowed to produce frames. 584 // But we still have to return the initial config bitrate + let the 585 // observer know that it can not produce frames. 586 587 BitrateAllocationUpdate update; 588 update.target_bitrate = DataRate::Zero(); 589 update.packet_loss_ratio = last_fraction_loss_ / 256.0; 590 update.round_trip_time = TimeDelta::Millis(last_rtt_); 591 update.bwe_period = TimeDelta::Millis(last_bwe_period_ms_); 592 observer->OnBitrateUpdated(update); 593 } 594 UpdateAllocationLimits(); 595 } 596 597 bool BitrateAllocator::RecomputeAllocationIfNeeded() { 598 RTC_DCHECK_RUN_ON(&sequenced_checker_); 599 600 if (upper_elastic_rate_limit_.IsZero()) { 601 return false; 602 } 603 604 bool need_recompute = false; 605 bool has_contributor = false; 606 bool has_consumer = false; 607 608 // Recomputes if there is a kCanContribute* track whose current bitrate usage 609 // has a jump (i.e., increase only) larger than 20% of allocated_bitrate. 610 constexpr double kUsageJumpRatioThreshold = 0.2; 611 for (auto& track : allocatable_tracks_) { 612 if (track.config.rate_elasticity.has_value()) { 613 const TrackRateElasticity elasticity = *track.config.rate_elasticity; 614 if (elasticity == TrackRateElasticity::kCanContributeUnusedRate || 615 elasticity == TrackRateElasticity::kCanContributeAndConsume) { 616 DataRate current_usage = 617 track.observer->GetUsedRate().value_or(DataRate::Zero()); 618 DataRate last_usage = 619 track.last_used_bitrate.value_or(DataRate::Zero()); 620 if (!last_usage.IsZero()) { 621 has_contributor = true; 622 DataRate recompute_threshold = 623 DataRate::BitsPerSec(track.LastAllocatedBitrate()) * 624 kUsageJumpRatioThreshold; 625 if (current_usage > last_usage + recompute_threshold) { 626 need_recompute = true; 627 } 628 } 629 } 630 if (elasticity == TrackRateElasticity::kCanConsumeExtraRate || 631 elasticity == TrackRateElasticity::kCanContributeAndConsume) { 632 has_consumer = true; 633 } 634 } 635 } 636 if (has_contributor == false || has_consumer == false) 637 return false; 638 639 if (need_recompute && last_target_bps_ > 0) { 640 // Calculate a new allocation and update all observers. 641 auto allocation = AllocateBitrates(allocatable_tracks_, last_target_bps_, 642 upper_elastic_rate_limit_); 643 for (auto& track : allocatable_tracks_) { 644 DataRate allocated_bitrate = 645 DataRate::BitsPerSec(allocation[track.observer]); 646 BitrateAllocationUpdate update; 647 update.target_bitrate = allocated_bitrate; 648 update.packet_loss_ratio = last_fraction_loss_ / 256.0; 649 update.round_trip_time = TimeDelta::Millis(last_rtt_); 650 update.bwe_period = TimeDelta::Millis(last_bwe_period_ms_); 651 DataRate protection_bitrate = 652 DataRate::BitsPerSec(track.observer->OnBitrateUpdated(update)); 653 track.allocated_bitrate_bps = allocated_bitrate.bps(); 654 track.last_used_bitrate = track.observer->GetUsedRate(); 655 if (allocated_bitrate.bps() > 0) 656 track.media_ratio = 657 MediaRatio(allocated_bitrate.bps(), protection_bitrate.bps()); 658 } 659 UpdateAllocationLimits(); 660 } 661 return true; 662 } 663 664 void BitrateAllocator::UpdateAllocationLimits() { 665 BitrateAllocationLimits limits; 666 for (const auto& track : allocatable_tracks_) { 667 uint32_t stream_padding = track.config.pad_up_bitrate_bps; 668 if (track.config.enforce_min_bitrate) { 669 limits.min_allocatable_rate += 670 DataRate::BitsPerSec(track.config.min_bitrate_bps); 671 } else if (track.allocated_bitrate_bps == 0) { 672 stream_padding = 673 std::max(track.MinBitrateWithHysteresis(), stream_padding); 674 } 675 limits.max_padding_rate += DataRate::BitsPerSec(stream_padding); 676 limits.max_allocatable_rate += 677 DataRate::BitsPerSec(track.config.max_bitrate_bps); 678 } 679 680 if (limits.min_allocatable_rate == current_limits_.min_allocatable_rate && 681 limits.max_allocatable_rate == current_limits_.max_allocatable_rate && 682 limits.max_padding_rate == current_limits_.max_padding_rate) { 683 return; 684 } 685 current_limits_ = limits; 686 687 RTC_LOG(LS_INFO) << "UpdateAllocationLimits : total_requested_min_bitrate: " 688 << ToString(limits.min_allocatable_rate) 689 << ", total_requested_padding_bitrate: " 690 << ToString(limits.max_padding_rate) 691 << ", total_requested_max_bitrate: " 692 << ToString(limits.max_allocatable_rate); 693 694 limit_observer_->OnAllocationLimitsChanged(limits); 695 } 696 697 void BitrateAllocator::RemoveObserver(BitrateAllocatorObserver* observer) { 698 RTC_DCHECK_RUN_ON(&sequenced_checker_); 699 for (auto it = allocatable_tracks_.begin(); it != allocatable_tracks_.end(); 700 ++it) { 701 if (it->observer == observer) { 702 allocatable_tracks_.erase(it); 703 break; 704 } 705 } 706 707 UpdateAllocationLimits(); 708 } 709 710 int BitrateAllocator::GetStartBitrate( 711 BitrateAllocatorObserver* observer) const { 712 RTC_DCHECK_RUN_ON(&sequenced_checker_); 713 auto it = absl::c_find_if( 714 allocatable_tracks_, 715 [observer](const auto& config) { return config.observer == observer; }); 716 if (it == allocatable_tracks_.end()) { 717 // This observer hasn't been added yet, just give it its fair share. 718 return last_non_zero_bitrate_bps_ / 719 static_cast<int>((allocatable_tracks_.size() + 1)); 720 } else if (it->allocated_bitrate_bps == -1) { 721 // This observer hasn't received an allocation yet, so do the same. 722 return last_non_zero_bitrate_bps_ / 723 static_cast<int>(allocatable_tracks_.size()); 724 } else { 725 // This observer already has an allocation. 726 return it->allocated_bitrate_bps; 727 } 728 } 729 730 uint32_t bitrate_allocator_impl::AllocatableTrack::LastAllocatedBitrate() 731 const { 732 // Return the configured minimum bitrate for newly added observers, to avoid 733 // requiring an extra high bitrate for the observer to get an allocated 734 // bitrate. 735 return allocated_bitrate_bps == -1 ? config.min_bitrate_bps 736 : allocated_bitrate_bps; 737 } 738 739 uint32_t bitrate_allocator_impl::AllocatableTrack::MinBitrateWithHysteresis() 740 const { 741 uint32_t min_bitrate = config.min_bitrate_bps; 742 if (LastAllocatedBitrate() == 0) { 743 min_bitrate += std::max(static_cast<uint32_t>(kToggleFactor * min_bitrate), 744 kMinToggleBitrateBps); 745 } 746 // Account for protection bitrate used by this observer in the previous 747 // allocation. 748 // Note: the ratio will only be updated when the stream is active, meaning a 749 // paused stream won't get any ratio updates. This might lead to waiting a bit 750 // longer than necessary if the network condition improves, but this is to 751 // avoid too much toggling. 752 if (media_ratio > 0.0 && media_ratio < 1.0) 753 min_bitrate += min_bitrate * (1.0 - media_ratio); 754 755 return min_bitrate; 756 } 757 758 // TODO(b/350555527): Remove after experiment 759 const char kElasticBitrateAllocator[] = "WebRTC-ElasticBitrateAllocation"; 760 DataRate GetElasticRateAllocationFieldTrialParameter( 761 const FieldTrialsView& field_trials) { 762 FieldTrialParameter<DataRate> elastic_rate_limit("upper_limit", 763 DataRate::Zero()); 764 std::string trial_string = field_trials.Lookup(kElasticBitrateAllocator); 765 ParseFieldTrial({&elastic_rate_limit}, trial_string); 766 return elastic_rate_limit.Get(); 767 } 768 769 } // namespace webrtc