/* * 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/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() : crit_sect_(CriticalSectionWrapper::CreateCriticalSection()), bitrate_observers_(), bitrate_observers_modified_(false), enforce_min_bitrate_(true), last_bitrate_bps_(kDefaultBitrateBps), last_fraction_loss_(0), last_rtt_(0) {} uint32_t BitrateAllocator::OnNetworkChanged(uint32_t bitrate, uint8_t fraction_loss, int64_t rtt) { CriticalSectionScoped lock(crit_sect_.get()); last_bitrate_bps_ = bitrate; last_fraction_loss_ = fraction_loss; last_rtt_ = rtt; uint32_t allocated_bitrate_bps = 0; ObserverBitrateMap allocation = AllocateBitrates(); for (const auto& kv : allocation) { kv.first->OnNetworkChanged(kv.second, last_fraction_loss_, last_rtt_); allocated_bitrate_bps += kv.second; } return allocated_bitrate_bps; } BitrateAllocator::ObserverBitrateMap BitrateAllocator::AllocateBitrates() { if (bitrate_observers_.empty()) return ObserverBitrateMap(); uint32_t sum_min_bitrates = 0; for (const auto& observer : bitrate_observers_) sum_min_bitrates += observer.second.min_bitrate; if (last_bitrate_bps_ <= sum_min_bitrates) return LowRateAllocation(last_bitrate_bps_); else return NormalRateAllocation(last_bitrate_bps_, sum_min_bitrates); } int BitrateAllocator::AddBitrateObserver(BitrateObserver* observer, uint32_t min_bitrate_bps, uint32_t max_bitrate_bps) { CriticalSectionScoped lock(crit_sect_.get()); BitrateObserverConfList::iterator it = FindObserverConfigurationPair(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_observers_.end()) { // Update current configuration. it->second.min_bitrate = min_bitrate_bps; it->second.max_bitrate = max_bitrate_bps; } else { // Add new settings. bitrate_observers_.push_back(BitrateObserverConfiguration( observer, BitrateConfiguration(min_bitrate_bps, max_bitrate_bps))); bitrate_observers_modified_ = true; } ObserverBitrateMap allocation = AllocateBitrates(); int new_observer_bitrate_bps = 0; for (auto& kv : allocation) { kv.first->OnNetworkChanged(kv.second, last_fraction_loss_, last_rtt_); if (kv.first == observer) new_observer_bitrate_bps = kv.second; } return new_observer_bitrate_bps; } void BitrateAllocator::RemoveBitrateObserver(BitrateObserver* observer) { CriticalSectionScoped lock(crit_sect_.get()); BitrateObserverConfList::iterator it = FindObserverConfigurationPair(observer); if (it != bitrate_observers_.end()) { bitrate_observers_.erase(it); bitrate_observers_modified_ = true; } } void BitrateAllocator::GetMinMaxBitrateSumBps(int* min_bitrate_sum_bps, int* max_bitrate_sum_bps) const { *min_bitrate_sum_bps = 0; *max_bitrate_sum_bps = 0; CriticalSectionScoped lock(crit_sect_.get()); for (const auto& observer : bitrate_observers_) { *min_bitrate_sum_bps += observer.second.min_bitrate; *max_bitrate_sum_bps += observer.second.max_bitrate; } } BitrateAllocator::BitrateObserverConfList::iterator BitrateAllocator::FindObserverConfigurationPair( const BitrateObserver* observer) { for (auto it = bitrate_observers_.begin(); it != bitrate_observers_.end(); ++it) { if (it->first == observer) return it; } return bitrate_observers_.end(); } void BitrateAllocator::EnforceMinBitrate(bool enforce_min_bitrate) { CriticalSectionScoped lock(crit_sect_.get()); enforce_min_bitrate_ = enforce_min_bitrate; } BitrateAllocator::ObserverBitrateMap BitrateAllocator::NormalRateAllocation( uint32_t bitrate, uint32_t sum_min_bitrates) { uint32_t number_of_observers = static_cast(bitrate_observers_.size()); uint32_t bitrate_per_observer = (bitrate - sum_min_bitrates) / number_of_observers; // Use map to sort list based on max bitrate. ObserverSortingMap list_max_bitrates; for (const auto& observer : bitrate_observers_) { list_max_bitrates.insert(std::pair( observer.second.max_bitrate, ObserverConfiguration(observer.first, observer.second.min_bitrate))); } ObserverBitrateMap allocation; ObserverSortingMap::iterator max_it = list_max_bitrates.begin(); while (max_it != list_max_bitrates.end()) { number_of_observers--; uint32_t observer_allowance = max_it->second.min_bitrate + 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 (number_of_observers != 0) { bitrate_per_observer += remainder / number_of_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::ObserverBitrateMap BitrateAllocator::LowRateAllocation( uint32_t bitrate) { ObserverBitrateMap allocation; if (enforce_min_bitrate_) { // Min bitrate to all observers. for (const auto& observer : bitrate_observers_) allocation[observer.first] = observer.second.min_bitrate; } else { // Allocate up to |min_bitrate| to one observer at a time, until // |bitrate| is depleted. uint32_t remainder = bitrate; for (const auto& observer : bitrate_observers_) { uint32_t allocated_bitrate = std::min(remainder, observer.second.min_bitrate); allocation[observer.first] = allocated_bitrate; remainder -= allocated_bitrate; } } return allocation; } } // namespace webrtc