diff --git a/api/DEPS b/api/DEPS index 58b673646e..f49cd810be 100644 --- a/api/DEPS +++ b/api/DEPS @@ -120,6 +120,7 @@ specific_include_rules = { "+media/base/media_config.h", "+media/base/media_engine.h", "+p2p/base/port_allocator.h", + "+rtc_base/bitrate_allocation_strategy.h", "+rtc_base/network.h", "+rtc_base/rtc_certificate.h", "+rtc_base/rtc_certificate_generator.h", diff --git a/api/peer_connection_interface.h b/api/peer_connection_interface.h index 69935d2fa9..6841e14477 100644 --- a/api/peer_connection_interface.h +++ b/api/peer_connection_interface.h @@ -105,6 +105,8 @@ // PortAllocator in the PeerConnection api. #include "media/base/media_engine.h" // nogncheck #include "p2p/base/port_allocator.h" // nogncheck +// TODO(nisse): The interface for bitrate allocation strategy belongs in api/. +#include "rtc_base/bitrate_allocation_strategy.h" #include "rtc_base/network.h" #include "rtc_base/rtc_certificate.h" #include "rtc_base/rtc_certificate_generator.h" @@ -1034,6 +1036,14 @@ class RTC_EXPORT PeerConnectionInterface : public rtc::RefCountInterface { // of the methods. virtual RTCError SetBitrate(const BitrateParameters& bitrate_parameters); + // Sets current strategy. If not set default WebRTC allocator will be used. + // May be changed during an active session. The strategy + // ownership is passed with std::unique_ptr + // TODO(alexnarest): Make this pure virtual when tests will be updated + virtual void SetBitrateAllocationStrategy( + std::unique_ptr + bitrate_allocation_strategy) {} + // Enable/disable playout of received audio streams. Enabled by default. Note // that even if playout is enabled, streams will only be played out if the // appropriate SDP is also applied. Setting |playout| to false will stop diff --git a/api/peer_connection_proxy.h b/api/peer_connection_proxy.h index 61ac6a1ca3..70bdd11a2e 100644 --- a/api/peer_connection_proxy.h +++ b/api/peer_connection_proxy.h @@ -117,6 +117,9 @@ PROXY_METHOD1(bool, PROXY_METHOD1(bool, AddIceCandidate, const IceCandidateInterface*) PROXY_METHOD1(bool, RemoveIceCandidates, const std::vector&) PROXY_METHOD1(RTCError, SetBitrate, const BitrateSettings&) +PROXY_METHOD1(void, + SetBitrateAllocationStrategy, + std::unique_ptr) PROXY_METHOD1(void, SetAudioPlayout, bool) PROXY_METHOD1(void, SetAudioRecording, bool) PROXY_METHOD1(rtc::scoped_refptr, diff --git a/api/test/mock_peerconnectioninterface.h b/api/test/mock_peerconnectioninterface.h index 8e9c54a574..fa132b4aaa 100644 --- a/api/test/mock_peerconnectioninterface.h +++ b/api/test/mock_peerconnectioninterface.h @@ -117,6 +117,8 @@ class MockPeerConnectionInterface bool(const std::vector&)); MOCK_METHOD1(SetBitrate, RTCError(const BitrateSettings&)); MOCK_METHOD1(SetBitrate, RTCError(const BitrateParameters&)); + MOCK_METHOD1(SetBitrateAllocationStrategy, + void(std::unique_ptr)); MOCK_METHOD1(SetAudioPlayout, void(bool)); MOCK_METHOD1(SetAudioRecording, void(bool)); MOCK_METHOD0(signaling_state, SignalingState()); diff --git a/audio/audio_send_stream.cc b/audio/audio_send_stream.cc index d387ff181f..9190441678 100644 --- a/audio/audio_send_stream.cc +++ b/audio/audio_send_stream.cc @@ -827,6 +827,7 @@ void AudioSendStream::ConfigureBitrateObserver() { MediaStreamAllocationConfig{ constraints.min.bps(), constraints.max.bps(), 0, allocation_settings_.DefaultPriorityBitrate().bps(), true, + config_.track_id, allocation_settings_.BitratePriority().value_or( config_.bitrate_priority)}); } diff --git a/call/bitrate_allocator.cc b/call/bitrate_allocator.cc index 487dd47ad8..97a2bb69ec 100644 --- a/call/bitrate_allocator.cc +++ b/call/bitrate_allocator.cc @@ -64,8 +64,11 @@ BitrateAllocator::BitrateAllocator(Clock* clock, LimitObserver* limit_observer) total_requested_padding_bitrate_(0), total_requested_min_bitrate_(0), total_requested_max_bitrate_(0), + bitrate_allocation_strategy_(nullptr), transmission_max_bitrate_multiplier_( - GetTransmissionMaxBitrateMultiplier()) { + GetTransmissionMaxBitrateMultiplier()), + ignore_injected_strategy_( + field_trial::IsEnabled("WebRTC-IgnoreInjectedAllocationStrategy")) { sequenced_checker_.Detach(); } @@ -172,10 +175,10 @@ void BitrateAllocator::AddObserver(BitrateAllocatorObserver* observer, it->enforce_min_bitrate = config.enforce_min_bitrate; it->bitrate_priority = config.bitrate_priority; } else { - bitrate_observer_configs_.push_back( - ObserverConfig(observer, config.min_bitrate_bps, config.max_bitrate_bps, - config.pad_up_bitrate_bps, config.priority_bitrate_bps, - config.enforce_min_bitrate, config.bitrate_priority)); + bitrate_observer_configs_.push_back(ObserverConfig( + observer, config.min_bitrate_bps, config.max_bitrate_bps, + config.pad_up_bitrate_bps, config.priority_bitrate_bps, + config.enforce_min_bitrate, config.track_id, config.bitrate_priority)); } if (last_target_bps_ > 0) { @@ -280,6 +283,13 @@ int BitrateAllocator::GetStartBitrate( } } +void BitrateAllocator::SetBitrateAllocationStrategy( + std::unique_ptr + bitrate_allocation_strategy) { + RTC_DCHECK_RUN_ON(&sequenced_checker_); + bitrate_allocation_strategy_ = std::move(bitrate_allocation_strategy); +} + BitrateAllocator::ObserverConfigs::const_iterator BitrateAllocator::FindObserverConfig( const BitrateAllocatorObserver* observer) const { @@ -306,6 +316,25 @@ BitrateAllocator::ObserverAllocation BitrateAllocator::AllocateBitrates( if (bitrate_observer_configs_.empty()) return ObserverAllocation(); + if (!ignore_injected_strategy_ && bitrate_allocation_strategy_ != nullptr) { + // Note: This intentionally causes slicing, we only copy the fields in + // ObserverConfig that are inherited from TrackConfig. + std::vector track_configs( + bitrate_observer_configs_.begin(), bitrate_observer_configs_.end()); + + std::vector track_allocations = + bitrate_allocation_strategy_->AllocateBitrates( + bitrate, std::move(track_configs)); + // The strategy should return allocation for all tracks. + RTC_CHECK(track_allocations.size() == bitrate_observer_configs_.size()); + ObserverAllocation allocation; + auto track_allocations_it = track_allocations.begin(); + for (const auto& observer_config : bitrate_observer_configs_) { + allocation[observer_config.observer] = *track_allocations_it++; + } + return allocation; + } + if (bitrate == 0) return ZeroRateAllocation(); diff --git a/call/bitrate_allocator.h b/call/bitrate_allocator.h index ecff422b92..8611a8967b 100644 --- a/call/bitrate_allocator.h +++ b/call/bitrate_allocator.h @@ -20,6 +20,7 @@ #include #include "api/call/bitrate_allocation.h" +#include "rtc_base/bitrate_allocation_strategy.h" #include "rtc_base/synchronization/sequence_checker.h" namespace webrtc { @@ -56,6 +57,7 @@ struct MediaStreamAllocationConfig { uint32_t pad_up_bitrate_bps; int64_t priority_bitrate_bps; bool enforce_min_bitrate; + std::string track_id; double bitrate_priority; }; @@ -114,24 +116,33 @@ class BitrateAllocator : public BitrateAllocatorInterface { // the list of added observers, a best guess is returned. int GetStartBitrate(BitrateAllocatorObserver* observer) const override; + // Sets external allocation strategy. If strategy is not set default WebRTC + // allocation mechanism will be used. The strategy may be changed during call. + // Setting NULL value will restore default WEBRTC allocation strategy. + void SetBitrateAllocationStrategy( + std::unique_ptr + bitrate_allocation_strategy); + private: - struct ObserverConfig { + struct ObserverConfig : rtc::BitrateAllocationStrategy::TrackConfig { ObserverConfig(BitrateAllocatorObserver* observer, uint32_t min_bitrate_bps, uint32_t max_bitrate_bps, uint32_t pad_up_bitrate_bps, int64_t priority_bitrate_bps, bool enforce_min_bitrate, + std::string track_id, double bitrate_priority) - : observer(observer), + : TrackConfig(min_bitrate_bps, + max_bitrate_bps, + enforce_min_bitrate, + track_id), + observer(observer), pad_up_bitrate_bps(pad_up_bitrate_bps), priority_bitrate_bps(priority_bitrate_bps), allocated_bitrate_bps(-1), media_ratio(1.0), - bitrate_priority(bitrate_priority), - min_bitrate_bps(min_bitrate_bps), - max_bitrate_bps(max_bitrate_bps), - enforce_min_bitrate(enforce_min_bitrate) {} + bitrate_priority(bitrate_priority) {} BitrateAllocatorObserver* observer; uint32_t pad_up_bitrate_bps; @@ -143,15 +154,6 @@ class BitrateAllocator : public BitrateAllocatorInterface { // observers, it should be allocated twice the bitrate above its min. double bitrate_priority; - // Minimum bitrate supported by track. - uint32_t min_bitrate_bps; - - // Maximum bitrate supported by track. - uint32_t max_bitrate_bps; - - // True means track may not be paused by allocating 0 bitrate. - bool enforce_min_bitrate; - uint32_t LastAllocatedBitrate() const; // The minimum bitrate required by this observer, including // enable-hysteresis if the observer is in a paused state. @@ -220,7 +222,8 @@ class BitrateAllocator : public BitrateAllocatorInterface { // Allow packets to be transmitted in up to 2 times max video bitrate if the // bandwidth estimate allows it. // TODO(bugs.webrtc.org/8541): May be worth to refactor to keep this logic in - // video send stream. + // video send stream. Similar logic is implemented in + // AudioPriorityBitrateAllocationStrategy. static uint8_t GetTransmissionMaxBitrateMultiplier(); SequenceChecker sequenced_checker_; @@ -240,7 +243,10 @@ class BitrateAllocator : public BitrateAllocatorInterface { uint32_t total_requested_padding_bitrate_ RTC_GUARDED_BY(&sequenced_checker_); uint32_t total_requested_min_bitrate_ RTC_GUARDED_BY(&sequenced_checker_); uint32_t total_requested_max_bitrate_ RTC_GUARDED_BY(&sequenced_checker_); + std::unique_ptr bitrate_allocation_strategy_ + RTC_GUARDED_BY(&sequenced_checker_); const uint8_t transmission_max_bitrate_multiplier_; + const bool ignore_injected_strategy_; }; } // namespace webrtc diff --git a/call/bitrate_allocator_unittest.cc b/call/bitrate_allocator_unittest.cc index 69dfa1a035..f177cafc08 100644 --- a/call/bitrate_allocator_unittest.cc +++ b/call/bitrate_allocator_unittest.cc @@ -97,11 +97,12 @@ class BitrateAllocatorTest : public ::testing::Test { uint32_t max_bitrate_bps, uint32_t pad_up_bitrate_bps, bool enforce_min_bitrate, + std::string track_id, double bitrate_priority) { allocator_->AddObserver( - observer, - {min_bitrate_bps, max_bitrate_bps, pad_up_bitrate_bps, - /* priority_bitrate */ 0, enforce_min_bitrate, bitrate_priority}); + observer, {min_bitrate_bps, max_bitrate_bps, pad_up_bitrate_bps, + /* priority_bitrate */ 0, enforce_min_bitrate, track_id, + bitrate_priority}); } MediaStreamAllocationConfig DefaultConfig() const { MediaStreamAllocationConfig default_config; @@ -110,6 +111,7 @@ class BitrateAllocatorTest : public ::testing::Test { default_config.pad_up_bitrate_bps = 0; default_config.priority_bitrate_bps = 0; default_config.enforce_min_bitrate = true; + default_config.track_id = ""; default_config.bitrate_priority = kDefaultBitratePriority; return default_config; } @@ -163,7 +165,7 @@ TEST_F(BitrateAllocatorTest, UpdatingBitrateObserver) { OnAllocationLimitsChanged(kMinSendBitrateBps, kPadUpToBitrateBps, kMaxBitrateBps)); AddObserver(&bitrate_observer, kMinSendBitrateBps, kMaxBitrateBps, - kPadUpToBitrateBps, true, kDefaultBitratePriority); + kPadUpToBitrateBps, true, "", kDefaultBitratePriority); EXPECT_EQ(300000, allocator_->GetStartBitrate(&bitrate_observer)); allocator_->OnNetworkChanged(200000, 0, 0, kDefaultProbingIntervalMs); EXPECT_EQ(200000, allocator_->GetStartBitrate(&bitrate_observer)); @@ -176,14 +178,14 @@ TEST_F(BitrateAllocatorTest, UpdatingBitrateObserver) { // Expect |max_padding_bitrate_bps| to change to 0 if the observer is updated. EXPECT_CALL(limit_observer_, OnAllocationLimitsChanged(kMinSendBitrateBps, 0, _)); - AddObserver(&bitrate_observer, kMinSendBitrateBps, 4000000, 0, true, + AddObserver(&bitrate_observer, kMinSendBitrateBps, 4000000, 0, true, "", kDefaultBitratePriority); EXPECT_CALL(limit_observer_, OnAllocationLimitsChanged(kMinSendBitrateBps, 0, _)); EXPECT_EQ(4000000, allocator_->GetStartBitrate(&bitrate_observer)); AddObserver(&bitrate_observer, kMinSendBitrateBps, kMaxBitrateBps, 0, true, - kDefaultBitratePriority); + "", kDefaultBitratePriority); EXPECT_EQ(3000000, allocator_->GetStartBitrate(&bitrate_observer)); EXPECT_EQ(3000000u, bitrate_observer.last_bitrate_bps_); allocator_->OnNetworkChanged(kMaxBitrateBps, 0, 0, kDefaultProbingIntervalMs); @@ -202,14 +204,14 @@ TEST_F(BitrateAllocatorTest, TwoBitrateObserversOneRtcpObserver) { limit_observer_, OnAllocationLimitsChanged(kObs1StartBitrateBps, 0, kObs1MaxBitrateBps)); AddObserver(&bitrate_observer_1, kObs1StartBitrateBps, kObs1MaxBitrateBps, 0, - true, kDefaultBitratePriority); + true, "", kDefaultBitratePriority); EXPECT_EQ(static_cast(kObs1MaxBitrateBps), allocator_->GetStartBitrate(&bitrate_observer_1)); EXPECT_CALL(limit_observer_, OnAllocationLimitsChanged( kObs1StartBitrateBps + kObs2StartBitrateBps, 0, kObs1MaxBitrateBps + kObs2MaxBitrateBps)); AddObserver(&bitrate_observer_2, kObs2StartBitrateBps, kObs2MaxBitrateBps, 0, - true, kDefaultBitratePriority); + true, "", kDefaultBitratePriority); EXPECT_EQ(static_cast(kObs2StartBitrateBps), allocator_->GetStartBitrate(&bitrate_observer_2)); @@ -258,7 +260,7 @@ TEST_F(BitrateAllocatorTest, RemoveObserverTriggersLimitObserver) { OnAllocationLimitsChanged(kMinSendBitrateBps, kPadUpToBitrateBps, kMaxBitrateBps)); AddObserver(&bitrate_observer, kMinSendBitrateBps, kMaxBitrateBps, - kPadUpToBitrateBps, true, kDefaultBitratePriority); + kPadUpToBitrateBps, true, "", kDefaultBitratePriority); EXPECT_CALL(limit_observer_, OnAllocationLimitsChanged(0, 0, _)); allocator_->RemoveObserver(&bitrate_observer); } @@ -280,7 +282,7 @@ class BitrateAllocatorTestNoEnforceMin : public ::testing::Test { double bitrate_priority) { allocator_->AddObserver( observer, {min_bitrate_bps, max_bitrate_bps, pad_up_bitrate_bps, 0, - enforce_min_bitrate, bitrate_priority}); + enforce_min_bitrate, track_id, bitrate_priority}); } NiceMock limit_observer_; std::unique_ptr allocator_; @@ -532,16 +534,16 @@ TEST_F(BitrateAllocatorTest, ThreeBitrateObserversLowBweEnforceMin) { TestBitrateObserver bitrate_observer_2; TestBitrateObserver bitrate_observer_3; - AddObserver(&bitrate_observer_1, 100000, 400000, 0, true, + AddObserver(&bitrate_observer_1, 100000, 400000, 0, true, "", kDefaultBitratePriority); EXPECT_EQ(300000, allocator_->GetStartBitrate(&bitrate_observer_1)); - AddObserver(&bitrate_observer_2, 200000, 400000, 0, true, + AddObserver(&bitrate_observer_2, 200000, 400000, 0, true, "", kDefaultBitratePriority); EXPECT_EQ(200000, allocator_->GetStartBitrate(&bitrate_observer_2)); EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_bps_); - AddObserver(&bitrate_observer_3, 300000, 400000, 0, true, + AddObserver(&bitrate_observer_3, 300000, 400000, 0, true, "", kDefaultBitratePriority); EXPECT_EQ(300000, allocator_->GetStartBitrate(&bitrate_observer_3)); EXPECT_EQ(100000, static_cast(bitrate_observer_1.last_bitrate_bps_)); @@ -563,7 +565,7 @@ TEST_F(BitrateAllocatorTest, AddObserverWhileNetworkDown) { TestBitrateObserver bitrate_observer_1; EXPECT_CALL(limit_observer_, OnAllocationLimitsChanged(50000, 0, _)); - AddObserver(&bitrate_observer_1, 50000, 400000, 0, true, + AddObserver(&bitrate_observer_1, 50000, 400000, 0, true, "", kDefaultBitratePriority); EXPECT_EQ(300000, allocator_->GetStartBitrate(&bitrate_observer_1)); @@ -575,7 +577,7 @@ TEST_F(BitrateAllocatorTest, AddObserverWhileNetworkDown) { TestBitrateObserver bitrate_observer_2; // Adding an observer while the network is down should not affect the limits. EXPECT_CALL(limit_observer_, OnAllocationLimitsChanged(50000 + 50000, 0, _)); - AddObserver(&bitrate_observer_2, 50000, 400000, 0, true, + AddObserver(&bitrate_observer_2, 50000, 400000, 0, true, "", kDefaultBitratePriority); // Expect the start_bitrate to be set as if the network was still up but that @@ -592,12 +594,12 @@ TEST_F(BitrateAllocatorTest, AddObserverWhileNetworkDown) { TEST_F(BitrateAllocatorTest, MixedEnforecedConfigs) { TestBitrateObserver enforced_observer; - AddObserver(&enforced_observer, 6000, 30000, 0, true, + AddObserver(&enforced_observer, 6000, 30000, 0, true, "", kDefaultBitratePriority); EXPECT_EQ(60000, allocator_->GetStartBitrate(&enforced_observer)); TestBitrateObserver not_enforced_observer; - AddObserver(¬_enforced_observer, 30000, 2500000, 0, false, + AddObserver(¬_enforced_observer, 30000, 2500000, 0, false, "", kDefaultBitratePriority); EXPECT_EQ(270000, allocator_->GetStartBitrate(¬_enforced_observer)); EXPECT_EQ(30000u, enforced_observer.last_bitrate_bps_); @@ -636,7 +638,7 @@ TEST_F(BitrateAllocatorTest, MixedEnforecedConfigs) { TEST_F(BitrateAllocatorTest, AvoidToggleAbsolute) { TestBitrateObserver observer; - AddObserver(&observer, 30000, 300000, 0, false, kDefaultBitratePriority); + AddObserver(&observer, 30000, 300000, 0, false, "", kDefaultBitratePriority); EXPECT_EQ(300000, allocator_->GetStartBitrate(&observer)); allocator_->OnNetworkChanged(30000, 0, 50, kDefaultProbingIntervalMs); @@ -662,7 +664,7 @@ TEST_F(BitrateAllocatorTest, AvoidToggleAbsolute) { TEST_F(BitrateAllocatorTest, AvoidTogglePercent) { TestBitrateObserver observer; - AddObserver(&observer, 300000, 600000, 0, false, kDefaultBitratePriority); + AddObserver(&observer, 300000, 600000, 0, false, "", kDefaultBitratePriority); EXPECT_EQ(300000, allocator_->GetStartBitrate(&observer)); allocator_->OnNetworkChanged(300000, 0, 50, kDefaultProbingIntervalMs); @@ -688,7 +690,7 @@ TEST_F(BitrateAllocatorTest, AvoidTogglePercent) { TEST_F(BitrateAllocatorTest, PassProbingInterval) { TestBitrateObserver observer; - AddObserver(&observer, 300000, 600000, 0, false, kDefaultBitratePriority); + AddObserver(&observer, 300000, 600000, 0, false, "", kDefaultBitratePriority); EXPECT_EQ(300000, allocator_->GetStartBitrate(&observer)); allocator_->OnNetworkChanged(300000, 0, 50, 5000); @@ -703,7 +705,8 @@ TEST_F(BitrateAllocatorTest, PriorityRateOneObserverBasic) { const uint32_t kMaxSendBitrateBps = 60; const uint32_t kNetworkBandwidthBps = 30; - AddObserver(&observer, kMinSendBitrateBps, kMaxSendBitrateBps, 0, true, 2.0); + AddObserver(&observer, kMinSendBitrateBps, kMaxSendBitrateBps, 0, true, "", + 2.0); allocator_->OnNetworkChanged(kNetworkBandwidthBps, 0, 0, kDefaultProbingIntervalMs); @@ -721,9 +724,9 @@ TEST_F(BitrateAllocatorTest, PriorityRateTwoObserversBasic) { const uint32_t kMaxSendBitrateBps = 60; const uint32_t kNetworkBandwidthBps = 60; AddObserver(&observer_low_1, kMinSendBitrateBps, kMaxSendBitrateBps, 0, false, - 2.0); + "low1", 2.0); AddObserver(&observer_low_2, kMinSendBitrateBps, kMaxSendBitrateBps, 0, false, - 2.0); + "low2", 2.0); allocator_->OnNetworkChanged(kNetworkBandwidthBps, 0, 0, kDefaultProbingIntervalMs); @@ -743,9 +746,9 @@ TEST_F(BitrateAllocatorTest, PriorityRateTwoObserversBasicMinEnforced) { const uint32_t kMaxSendBitrateBps = 60; const uint32_t kNetworkBandwidthBps = 60; AddObserver(&observer_low_1, kMinSendBitrateBps, kMaxSendBitrateBps, 0, true, - 2.0); + "low1", 2.0); AddObserver(&observer_low_2, kMinSendBitrateBps, kMaxSendBitrateBps, 0, true, - 2.0); + "low2", 2.0); allocator_->OnNetworkChanged(kNetworkBandwidthBps, 0, 0, kDefaultProbingIntervalMs); @@ -765,9 +768,9 @@ TEST_F(BitrateAllocatorTest, PriorityRateTwoObserversBothAllocatedMax) { const uint32_t kMaxSendBitrateBps = 60; const uint32_t kNetworkBandwidthBps = kMaxSendBitrateBps * 2; AddObserver(&observer_low, kMinSendBitrateBps, kMaxSendBitrateBps, 0, true, - 2.0); + "low", 2.0); AddObserver(&observer_mid, kMinSendBitrateBps, kMaxSendBitrateBps, 0, true, - 4.0); + "mid", 4.0); allocator_->OnNetworkChanged(kNetworkBandwidthBps, 0, 0, kDefaultProbingIntervalMs); @@ -784,8 +787,8 @@ TEST_F(BitrateAllocatorTest, PriorityRateTwoObserversBothAllocatedMax) { TEST_F(BitrateAllocatorTest, PriorityRateTwoObserversOneAllocatedToMax) { TestBitrateObserver observer_low; TestBitrateObserver observer_mid; - AddObserver(&observer_low, 10, 50, 0, false, 2.0); - AddObserver(&observer_mid, 10, 50, 0, false, 4.0); + AddObserver(&observer_low, 10, 50, 0, false, "low", 2.0); + AddObserver(&observer_mid, 10, 50, 0, false, "mid", 4.0); allocator_->OnNetworkChanged(90, 0, 0, kDefaultProbingIntervalMs); EXPECT_EQ(40u, observer_low.last_bitrate_bps_); @@ -810,9 +813,12 @@ TEST_F(BitrateAllocatorTest, const double kHighBitratePriority = 8.0; const double kTotalBitratePriority = kLowBitratePriority + kMidBitratePriority + kHighBitratePriority; - AddObserver(&observer_low, 0, kMaxBitrate, 0, false, kLowBitratePriority); - AddObserver(&observer_mid, 0, kMaxBitrate, 0, false, kMidBitratePriority); - AddObserver(&observer_high, 0, kMaxBitrate, 0, false, kHighBitratePriority); + AddObserver(&observer_low, 0, kMaxBitrate, 0, false, "low", + kLowBitratePriority); + AddObserver(&observer_mid, 0, kMaxBitrate, 0, false, "mid", + kMidBitratePriority); + AddObserver(&observer_high, 0, kMaxBitrate, 0, false, "high", + kHighBitratePriority); allocator_->OnNetworkChanged(kNetworkBandwidthBps, 0, 0, kDefaultProbingIntervalMs); @@ -853,11 +859,11 @@ TEST_F(BitrateAllocatorTest, PriorityRateThreeObserversHighAllocatedToMax) { const uint32_t kRemainingBitrate = kAvailableBitrate - kMaxBitrate - (2 * kMinBitrate); - AddObserver(&observer_low, kMinBitrate, kMaxBitrate, 0, false, + AddObserver(&observer_low, kMinBitrate, kMaxBitrate, 0, false, "low", kLowBitratePriority); - AddObserver(&observer_mid, kMinBitrate, kMaxBitrate, 0, false, + AddObserver(&observer_mid, kMinBitrate, kMaxBitrate, 0, false, "mid", kMidBitratePriority); - AddObserver(&observer_high, kMinBitrate, kMaxBitrate, 0, false, + AddObserver(&observer_high, kMinBitrate, kMaxBitrate, 0, false, "high", kHighBitratePriority); allocator_->OnNetworkChanged(kAvailableBitrate, 0, 0, kDefaultProbingIntervalMs); @@ -897,11 +903,11 @@ TEST_F(BitrateAllocatorTest, PriorityRateThreeObserversLowAllocatedToMax) { // available bitrate, so 70 bps would be sufficient network bandwidth. const uint32_t kRemainingBitrate = kAvailableBitrate - kLowMaxBitrate; - AddObserver(&observer_low, kMinBitrate, kLowMaxBitrate, 0, false, + AddObserver(&observer_low, kMinBitrate, kLowMaxBitrate, 0, false, "low", kLowBitratePriority); - AddObserver(&observer_mid, kMinBitrate, kMaxBitrate, 0, false, + AddObserver(&observer_mid, kMinBitrate, kMaxBitrate, 0, false, "mid", kMidBitratePriority); - AddObserver(&observer_high, kMinBitrate, kMaxBitrate, 0, false, + AddObserver(&observer_high, kMinBitrate, kMaxBitrate, 0, false, "high", kHighBitratePriority); allocator_->OnNetworkChanged(kAvailableBitrate, 0, 0, kDefaultProbingIntervalMs); @@ -931,12 +937,12 @@ TEST_F(BitrateAllocatorTest, PriorityRateThreeObserversTwoAllocatedToMax) { TestBitrateObserver observer_low; TestBitrateObserver observer_mid; TestBitrateObserver observer_high; - AddObserver(&observer_low, 10, 40, 0, false, 2.0); + AddObserver(&observer_low, 10, 40, 0, false, "low", 2.0); // Scaled allocation above the min allocation is the same for these two, // meaning they will get allocated their max at the same time. // Scaled (target allocation) = (max - min) / bitrate priority - AddObserver(&observer_mid, 10, 30, 0, false, 4.0); - AddObserver(&observer_high, 10, 50, 0, false, 8.0); + AddObserver(&observer_mid, 10, 30, 0, false, "mid", 4.0); + AddObserver(&observer_high, 10, 50, 0, false, "high", 8.0); allocator_->OnNetworkChanged(110, 0, 0, kDefaultProbingIntervalMs); EXPECT_EQ(30u, observer_low.last_bitrate_bps_); diff --git a/call/call.cc b/call/call.cc index bd9a462663..293afa9779 100644 --- a/call/call.cc +++ b/call/call.cc @@ -215,6 +215,10 @@ class Call final : public webrtc::Call, // Implements RecoveredPacketReceiver. void OnRecoveredPacket(const uint8_t* packet, size_t length) override; + void SetBitrateAllocationStrategy( + std::unique_ptr + bitrate_allocation_strategy) override; + void SignalChannelNetworkState(MediaType media, NetworkState state) override; void OnAudioTransportOverheadChanged( @@ -1076,6 +1080,24 @@ Call::Stats Call::GetStats() const { return stats; } +void Call::SetBitrateAllocationStrategy( + std::unique_ptr + bitrate_allocation_strategy) { + // TODO(srte): This function should be moved to RtpTransportControllerSend + // when BitrateAllocator is moved there. + struct Functor { + void operator()() { + bitrate_allocator_->SetBitrateAllocationStrategy( + std::move(bitrate_allocation_strategy_)); + } + BitrateAllocator* bitrate_allocator_; + std::unique_ptr + bitrate_allocation_strategy_; + }; + transport_send_ptr_->GetWorkerQueue()->PostTask(Functor{ + bitrate_allocator_.get(), std::move(bitrate_allocation_strategy)}); +} + void Call::SignalChannelNetworkState(MediaType media, NetworkState state) { RTC_DCHECK_RUN_ON(&configuration_sequence_checker_); switch (media) { diff --git a/call/call.h b/call/call.h index 2c5aca2a77..1c29feec0f 100644 --- a/call/call.h +++ b/call/call.h @@ -25,6 +25,7 @@ #include "call/video_receive_stream.h" #include "call/video_send_stream.h" #include "modules/utility/include/process_thread.h" +#include "rtc_base/bitrate_allocation_strategy.h" #include "rtc_base/copy_on_write_buffer.h" #include "rtc_base/network/sent_packet.h" #include "rtc_base/network_route.h" @@ -106,6 +107,10 @@ class Call { // pacing delay, etc. virtual Stats GetStats() const = 0; + virtual void SetBitrateAllocationStrategy( + std::unique_ptr + bitrate_allocation_strategy) = 0; + // TODO(skvlad): When the unbundled case with multiple streams for the same // media type going over different networks is supported, track the state // for each stream separately. Right now it's global per media type. diff --git a/call/call_perf_tests.cc b/call/call_perf_tests.cc index 43af881aa1..46913b83a6 100644 --- a/call/call_perf_tests.cc +++ b/call/call_perf_tests.cc @@ -28,6 +28,7 @@ #include "modules/audio_device/include/test_audio_device.h" #include "modules/audio_mixer/audio_mixer_impl.h" #include "modules/rtp_rtcp/include/rtp_header_parser.h" +#include "rtc_base/bitrate_allocation_strategy.h" #include "rtc_base/checks.h" #include "rtc_base/thread_annotations.h" #include "system_wrappers/include/metrics.h" @@ -80,7 +81,8 @@ class CallPerfTest : public test::CallTest { int threshold_ms, int start_time_ms, int run_time_ms); - void TestMinAudioVideoBitrate(int test_bitrate_from, + void TestMinAudioVideoBitrate(bool use_bitrate_allocation_strategy, + int test_bitrate_from, int test_bitrate_to, int test_bitrate_step, int min_bwe, @@ -840,17 +842,22 @@ TEST_F(CallPerfTest, MAYBE_KeepsHighBitrateWhenReconfiguringSender) { // considered supported if Rtt does not go above 400ms with the network // contrained to the test bitrate. // +// |use_bitrate_allocation_strategy| use AudioPriorityBitrateAllocationStrategy // |test_bitrate_from test_bitrate_to| bitrate constraint range // |test_bitrate_step| bitrate constraint update step during the test // |min_bwe max_bwe| BWE range // |start_bwe| initial BWE -void CallPerfTest::TestMinAudioVideoBitrate(int test_bitrate_from, - int test_bitrate_to, - int test_bitrate_step, - int min_bwe, - int start_bwe, - int max_bwe) { +void CallPerfTest::TestMinAudioVideoBitrate( + bool use_bitrate_allocation_strategy, + int test_bitrate_from, + int test_bitrate_to, + int test_bitrate_step, + int min_bwe, + int start_bwe, + int max_bwe) { static const std::string kAudioTrackId = "audio_track_0"; + static constexpr uint32_t kSufficientAudioBitrateBps = 16000; + static constexpr int kOpusMinBitrateBps = 6000; static constexpr int kOpusBitrateFbBps = 32000; static constexpr int kBitrateStabilizationMs = 10000; static constexpr int kBitrateMeasurements = 10; @@ -860,13 +867,18 @@ void CallPerfTest::TestMinAudioVideoBitrate(int test_bitrate_from, class MinVideoAndAudioBitrateTester : public test::EndToEndTest { public: - MinVideoAndAudioBitrateTester(int test_bitrate_from, + MinVideoAndAudioBitrateTester(bool use_bitrate_allocation_strategy, + int test_bitrate_from, int test_bitrate_to, int test_bitrate_step, int min_bwe, int start_bwe, int max_bwe) : EndToEndTest(), + allocation_strategy_(new rtc::AudioPriorityBitrateAllocationStrategy( + kAudioTrackId, + kSufficientAudioBitrateBps)), + use_bitrate_allocation_strategy_(use_bitrate_allocation_strategy), test_bitrate_from_(test_bitrate_from), test_bitrate_to_(test_bitrate_to), test_bitrate_step_(test_bitrate_step), @@ -941,8 +953,11 @@ void CallPerfTest::TestMinAudioVideoBitrate(int test_bitrate_from, } EXPECT_GT(last_passed_test_bitrate, -1) << "Minimum supported bitrate out of the test scope"; - webrtc::test::PrintResult("min_test_bitrate_", "", "min_bitrate", - last_passed_test_bitrate, "kbps", false); + webrtc::test::PrintResult( + "min_test_bitrate_", + use_bitrate_allocation_strategy_ ? "with_allocation_strategy" + : "no_allocation_strategy", + "min_bitrate", last_passed_test_bitrate, "kbps", false); } void OnCallsCreated(Call* sender_call, Call* receiver_call) override { @@ -953,6 +968,10 @@ void CallPerfTest::TestMinAudioVideoBitrate(int test_bitrate_from, bitrate_config.max_bitrate_bps = max_bwe_; sender_call->GetTransportControllerSend()->SetSdpBitrateParameters( bitrate_config); + if (use_bitrate_allocation_strategy_) { + sender_call->SetBitrateAllocationStrategy( + std::move(allocation_strategy_)); + } } size_t GetNumVideoStreams() const override { return 1; } @@ -962,11 +981,19 @@ void CallPerfTest::TestMinAudioVideoBitrate(int test_bitrate_from, void ModifyAudioConfigs( AudioSendStream::Config* send_config, std::vector* receive_configs) override { - send_config->send_codec_spec->target_bitrate_bps = - absl::optional(kOpusBitrateFbBps); + if (use_bitrate_allocation_strategy_) { + send_config->track_id = kAudioTrackId; + send_config->min_bitrate_bps = kOpusMinBitrateBps; + send_config->max_bitrate_bps = kOpusBitrateFbBps; + } else { + send_config->send_codec_spec->target_bitrate_bps = + absl::optional(kOpusBitrateFbBps); + } } private: + std::unique_ptr allocation_strategy_; + const bool use_bitrate_allocation_strategy_; const int test_bitrate_from_; const int test_bitrate_to_; const int test_bitrate_step_; @@ -976,8 +1003,8 @@ void CallPerfTest::TestMinAudioVideoBitrate(int test_bitrate_from, SimulatedNetwork* send_simulated_network_; SimulatedNetwork* receive_simulated_network_; Call* sender_call_; - } test(test_bitrate_from, test_bitrate_to, test_bitrate_step, min_bwe, - start_bwe, max_bwe); + } test(use_bitrate_allocation_strategy, test_bitrate_from, test_bitrate_to, + test_bitrate_step, min_bwe, start_bwe, max_bwe); RunBaseTest(&test); } @@ -989,7 +1016,10 @@ void CallPerfTest::TestMinAudioVideoBitrate(int test_bitrate_from, #define MAYBE_MinVideoAndAudioBitrate MinVideoAndAudioBitrate #endif TEST_F(CallPerfTest, MAYBE_MinVideoAndAudioBitrate) { - TestMinAudioVideoBitrate(110, 40, -10, 10000, 70000, 200000); + TestMinAudioVideoBitrate(false, 110, 40, -10, 10000, 70000, 200000); +} +TEST_F(CallPerfTest, MinVideoAndAudioBitrateWStrategy) { + TestMinAudioVideoBitrate(true, 110, 40, -10, 10000, 70000, 200000); } } // namespace webrtc diff --git a/call/degraded_call.cc b/call/degraded_call.cc index 4b71e86f9d..20a7d7dd21 100644 --- a/call/degraded_call.cc +++ b/call/degraded_call.cc @@ -196,6 +196,12 @@ Call::Stats DegradedCall::GetStats() const { return call_->GetStats(); } +void DegradedCall::SetBitrateAllocationStrategy( + std::unique_ptr + bitrate_allocation_strategy) { + call_->SetBitrateAllocationStrategy(std::move(bitrate_allocation_strategy)); +} + void DegradedCall::SignalChannelNetworkState(MediaType media, NetworkState state) { call_->SignalChannelNetworkState(media, state); diff --git a/call/degraded_call.h b/call/degraded_call.h index adac631478..57480ed3ee 100644 --- a/call/degraded_call.h +++ b/call/degraded_call.h @@ -35,6 +35,7 @@ #include "call/video_send_stream.h" #include "modules/include/module.h" #include "modules/utility/include/process_thread.h" +#include "rtc_base/bitrate_allocation_strategy.h" #include "rtc_base/copy_on_write_buffer.h" #include "rtc_base/network/sent_packet.h" #include "system_wrappers/include/clock.h" @@ -106,6 +107,10 @@ class DegradedCall : public Call, private Transport, private PacketReceiver { Stats GetStats() const override; + void SetBitrateAllocationStrategy( + std::unique_ptr + bitrate_allocation_strategy) override; + void SignalChannelNetworkState(MediaType media, NetworkState state) override; void OnAudioTransportOverheadChanged( int transport_overhead_per_packet) override; diff --git a/call/video_send_stream.h b/call/video_send_stream.h index c715863651..daf2d39bd7 100644 --- a/call/video_send_stream.h +++ b/call/video_send_stream.h @@ -156,6 +156,9 @@ class VideoSendStream { // Enables periodic bandwidth probing in application-limited region. bool periodic_alr_bandwidth_probing = false; + // Track ID as specified during track creation. + std::string track_id; + // An optional custom frame encryptor that allows the entire frame to be // encrypted in whatever way the caller chooses. This is not required by // default. diff --git a/media/engine/fake_webrtc_call.cc b/media/engine/fake_webrtc_call.cc index dcab48b008..a9cbf322d6 100644 --- a/media/engine/fake_webrtc_call.cc +++ b/media/engine/fake_webrtc_call.cc @@ -618,6 +618,12 @@ webrtc::Call::Stats FakeCall::GetStats() const { return stats_; } +void FakeCall::SetBitrateAllocationStrategy( + std::unique_ptr + bitrate_allocation_strategy) { + // TODO(alexnarest): not implemented +} + void FakeCall::SignalChannelNetworkState(webrtc::MediaType media, webrtc::NetworkState state) { switch (media) { diff --git a/media/engine/fake_webrtc_call.h b/media/engine/fake_webrtc_call.h index e87c24f905..134dd47cd3 100644 --- a/media/engine/fake_webrtc_call.h +++ b/media/engine/fake_webrtc_call.h @@ -347,6 +347,10 @@ class FakeCall final : public webrtc::Call, public webrtc::PacketReceiver { webrtc::Call::Stats GetStats() const override; + void SetBitrateAllocationStrategy( + std::unique_ptr + bitrate_allocation_strategy) override; + void SignalChannelNetworkState(webrtc::MediaType media, webrtc::NetworkState state) override; void OnAudioTransportOverheadChanged( diff --git a/media/engine/webrtc_video_engine.cc b/media/engine/webrtc_video_engine.cc index 9658ade62d..13b44931a3 100644 --- a/media/engine/webrtc_video_engine.cc +++ b/media/engine/webrtc_video_engine.cc @@ -1839,6 +1839,7 @@ WebRtcVideoChannel::WebRtcVideoSendStream::WebRtcVideoSendStream( } parameters_.config.rtp.c_name = sp.cname; + parameters_.config.track_id = sp.id; if (rtp_extensions) { parameters_.config.rtp.extensions = *rtp_extensions; rtp_parameters_.header_extensions = *rtp_extensions; diff --git a/pc/BUILD.gn b/pc/BUILD.gn index 8c54f7d5d9..c455bbef44 100644 --- a/pc/BUILD.gn +++ b/pc/BUILD.gn @@ -235,7 +235,6 @@ rtc_static_library("peerconnection") { "../rtc_base:checks", "../rtc_base:rtc_base_approved", "../rtc_base:safe_minmax", - "../rtc_base/experiments:field_trial_parser", "../rtc_base/system:file_wrapper", "../rtc_base/system:rtc_export", "../rtc_base/third_party/base64", diff --git a/pc/peer_connection.cc b/pc/peer_connection.cc index e677e5d4df..0c8202779f 100644 --- a/pc/peer_connection.cc +++ b/pc/peer_connection.cc @@ -3724,6 +3724,29 @@ RTCError PeerConnection::SetBitrate(const BitrateSettings& bitrate) { return RTCError::OK(); } +void PeerConnection::SetBitrateAllocationStrategy( + std::unique_ptr + bitrate_allocation_strategy) { + if (!worker_thread()->IsCurrent()) { + // TODO(kwiberg): Use a lambda instead when C++14 makes it possible to + // move-capture values in lambdas. + struct Task { + PeerConnection* const pc; + std::unique_ptr strategy; + void operator()() { + RTC_DCHECK_RUN_ON(pc->worker_thread()); + pc->call_->SetBitrateAllocationStrategy(std::move(strategy)); + } + }; + worker_thread()->Invoke( + RTC_FROM_HERE, Task{this, std::move(bitrate_allocation_strategy)}); + return; + } + RTC_DCHECK_RUN_ON(worker_thread()); + RTC_DCHECK(call_.get()); + call_->SetBitrateAllocationStrategy(std::move(bitrate_allocation_strategy)); +} + void PeerConnection::SetAudioPlayout(bool playout) { if (!worker_thread()->IsCurrent()) { worker_thread()->Invoke( diff --git a/pc/peer_connection.h b/pc/peer_connection.h index ed8c54cd6b..917ad62d63 100644 --- a/pc/peer_connection.h +++ b/pc/peer_connection.h @@ -31,7 +31,6 @@ #include "pc/stats_collector.h" #include "pc/stream_collection.h" #include "pc/webrtc_session_description_factory.h" -#include "rtc_base/experiments/field_trial_parser.h" #include "rtc_base/race_checker.h" #include "rtc_base/unique_id_generator.h" @@ -196,6 +195,10 @@ class PeerConnection : public PeerConnectionInternal, RTCError SetBitrate(const BitrateSettings& bitrate) override; + void SetBitrateAllocationStrategy( + std::unique_ptr + bitrate_allocation_strategy) override; + void SetAudioPlayout(bool playout) override; void SetAudioRecording(bool recording) override; diff --git a/pc/test/fake_peer_connection_base.h b/pc/test/fake_peer_connection_base.h index f88eb1ebfc..67890cbcce 100644 --- a/pc/test/fake_peer_connection_base.h +++ b/pc/test/fake_peer_connection_base.h @@ -186,6 +186,10 @@ class FakePeerConnectionBase : public PeerConnectionInternal { return RTCError(RTCErrorType::UNSUPPORTED_OPERATION, "Not implemented"); } + void SetBitrateAllocationStrategy( + std::unique_ptr + bitrate_allocation_strategy) override {} + void SetAudioPlayout(bool playout) override {} void SetAudioRecording(bool recording) override {} diff --git a/rtc_base/BUILD.gn b/rtc_base/BUILD.gn index 1f84777249..5feb98146e 100644 --- a/rtc_base/BUILD.gn +++ b/rtc_base/BUILD.gn @@ -75,10 +75,13 @@ rtc_source_set("rtc_base_approved") { ":checks", ":rtc_task_queue", ":safe_compare", + ":safe_minmax", ":type_traits", "../api:array_view", "../api:function_view", "../api:scoped_refptr", + "../system_wrappers:field_trial", + "experiments:field_trial_parser", "system:arch", "system:unused", "third_party/base64", @@ -91,6 +94,8 @@ rtc_source_set("rtc_base_approved") { "bind.h", "bit_buffer.cc", "bit_buffer.h", + "bitrate_allocation_strategy.cc", + "bitrate_allocation_strategy.h", "buffer.h", "buffer_queue.cc", "buffer_queue.h", @@ -1155,6 +1160,7 @@ if (rtc_include_tests) { "base64_unittest.cc", "bind_unittest.cc", "bit_buffer_unittest.cc", + "bitrate_allocation_strategy_unittest.cc", "buffer_queue_unittest.cc", "buffer_unittest.cc", "byte_buffer_unittest.cc", diff --git a/rtc_base/bitrate_allocation_strategy.cc b/rtc_base/bitrate_allocation_strategy.cc new file mode 100644 index 0000000000..34a61ef5a2 --- /dev/null +++ b/rtc_base/bitrate_allocation_strategy.cc @@ -0,0 +1,169 @@ +/* + * Copyright 2017 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 "rtc_base/bitrate_allocation_strategy.h" + +#include +#include +#include +#include +#include + +#include "rtc_base/numerics/safe_minmax.h" +#include "system_wrappers/include/field_trial.h" + +namespace webrtc { +AudioPriorityConfig::AudioPriorityConfig() + : min_rate("min"), max_rate("max"), target_rate("target") { + std::string trial_string; +// TODO(bugs.webrtc.org/9889): Remove this when Chromium build has been fixed. +#if !defined(WEBRTC_CHROMIUM_BUILD) + trial_string = field_trial::FindFullName("WebRTC-Bwe-AudioPriority"); +#endif + ParseFieldTrial({&min_rate, &max_rate, &target_rate}, trial_string); +} +AudioPriorityConfig::AudioPriorityConfig(const AudioPriorityConfig&) = default; +AudioPriorityConfig::~AudioPriorityConfig() = default; + +} // namespace webrtc + +namespace rtc { + +// The purpose of this is to allow video streams to use extra bandwidth for FEC. +// TODO(bugs.webrtc.org/8541): May be worth to refactor to keep this logic in +// video send stream. Similar logic is implemented in BitrateAllocator. + +const int kTransmissionMaxBitrateMultiplier = 2; + +std::vector BitrateAllocationStrategy::SetAllBitratesToMinimum( + const std::vector& track_configs) { + std::vector track_allocations; + track_allocations.reserve(track_configs.size()); + for (const auto& track_config : track_configs) { + track_allocations.push_back(track_config.min_bitrate_bps); + } + return track_allocations; +} + +std::vector BitrateAllocationStrategy::DistributeBitratesEvenly( + const std::vector& track_configs, + uint32_t available_bitrate) { + std::vector track_allocations = + SetAllBitratesToMinimum(track_configs); + uint32_t sum_min_bitrates = 0; + uint32_t sum_max_bitrates = 0; + for (const auto& track_config : track_configs) { + sum_min_bitrates += track_config.min_bitrate_bps; + sum_max_bitrates += track_config.max_bitrate_bps; + } + if (sum_min_bitrates >= available_bitrate) { + return track_allocations; + } else if (available_bitrate >= sum_max_bitrates) { + auto track_allocations_it = track_allocations.begin(); + for (const auto& track_config : track_configs) { + *track_allocations_it++ = track_config.max_bitrate_bps; + } + return track_allocations; + } else { + // If sum_min_bitrates < available_bitrate < sum_max_bitrates allocate + // bitrates evenly up to max_bitrate_bps starting from the track with the + // lowest max_bitrate_bps. Remainder of available bitrate split evenly among + // remaining tracks. + std::multimap max_bitrate_sorted_configs; + for (const auto& track_config : track_configs) { + max_bitrate_sorted_configs.insert( + std::make_pair(track_config.max_bitrate_bps, + &track_config - &track_configs.front())); + } + uint32_t total_available_increase = available_bitrate - sum_min_bitrates; + int processed_configs = 0; + for (const auto& track_config_pair : max_bitrate_sorted_configs) { + uint32_t available_increase = + total_available_increase / + (static_cast(track_configs.size() - processed_configs)); + uint32_t consumed_increase = + std::min(track_configs[track_config_pair.second].max_bitrate_bps - + track_configs[track_config_pair.second].min_bitrate_bps, + available_increase); + track_allocations[track_config_pair.second] += consumed_increase; + total_available_increase -= consumed_increase; + ++processed_configs; + } + return track_allocations; + } +} +AudioPriorityBitrateAllocationStrategy::AudioPriorityBitrateAllocationStrategy( + std::string audio_track_id, + uint32_t sufficient_audio_bitrate) + : audio_track_id_(audio_track_id), + sufficient_audio_bitrate_(sufficient_audio_bitrate) { + if (config_.target_rate) { + sufficient_audio_bitrate_ = config_.target_rate->bps(); + } +} + +std::vector AudioPriorityBitrateAllocationStrategy::AllocateBitrates( + uint32_t available_bitrate, + std::vector track_configs) { + TrackConfig* audio_track_config = nullptr; + size_t audio_config_index = 0; + uint32_t sum_min_bitrates = 0; + uint32_t sum_max_bitrates = 0; + + for (auto& track_config : track_configs) { + if (track_config.track_id == audio_track_id_) { + audio_config_index = &track_config - &track_configs[0]; + audio_track_config = &track_config; + if (config_.min_rate) + audio_track_config->min_bitrate_bps = config_.min_rate->bps(); + if (config_.max_rate) + audio_track_config->max_bitrate_bps = config_.max_rate->bps(); + } + sum_min_bitrates += track_config.min_bitrate_bps; + sum_max_bitrates += track_config.max_bitrate_bps; + } + if (sum_max_bitrates < available_bitrate) { + // Allow non audio streams to go above max upto + // kTransmissionMaxBitrateMultiplier * max_bitrate_bps + for (auto& track_config : track_configs) { + if (&track_config != audio_track_config) + track_config.max_bitrate_bps *= kTransmissionMaxBitrateMultiplier; + } + return DistributeBitratesEvenly(track_configs, available_bitrate); + } + if (!audio_track_config) { + return DistributeBitratesEvenly(track_configs, available_bitrate); + } + auto safe_sufficient_audio_bitrate = rtc::SafeClamp( + sufficient_audio_bitrate_, audio_track_config->min_bitrate_bps, + audio_track_config->max_bitrate_bps); + if (available_bitrate <= sum_min_bitrates) { + return SetAllBitratesToMinimum(track_configs); + } else { + if (available_bitrate <= sum_min_bitrates + safe_sufficient_audio_bitrate - + audio_track_config->min_bitrate_bps) { + std::vector track_allocations = + SetAllBitratesToMinimum(track_configs); + track_allocations[audio_config_index] += + available_bitrate - sum_min_bitrates; + return track_allocations; + } else { + // Setting audio track minimum to safe_sufficient_audio_bitrate will + // allow using DistributeBitratesEvenly to allocate at least sufficient + // bitrate for audio and the rest evenly. + audio_track_config->min_bitrate_bps = safe_sufficient_audio_bitrate; + std::vector track_allocations = + DistributeBitratesEvenly(track_configs, available_bitrate); + return track_allocations; + } + } +} + +} // namespace rtc diff --git a/rtc_base/bitrate_allocation_strategy.h b/rtc_base/bitrate_allocation_strategy.h new file mode 100644 index 0000000000..def7736310 --- /dev/null +++ b/rtc_base/bitrate_allocation_strategy.h @@ -0,0 +1,121 @@ +/* + * Copyright 2017 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. + */ + +#ifndef RTC_BASE_BITRATE_ALLOCATION_STRATEGY_H_ +#define RTC_BASE_BITRATE_ALLOCATION_STRATEGY_H_ + +#include + +#include +#include + +#include "api/array_view.h" +#include "rtc_base/experiments/field_trial_parser.h" +#include "rtc_base/experiments/field_trial_units.h" + +namespace rtc { + +// Pluggable strategy allows configuration of bitrate allocation per media +// track. +// +// The strategy should provide allocation for every track passed with +// track_configs in AllocateBitrates. The allocations are constrained by +// max_bitrate_bps, min_bitrate_bps defining the track supported range and +// enforce_min_bitrate indicating if the track my be paused by allocating 0 +// bitrate. +class BitrateAllocationStrategy { + public: + struct TrackConfig { + TrackConfig(uint32_t min_bitrate_bps, + uint32_t max_bitrate_bps, + bool enforce_min_bitrate, + std::string track_id) + : min_bitrate_bps(min_bitrate_bps), + max_bitrate_bps(max_bitrate_bps), + enforce_min_bitrate(enforce_min_bitrate), + track_id(track_id) {} + TrackConfig(const TrackConfig& track_config) = default; + virtual ~TrackConfig() = default; + TrackConfig() {} + + // Minimum bitrate supported by track. + uint32_t min_bitrate_bps; + + // Maximum bitrate supported by track. + uint32_t max_bitrate_bps; + + // True means track may not be paused by allocating 0 bitrate. + bool enforce_min_bitrate; + + // MediaStreamTrack ID as defined by application. May be empty. + std::string track_id; + }; + + // These are only used by AudioPriorityBitrateAllocationStrategy. They are + // exposed here to they can be unit tested. + static std::vector SetAllBitratesToMinimum( + const std::vector& track_configs); + static std::vector DistributeBitratesEvenly( + const std::vector& track_configs, + uint32_t available_bitrate); + + // Strategy is expected to allocate all available_bitrate up to the sum of + // max_bitrate_bps of all tracks. If available_bitrate is less than the sum of + // min_bitrate_bps of all tracks, tracks having enforce_min_bitrate set to + // false may get 0 allocation and are suppoused to pause, tracks with + // enforce_min_bitrate set to true are expecting to get min_bitrate_bps. + // + // If the strategy will allocate more than available_bitrate it may cause + // overuse of the currently available network capacity and may cause increase + // in RTT and packet loss. Allocating less than available bitrate may cause + // available_bitrate decrease. + virtual std::vector AllocateBitrates( + uint32_t available_bitrate, + std::vector track_configs) = 0; + + virtual ~BitrateAllocationStrategy() = default; +}; +} // namespace rtc + +namespace webrtc { +struct AudioPriorityConfig { + FieldTrialOptional min_rate; + FieldTrialOptional max_rate; + FieldTrialOptional target_rate; + AudioPriorityConfig(); + AudioPriorityConfig(const AudioPriorityConfig&); + AudioPriorityConfig& operator=(const AudioPriorityConfig&) = default; + ~AudioPriorityConfig(); +}; +} // namespace webrtc + +namespace rtc { +// Simple allocation strategy giving priority to audio until +// sufficient_audio_bitrate is reached. Bitrate is distributed evenly between +// the tracks after sufficient_audio_bitrate is reached. This implementation +// does not pause tracks even if enforce_min_bitrate is false. +class AudioPriorityBitrateAllocationStrategy + : public BitrateAllocationStrategy { + public: + AudioPriorityBitrateAllocationStrategy(std::string audio_track_id, + uint32_t sufficient_audio_bitrate); + std::vector AllocateBitrates( + uint32_t available_bitrate, + std::vector track_configs) + override; + + private: + webrtc::AudioPriorityConfig config_; + std::string audio_track_id_; + uint32_t sufficient_audio_bitrate_; +}; +} // namespace rtc + +#endif // RTC_BASE_BITRATE_ALLOCATION_STRATEGY_H_ diff --git a/rtc_base/bitrate_allocation_strategy_unittest.cc b/rtc_base/bitrate_allocation_strategy_unittest.cc new file mode 100644 index 0000000000..aea3966f48 --- /dev/null +++ b/rtc_base/bitrate_allocation_strategy_unittest.cc @@ -0,0 +1,237 @@ +/* + * Copyright 2017 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 "rtc_base/bitrate_allocation_strategy.h" + +#include + +#include "test/gtest.h" + +namespace rtc { + +std::vector +MakeTrackConfigPtrsVector( + const std::vector& track_configs) { + std::vector + track_config_ptrs(track_configs.size()); + int i = 0; + for (const auto& c : track_configs) { + track_config_ptrs[i++] = &c; + } + return track_config_ptrs; +} + +TEST(BitrateAllocationStrategyTest, SetAllBitratesToMinimum) { + const std::string audio_track_id = "audio_track"; + constexpr uint32_t min_audio_bitrate = 6000; + constexpr uint32_t max_audio_bitrate = 64000; + const std::string video_track_id = "video_track"; + constexpr uint32_t min_video_bitrate = 30000; + constexpr uint32_t max_video_bitrate = 300000; + constexpr uint32_t min_other_bitrate = 3000; + constexpr uint32_t max_other_bitrate = 30000; + + std::vector track_configs = { + BitrateAllocationStrategy::TrackConfig( + min_audio_bitrate, max_audio_bitrate, false, audio_track_id), + BitrateAllocationStrategy::TrackConfig( + min_video_bitrate, max_video_bitrate, false, video_track_id), + BitrateAllocationStrategy::TrackConfig(min_other_bitrate, + max_other_bitrate, false, "")}; + + std::vector allocations = + BitrateAllocationStrategy::SetAllBitratesToMinimum(track_configs); + EXPECT_EQ(min_audio_bitrate, allocations[0]); + EXPECT_EQ(min_video_bitrate, allocations[1]); + EXPECT_EQ(min_other_bitrate, allocations[2]); +} + +TEST(BitrateAllocationStrategyTest, DistributeBitratesEvenly) { + const std::string audio_track_id = "audio_track"; + constexpr uint32_t min_audio_bitrate = 16000; + constexpr uint32_t max_audio_bitrate = 64000; + const std::string video_track_id = "video_track"; + constexpr uint32_t min_video_bitrate = 30000; + constexpr uint32_t max_video_bitrate = 300000; + constexpr uint32_t min_other_bitrate = 3000; + constexpr uint32_t max_other_bitrate = 30000; + constexpr uint32_t available_bitrate = 52000; + constexpr uint32_t even_bitrate_increase = + (available_bitrate - min_audio_bitrate - min_video_bitrate - + min_other_bitrate) / + 3; + + std::vector track_configs = { + BitrateAllocationStrategy::TrackConfig( + min_audio_bitrate, max_audio_bitrate, false, audio_track_id), + BitrateAllocationStrategy::TrackConfig( + min_video_bitrate, max_video_bitrate, false, video_track_id), + BitrateAllocationStrategy::TrackConfig(min_other_bitrate, + max_other_bitrate, false, "")}; + + std::vector allocations = + BitrateAllocationStrategy::DistributeBitratesEvenly(track_configs, + available_bitrate); + EXPECT_EQ(min_audio_bitrate + even_bitrate_increase, allocations[0]); + EXPECT_EQ(min_video_bitrate + even_bitrate_increase, allocations[1]); + EXPECT_EQ(min_other_bitrate + even_bitrate_increase, allocations[2]); +} + +std::vector RunAudioPriorityAllocation( + uint32_t sufficient_audio_bitrate, + std::string audio_track_id, + uint32_t min_audio_bitrate, + uint32_t max_audio_bitrate, + std::string video_track_id, + uint32_t min_video_bitrate, + uint32_t max_video_bitrate, + uint32_t min_other_bitrate, + uint32_t max_other_bitrate, + uint32_t available_bitrate) { + AudioPriorityBitrateAllocationStrategy allocation_strategy( + audio_track_id, sufficient_audio_bitrate); + std::vector track_configs = { + BitrateAllocationStrategy::TrackConfig( + min_audio_bitrate, max_audio_bitrate, false, audio_track_id), + BitrateAllocationStrategy::TrackConfig( + min_video_bitrate, max_video_bitrate, false, video_track_id), + BitrateAllocationStrategy::TrackConfig(min_other_bitrate, + max_other_bitrate, false, "")}; + + return allocation_strategy.AllocateBitrates(available_bitrate, track_configs); +} + +// Test that when the available bitrate is less than the sum of the minimum +// bitrates, the minimum bitrate is allocated for each track. +TEST(AudioPriorityBitrateAllocationStrategyTest, MinAllocateBitrate) { + constexpr uint32_t sufficient_audio_bitrate = 16000; + const std::string audio_track_id = "audio_track"; + constexpr uint32_t min_audio_bitrate = 6000; + constexpr uint32_t max_audio_bitrate = 64000; + const std::string video_track_id = "video_track"; + constexpr uint32_t min_video_bitrate = 30000; + constexpr uint32_t max_video_bitrate = 300000; + constexpr uint32_t min_other_bitrate = 3000; + constexpr uint32_t max_other_bitrate = 30000; + constexpr uint32_t available_bitrate = 10000; + + std::vector allocations = RunAudioPriorityAllocation( + sufficient_audio_bitrate, audio_track_id, min_audio_bitrate, + max_audio_bitrate, video_track_id, min_video_bitrate, max_video_bitrate, + min_other_bitrate, max_other_bitrate, available_bitrate); + EXPECT_EQ(min_audio_bitrate, allocations[0]); + EXPECT_EQ(min_video_bitrate, allocations[1]); + EXPECT_EQ(min_other_bitrate, allocations[2]); +} + +// Test that when the available bitrate is more than the sum of the max +// bitrates, the max bitrate is allocated for each track. +TEST(AudioPriorityBitrateAllocationStrategyTest, MaxAllocateBitrate) { + constexpr uint32_t sufficient_audio_bitrate = 16000; + const std::string audio_track_id = "audio_track"; + constexpr uint32_t min_audio_bitrate = 6000; + constexpr uint32_t max_audio_bitrate = 64000; + const std::string video_track_id = "video_track"; + constexpr uint32_t min_video_bitrate = 30000; + constexpr uint32_t max_video_bitrate = 300000; + constexpr uint32_t min_other_bitrate = 3000; + constexpr uint32_t max_other_bitrate = 30000; + constexpr uint32_t available_bitrate = 400000; + + std::vector allocations = RunAudioPriorityAllocation( + sufficient_audio_bitrate, audio_track_id, min_audio_bitrate, + max_audio_bitrate, video_track_id, min_video_bitrate, max_video_bitrate, + min_other_bitrate, max_other_bitrate, available_bitrate); + + // TODO(bugs.webrtc.org/8541): Until the bug is fixed not audio streams will + // get up to kTransmissionMaxBitrateMultiplier*max_bitrate + constexpr uint32_t video_bitrate = + (available_bitrate - max_audio_bitrate - max_other_bitrate * 2); + EXPECT_EQ(max_audio_bitrate, allocations[0]); + EXPECT_EQ(video_bitrate, allocations[1]); + EXPECT_EQ(max_other_bitrate * 2, allocations[2]); +} + +// Test that audio track will get up to sufficient bitrate before video and +// other bitrate will be allocated. +TEST(AudioPriorityBitrateAllocationStrategyTest, AudioPriorityAllocateBitrate) { + constexpr uint32_t sufficient_audio_bitrate = 16000; + const std::string audio_track_id = "audio_track"; + constexpr uint32_t min_audio_bitrate = 6000; + constexpr uint32_t max_audio_bitrate = 64000; + const std::string video_track_id = "video_track"; + constexpr uint32_t min_video_bitrate = 30000; + constexpr uint32_t max_video_bitrate = 300000; + constexpr uint32_t min_other_bitrate = 3000; + constexpr uint32_t max_other_bitrate = 30000; + constexpr uint32_t available_bitrate = 49000; + + std::vector allocations = RunAudioPriorityAllocation( + sufficient_audio_bitrate, audio_track_id, min_audio_bitrate, + max_audio_bitrate, video_track_id, min_video_bitrate, max_video_bitrate, + min_other_bitrate, max_other_bitrate, available_bitrate); + EXPECT_EQ(sufficient_audio_bitrate, allocations[0]); + EXPECT_EQ(min_video_bitrate, allocations[1]); + EXPECT_EQ(min_other_bitrate, allocations[2]); +} + +// Test that bitrate will be allocated evenly after sufficient audio bitrate is +// allocated. +TEST(AudioPriorityBitrateAllocationStrategyTest, EvenAllocateBitrate) { + constexpr uint32_t sufficient_audio_bitrate = 16000; + const std::string audio_track_id = "audio_track"; + constexpr uint32_t min_audio_bitrate = 6000; + constexpr uint32_t max_audio_bitrate = 64000; + const std::string video_track_id = "video_track"; + constexpr uint32_t min_video_bitrate = 30000; + constexpr uint32_t max_video_bitrate = 300000; + constexpr uint32_t min_other_bitrate = 3000; + constexpr uint32_t max_other_bitrate = 30000; + constexpr uint32_t available_bitrate = 52000; + constexpr uint32_t even_bitrate_increase = + (available_bitrate - sufficient_audio_bitrate - min_video_bitrate - + min_other_bitrate) / + 3; + + std::vector allocations = RunAudioPriorityAllocation( + sufficient_audio_bitrate, audio_track_id, min_audio_bitrate, + max_audio_bitrate, video_track_id, min_video_bitrate, max_video_bitrate, + min_other_bitrate, max_other_bitrate, available_bitrate); + EXPECT_EQ(sufficient_audio_bitrate + even_bitrate_increase, allocations[0]); + EXPECT_EQ(min_video_bitrate + even_bitrate_increase, allocations[1]); + EXPECT_EQ(min_other_bitrate + even_bitrate_increase, allocations[2]); +} + +// Test that bitrate will be allocated to video after audio and other max +// allocation. +TEST(AudioPriorityBitrateAllocationStrategyTest, VideoAllocateBitrate) { + constexpr uint32_t sufficient_audio_bitrate = 16000; + const std::string audio_track_id = "audio_track"; + constexpr uint32_t min_audio_bitrate = 6000; + constexpr uint32_t max_audio_bitrate = 64000; + const std::string video_track_id = "video_track"; + constexpr uint32_t min_video_bitrate = 30000; + constexpr uint32_t max_video_bitrate = 300000; + constexpr uint32_t min_other_bitrate = 3000; + constexpr uint32_t max_other_bitrate = 30000; + constexpr uint32_t available_bitrate = 200000; + constexpr uint32_t video_bitrate = + available_bitrate - max_audio_bitrate - max_other_bitrate; + + std::vector allocations = RunAudioPriorityAllocation( + sufficient_audio_bitrate, audio_track_id, min_audio_bitrate, + max_audio_bitrate, video_track_id, min_video_bitrate, max_video_bitrate, + min_other_bitrate, max_other_bitrate, available_bitrate); + EXPECT_EQ(max_audio_bitrate, allocations[0]); + EXPECT_EQ(video_bitrate, allocations[1]); + EXPECT_EQ(max_other_bitrate, allocations[2]); +} + +} // namespace rtc diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn index 8303d8af46..241b88f0d2 100644 --- a/sdk/BUILD.gn +++ b/sdk/BUILD.gn @@ -840,6 +840,7 @@ if (is_ios || is_mac) { "objc/api/peerconnection/RTCMetricsSampleInfo.h", "objc/api/peerconnection/RTCMetricsSampleInfo.mm", "objc/api/peerconnection/RTCPeerConnection+DataChannel.mm", + "objc/api/peerconnection/RTCPeerConnection+Native.h", "objc/api/peerconnection/RTCPeerConnection+Private.h", "objc/api/peerconnection/RTCPeerConnection+Stats.mm", "objc/api/peerconnection/RTCPeerConnection.h", @@ -955,6 +956,7 @@ if (is_ios || is_mac) { "objc/Framework/Classes/Common/NSString+StdString.h", "objc/Framework/Classes/Common/scoped_cftyperef.h", "objc/Framework/Classes/PeerConnection/RTCConfiguration+Native.h", + "objc/Framework/Classes/PeerConnection/RTCPeerConnection+Native.h", "objc/Framework/Classes/PeerConnection/RTCPeerConnectionFactory+Native.h", "objc/Framework/Classes/PeerConnection/RTCVideoCodec+Private.h", "objc/Framework/Classes/Video/RTCDefaultShader.h", diff --git a/sdk/objc/Framework/Classes/PeerConnection/RTCPeerConnection+Native.h b/sdk/objc/Framework/Classes/PeerConnection/RTCPeerConnection+Native.h new file mode 100644 index 0000000000..7d8ab9af27 --- /dev/null +++ b/sdk/objc/Framework/Classes/PeerConnection/RTCPeerConnection+Native.h @@ -0,0 +1,11 @@ +/* + * Copyright 2017 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. + */ + +#import "api/peerconnection/RTCPeerConnection+Native.h" diff --git a/sdk/objc/api/peerconnection/RTCPeerConnection+Native.h b/sdk/objc/api/peerconnection/RTCPeerConnection+Native.h new file mode 100644 index 0000000000..f0322a78f5 --- /dev/null +++ b/sdk/objc/api/peerconnection/RTCPeerConnection+Native.h @@ -0,0 +1,34 @@ +/* + * Copyright 2017 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. + */ + +#import "RTCPeerConnection.h" + +#include + +namespace rtc { +class BitrateAllocationStrategy; +} // namespace rtc + +NS_ASSUME_NONNULL_BEGIN + +/** + * This class extension exposes methods that work directly with injectable C++ components. + */ +@interface RTCPeerConnection () + +/** Sets current strategy. If not set default WebRTC allocator will be used. May be changed during + * an active session. + */ +- (void)setBitrateAllocationStrategy: + (std::unique_ptr)bitrateAllocationStrategy; + +@end + +NS_ASSUME_NONNULL_END diff --git a/sdk/objc/api/peerconnection/RTCPeerConnection.mm b/sdk/objc/api/peerconnection/RTCPeerConnection.mm index 659e1f379e..04b07f7533 100644 --- a/sdk/objc/api/peerconnection/RTCPeerConnection.mm +++ b/sdk/objc/api/peerconnection/RTCPeerConnection.mm @@ -17,6 +17,7 @@ #import "RTCMediaConstraints+Private.h" #import "RTCMediaStream+Private.h" #import "RTCMediaStreamTrack+Private.h" +#import "RTCPeerConnection+Native.h" #import "RTCPeerConnectionFactory+Private.h" #import "RTCRtpReceiver+Private.h" #import "RTCRtpSender+Private.h" @@ -521,6 +522,11 @@ void PeerConnectionDelegateAdapter::OnRemoveTrack( return _peerConnection->SetBitrate(params).ok(); } +- (void)setBitrateAllocationStrategy: + (std::unique_ptr)bitrateAllocationStrategy { + _peerConnection->SetBitrateAllocationStrategy(std::move(bitrateAllocationStrategy)); +} + - (BOOL)startRtcEventLogWithFilePath:(NSString *)filePath maxSizeInBytes:(int64_t)maxSizeInBytes { RTC_DCHECK(filePath.length); diff --git a/test/scenario/audio_stream.cc b/test/scenario/audio_stream.cc index 79ac2e72a8..4ff3593c15 100644 --- a/test/scenario/audio_stream.cc +++ b/test/scenario/audio_stream.cc @@ -10,6 +10,7 @@ #include "test/scenario/audio_stream.h" #include "absl/memory/memory.h" +#include "rtc_base/bitrate_allocation_strategy.h" #include "test/call_test.h" #if WEBRTC_ENABLE_PROTOBUF @@ -129,6 +130,10 @@ SendAudioStream::SendAudioStream( if (config.encoder.priority_rate) { send_config.track_id = sender->GetNextPriorityId(); + sender_->call_->SetBitrateAllocationStrategy( + absl::make_unique( + send_config.track_id, + config.encoder.priority_rate->bps())); } sender_->SendTask([&] { send_stream_ = sender_->call_->CreateAudioSendStream(send_config); diff --git a/video/BUILD.gn b/video/BUILD.gn index 89c1f32c93..a2cf13a3f9 100644 --- a/video/BUILD.gn +++ b/video/BUILD.gn @@ -100,7 +100,6 @@ rtc_static_library("video") { "../rtc_base:stringutils", "../rtc_base:weak_ptr", "../rtc_base/experiments:alr_experiment", - "../rtc_base/experiments:field_trial_parser", "../rtc_base/experiments:keyframe_interval_settings_experiment", "../rtc_base/experiments:quality_scaling_experiment", "../rtc_base/experiments:rate_control_settings", diff --git a/video/video_send_stream_impl.cc b/video/video_send_stream_impl.cc index 50bbb1f978..7de991c79e 100644 --- a/video/video_send_stream_impl.cc +++ b/video/video_send_stream_impl.cc @@ -511,6 +511,7 @@ MediaStreamAllocationConfig VideoSendStreamImpl::GetAllocationConfig() const { static_cast(disable_padding_ ? 0 : max_padding_bitrate_), /* priority_bitrate */ 0, !config_->suspend_below_min_bitrate, + config_->track_id, encoder_bitrate_priority_}; } diff --git a/video/video_send_stream_impl.h b/video/video_send_stream_impl.h index 64826a3ad9..7f734e95ae 100644 --- a/video/video_send_stream_impl.h +++ b/video/video_send_stream_impl.h @@ -36,7 +36,6 @@ #include "modules/utility/include/process_thread.h" #include "modules/video_coding/include/video_codec_interface.h" #include "rtc_base/critical_section.h" -#include "rtc_base/experiments/field_trial_parser.h" #include "rtc_base/task_queue.h" #include "rtc_base/task_utils/repeating_task.h" #include "rtc_base/thread_annotations.h" diff --git a/video/video_send_stream_impl_unittest.cc b/video/video_send_stream_impl_unittest.cc index e6a291fb7d..51e31f78e1 100644 --- a/video/video_send_stream_impl_unittest.cc +++ b/video/video_send_stream_impl_unittest.cc @@ -154,6 +154,7 @@ class VideoSendStreamImplTest : public ::testing::Test { TEST_F(VideoSendStreamImplTest, RegistersAsBitrateObserverOnStart) { test_queue_.SendTask([this] { + config_.track_id = "test"; const bool kSuspend = false; config_.suspend_below_min_bitrate = kSuspend; auto vss_impl = CreateVideoSendStreamImpl( @@ -166,6 +167,7 @@ TEST_F(VideoSendStreamImplTest, RegistersAsBitrateObserverOnStart) { EXPECT_EQ(config.max_bitrate_bps, kDefaultInitialBitrateBps); EXPECT_EQ(config.pad_up_bitrate_bps, 0u); EXPECT_EQ(config.enforce_min_bitrate, !kSuspend); + EXPECT_EQ(config.track_id, "test"); EXPECT_EQ(config.bitrate_priority, kDefaultBitratePriority); })); vss_impl->Start(); @@ -176,6 +178,7 @@ TEST_F(VideoSendStreamImplTest, RegistersAsBitrateObserverOnStart) { TEST_F(VideoSendStreamImplTest, UpdatesObserverOnConfigurationChange) { test_queue_.SendTask([this] { + config_.track_id = "test"; const bool kSuspend = false; config_.suspend_below_min_bitrate = kSuspend; config_.rtp.extensions.emplace_back( @@ -238,6 +241,7 @@ TEST_F(VideoSendStreamImplTest, UpdatesObserverOnConfigurationChange) { TEST_F(VideoSendStreamImplTest, UpdatesObserverOnConfigurationChangeWithAlr) { test_queue_.SendTask([this] { + config_.track_id = "test"; const bool kSuspend = false; config_.suspend_below_min_bitrate = kSuspend; config_.rtp.extensions.emplace_back( @@ -626,6 +630,7 @@ TEST_F(VideoSendStreamImplTest, ForwardsVideoBitrateAllocationAfterTimeout) { TEST_F(VideoSendStreamImplTest, CallsVideoStreamEncoderOnBitrateUpdate) { test_queue_.SendTask([this] { + config_.track_id = "test"; const bool kSuspend = false; config_.suspend_below_min_bitrate = kSuspend; config_.rtp.extensions.emplace_back( @@ -753,6 +758,8 @@ TEST_F(VideoSendStreamImplTest, DisablesPaddingOnPausedEncoder) { EXPECT_CALL(rtp_video_sender_, OnEncodedImage(_, _, _)) .WillRepeatedly(Return( EncodedImageCallback::Result(EncodedImageCallback::Result::OK))); + + config_.track_id = "test"; const bool kSuspend = false; config_.suspend_below_min_bitrate = kSuspend; config_.rtp.extensions.emplace_back(