Implementing auto pausing of video streams.
This CL implements auto pausing video streams per stream with logic to
avoid toggling state too often.
Also re-enabling tests disabled for Mac, with the assumption the new
logic removes flakiness.
BUG=webrtc:5868,webrtc:5407
R=pbos@webrtc.org, stefan@webrtc.org
Review URL: https://codereview.webrtc.org/2035383002 .
Cr-Commit-Position: refs/heads/master@{#13092}
diff --git a/webrtc/call/bitrate_allocator.cc b/webrtc/call/bitrate_allocator.cc
index 3672ef5..e4b1ad4 100644
--- a/webrtc/call/bitrate_allocator.cc
+++ b/webrtc/call/bitrate_allocator.cc
@@ -24,30 +24,34 @@
const int kTransmissionMaxBitrateMultiplier = 2;
const int kDefaultBitrateBps = 300000;
+// Require a bitrate increase of max(10%, 20kbps) to resume paused streams.
+const double kToggleFactor = 0.1;
+const uint32_t kMinToggleBitrateBps = 20000;
+
BitrateAllocator::BitrateAllocator()
: bitrate_observer_configs_(),
- enforce_min_bitrate_(true),
last_bitrate_bps_(kDefaultBitrateBps),
last_non_zero_bitrate_bps_(kDefaultBitrateBps),
last_fraction_loss_(0),
last_rtt_(0) {}
-uint32_t BitrateAllocator::OnNetworkChanged(uint32_t bitrate,
+uint32_t BitrateAllocator::OnNetworkChanged(uint32_t target_bitrate_bps,
uint8_t fraction_loss,
int64_t rtt) {
rtc::CritScope lock(&crit_sect_);
- last_bitrate_bps_ = bitrate;
+ last_bitrate_bps_ = target_bitrate_bps;
last_non_zero_bitrate_bps_ =
- bitrate > 0 ? bitrate : last_non_zero_bitrate_bps_;
+ target_bitrate_bps > 0 ? target_bitrate_bps : last_non_zero_bitrate_bps_;
last_fraction_loss_ = fraction_loss;
last_rtt_ = rtt;
uint32_t allocated_bitrate_bps = 0;
- ObserverAllocation allocation = AllocateBitrates(bitrate);
+ ObserverAllocation allocation = AllocateBitrates(target_bitrate_bps);
for (const auto& kv : allocation) {
kv.first->OnBitrateUpdated(kv.second, last_fraction_loss_, last_rtt_);
allocated_bitrate_bps += kv.second;
}
+ last_allocation_ = allocation;
return allocated_bitrate_bps;
}
@@ -56,45 +60,33 @@
uint32_t max_bitrate_bps,
bool enforce_min_bitrate) {
rtc::CritScope lock(&crit_sect_);
- // TODO(mflodman): Enforce this per observer.
- EnforceMinBitrate(enforce_min_bitrate);
-
auto it = FindObserverConfig(observer);
- // Allow the max bitrate to be exceeded for FEC and retransmissions.
- // TODO(holmer): We have to get rid of this hack as it makes it difficult to
- // properly allocate bitrate. The allocator should instead distribute any
- // extra bitrate after all streams have maxed out.
- max_bitrate_bps *= kTransmissionMaxBitrateMultiplier;
+ // Update settings if the observer already exists, create a new one otherwise.
if (it != bitrate_observer_configs_.end()) {
- // Update current configuration.
it->min_bitrate_bps = min_bitrate_bps;
it->max_bitrate_bps = max_bitrate_bps;
+ it->enforce_min_bitrate = enforce_min_bitrate;
} else {
- // Add new settings.
bitrate_observer_configs_.push_back(ObserverConfig(
observer, min_bitrate_bps, max_bitrate_bps, enforce_min_bitrate));
}
- int new_observer_bitrate_bps = 0;
- if (last_bitrate_bps_ > 0) { // We have a bitrate to allocate.
- ObserverAllocation allocation = AllocateBitrates(last_bitrate_bps_);
- for (auto& kv : allocation) {
- // Update all observers with the new allocation.
+ ObserverAllocation allocation;
+ if (last_bitrate_bps_ > 0) {
+ // Calculate a new allocation and update all observers.
+ allocation = AllocateBitrates(last_bitrate_bps_);
+ for (const auto& kv : allocation)
kv.first->OnBitrateUpdated(kv.second, last_fraction_loss_, last_rtt_);
- if (kv.first == observer)
- new_observer_bitrate_bps = kv.second;
- }
} else {
// Currently, an encoder is not allowed to produce frames.
// But we still have to return the initial config bitrate + let the
// observer know that it can not produce frames.
- ObserverAllocation allocation =
- AllocateBitrates(last_non_zero_bitrate_bps_);
+ allocation = AllocateBitrates(last_non_zero_bitrate_bps_);
observer->OnBitrateUpdated(0, last_fraction_loss_, last_rtt_);
- new_observer_bitrate_bps = allocation[observer];
}
- return new_observer_bitrate_bps;
+ last_allocation_ = allocation;
+ return allocation[observer];
}
void BitrateAllocator::RemoveObserver(BitrateAllocatorObserver* observer) {
@@ -105,10 +97,6 @@
}
}
-void BitrateAllocator::EnforceMinBitrate(bool enforce_min_bitrate) {
- enforce_min_bitrate_ = enforce_min_bitrate;
-}
-
BitrateAllocator::ObserverConfigList::iterator
BitrateAllocator::FindObserverConfig(
const BitrateAllocatorObserver* observer) {
@@ -129,56 +117,28 @@
return ZeroRateAllocation();
uint32_t sum_min_bitrates = 0;
- for (const auto& observer_config : bitrate_observer_configs_)
+ uint32_t sum_max_bitrates = 0;
+ for (const auto& observer_config : bitrate_observer_configs_) {
sum_min_bitrates += observer_config.min_bitrate_bps;
- if (bitrate <= sum_min_bitrates)
+ sum_max_bitrates += observer_config.max_bitrate_bps;
+ }
+
+ // Not enough for all observers to get an allocation, allocate according to:
+ // enforced min bitrate -> allocated bitrate previous round -> restart paused
+ // streams.
+ if (!EnoughBitrateForAllObservers(bitrate, sum_min_bitrates))
return LowRateAllocation(bitrate);
- return NormalRateAllocation(bitrate, sum_min_bitrates);
-}
+ // All observers will get their min bitrate plus an even share of the rest.
+ if (bitrate <= sum_max_bitrates)
+ return NormalRateAllocation(bitrate, sum_min_bitrates);
-BitrateAllocator::ObserverAllocation BitrateAllocator::NormalRateAllocation(
- uint32_t bitrate,
- uint32_t sum_min_bitrates) {
- uint32_t num_remaining_observers =
- static_cast<uint32_t>(bitrate_observer_configs_.size());
- RTC_DCHECK_GT(num_remaining_observers, 0u);
-
- uint32_t bitrate_per_observer =
- (bitrate - sum_min_bitrates) / num_remaining_observers;
- // Use map to sort list based on max bitrate.
- ObserverSortingMap list_max_bitrates;
- for (const auto& config : bitrate_observer_configs_) {
- list_max_bitrates.insert(std::pair<uint32_t, const ObserverConfig*>(
- config.max_bitrate_bps, &config));
- }
-
- ObserverAllocation allocation;
- ObserverSortingMap::iterator max_it = list_max_bitrates.begin();
- while (max_it != list_max_bitrates.end()) {
- num_remaining_observers--;
- uint32_t observer_allowance =
- max_it->second->min_bitrate_bps + bitrate_per_observer;
- if (max_it->first < observer_allowance) {
- // We have more than enough for this observer.
- // Carry the remainder forward.
- uint32_t remainder = observer_allowance - max_it->first;
- if (num_remaining_observers != 0)
- bitrate_per_observer += remainder / num_remaining_observers;
- allocation[max_it->second->observer] = max_it->first;
- } else {
- allocation[max_it->second->observer] = observer_allowance;
- }
- list_max_bitrates.erase(max_it);
- // Prepare next iteration.
- max_it = list_max_bitrates.begin();
- }
- return allocation;
+ // All observers will get up to kTransmissionMaxBitrateMultiplier x max.
+ return MaxRateAllocation(bitrate, sum_max_bitrates);
}
BitrateAllocator::ObserverAllocation BitrateAllocator::ZeroRateAllocation() {
ObserverAllocation allocation;
- // Zero bitrate to all observers.
for (const auto& observer_config : bitrate_observer_configs_)
allocation[observer_config.observer] = 0;
return allocation;
@@ -187,21 +147,153 @@
BitrateAllocator::ObserverAllocation BitrateAllocator::LowRateAllocation(
uint32_t bitrate) {
ObserverAllocation allocation;
- if (enforce_min_bitrate_) {
- // Min bitrate to all observers.
- for (const auto& observer_config : bitrate_observer_configs_)
- allocation[observer_config.observer] = observer_config.min_bitrate_bps;
- } else {
- // Allocate up to |min_bitrate_bps| to one observer at a time, until
- // |bitrate| is depleted.
- uint32_t remainder = bitrate;
+
+ // Start by allocating bitrate to observers enforcing a min bitrate, hence
+ // remaining_bitrate might turn negative.
+ int64_t remaining_bitrate = bitrate;
+ for (const auto& observer_config : bitrate_observer_configs_) {
+ int32_t allocated_bitrate = 0;
+ if (observer_config.enforce_min_bitrate)
+ allocated_bitrate = observer_config.min_bitrate_bps;
+
+ allocation[observer_config.observer] = allocated_bitrate;
+ remaining_bitrate -= allocated_bitrate;
+ }
+
+ // Allocate bitrate to all previously active streams.
+ if (remaining_bitrate > 0) {
for (const auto& observer_config : bitrate_observer_configs_) {
- uint32_t allocated_bitrate =
- std::min(remainder, observer_config.min_bitrate_bps);
- allocation[observer_config.observer] = allocated_bitrate;
- remainder -= allocated_bitrate;
+ if (observer_config.enforce_min_bitrate ||
+ LastAllocatedBitrate(observer_config) == 0)
+ continue;
+
+ if (remaining_bitrate >= observer_config.min_bitrate_bps) {
+ allocation[observer_config.observer] = observer_config.min_bitrate_bps;
+ remaining_bitrate -= observer_config.min_bitrate_bps;
+ }
}
}
+
+ // Allocate bitrate to previously paused streams.
+ if (remaining_bitrate > 0) {
+ for (const auto& observer_config : bitrate_observer_configs_) {
+ if (LastAllocatedBitrate(observer_config) != 0)
+ continue;
+
+ // Add a hysteresis to avoid toggling.
+ uint32_t required_bitrate = MinBitrateWithHysteresis(observer_config);
+ if (remaining_bitrate >= required_bitrate) {
+ allocation[observer_config.observer] = required_bitrate;
+ remaining_bitrate -= required_bitrate;
+ }
+ }
+ }
+
+ // Split a possible remainder evenly on all streams with an allocation.
+ if (remaining_bitrate > 0)
+ DistributeBitrateEvenly(remaining_bitrate, false, 1, &allocation);
+
+ RTC_DCHECK_EQ(allocation.size(), bitrate_observer_configs_.size());
return allocation;
}
+
+BitrateAllocator::ObserverAllocation BitrateAllocator::NormalRateAllocation(
+ uint32_t bitrate,
+ uint32_t sum_min_bitrates) {
+
+ ObserverAllocation allocation;
+ for (const auto& observer_config : bitrate_observer_configs_)
+ allocation[observer_config.observer] = observer_config.min_bitrate_bps;
+
+ bitrate -= sum_min_bitrates;
+ if (bitrate > 0)
+ DistributeBitrateEvenly(bitrate, true, 1, &allocation);
+
+ return allocation;
+}
+
+BitrateAllocator::ObserverAllocation BitrateAllocator::MaxRateAllocation(
+ uint32_t bitrate, uint32_t sum_max_bitrates) {
+ ObserverAllocation allocation;
+
+ for (const auto& observer_config : bitrate_observer_configs_) {
+ allocation[observer_config.observer] = observer_config.max_bitrate_bps;
+ bitrate -= observer_config.max_bitrate_bps;
+ }
+ DistributeBitrateEvenly(bitrate, true, kTransmissionMaxBitrateMultiplier,
+ &allocation);
+ return allocation;
+}
+
+uint32_t BitrateAllocator::LastAllocatedBitrate(
+ const ObserverConfig& observer_config) {
+
+ const auto& it = last_allocation_.find(observer_config.observer);
+ if (it != last_allocation_.end())
+ return it->second;
+
+ // Return the configured minimum bitrate for newly added observers, to avoid
+ // requiring an extra high bitrate for the observer to get an allocated
+ // bitrate.
+ return observer_config.min_bitrate_bps;
+}
+
+uint32_t BitrateAllocator::MinBitrateWithHysteresis(
+ const ObserverConfig& observer_config) {
+ uint32_t min_bitrate = observer_config.min_bitrate_bps;
+ if (LastAllocatedBitrate(observer_config) == 0) {
+ min_bitrate += std::max(static_cast<uint32_t>(kToggleFactor * min_bitrate),
+ kMinToggleBitrateBps);
+ }
+ return min_bitrate;
+}
+
+void BitrateAllocator::DistributeBitrateEvenly(uint32_t bitrate,
+ bool include_zero_allocations,
+ int max_multiplier,
+ ObserverAllocation* allocation) {
+ RTC_DCHECK_EQ(allocation->size(), bitrate_observer_configs_.size());
+
+ ObserverSortingMap list_max_bitrates;
+ for (const auto& observer_config : bitrate_observer_configs_) {
+ if (include_zero_allocations ||
+ allocation->at(observer_config.observer) != 0) {
+ list_max_bitrates.insert(std::pair<uint32_t, const ObserverConfig*>(
+ observer_config.max_bitrate_bps, &observer_config));
+ }
+ }
+ auto it = list_max_bitrates.begin();
+ while (it != list_max_bitrates.end()) {
+ RTC_DCHECK_GT(bitrate, 0u);
+ uint32_t extra_allocation =
+ bitrate / static_cast<uint32_t>(list_max_bitrates.size());
+ uint32_t total_allocation =
+ extra_allocation + allocation->at(it->second->observer);
+ bitrate -= extra_allocation;
+ if (total_allocation > max_multiplier * it->first) {
+ // There is more than we can fit for this observer, carry over to the
+ // remaining observers.
+ bitrate += total_allocation - max_multiplier * it->first;
+ total_allocation = max_multiplier * it->first;
+ }
+ // Finally, update the allocation for this observer.
+ allocation->at(it->second->observer) = total_allocation;
+ it = list_max_bitrates.erase(it);
+ }
+}
+
+bool BitrateAllocator::EnoughBitrateForAllObservers(uint32_t bitrate,
+ uint32_t sum_min_bitrates) {
+ if (bitrate < sum_min_bitrates)
+ return false;
+
+ uint32_t extra_bitrate_per_observer = (bitrate - sum_min_bitrates) /
+ static_cast<uint32_t>(bitrate_observer_configs_.size());
+ for (const auto& observer_config : bitrate_observer_configs_) {
+ if (observer_config.min_bitrate_bps + extra_bitrate_per_observer <
+ MinBitrateWithHysteresis(observer_config))
+ return false;
+ }
+ return true;
+}
} // namespace webrtc
diff --git a/webrtc/call/bitrate_allocator.h b/webrtc/call/bitrate_allocator.h
index bf26a6a..fd9fe71 100644
--- a/webrtc/call/bitrate_allocator.h
+++ b/webrtc/call/bitrate_allocator.h
@@ -42,9 +42,9 @@
BitrateAllocator();
// Allocate target_bitrate across the registered BitrateAllocatorObservers.
- // Returns actual bitrate allocated (might be higher than target_bitrate if
- // for instance EnforceMinBitrate() is enabled.
- uint32_t OnNetworkChanged(uint32_t target_bitrate,
+ // Returns actual bitrate allocated, which might be higher than target_bitrate
+ // if for instance EnforceMinBitrate() is enabled.
+ uint32_t OnNetworkChanged(uint32_t target_bitrate_bps,
uint8_t fraction_loss,
int64_t rtt);
@@ -66,9 +66,12 @@
uint32_t max_bitrate_bps,
bool enforce_min_bitrate);
+ // Removes a previously added observer, but will not trigger a new bitrate
+ // allocation.
void RemoveObserver(BitrateAllocatorObserver* observer);
private:
+ // Note: All bitrates for member variables and methods are in bps.
struct ObserverConfig {
ObserverConfig(BitrateAllocatorObserver* observer,
uint32_t min_bitrate_bps,
@@ -84,14 +87,6 @@
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)
- EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
-
typedef std::list<ObserverConfig> ObserverConfigList;
ObserverConfigList::iterator FindObserverConfig(
const BitrateAllocatorObserver* observer)
@@ -102,22 +97,44 @@
ObserverAllocation AllocateBitrates(uint32_t bitrate)
EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
- ObserverAllocation NormalRateAllocation(uint32_t bitrate,
- uint32_t sum_min_bitrates)
- EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
ObserverAllocation ZeroRateAllocation() EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
ObserverAllocation LowRateAllocation(uint32_t bitrate)
EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
+ ObserverAllocation NormalRateAllocation(uint32_t bitrate,
+ uint32_t sum_min_bitrates)
+ EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
+ ObserverAllocation MaxRateAllocation(uint32_t bitrate,
+ uint32_t sum_max_bitrates)
+ EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
+
+ uint32_t LastAllocatedBitrate(const ObserverConfig& observer_config)
+ EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
+ // The minimum bitrate required by this observer, including enable-hysteresis
+ // if the observer is in a paused state.
+ uint32_t MinBitrateWithHysteresis(const ObserverConfig& observer_config)
+ EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
+ // Splits |bitrate| evenly to observers already in |allocation|.
+ // |include_zero_allocations| decides if zero allocations should be part of
+ // the distribution or not. The allowed max bitrate is |max_multiplier| x
+ // observer max bitrate.
+ void DistributeBitrateEvenly(uint32_t bitrate,
+ bool include_zero_allocations,
+ int max_multiplier,
+ ObserverAllocation* allocation)
+ EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
+ bool EnoughBitrateForAllObservers(uint32_t bitrate, uint32_t sum_min_bitrates)
+ EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
+
rtc::CriticalSection crit_sect_;
// Stored in a list to keep track of the insertion order.
ObserverConfigList bitrate_observer_configs_ GUARDED_BY(crit_sect_);
- bool enforce_min_bitrate_ GUARDED_BY(crit_sect_);
uint32_t last_bitrate_bps_ GUARDED_BY(crit_sect_);
uint32_t last_non_zero_bitrate_bps_ GUARDED_BY(crit_sect_);
uint8_t last_fraction_loss_ GUARDED_BY(crit_sect_);
int64_t last_rtt_ GUARDED_BY(crit_sect_);
+ ObserverAllocation last_allocation_ GUARDED_BY(crit_sect_);
};
} // namespace webrtc
#endif // WEBRTC_CALL_BITRATE_ALLOCATOR_H_
diff --git a/webrtc/call/bitrate_allocator_unittest.cc b/webrtc/call/bitrate_allocator_unittest.cc
index 4017645..9cb5f6c 100644
--- a/webrtc/call/bitrate_allocator_unittest.cc
+++ b/webrtc/call/bitrate_allocator_unittest.cc
@@ -21,18 +21,18 @@
class TestBitrateObserver : public BitrateAllocatorObserver {
public:
TestBitrateObserver()
- : last_bitrate_(0), last_fraction_loss_(0), last_rtt_(0) {}
+ : last_bitrate_bps_(0), last_fraction_loss_(0), last_rtt_ms_(0) {}
- virtual void OnBitrateUpdated(uint32_t bitrate,
- uint8_t fraction_loss,
- int64_t rtt) {
- last_bitrate_ = bitrate;
+ void OnBitrateUpdated(uint32_t bitrate_bps,
+ uint8_t fraction_loss,
+ int64_t rtt) override {
+ last_bitrate_bps_ = bitrate_bps;
last_fraction_loss_ = fraction_loss;
- last_rtt_ = rtt;
+ last_rtt_ms_ = rtt;
}
- uint32_t last_bitrate_;
+ uint32_t last_bitrate_bps_;
uint8_t last_fraction_loss_;
- int64_t last_rtt_;
+ int64_t last_rtt_ms_;
};
class BitrateAllocatorTest : public ::testing::Test {
@@ -51,12 +51,12 @@
allocator_->AddObserver(&bitrate_observer, 100000, 1500000, true);
EXPECT_EQ(300000, start_bitrate);
allocator_->OnNetworkChanged(200000, 0, 0);
- EXPECT_EQ(200000u, bitrate_observer.last_bitrate_);
+ EXPECT_EQ(200000u, bitrate_observer.last_bitrate_bps_);
// TODO(pbos): Expect capping to 1.5M instead of 3M when not boosting the max
// bitrate for FEC/retransmissions (see todo in BitrateAllocator).
allocator_->OnNetworkChanged(4000000, 0, 0);
- EXPECT_EQ(3000000u, bitrate_observer.last_bitrate_);
+ EXPECT_EQ(3000000u, bitrate_observer.last_bitrate_bps_);
start_bitrate =
allocator_->AddObserver(&bitrate_observer, 100000, 4000000, true);
EXPECT_EQ(4000000, start_bitrate);
@@ -64,9 +64,9 @@
start_bitrate =
allocator_->AddObserver(&bitrate_observer, 100000, 1500000, true);
EXPECT_EQ(3000000, start_bitrate);
- EXPECT_EQ(3000000u, bitrate_observer.last_bitrate_);
+ EXPECT_EQ(3000000u, bitrate_observer.last_bitrate_bps_);
allocator_->OnNetworkChanged(1500000, 0, 0);
- EXPECT_EQ(1500000u, bitrate_observer.last_bitrate_);
+ EXPECT_EQ(1500000u, bitrate_observer.last_bitrate_bps_);
}
TEST_F(BitrateAllocatorTest, TwoBitrateObserversOneRtcpObserver) {
@@ -82,29 +82,31 @@
// Test too low start bitrate, hence lower than sum of min. Min bitrates will
// be allocated to all observers.
allocator_->OnNetworkChanged(200000, 0, 50);
- EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_);
+ EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_bps_);
EXPECT_EQ(0, bitrate_observer_1.last_fraction_loss_);
- EXPECT_EQ(50, bitrate_observer_1.last_rtt_);
- EXPECT_EQ(200000u, bitrate_observer_2.last_bitrate_);
+ EXPECT_EQ(50, bitrate_observer_1.last_rtt_ms_);
+ EXPECT_EQ(200000u, bitrate_observer_2.last_bitrate_bps_);
EXPECT_EQ(0, bitrate_observer_2.last_fraction_loss_);
- EXPECT_EQ(50, bitrate_observer_2.last_rtt_);
+ EXPECT_EQ(50, bitrate_observer_2.last_rtt_ms_);
// Test a bitrate which should be distributed equally.
allocator_->OnNetworkChanged(500000, 0, 50);
const uint32_t kBitrateToShare = 500000 - 200000 - 100000;
- EXPECT_EQ(100000u + kBitrateToShare / 2, bitrate_observer_1.last_bitrate_);
- EXPECT_EQ(200000u + kBitrateToShare / 2, bitrate_observer_2.last_bitrate_);
+ EXPECT_EQ(100000u + kBitrateToShare / 2,
+ bitrate_observer_1.last_bitrate_bps_);
+ EXPECT_EQ(200000u + kBitrateToShare / 2,
+ bitrate_observer_2.last_bitrate_bps_);
// Limited by 2x max bitrates since we leave room for FEC and retransmissions.
allocator_->OnNetworkChanged(1500000, 0, 50);
- EXPECT_EQ(600000u, bitrate_observer_1.last_bitrate_);
- EXPECT_EQ(600000u, bitrate_observer_2.last_bitrate_);
+ EXPECT_EQ(600000u, bitrate_observer_1.last_bitrate_bps_);
+ EXPECT_EQ(600000u, bitrate_observer_2.last_bitrate_bps_);
// Verify that if the bandwidth estimate is set to zero, the allocated rate is
// zero.
allocator_->OnNetworkChanged(0, 0, 50);
- EXPECT_EQ(0u, bitrate_observer_1.last_bitrate_);
- EXPECT_EQ(0u, bitrate_observer_2.last_bitrate_);
+ EXPECT_EQ(0u, bitrate_observer_1.last_bitrate_bps_);
+ EXPECT_EQ(0u, bitrate_observer_2.last_bitrate_bps_);
}
class BitrateAllocatorTestNoEnforceMin : public ::testing::Test {
@@ -117,21 +119,21 @@
std::unique_ptr<BitrateAllocator> allocator_;
};
-// The following three tests verify that the EnforceMinBitrate() method works
-// as intended.
+// The following three tests verify enforcing a minimum bitrate works as
+// intended.
TEST_F(BitrateAllocatorTestNoEnforceMin, OneBitrateObserver) {
TestBitrateObserver bitrate_observer_1;
int start_bitrate =
allocator_->AddObserver(&bitrate_observer_1, 100000, 400000, false);
EXPECT_EQ(300000, start_bitrate);
- // High REMB.
+ // High BWE.
allocator_->OnNetworkChanged(150000, 0, 0);
- EXPECT_EQ(150000u, bitrate_observer_1.last_bitrate_);
+ EXPECT_EQ(150000u, bitrate_observer_1.last_bitrate_bps_);
- // Low REMB.
+ // Low BWE.
allocator_->OnNetworkChanged(10000, 0, 0);
- EXPECT_EQ(10000u, bitrate_observer_1.last_bitrate_);
+ EXPECT_EQ(0u, bitrate_observer_1.last_bitrate_bps_);
allocator_->RemoveObserver(&bitrate_observer_1);
}
@@ -148,52 +150,59 @@
start_bitrate =
allocator_->AddObserver(&bitrate_observer_2, 200000, 400000, false);
EXPECT_EQ(200000, start_bitrate);
- EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_);
+ EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_bps_);
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_);
+ EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_bps_);
+ EXPECT_EQ(200000u, bitrate_observer_2.last_bitrate_bps_);
- // High REMB. Make sure the controllers get a fair share of the surplus
- // (i.e., what is left after each controller gets its min rate).
+ // High BWE. Make sure the controllers get a fair share of the surplus (i.e.,
+ // what is left after each controller gets its min rate).
allocator_->OnNetworkChanged(690000, 0, 0);
// Verify that each observer gets its min rate (sum of min rates is 600000),
// and that the remaining 90000 is divided equally among the three.
uint32_t bitrate_to_share = 690000u - 100000u - 200000u - 300000u;
- EXPECT_EQ(100000u + bitrate_to_share / 3, bitrate_observer_1.last_bitrate_);
- EXPECT_EQ(200000u + bitrate_to_share / 3, bitrate_observer_2.last_bitrate_);
- EXPECT_EQ(300000u + bitrate_to_share / 3, bitrate_observer_3.last_bitrate_);
+ EXPECT_EQ(100000u + bitrate_to_share / 3,
+ bitrate_observer_1.last_bitrate_bps_);
+ EXPECT_EQ(200000u + bitrate_to_share / 3,
+ bitrate_observer_2.last_bitrate_bps_);
+ EXPECT_EQ(300000u + bitrate_to_share / 3,
+ bitrate_observer_3.last_bitrate_bps_);
- // High REMB, but below the sum of min bitrates.
+ // BWE below the sum of observer's min bitrate.
+ allocator_->OnNetworkChanged(300000, 0, 0);
+ EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_bps_); // Min bitrate.
+ EXPECT_EQ(200000u, bitrate_observer_2.last_bitrate_bps_); // Min bitrate.
+ EXPECT_EQ(0u, bitrate_observer_3.last_bitrate_bps_); // Nothing.
+
+ // Increased BWE, but still below the sum of configured min bitrates for all
+ // observers and too little for observer 3. 1 and 2 will share the rest.
allocator_->OnNetworkChanged(500000, 0, 0);
- // Verify that the first and second observers get their min bitrates, and the
- // third gets the remainder.
- EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_); // Min bitrate.
- EXPECT_EQ(200000u, bitrate_observer_2.last_bitrate_); // Min bitrate.
- EXPECT_EQ(200000u, bitrate_observer_3.last_bitrate_); // Remainder.
+ EXPECT_EQ(200000u, bitrate_observer_1.last_bitrate_bps_); // Min + split.
+ EXPECT_EQ(300000u, bitrate_observer_2.last_bitrate_bps_); // Min + split.
+ EXPECT_EQ(0u, bitrate_observer_3.last_bitrate_bps_); // Nothing.
- // Low REMB.
+ // Below min for all.
allocator_->OnNetworkChanged(10000, 0, 0);
- // Verify that the first observer gets all the rate, and the rest get zero.
- EXPECT_EQ(10000u, bitrate_observer_1.last_bitrate_);
- EXPECT_EQ(0u, bitrate_observer_2.last_bitrate_);
- EXPECT_EQ(0u, bitrate_observer_3.last_bitrate_);
+ EXPECT_EQ(0u, bitrate_observer_1.last_bitrate_bps_);
+ EXPECT_EQ(0u, bitrate_observer_2.last_bitrate_bps_);
+ EXPECT_EQ(0u, bitrate_observer_3.last_bitrate_bps_);
- allocator_->OnNetworkChanged(0, 0, 0);
// Verify that zero estimated bandwidth, means that that all gets zero,
// regardless of set min bitrate.
- EXPECT_EQ(0u, bitrate_observer_1.last_bitrate_);
- EXPECT_EQ(0u, bitrate_observer_2.last_bitrate_);
- EXPECT_EQ(0u, bitrate_observer_3.last_bitrate_);
+ allocator_->OnNetworkChanged(0, 0, 0);
+ EXPECT_EQ(0u, bitrate_observer_1.last_bitrate_bps_);
+ EXPECT_EQ(0u, bitrate_observer_2.last_bitrate_bps_);
+ EXPECT_EQ(0u, bitrate_observer_3.last_bitrate_bps_);
allocator_->RemoveObserver(&bitrate_observer_1);
allocator_->RemoveObserver(&bitrate_observer_2);
allocator_->RemoveObserver(&bitrate_observer_3);
}
-TEST_F(BitrateAllocatorTest, ThreeBitrateObserversLowRembEnforceMin) {
+TEST_F(BitrateAllocatorTest, ThreeBitrateObserversLowBweEnforceMin) {
TestBitrateObserver bitrate_observer_1;
TestBitrateObserver bitrate_observer_2;
TestBitrateObserver bitrate_observer_3;
@@ -204,19 +213,19 @@
start_bitrate =
allocator_->AddObserver(&bitrate_observer_2, 200000, 400000, true);
EXPECT_EQ(200000, start_bitrate);
- EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_);
+ EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_bps_);
start_bitrate =
allocator_->AddObserver(&bitrate_observer_3, 300000, 400000, true);
EXPECT_EQ(300000, start_bitrate);
- EXPECT_EQ(100000, static_cast<int>(bitrate_observer_1.last_bitrate_));
- EXPECT_EQ(200000, static_cast<int>(bitrate_observer_2.last_bitrate_));
+ EXPECT_EQ(100000, static_cast<int>(bitrate_observer_1.last_bitrate_bps_));
+ EXPECT_EQ(200000, static_cast<int>(bitrate_observer_2.last_bitrate_bps_));
- // Low REMB. Verify that all observers still get their respective min bitrate.
+ // Low BWE. Verify that all observers still get their respective min bitrate.
allocator_->OnNetworkChanged(1000, 0, 0);
- EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_); // Min cap.
- EXPECT_EQ(200000u, bitrate_observer_2.last_bitrate_); // Min cap.
- EXPECT_EQ(300000u, bitrate_observer_3.last_bitrate_); // Min cap.
+ EXPECT_EQ(100000u, bitrate_observer_1.last_bitrate_bps_); // Min cap.
+ EXPECT_EQ(200000u, bitrate_observer_2.last_bitrate_bps_); // Min cap.
+ EXPECT_EQ(300000u, bitrate_observer_3.last_bitrate_bps_); // Min cap.
allocator_->RemoveObserver(&bitrate_observer_1);
allocator_->RemoveObserver(&bitrate_observer_2);
@@ -232,7 +241,7 @@
// Set network down, ie, no available bitrate.
allocator_->OnNetworkChanged(0, 0, 0);
- EXPECT_EQ(0u, bitrate_observer_1.last_bitrate_);
+ EXPECT_EQ(0u, bitrate_observer_1.last_bitrate_bps_);
TestBitrateObserver bitrate_observer_2;
start_bitrate =
@@ -241,13 +250,111 @@
// Expect the start_bitrate to be set as if the network was still up but that
// the new observer have been notified that the network is down.
EXPECT_EQ(300000 / 2, start_bitrate);
- EXPECT_EQ(0u, bitrate_observer_1.last_bitrate_);
- EXPECT_EQ(0u, bitrate_observer_2.last_bitrate_);
+ EXPECT_EQ(0u, bitrate_observer_1.last_bitrate_bps_);
+ EXPECT_EQ(0u, bitrate_observer_2.last_bitrate_bps_);
// Set network back up.
allocator_->OnNetworkChanged(1500000, 0, 50);
- EXPECT_EQ(750000u, bitrate_observer_1.last_bitrate_);
- EXPECT_EQ(750000u, bitrate_observer_2.last_bitrate_);
+ EXPECT_EQ(750000u, bitrate_observer_1.last_bitrate_bps_);
+ EXPECT_EQ(750000u, bitrate_observer_2.last_bitrate_bps_);
+}
+
+TEST_F(BitrateAllocatorTest, MixedEnforecedConfigs) {
+ TestBitrateObserver enforced_observer;
+ int start_bitrate =
+ allocator_->AddObserver(&enforced_observer, 6000, 30000, true);
+ EXPECT_EQ(60000, start_bitrate);
+
+ TestBitrateObserver not_enforced_observer;
+ start_bitrate =
+ allocator_->AddObserver(¬_enforced_observer, 30000, 2500000, false);
+ EXPECT_EQ(270000, start_bitrate);
+ EXPECT_EQ(30000u, enforced_observer.last_bitrate_bps_);
+
+ allocator_->OnNetworkChanged(36000, 0, 50);
+ EXPECT_EQ(6000u, enforced_observer.last_bitrate_bps_);
+ EXPECT_EQ(30000u, not_enforced_observer.last_bitrate_bps_);
+
+ allocator_->OnNetworkChanged(35000, 0, 50);
+ EXPECT_EQ(30000u, enforced_observer.last_bitrate_bps_);
+ EXPECT_EQ(0u, not_enforced_observer.last_bitrate_bps_);
+
+ allocator_->OnNetworkChanged(5000, 0, 50);
+ EXPECT_EQ(6000u, enforced_observer.last_bitrate_bps_);
+ EXPECT_EQ(0u, not_enforced_observer.last_bitrate_bps_);
+
+ allocator_->OnNetworkChanged(36000, 0, 50);
+ EXPECT_EQ(30000u, enforced_observer.last_bitrate_bps_);
+ EXPECT_EQ(0u, not_enforced_observer.last_bitrate_bps_);
+
+ allocator_->OnNetworkChanged(55000, 0, 50);
+ EXPECT_EQ(30000u, enforced_observer.last_bitrate_bps_);
+ EXPECT_EQ(0u, not_enforced_observer.last_bitrate_bps_);
+
+ allocator_->OnNetworkChanged(56000, 0, 50);
+ EXPECT_EQ(6000u, enforced_observer.last_bitrate_bps_);
+ EXPECT_EQ(50000u, not_enforced_observer.last_bitrate_bps_);
+
+ allocator_->OnNetworkChanged(56000, 0, 50);
+ EXPECT_EQ(16000u, enforced_observer.last_bitrate_bps_);
+ EXPECT_EQ(40000u, not_enforced_observer.last_bitrate_bps_);
+
+ allocator_->RemoveObserver(&enforced_observer);
+ allocator_->RemoveObserver(¬_enforced_observer);
+}
+
+TEST_F(BitrateAllocatorTest, AvoidToggleAbsolute) {
+ TestBitrateObserver observer;
+ int start_bitrate =
+ allocator_->AddObserver(&observer, 30000, 300000, false);
+ EXPECT_EQ(300000, start_bitrate);
+
+ allocator_->OnNetworkChanged(30000, 0, 50);
+ EXPECT_EQ(30000u, observer.last_bitrate_bps_);
+
+ allocator_->OnNetworkChanged(20000, 0, 50);
+ EXPECT_EQ(0u, observer.last_bitrate_bps_);
+
+ allocator_->OnNetworkChanged(30000, 0, 50);
+ EXPECT_EQ(0u, observer.last_bitrate_bps_);
+
+ allocator_->OnNetworkChanged(49000, 0, 50);
+ EXPECT_EQ(0u, observer.last_bitrate_bps_);
+
+ allocator_->OnNetworkChanged(50000, 0, 50);
+ EXPECT_EQ(50000u, observer.last_bitrate_bps_);
+
+ allocator_->OnNetworkChanged(30000, 0, 50);
+ EXPECT_EQ(30000u, observer.last_bitrate_bps_);
+
+ allocator_->RemoveObserver(&observer);
+}
+
+TEST_F(BitrateAllocatorTest, AvoidTogglePercent) {
+ TestBitrateObserver observer;
+ int start_bitrate =
+ allocator_->AddObserver(&observer, 300000, 600000, false);
+ EXPECT_EQ(300000, start_bitrate);
+
+ allocator_->OnNetworkChanged(300000, 0, 50);
+ EXPECT_EQ(300000u, observer.last_bitrate_bps_);
+
+ allocator_->OnNetworkChanged(200000, 0, 50);
+ EXPECT_EQ(0u, observer.last_bitrate_bps_);
+
+ allocator_->OnNetworkChanged(300000, 0, 50);
+ EXPECT_EQ(0u, observer.last_bitrate_bps_);
+
+ allocator_->OnNetworkChanged(329000, 0, 50);
+ EXPECT_EQ(0u, observer.last_bitrate_bps_);
+
+ allocator_->OnNetworkChanged(330000, 0, 50);
+ EXPECT_EQ(330000u, observer.last_bitrate_bps_);
+
+ allocator_->OnNetworkChanged(300000, 0, 50);
+ EXPECT_EQ(300000u, observer.last_bitrate_bps_);
+
+ allocator_->RemoveObserver(&observer);
}
} // namespace webrtc
diff --git a/webrtc/call/call.cc b/webrtc/call/call.cc
index e3c6ec7..0ac5a0f 100644
--- a/webrtc/call/call.cc
+++ b/webrtc/call/call.cc
@@ -10,6 +10,7 @@
#include <string.h>
+#include <algorithm>
#include <map>
#include <memory>
#include <vector>
@@ -700,6 +701,10 @@
pacer_bitrate_sum_kbits_ += pacer_bitrate_bps / 1000;
++num_bitrate_updates_;
}
+
+ // Make sure to not ask for more padding than the current BWE allows for.
+ pad_up_to_bitrate_bps = std::min(static_cast<uint32_t>(pad_up_to_bitrate_bps),
+ target_bitrate_bps);
congestion_controller_->SetAllocatedSendBitrate(allocated_bitrate_bps,
pad_up_to_bitrate_bps);
}
diff --git a/webrtc/call/rampup_tests.cc b/webrtc/call/rampup_tests.cc
index d6271d3..150fc770 100644
--- a/webrtc/call/rampup_tests.cc
+++ b/webrtc/call/rampup_tests.cc
@@ -340,7 +340,6 @@
for (auto it : stats.substreams) {
transmit_bitrate_bps += it.second.total_bitrate_bps;
}
-
EvolveTestState(transmit_bitrate_bps, stats.suspended);
}
@@ -464,10 +463,6 @@
RunBaseTest(&test);
}
-// Disabled on Mac due to flakiness, see
-// https://bugs.chromium.org/p/webrtc/issues/detail?id=5407
-#ifndef WEBRTC_MAC
-
static const uint32_t kStartBitrateBps = 60000;
// Disabled: https://bugs.chromium.org/p/webrtc/issues/detail?id=5576
@@ -525,8 +520,6 @@
RunBaseTest(&test);
}
-#endif
-
TEST_F(RampUpTest, AbsSendTimeSingleStream) {
RampUpTester test(1, 0, 0, RtpExtension::kAbsSendTimeUri, false, false);
RunBaseTest(&test);
diff --git a/webrtc/video/video_send_stream.cc b/webrtc/video/video_send_stream.cc
index d1811d2..1c2a642 100644
--- a/webrtc/video/video_send_stream.cc
+++ b/webrtc/video/video_send_stream.cc
@@ -560,10 +560,6 @@
encoder_settings->min_transmit_bitrate_bps,
payload_router_.MaxPayloadLength());
- // 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) {
diff --git a/webrtc/video/video_send_stream_tests.cc b/webrtc/video/video_send_stream_tests.cc
index 87abfea..265d749 100644
--- a/webrtc/video/video_send_stream_tests.cc
+++ b/webrtc/video/video_send_stream_tests.cc
@@ -905,7 +905,7 @@
send_config->suspend_below_min_bitrate = true;
int min_bitrate_bps = encoder_config->streams[0].min_bitrate_bps;
set_low_remb_bps(min_bitrate_bps - 10000);
- int threshold_window = std::max(min_bitrate_bps / 10, 10000);
+ int threshold_window = std::max(min_bitrate_bps / 10, 20000);
ASSERT_GT(encoder_config->streams[0].max_bitrate_bps,
min_bitrate_bps + threshold_window + 5000);
set_high_remb_bps(min_bitrate_bps + threshold_window + 5000);
diff --git a/webrtc/video/vie_encoder.cc b/webrtc/video/vie_encoder.cc
index 73b29f3..529b38f 100644
--- a/webrtc/video/vie_encoder.cc
+++ b/webrtc/video/vie_encoder.cc
@@ -132,8 +132,8 @@
int ViEEncoder::GetPaddingNeededBps() const {
int64_t time_of_last_frame_activity_ms;
int min_transmit_bitrate_bps;
- int bitrate_bps;
VideoCodec send_codec;
+ bool video_is_suspended;
{
rtc::CritScope lock(&data_cs_);
bool send_padding = encoder_config_.numberOfSimulcastStreams > 1 ||
@@ -142,12 +142,10 @@
return 0;
time_of_last_frame_activity_ms = time_of_last_frame_activity_ms_;
min_transmit_bitrate_bps = min_transmit_bitrate_bps_;
- bitrate_bps = last_observed_bitrate_bps_;
send_codec = encoder_config_;
+ video_is_suspended = video_suspended_;
}
- bool video_is_suspended = video_sender_.VideoSuspended();
-
// Find the max amount of padding we can allow ourselves to send at this
// point, based on which streams are currently active and what our current
// available bandwidth is.
@@ -179,10 +177,6 @@
if (pad_up_to_bitrate_bps < min_transmit_bitrate_bps)
pad_up_to_bitrate_bps = min_transmit_bitrate_bps;
- // Padding may never exceed bitrate estimate.
- if (pad_up_to_bitrate_bps > bitrate_bps)
- pad_up_to_bitrate_bps = bitrate_bps;
-
return pad_up_to_bitrate_bps;
}
@@ -320,8 +314,8 @@
<< " rtt " << round_trip_time_ms;
video_sender_.SetChannelParameters(bitrate_bps, fraction_lost,
round_trip_time_ms);
- bool video_is_suspended = video_sender_.VideoSuspended();
bool video_suspension_changed;
+ bool video_is_suspended = bitrate_bps == 0;
{
rtc::CritScope lock(&data_cs_);
last_observed_bitrate_bps_ = bitrate_bps;
@@ -329,13 +323,10 @@
video_suspended_ = video_is_suspended;
}
- if (!video_suspension_changed)
- return;
- // Video suspend-state changed, inform codec observer.
- LOG(LS_INFO) << "Video suspend state changed " << video_is_suspended;
-
- if (stats_proxy_)
+ if (stats_proxy_ && video_suspension_changed) {
+ LOG(LS_INFO) << "Video suspend state changed " << video_is_suspended;
stats_proxy_->OnSuspendChange(video_is_suspended);
+ }
}
} // namespace webrtc
diff --git a/webrtc/video/vie_encoder.h b/webrtc/video/vie_encoder.h
index 4372bd1..91497df 100644
--- a/webrtc/video/vie_encoder.h
+++ b/webrtc/video/vie_encoder.h
@@ -106,6 +106,8 @@
virtual void OnReceivedSLI(uint8_t picture_id);
virtual void OnReceivedRPSI(uint64_t picture_id);
+ // Note that this method might return a value higher than the current BWE and
+ // it's up to the caller to possibly limit the value.
int GetPaddingNeededBps() const;
void OnBitrateUpdated(uint32_t bitrate_bps,