/* * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. * */ #include "webrtc/call/bitrate_allocator.h" #include #include #include "webrtc/base/checks.h" #include "webrtc/modules/bitrate_controller/include/bitrate_controller.h" namespace webrtc { // Allow packets to be transmitted in up to 2 times max video bitrate if the // bandwidth estimate allows it. const int kTransmissionMaxBitrateMultiplier = 2; const int kDefaultBitrateBps = 300000; BitrateAllocator::BitrateAllocator() : bitrate_observer_configs_(), enforce_min_bitrate_(true), last_bitrate_bps_(kDefaultBitrateBps), last_non_zero_bitrate_bps_(kDefaultBitrateBps), last_fraction_loss_(0), last_rtt_(0) {} uint32_t BitrateAllocator::OnNetworkChanged(uint32_t bitrate, uint8_t fraction_loss, int64_t rtt) { rtc::CritScope lock(&crit_sect_); last_bitrate_bps_ = bitrate; last_non_zero_bitrate_bps_ = bitrate > 0 ? bitrate : last_non_zero_bitrate_bps_; last_fraction_loss_ = fraction_loss; last_rtt_ = rtt; uint32_t allocated_bitrate_bps = 0; ObserverAllocation allocation = AllocateBitrates(bitrate); for (const auto& kv : allocation) { kv.first->OnBitrateUpdated(kv.second, last_fraction_loss_, last_rtt_); allocated_bitrate_bps += kv.second; } return allocated_bitrate_bps; } int BitrateAllocator::AddObserver(BitrateAllocatorObserver* observer, uint32_t min_bitrate_bps, uint32_t max_bitrate_bps, bool enforce_min_bitrate) { rtc::CritScope lock(&crit_sect_); // TODO(mflodman): Enforce this per observer. EnforceMinBitrate(enforce_min_bitrate); auto it = FindObserverConfig(observer); // Allow the max bitrate to be exceeded for FEC and retransmissions. // TODO(holmer): We have to get rid of this hack as it makes it difficult to // properly allocate bitrate. The allocator should instead distribute any // extra bitrate after all streams have maxed out. max_bitrate_bps *= kTransmissionMaxBitrateMultiplier; if (it != bitrate_observer_configs_.end()) { // Update current configuration. it->min_bitrate_bps = min_bitrate_bps; it->max_bitrate_bps = max_bitrate_bps; } else { // Add new settings. bitrate_observer_configs_.push_back(ObserverConfig( observer, min_bitrate_bps, max_bitrate_bps, enforce_min_bitrate)); } int new_observer_bitrate_bps = 0; if (last_bitrate_bps_ > 0) { // We have a bitrate to allocate. ObserverAllocation allocation = AllocateBitrates(last_bitrate_bps_); for (auto& kv : allocation) { // Update all observers with the new allocation. kv.first->OnBitrateUpdated(kv.second, last_fraction_loss_, last_rtt_); if (kv.first == observer) new_observer_bitrate_bps = kv.second; } } else { // Currently, an encoder is not allowed to produce frames. // But we still have to return the initial config bitrate + let the // observer know that it can not produce frames. ObserverAllocation allocation = AllocateBitrates(last_non_zero_bitrate_bps_); observer->OnBitrateUpdated(0, last_fraction_loss_, last_rtt_); new_observer_bitrate_bps = allocation[observer]; } return new_observer_bitrate_bps; } void BitrateAllocator::RemoveObserver(BitrateAllocatorObserver* observer) { rtc::CritScope lock(&crit_sect_); auto it = FindObserverConfig(observer); if (it != bitrate_observer_configs_.end()) { bitrate_observer_configs_.erase(it); } } void BitrateAllocator::EnforceMinBitrate(bool enforce_min_bitrate) { enforce_min_bitrate_ = enforce_min_bitrate; } BitrateAllocator::ObserverConfigList::iterator BitrateAllocator::FindObserverConfig( const BitrateAllocatorObserver* observer) { for (auto it = bitrate_observer_configs_.begin(); it != bitrate_observer_configs_.end(); ++it) { if (it->observer == observer) return it; } return bitrate_observer_configs_.end(); } BitrateAllocator::ObserverAllocation BitrateAllocator::AllocateBitrates( uint32_t bitrate) { if (bitrate_observer_configs_.empty()) return ObserverAllocation(); if (bitrate == 0) return ZeroRateAllocation(); uint32_t sum_min_bitrates = 0; for (const auto& observer_config : bitrate_observer_configs_) sum_min_bitrates += observer_config.min_bitrate_bps; if (bitrate <= sum_min_bitrates) return LowRateAllocation(bitrate); return NormalRateAllocation(bitrate, sum_min_bitrates); } BitrateAllocator::ObserverAllocation BitrateAllocator::NormalRateAllocation( uint32_t bitrate, uint32_t sum_min_bitrates) { uint32_t num_remaining_observers = static_cast(bitrate_observer_configs_.size()); RTC_DCHECK_GT(num_remaining_observers, 0u); uint32_t bitrate_per_observer = (bitrate - sum_min_bitrates) / num_remaining_observers; // Use map to sort list based on max bitrate. ObserverSortingMap list_max_bitrates; for (const auto& config : bitrate_observer_configs_) { list_max_bitrates.insert(std::pair( config.max_bitrate_bps, &config)); } ObserverAllocation allocation; ObserverSortingMap::iterator max_it = list_max_bitrates.begin(); while (max_it != list_max_bitrates.end()) { num_remaining_observers--; uint32_t observer_allowance = max_it->second->min_bitrate_bps + bitrate_per_observer; if (max_it->first < observer_allowance) { // We have more than enough for this observer. // Carry the remainder forward. uint32_t remainder = observer_allowance - max_it->first; if (num_remaining_observers != 0) bitrate_per_observer += remainder / num_remaining_observers; allocation[max_it->second->observer] = max_it->first; } else { allocation[max_it->second->observer] = observer_allowance; } list_max_bitrates.erase(max_it); // Prepare next iteration. max_it = list_max_bitrates.begin(); } return allocation; } BitrateAllocator::ObserverAllocation BitrateAllocator::ZeroRateAllocation() { ObserverAllocation allocation; // Zero bitrate to all observers. for (const auto& observer_config : bitrate_observer_configs_) allocation[observer_config.observer] = 0; return allocation; } BitrateAllocator::ObserverAllocation BitrateAllocator::LowRateAllocation( uint32_t bitrate) { ObserverAllocation allocation; if (enforce_min_bitrate_) { // Min bitrate to all observers. for (const auto& observer_config : bitrate_observer_configs_) allocation[observer_config.observer] = observer_config.min_bitrate_bps; } else { // Allocate up to |min_bitrate_bps| to one observer at a time, until // |bitrate| is depleted. uint32_t remainder = bitrate; for (const auto& observer_config : bitrate_observer_configs_) { uint32_t allocated_bitrate = std::min(remainder, observer_config.min_bitrate_bps); allocation[observer_config.observer] = allocated_bitrate; remainder -= allocated_bitrate; } } return allocation; } } // namespace webrtc