Chromium Code Reviews| Index: webrtc/call/bitrate_allocator.cc |
| diff --git a/webrtc/call/bitrate_allocator.cc b/webrtc/call/bitrate_allocator.cc |
| index e82123a8b09c9069342aa4aaa62e0793d3da5190..cc29f7ed76817cdc16f842d9767731b84a92e299 100644 |
| --- a/webrtc/call/bitrate_allocator.cc |
| +++ b/webrtc/call/bitrate_allocator.cc |
| @@ -15,7 +15,10 @@ |
| #include <utility> |
| #include "webrtc/base/checks.h" |
| +#include "webrtc/base/logging.h" |
| #include "webrtc/modules/bitrate_controller/include/bitrate_controller.h" |
| +#include "webrtc/system_wrappers/include/clock.h" |
| +#include "webrtc/system_wrappers/include/metrics.h" |
| namespace webrtc { |
| @@ -28,13 +31,23 @@ const int kDefaultBitrateBps = 300000; |
| const double kToggleFactor = 0.1; |
| const uint32_t kMinToggleBitrateBps = 20000; |
| +const int64_t kBweLogIntervalMs = 5000; |
| + |
| BitrateAllocator::BitrateAllocator(LimitObserver* limit_observer) |
| : limit_observer_(limit_observer), |
| bitrate_observer_configs_(), |
| last_bitrate_bps_(kDefaultBitrateBps), |
| last_non_zero_bitrate_bps_(kDefaultBitrateBps), |
| last_fraction_loss_(0), |
| - last_rtt_(0) {} |
| + last_rtt_(0), |
| + num_pause_events_(0), |
| + clock_(Clock::GetRealTimeClock()), |
| + last_bwe_log_time_(0) {} |
| + |
| +BitrateAllocator::~BitrateAllocator() { |
| + RTC_LOGGED_HISTOGRAM_COUNTS_100("WebRTC.Call.NumberOfPauseEvents", |
| + num_pause_events_); |
|
stefan-webrtc
2016/06/30 16:17:38
Good to have! Remember to add it to the uma config
mflodman
2016/07/01 09:40:15
Thanks for the reminder, I'll make sure this happe
|
| +} |
| void BitrateAllocator::OnNetworkChanged(uint32_t target_bitrate_bps, |
| uint8_t fraction_loss, |
| @@ -46,11 +59,45 @@ void BitrateAllocator::OnNetworkChanged(uint32_t target_bitrate_bps, |
| last_fraction_loss_ = fraction_loss; |
| last_rtt_ = rtt; |
| + // Periodically log the incoming BWE. |
| + int64_t now = clock_->TimeInMilliseconds(); |
| + if (now > last_bwe_log_time_ + kBweLogIntervalMs) { |
| + LOG(LS_INFO) << "Current BWE " << target_bitrate_bps; |
| + last_bwe_log_time_ = now; |
| + } |
| + |
| ObserverAllocation allocation = AllocateBitrates(target_bitrate_bps); |
| - for (const auto& kv : allocation) { |
| - kv.first->OnBitrateUpdated(kv.second, last_fraction_loss_, last_rtt_); |
| + |
| + for (auto& config : bitrate_observer_configs_) { |
| + uint32_t allocated_bitrate = allocation[config.observer]; |
| + uint32_t protection_bitrate = config.observer->OnBitrateUpdated( |
| + allocated_bitrate, last_fraction_loss_, last_rtt_); |
| + |
| + if (allocated_bitrate == 0 && config.allocated_bitrate_bps > 0) { |
| + if (target_bitrate_bps > 0) |
| + ++num_pause_events_; |
| + uint32_t predicted_protection = |
|
stefan-webrtc
2016/06/30 16:17:38
_bps
Add a comment describing that this assumes t
mflodman
2016/07/01 09:40:15
Done.
|
| + (1.0 - config.media_ratio) * config.min_bitrate_bps; |
| + LOG(LS_INFO) << "Pausing observer " << config.observer |
| + << " with configured min bitrate " << config.min_bitrate_bps |
| + << " and current estimate of " << target_bitrate_bps |
|
stefan-webrtc
2016/06/30 16:17:38
Should you log the allocation here too?
mflodman
2016/07/01 09:40:15
Good point, added.
stefan-webrtc
2016/07/01 10:42:49
Can't see that it was added?
mflodman
2016/07/01 10:52:28
Sorry, bad reply from me. The allocation will be 0
|
| + << " and protection bitrate " << predicted_protection; |
| + } else if (allocated_bitrate > 0 && config.allocated_bitrate_bps == 0) { |
| + if (target_bitrate_bps > 0) |
| + ++num_pause_events_; |
| + LOG(LS_INFO) << "Resuming observer " << config.observer |
| + << " with configured min bitrate " << config.min_bitrate_bps |
| + << " and current allocation " << allocated_bitrate |
| + << " and protection bitrate " << protection_bitrate; |
| + } |
| + |
| + // Only update the media ratio if the observer got an allocation. |
| + if (allocated_bitrate > 0) { |
| + config.media_ratio = (allocated_bitrate - protection_bitrate) / |
|
stefan-webrtc
2016/06/30 16:17:38
Use a helper variable media_bitrate = allocated_bi
mflodman
2016/07/01 09:40:15
Done.
|
| + static_cast<double>(allocated_bitrate); |
| + } |
| + config.allocated_bitrate_bps = allocated_bitrate; |
| } |
| - last_allocation_ = allocation; |
| } |
| void BitrateAllocator::AddObserver(BitrateAllocatorObserver* observer, |
| @@ -77,8 +124,12 @@ void BitrateAllocator::AddObserver(BitrateAllocatorObserver* observer, |
| 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_); |
| + for (auto& config : bitrate_observer_configs_) { |
| + uint32_t allocated_bitrate = allocation[config.observer]; |
| + config.observer->OnBitrateUpdated( |
| + allocated_bitrate, last_fraction_loss_, last_rtt_); |
| + config.allocated_bitrate_bps = allocated_bitrate; |
|
stefan-webrtc
2016/06/30 16:17:38
Is there no need to update the media ratio here? I
mflodman
2016/07/01 09:40:15
That is a good question and I assumed it would be
stefan-webrtc
2016/07/01 10:42:49
Thanks. Better to do it and avoid others asking th
|
| + } |
| } else { |
| // Currently, an encoder is not allowed to produce frames. |
| // But we still have to return the initial config bitrate + let the |
| @@ -87,8 +138,6 @@ void BitrateAllocator::AddObserver(BitrateAllocatorObserver* observer, |
| observer->OnBitrateUpdated(0, last_fraction_loss_, last_rtt_); |
| } |
| UpdateAllocationLimits(); |
| - |
| - last_allocation_ = allocation; |
| } |
| void BitrateAllocator::UpdateAllocationLimits() { |
| @@ -122,17 +171,22 @@ void BitrateAllocator::RemoveObserver(BitrateAllocatorObserver* observer) { |
| int BitrateAllocator::GetStartBitrate(BitrateAllocatorObserver* observer) { |
| rtc::CritScope lock(&crit_sect_); |
| - const auto& it = last_allocation_.find(observer); |
| - if (it != last_allocation_.end()) |
| - return it->second; |
| - |
| - // This is a new observer that has not yet been started. Assume that if it is |
| - // added, all observers would split the available bitrate evenly. |
| - return last_non_zero_bitrate_bps_ / |
| - static_cast<int>((bitrate_observer_configs_.size() + 1)); |
| + const auto& it = FindObserverConfig(observer); |
| + if (it == bitrate_observer_configs_.end()) { |
| + // This observer hasn't been added yet, just give it its fair share. |
|
stefan-webrtc
2016/06/30 16:17:38
Not clear to me why this can happen? Is it correct
mflodman
2016/07/01 09:40:15
AS of now it is, the encoder is configured before
stefan-webrtc
2016/07/01 10:42:49
Acknowledged.
|
| + return last_non_zero_bitrate_bps_ / |
| + static_cast<int>((bitrate_observer_configs_.size() + 1)); |
| + } else if (it->allocated_bitrate_bps == -1) { |
| + // This observer hasn't received an allocation yet, so do the same. |
| + return last_non_zero_bitrate_bps_ / |
| + static_cast<int>(bitrate_observer_configs_.size()); |
| + } else { |
| + // This observer already has an allocation. |
| + return it->allocated_bitrate_bps; |
| + } |
| } |
| -BitrateAllocator::ObserverConfigList::iterator |
| +BitrateAllocator::ObserverConfigs::iterator |
| BitrateAllocator::FindObserverConfig( |
| const BitrateAllocatorObserver* observer) { |
| for (auto it = bitrate_observer_configs_.begin(); |
| @@ -202,9 +256,10 @@ BitrateAllocator::ObserverAllocation BitrateAllocator::LowRateAllocation( |
| 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; |
| + uint32_t required_bitrate = MinBitrateWithHysteresis(observer_config); |
| + if (remaining_bitrate >= required_bitrate) { |
| + allocation[observer_config.observer] = required_bitrate; |
| + remaining_bitrate -= required_bitrate; |
| } |
| } |
| } |
| @@ -263,14 +318,11 @@ BitrateAllocator::ObserverAllocation BitrateAllocator::MaxRateAllocation( |
| 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; |
| + return observer_config.allocated_bitrate_bps == -1 ? |
| + observer_config.min_bitrate_bps : observer_config.allocated_bitrate_bps; |
| } |
| uint32_t BitrateAllocator::MinBitrateWithHysteresis( |
| @@ -280,6 +332,15 @@ uint32_t BitrateAllocator::MinBitrateWithHysteresis( |
| min_bitrate += std::max(static_cast<uint32_t>(kToggleFactor * min_bitrate), |
| kMinToggleBitrateBps); |
| } |
| + // Account for protection bitrate used by this observer in the previous |
| + // allocation. |
| + // Note: the ratio will only be updated when the stream is active, meaning a |
| + // paused stream won't get any ratio updates. This might lead to waiting a bit |
| + // longer than necessary if the network condition improves, but this is to |
| + // avoid too much toggling. |
|
stefan-webrtc
2016/06/30 16:17:38
I wonder if this should be moved up to where the r
mflodman
2016/07/01 09:40:15
As of now I prefer it this way to have it separate
stefan-webrtc
2016/07/01 10:42:49
Acknowledged.
|
| + if (observer_config.media_ratio > 0.0 && observer_config.media_ratio < 1.0) |
| + min_bitrate += min_bitrate * (1.0 - observer_config.media_ratio); |
| + |
| return min_bitrate; |
| } |