aboutsummaryrefslogtreecommitdiff
path: root/webrtc/modules/bitrate_controller/bitrate_allocator.cc
diff options
context:
space:
mode:
Diffstat (limited to 'webrtc/modules/bitrate_controller/bitrate_allocator.cc')
-rw-r--r--webrtc/modules/bitrate_controller/bitrate_allocator.cc190
1 files changed, 190 insertions, 0 deletions
diff --git a/webrtc/modules/bitrate_controller/bitrate_allocator.cc b/webrtc/modules/bitrate_controller/bitrate_allocator.cc
new file mode 100644
index 0000000000..0aec528cde
--- /dev/null
+++ b/webrtc/modules/bitrate_controller/bitrate_allocator.cc
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ *
+ */
+
+#include "webrtc/modules/bitrate_controller/include/bitrate_allocator.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "webrtc/modules/bitrate_controller/include/bitrate_controller.h"
+
+namespace webrtc {
+
+// Allow packets to be transmitted in up to 2 times max video bitrate if the
+// bandwidth estimate allows it.
+const int kTransmissionMaxBitrateMultiplier = 2;
+const int kDefaultBitrateBps = 300000;
+
+BitrateAllocator::BitrateAllocator()
+ : crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
+ bitrate_observers_(),
+ enforce_min_bitrate_(true),
+ last_bitrate_bps_(kDefaultBitrateBps),
+ last_fraction_loss_(0),
+ last_rtt_(0) {
+}
+
+
+void BitrateAllocator::OnNetworkChanged(uint32_t bitrate,
+ uint8_t fraction_loss,
+ int64_t rtt) {
+ CriticalSectionScoped lock(crit_sect_.get());
+ last_bitrate_bps_ = bitrate;
+ last_fraction_loss_ = fraction_loss;
+ last_rtt_ = rtt;
+ ObserverBitrateMap allocation = AllocateBitrates();
+ for (const auto& kv : allocation)
+ kv.first->OnNetworkChanged(kv.second, last_fraction_loss_, last_rtt_);
+}
+
+BitrateAllocator::ObserverBitrateMap BitrateAllocator::AllocateBitrates() {
+ if (bitrate_observers_.empty())
+ return ObserverBitrateMap();
+
+ uint32_t sum_min_bitrates = 0;
+ for (const auto& observer : bitrate_observers_)
+ sum_min_bitrates += observer.second.min_bitrate;
+ if (last_bitrate_bps_ <= sum_min_bitrates)
+ return LowRateAllocation(last_bitrate_bps_);
+ else
+ return NormalRateAllocation(last_bitrate_bps_, sum_min_bitrates);
+}
+
+int BitrateAllocator::AddBitrateObserver(BitrateObserver* observer,
+ uint32_t min_bitrate_bps,
+ uint32_t max_bitrate_bps) {
+ CriticalSectionScoped lock(crit_sect_.get());
+
+ BitrateObserverConfList::iterator it =
+ FindObserverConfigurationPair(observer);
+
+ // Allow the max bitrate to be exceeded for FEC and retransmissions.
+ // TODO(holmer): We have to get rid of this hack as it makes it difficult to
+ // properly allocate bitrate. The allocator should instead distribute any
+ // extra bitrate after all streams have maxed out.
+ max_bitrate_bps *= kTransmissionMaxBitrateMultiplier;
+ if (it != bitrate_observers_.end()) {
+ // Update current configuration.
+ it->second.min_bitrate = min_bitrate_bps;
+ it->second.max_bitrate = max_bitrate_bps;
+ } else {
+ // Add new settings.
+ bitrate_observers_.push_back(BitrateObserverConfiguration(
+ observer, BitrateConfiguration(min_bitrate_bps, max_bitrate_bps)));
+ bitrate_observers_modified_ = true;
+ }
+
+ ObserverBitrateMap allocation = AllocateBitrates();
+ int new_observer_bitrate_bps = 0;
+ for (auto& kv : allocation) {
+ kv.first->OnNetworkChanged(kv.second, last_fraction_loss_, last_rtt_);
+ if (kv.first == observer)
+ new_observer_bitrate_bps = kv.second;
+ }
+ return new_observer_bitrate_bps;
+}
+
+void BitrateAllocator::RemoveBitrateObserver(BitrateObserver* observer) {
+ CriticalSectionScoped lock(crit_sect_.get());
+ BitrateObserverConfList::iterator it =
+ FindObserverConfigurationPair(observer);
+ if (it != bitrate_observers_.end()) {
+ bitrate_observers_.erase(it);
+ bitrate_observers_modified_ = true;
+ }
+}
+
+void BitrateAllocator::GetMinMaxBitrateSumBps(int* min_bitrate_sum_bps,
+ int* max_bitrate_sum_bps) const {
+ *min_bitrate_sum_bps = 0;
+ *max_bitrate_sum_bps = 0;
+
+ CriticalSectionScoped lock(crit_sect_.get());
+ for (const auto& observer : bitrate_observers_) {
+ *min_bitrate_sum_bps += observer.second.min_bitrate;
+ *max_bitrate_sum_bps += observer.second.max_bitrate;
+ }
+}
+
+BitrateAllocator::BitrateObserverConfList::iterator
+BitrateAllocator::FindObserverConfigurationPair(
+ const BitrateObserver* observer) {
+ for (auto it = bitrate_observers_.begin(); it != bitrate_observers_.end();
+ ++it) {
+ if (it->first == observer)
+ return it;
+ }
+ return bitrate_observers_.end();
+}
+
+void BitrateAllocator::EnforceMinBitrate(bool enforce_min_bitrate) {
+ CriticalSectionScoped lock(crit_sect_.get());
+ enforce_min_bitrate_ = enforce_min_bitrate;
+}
+
+BitrateAllocator::ObserverBitrateMap BitrateAllocator::NormalRateAllocation(
+ uint32_t bitrate,
+ uint32_t sum_min_bitrates) {
+ uint32_t number_of_observers = bitrate_observers_.size();
+ uint32_t bitrate_per_observer =
+ (bitrate - sum_min_bitrates) / number_of_observers;
+ // Use map to sort list based on max bitrate.
+ ObserverSortingMap list_max_bitrates;
+ for (const auto& observer : bitrate_observers_) {
+ list_max_bitrates.insert(std::pair<uint32_t, ObserverConfiguration>(
+ observer.second.max_bitrate,
+ ObserverConfiguration(observer.first, observer.second.min_bitrate)));
+ }
+ ObserverBitrateMap allocation;
+ ObserverSortingMap::iterator max_it = list_max_bitrates.begin();
+ while (max_it != list_max_bitrates.end()) {
+ number_of_observers--;
+ uint32_t observer_allowance =
+ max_it->second.min_bitrate + bitrate_per_observer;
+ if (max_it->first < observer_allowance) {
+ // We have more than enough for this observer.
+ // Carry the remainder forward.
+ uint32_t remainder = observer_allowance - max_it->first;
+ if (number_of_observers != 0) {
+ bitrate_per_observer += remainder / number_of_observers;
+ }
+ allocation[max_it->second.observer] = max_it->first;
+ } else {
+ allocation[max_it->second.observer] = observer_allowance;
+ }
+ list_max_bitrates.erase(max_it);
+ // Prepare next iteration.
+ max_it = list_max_bitrates.begin();
+ }
+ return allocation;
+}
+
+BitrateAllocator::ObserverBitrateMap BitrateAllocator::LowRateAllocation(
+ uint32_t bitrate) {
+ ObserverBitrateMap allocation;
+ if (enforce_min_bitrate_) {
+ // Min bitrate to all observers.
+ for (const auto& observer : bitrate_observers_)
+ allocation[observer.first] = observer.second.min_bitrate;
+ } else {
+ // Allocate up to |min_bitrate| to one observer at a time, until
+ // |bitrate| is depleted.
+ uint32_t remainder = bitrate;
+ for (const auto& observer : bitrate_observers_) {
+ uint32_t allocated_bitrate =
+ std::min(remainder, observer.second.min_bitrate);
+ allocation[observer.first] = allocated_bitrate;
+ remainder -= allocated_bitrate;
+ }
+ }
+ return allocation;
+}
+} // namespace webrtc