diff --git a/webrtc/call/bitrate_allocator.cc b/webrtc/call/bitrate_allocator.cc index 4c8d2a0c44..5b1d07ee04 100644 --- a/webrtc/call/bitrate_allocator.cc +++ b/webrtc/call/bitrate_allocator.cc @@ -14,6 +14,7 @@ #include #include +#include "webrtc/base/checks.h" #include "webrtc/modules/bitrate_controller/include/bitrate_controller.h" namespace webrtc { @@ -24,8 +25,7 @@ const int kTransmissionMaxBitrateMultiplier = 2; const int kDefaultBitrateBps = 300000; BitrateAllocator::BitrateAllocator() - : bitrate_observers_(), - bitrate_observers_modified_(false), + : bitrate_observer_configs_(), enforce_min_bitrate_(true), last_bitrate_bps_(kDefaultBitrateBps), last_fraction_loss_(0), @@ -38,8 +38,9 @@ uint32_t BitrateAllocator::OnNetworkChanged(uint32_t bitrate, last_bitrate_bps_ = bitrate; last_fraction_loss_ = fraction_loss; last_rtt_ = rtt; + uint32_t allocated_bitrate_bps = 0; - ObserverBitrateMap allocation = AllocateBitrates(); + ObserverAllocation allocation = AllocateBitrates(); for (const auto& kv : allocation) { kv.first->OnBitrateUpdated(kv.second, last_fraction_loss_, last_rtt_); allocated_bitrate_bps += kv.second; @@ -47,46 +48,32 @@ uint32_t BitrateAllocator::OnNetworkChanged(uint32_t bitrate, 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_ == 0) - return ZeroRateAllocation(); - else if (last_bitrate_bps_ <= sum_min_bitrates) - return LowRateAllocation(last_bitrate_bps_); - else - return NormalRateAllocation(last_bitrate_bps_, sum_min_bitrates); -} - int BitrateAllocator::AddObserver(BitrateAllocatorObserver* observer, uint32_t min_bitrate_bps, - uint32_t max_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); - BitrateObserverConfList::iterator it = - FindObserverConfigurationPair(observer); + 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_observers_.end()) { + if (it != bitrate_observer_configs_.end()) { // Update current configuration. - it->second.min_bitrate = min_bitrate_bps; - it->second.max_bitrate = max_bitrate_bps; + it->min_bitrate_bps = min_bitrate_bps; + it->max_bitrate_bps = max_bitrate_bps; } else { // Add new settings. - bitrate_observers_.push_back(BitrateObserverConfiguration( - observer, BitrateConfiguration(min_bitrate_bps, max_bitrate_bps))); - bitrate_observers_modified_ = true; + bitrate_observer_configs_.push_back(ObserverConfig( + observer, min_bitrate_bps, max_bitrate_bps, enforce_min_bitrate)); } - ObserverBitrateMap allocation = AllocateBitrates(); + ObserverAllocation allocation = AllocateBitrates(); int new_observer_bitrate_bps = 0; for (auto& kv : allocation) { kv.first->OnBitrateUpdated(kv.second, last_fraction_loss_, last_rtt_); @@ -98,60 +85,74 @@ int BitrateAllocator::AddObserver(BitrateAllocatorObserver* observer, void BitrateAllocator::RemoveObserver(BitrateAllocatorObserver* observer) { rtc::CritScope lock(&crit_sect_); - BitrateObserverConfList::iterator it = - FindObserverConfigurationPair(observer); - if (it != bitrate_observers_.end()) { - bitrate_observers_.erase(it); - bitrate_observers_modified_ = true; + auto it = FindObserverConfig(observer); + if (it != bitrate_observer_configs_.end()) { + bitrate_observer_configs_.erase(it); } } -BitrateAllocator::BitrateObserverConfList::iterator -BitrateAllocator::FindObserverConfigurationPair( - const BitrateAllocatorObserver* 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) { - rtc::CritScope lock(&crit_sect_); enforce_min_bitrate_ = enforce_min_bitrate; } -BitrateAllocator::ObserverBitrateMap BitrateAllocator::NormalRateAllocation( +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() { + if (bitrate_observer_configs_.empty()) + return ObserverAllocation(); + + if (last_bitrate_bps_ == 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 (last_bitrate_bps_ <= sum_min_bitrates) + return LowRateAllocation(last_bitrate_bps_); + + return NormalRateAllocation(last_bitrate_bps_, sum_min_bitrates); +} + +BitrateAllocator::ObserverAllocation BitrateAllocator::NormalRateAllocation( uint32_t bitrate, uint32_t sum_min_bitrates) { - uint32_t number_of_observers = - static_cast(bitrate_observers_.size()); + 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) / number_of_observers; + (bitrate - sum_min_bitrates) / num_remaining_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))); + for (const auto& config : bitrate_observer_configs_) { + list_max_bitrates.insert(std::pair( + config.max_bitrate_bps, &config)); } - ObserverBitrateMap allocation; + + ObserverAllocation allocation; ObserverSortingMap::iterator max_it = list_max_bitrates.begin(); while (max_it != list_max_bitrates.end()) { - number_of_observers--; + num_remaining_observers--; uint32_t observer_allowance = - max_it->second.min_bitrate + bitrate_per_observer; + 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 (number_of_observers != 0) { - bitrate_per_observer += remainder / number_of_observers; - } - allocation[max_it->second.observer] = 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; + allocation[max_it->second->observer] = observer_allowance; } list_max_bitrates.erase(max_it); // Prepare next iteration. @@ -160,29 +161,29 @@ BitrateAllocator::ObserverBitrateMap BitrateAllocator::NormalRateAllocation( return allocation; } -BitrateAllocator::ObserverBitrateMap BitrateAllocator::ZeroRateAllocation() { - ObserverBitrateMap allocation; +BitrateAllocator::ObserverAllocation BitrateAllocator::ZeroRateAllocation() { + ObserverAllocation allocation; // Zero bitrate to all observers. - for (const auto& observer : bitrate_observers_) - allocation[observer.first] = 0; + for (const auto& observer_config : bitrate_observer_configs_) + allocation[observer_config.observer] = 0; return allocation; } -BitrateAllocator::ObserverBitrateMap BitrateAllocator::LowRateAllocation( +BitrateAllocator::ObserverAllocation BitrateAllocator::LowRateAllocation( uint32_t bitrate) { - ObserverBitrateMap allocation; + ObserverAllocation allocation; if (enforce_min_bitrate_) { // Min bitrate to all observers. - for (const auto& observer : bitrate_observers_) - allocation[observer.first] = observer.second.min_bitrate; + for (const auto& observer_config : bitrate_observer_configs_) + allocation[observer_config.observer] = observer_config.min_bitrate_bps; } else { - // Allocate up to |min_bitrate| to one observer at a time, until + // Allocate up to |min_bitrate_bps| to one observer at a time, until // |bitrate| is depleted. uint32_t remainder = bitrate; - for (const auto& observer : bitrate_observers_) { + for (const auto& observer_config : bitrate_observer_configs_) { uint32_t allocated_bitrate = - std::min(remainder, observer.second.min_bitrate); - allocation[observer.first] = allocated_bitrate; + std::min(remainder, observer_config.min_bitrate_bps); + allocation[observer_config.observer] = allocated_bitrate; remainder -= allocated_bitrate; } } diff --git a/webrtc/call/bitrate_allocator.h b/webrtc/call/bitrate_allocator.h index fc88b783b5..4c24c5016a 100644 --- a/webrtc/call/bitrate_allocator.h +++ b/webrtc/call/bitrate_allocator.h @@ -53,55 +53,61 @@ class BitrateAllocator { // |observer| updates bitrates if already in use. // |min_bitrate_bps| = 0 equals no min bitrate. // |max_bitrate_bps| = 0 equals no max bitrate. - // Returns bitrate allocated for the bitrate observer. + // |enforce_min_bitrate| = 'true' will allocate at least |min_bitrate_bps| for + // this observer, even if the BWE is too low, 'false' will allocate 0 to + // the observer if BWE doesn't allow |min_bitrate_bps|. + // Returns bitrate allocated for |observer|. int AddObserver(BitrateAllocatorObserver* observer, uint32_t min_bitrate_bps, - uint32_t max_bitrate_bps); + uint32_t max_bitrate_bps, + bool enforce_min_bitrate); void RemoveObserver(BitrateAllocatorObserver* observer); + private: + struct ObserverConfig { + ObserverConfig(BitrateAllocatorObserver* observer, + uint32_t min_bitrate_bps, + uint32_t max_bitrate_bps, + bool enforce_min_bitrate) + : observer(observer), + min_bitrate_bps(min_bitrate_bps), + max_bitrate_bps(max_bitrate_bps), + enforce_min_bitrate(enforce_min_bitrate) {} + BitrateAllocatorObserver* const observer; + uint32_t min_bitrate_bps; + uint32_t max_bitrate_bps; + bool enforce_min_bitrate; + }; + // This method controls the behavior when the available bitrate is lower than // the minimum bitrate, or the sum of minimum bitrates. // When true, the bitrate will never be set lower than the minimum bitrate(s). // When false, the bitrate observers will be allocated rates up to their // respective minimum bitrate, satisfying one observer after the other. - void EnforceMinBitrate(bool enforce_min_bitrate); + void EnforceMinBitrate(bool enforce_min_bitrate) + EXCLUSIVE_LOCKS_REQUIRED(crit_sect_); - private: - struct BitrateConfiguration { - BitrateConfiguration(uint32_t min_bitrate, uint32_t max_bitrate) - : min_bitrate(min_bitrate), max_bitrate(max_bitrate) {} - uint32_t min_bitrate; - uint32_t max_bitrate; - }; - struct ObserverConfiguration { - ObserverConfiguration(BitrateAllocatorObserver* observer, uint32_t bitrate) - : observer(observer), min_bitrate(bitrate) {} - BitrateAllocatorObserver* const observer; - uint32_t min_bitrate; - }; - typedef std::pair - BitrateObserverConfiguration; - typedef std::list BitrateObserverConfList; - typedef std::multimap ObserverSortingMap; - typedef std::map ObserverBitrateMap; - - BitrateObserverConfList::iterator FindObserverConfigurationPair( + typedef std::list ObserverConfigList; + ObserverConfigList::iterator FindObserverConfig( const BitrateAllocatorObserver* observer) EXCLUSIVE_LOCKS_REQUIRED(crit_sect_); - ObserverBitrateMap AllocateBitrates() EXCLUSIVE_LOCKS_REQUIRED(crit_sect_); - ObserverBitrateMap NormalRateAllocation(uint32_t bitrate, + + typedef std::multimap ObserverSortingMap; + typedef std::map ObserverAllocation; + + ObserverAllocation AllocateBitrates() EXCLUSIVE_LOCKS_REQUIRED(crit_sect_); + ObserverAllocation NormalRateAllocation(uint32_t bitrate, uint32_t sum_min_bitrates) EXCLUSIVE_LOCKS_REQUIRED(crit_sect_); - ObserverBitrateMap ZeroRateAllocation() EXCLUSIVE_LOCKS_REQUIRED(crit_sect_); - ObserverBitrateMap LowRateAllocation(uint32_t bitrate) + ObserverAllocation ZeroRateAllocation() EXCLUSIVE_LOCKS_REQUIRED(crit_sect_); + ObserverAllocation LowRateAllocation(uint32_t bitrate) EXCLUSIVE_LOCKS_REQUIRED(crit_sect_); rtc::CriticalSection crit_sect_; // Stored in a list to keep track of the insertion order. - BitrateObserverConfList bitrate_observers_ GUARDED_BY(crit_sect_); - bool bitrate_observers_modified_ GUARDED_BY(crit_sect_); + ObserverConfigList bitrate_observer_configs_; bool enforce_min_bitrate_ GUARDED_BY(crit_sect_); uint32_t last_bitrate_bps_ GUARDED_BY(crit_sect_); uint8_t last_fraction_loss_ GUARDED_BY(crit_sect_); diff --git a/webrtc/call/bitrate_allocator_unittest.cc b/webrtc/call/bitrate_allocator_unittest.cc index 63149acbe3..253d3fb3df 100644 --- a/webrtc/call/bitrate_allocator_unittest.cc +++ b/webrtc/call/bitrate_allocator_unittest.cc @@ -48,7 +48,7 @@ class BitrateAllocatorTest : public ::testing::Test { TEST_F(BitrateAllocatorTest, UpdatingBitrateObserver) { TestBitrateObserver bitrate_observer; int start_bitrate = - allocator_->AddObserver(&bitrate_observer, 100000, 1500000); + allocator_->AddObserver(&bitrate_observer, 100000, 1500000, true); EXPECT_EQ(300000, start_bitrate); allocator_->OnNetworkChanged(200000, 0, 0); EXPECT_EQ(200000u, bitrate_observer.last_bitrate_); @@ -57,10 +57,12 @@ TEST_F(BitrateAllocatorTest, UpdatingBitrateObserver) { // bitrate for FEC/retransmissions (see todo in BitrateAllocator). allocator_->OnNetworkChanged(4000000, 0, 0); EXPECT_EQ(3000000u, bitrate_observer.last_bitrate_); - start_bitrate = allocator_->AddObserver(&bitrate_observer, 100000, 4000000); + start_bitrate = + allocator_->AddObserver(&bitrate_observer, 100000, 4000000, true); EXPECT_EQ(4000000, start_bitrate); - start_bitrate = allocator_->AddObserver(&bitrate_observer, 100000, 1500000); + start_bitrate = + allocator_->AddObserver(&bitrate_observer, 100000, 1500000, true); EXPECT_EQ(3000000, start_bitrate); EXPECT_EQ(3000000u, bitrate_observer.last_bitrate_); allocator_->OnNetworkChanged(1500000, 0, 0); @@ -71,9 +73,10 @@ TEST_F(BitrateAllocatorTest, TwoBitrateObserversOneRtcpObserver) { TestBitrateObserver bitrate_observer_1; TestBitrateObserver bitrate_observer_2; int start_bitrate = - allocator_->AddObserver(&bitrate_observer_1, 100000, 300000); + allocator_->AddObserver(&bitrate_observer_1, 100000, 300000, true); EXPECT_EQ(300000, start_bitrate); - start_bitrate = allocator_->AddObserver(&bitrate_observer_2, 200000, 300000); + start_bitrate = + allocator_->AddObserver(&bitrate_observer_2, 200000, 300000, true); EXPECT_EQ(200000, start_bitrate); // Test too low start bitrate, hence lower than sum of min. Min bitrates will @@ -107,7 +110,6 @@ TEST_F(BitrateAllocatorTest, TwoBitrateObserversOneRtcpObserver) { class BitrateAllocatorTestNoEnforceMin : public ::testing::Test { protected: BitrateAllocatorTestNoEnforceMin() : allocator_(new BitrateAllocator()) { - allocator_->EnforceMinBitrate(false); allocator_->OnNetworkChanged(300000u, 0, 0); } ~BitrateAllocatorTestNoEnforceMin() {} @@ -120,7 +122,7 @@ class BitrateAllocatorTestNoEnforceMin : public ::testing::Test { TEST_F(BitrateAllocatorTestNoEnforceMin, OneBitrateObserver) { TestBitrateObserver bitrate_observer_1; int start_bitrate = - allocator_->AddObserver(&bitrate_observer_1, 100000, 400000); + allocator_->AddObserver(&bitrate_observer_1, 100000, 400000, false); EXPECT_EQ(300000, start_bitrate); // High REMB. @@ -140,14 +142,16 @@ TEST_F(BitrateAllocatorTestNoEnforceMin, ThreeBitrateObservers) { TestBitrateObserver bitrate_observer_3; // Set up the observers with min bitrates at 100000, 200000, and 300000. int start_bitrate = - allocator_->AddObserver(&bitrate_observer_1, 100000, 400000); + allocator_->AddObserver(&bitrate_observer_1, 100000, 400000, false); EXPECT_EQ(300000, start_bitrate); - start_bitrate = allocator_->AddObserver(&bitrate_observer_2, 200000, 400000); + start_bitrate = + allocator_->AddObserver(&bitrate_observer_2, 200000, 400000, false); EXPECT_EQ(200000, start_bitrate); EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_); - start_bitrate = allocator_->AddObserver(&bitrate_observer_3, 300000, 400000); + start_bitrate = + allocator_->AddObserver(&bitrate_observer_3, 300000, 400000, false); EXPECT_EQ(0, start_bitrate); EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_); EXPECT_EQ(200000u, bitrate_observer_2.last_bitrate_); @@ -194,14 +198,16 @@ TEST_F(BitrateAllocatorTest, ThreeBitrateObserversLowRembEnforceMin) { TestBitrateObserver bitrate_observer_2; TestBitrateObserver bitrate_observer_3; int start_bitrate = - allocator_->AddObserver(&bitrate_observer_1, 100000, 400000); + allocator_->AddObserver(&bitrate_observer_1, 100000, 400000, true); EXPECT_EQ(300000, start_bitrate); - start_bitrate = allocator_->AddObserver(&bitrate_observer_2, 200000, 400000); + start_bitrate = + allocator_->AddObserver(&bitrate_observer_2, 200000, 400000, true); EXPECT_EQ(200000, start_bitrate); EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_); - start_bitrate = allocator_->AddObserver(&bitrate_observer_3, 300000, 400000); + start_bitrate = + allocator_->AddObserver(&bitrate_observer_3, 300000, 400000, true); EXPECT_EQ(300000, start_bitrate); EXPECT_EQ(100000, static_cast(bitrate_observer_1.last_bitrate_)); EXPECT_EQ(200000, static_cast(bitrate_observer_2.last_bitrate_)); diff --git a/webrtc/video/video_send_stream.cc b/webrtc/video/video_send_stream.cc index 840991b4ba..dcacf56388 100644 --- a/webrtc/video/video_send_stream.cc +++ b/webrtc/video/video_send_stream.cc @@ -562,7 +562,8 @@ void VideoSendStream::EncoderProcess() { encoder_settings->video_codec.startBitrate = bitrate_allocator_->AddObserver( this, encoder_settings->video_codec.minBitrate * 1000, - encoder_settings->video_codec.maxBitrate * 1000) / + encoder_settings->video_codec.maxBitrate * 1000, + !config_.suspend_below_min_bitrate) / 1000; payload_router_.SetSendStreams(encoder_settings->streams); @@ -570,16 +571,16 @@ void VideoSendStream::EncoderProcess() { encoder_settings->min_transmit_bitrate_bps, payload_router_.MaxPayloadLength(), this); + // vie_encoder_.SetEncoder must be called before this. + if (config_.suspend_below_min_bitrate) + video_sender_->SuspendBelowMinBitrate(); + // Clear stats for disabled layers. for (size_t i = encoder_settings->streams.size(); i < config_.rtp.ssrcs.size(); ++i) { stats_proxy_.OnInactiveSsrc(config_.rtp.ssrcs[i]); } - if (config_.suspend_below_min_bitrate) { - video_sender_->SuspendBelowMinBitrate(); - bitrate_allocator_->EnforceMinBitrate(false); - } // We might've gotten new settings while configuring the encoder settings, // restart from the top to see if that's the case before trying to encode // a frame (which might correspond to the last frame size).