blob: fc83e060a84369b0032e9d8030ee7754f63f7631 [file] [log] [blame]
stefan@webrtc.org792f1a12015-03-04 12:24:26 +00001/*
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 *
10 */
11
12#include "webrtc/modules/bitrate_controller/include/bitrate_allocator.h"
13
14#include <algorithm>
15#include <utility>
16
17#include "webrtc/modules/bitrate_controller/include/bitrate_controller.h"
18
19namespace webrtc {
20
Stefan Holmere5904162015-03-26 11:11:06 +010021// Allow packets to be transmitted in up to 2 times max video bitrate if the
22// bandwidth estimate allows it.
23const int kTransmissionMaxBitrateMultiplier = 2;
24const int kDefaultBitrateBps = 300000;
25
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000026BitrateAllocator::BitrateAllocator()
27 : crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
28 bitrate_observers_(),
Stefan Holmere5904162015-03-26 11:11:06 +010029 enforce_min_bitrate_(true),
30 last_bitrate_bps_(kDefaultBitrateBps),
31 last_fraction_loss_(0),
32 last_rtt_(0) {
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000033}
34
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000035
36void BitrateAllocator::OnNetworkChanged(uint32_t bitrate,
37 uint8_t fraction_loss,
38 int64_t rtt) {
39 CriticalSectionScoped lock(crit_sect_.get());
Stefan Holmere5904162015-03-26 11:11:06 +010040 last_bitrate_bps_ = bitrate;
41 last_fraction_loss_ = fraction_loss;
42 last_rtt_ = rtt;
43 ObserverBitrateMap allocation = AllocateBitrates();
44 for (const auto& kv : allocation)
45 kv.first->OnNetworkChanged(kv.second, last_fraction_loss_, last_rtt_);
46}
47
48BitrateAllocator::ObserverBitrateMap BitrateAllocator::AllocateBitrates() {
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000049 if (bitrate_observers_.empty())
Stefan Holmere5904162015-03-26 11:11:06 +010050 return ObserverBitrateMap();
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000051
52 uint32_t sum_min_bitrates = 0;
Stefan Holmere5904162015-03-26 11:11:06 +010053 for (const auto& observer : bitrate_observers_)
54 sum_min_bitrates += observer.second.min_bitrate_;
55 if (last_bitrate_bps_ <= sum_min_bitrates)
56 return LowRateAllocation(last_bitrate_bps_);
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000057 else
Stefan Holmere5904162015-03-26 11:11:06 +010058 return NormalRateAllocation(last_bitrate_bps_, sum_min_bitrates);
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000059}
60
61int BitrateAllocator::AddBitrateObserver(BitrateObserver* observer,
Stefan Holmere5904162015-03-26 11:11:06 +010062 uint32_t start_bitrate_bps,
63 uint32_t min_bitrate_bps,
64 uint32_t max_bitrate_bps,
65 int* new_observer_bitrate_bps) {
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000066 CriticalSectionScoped lock(crit_sect_.get());
67
68 BitrateObserverConfList::iterator it =
69 FindObserverConfigurationPair(observer);
70
Stefan Holmere5904162015-03-26 11:11:06 +010071 // Allow the max bitrate to be exceeded for FEC and retransmissions.
72 // TODO(holmer): We have to get rid of this hack as it makes it difficult to
73 // properly allocate bitrate. The allocator should instead distribute any
74 // extra bitrate after all streams have maxed out.
75 max_bitrate_bps *= kTransmissionMaxBitrateMultiplier;
76 int new_bwe_candidate_bps = 0;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000077 if (it != bitrate_observers_.end()) {
78 // Update current configuration.
Stefan Holmere5904162015-03-26 11:11:06 +010079 it->second.start_bitrate_ = start_bitrate_bps;
80 it->second.min_bitrate_ = min_bitrate_bps;
81 it->second.max_bitrate_ = max_bitrate_bps;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000082 // Set the send-side bandwidth to the max of the sum of start bitrates and
83 // the current estimate, so that if the user wants to immediately use more
84 // bandwidth, that can be enforced.
Stefan Holmere5904162015-03-26 11:11:06 +010085 for (const auto& observer : bitrate_observers_)
86 new_bwe_candidate_bps += observer.second.start_bitrate_;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000087 } else {
88 // Add new settings.
89 bitrate_observers_.push_back(BitrateObserverConfiguration(
Stefan Holmere5904162015-03-26 11:11:06 +010090 observer, BitrateConfiguration(start_bitrate_bps, min_bitrate_bps,
91 max_bitrate_bps)));
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000092 bitrate_observers_modified_ = true;
93
94 // TODO(andresp): This is a ugly way to set start bitrate.
95 //
96 // Only change start bitrate if we have exactly one observer. By definition
97 // you can only have one start bitrate, once we have our first estimate we
98 // will adapt from there.
99 if (bitrate_observers_.size() == 1)
Stefan Holmere5904162015-03-26 11:11:06 +0100100 new_bwe_candidate_bps = start_bitrate_bps;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000101 }
Stefan Holmere5904162015-03-26 11:11:06 +0100102
103 last_bitrate_bps_ = std::max<int>(new_bwe_candidate_bps, last_bitrate_bps_);
104
105 ObserverBitrateMap allocation = AllocateBitrates();
106 *new_observer_bitrate_bps = 0;
107 for (auto& kv : allocation) {
108 kv.first->OnNetworkChanged(kv.second, last_fraction_loss_, last_rtt_);
109 if (kv.first == observer)
110 *new_observer_bitrate_bps = kv.second;
111 }
112 return last_bitrate_bps_;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000113}
114
115void BitrateAllocator::RemoveBitrateObserver(BitrateObserver* observer) {
116 CriticalSectionScoped lock(crit_sect_.get());
117 BitrateObserverConfList::iterator it =
118 FindObserverConfigurationPair(observer);
119 if (it != bitrate_observers_.end()) {
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000120 bitrate_observers_.erase(it);
121 bitrate_observers_modified_ = true;
122 }
123}
124
125void BitrateAllocator::GetMinMaxBitrateSumBps(int* min_bitrate_sum_bps,
126 int* max_bitrate_sum_bps) const {
127 *min_bitrate_sum_bps = 0;
128 *max_bitrate_sum_bps = 0;
129
130 CriticalSectionScoped lock(crit_sect_.get());
Stefan Holmere5904162015-03-26 11:11:06 +0100131 for (const auto& observer : bitrate_observers_) {
132 *min_bitrate_sum_bps += observer.second.min_bitrate_;
133 *max_bitrate_sum_bps += observer.second.max_bitrate_;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000134 }
135}
136
137BitrateAllocator::BitrateObserverConfList::iterator
138BitrateAllocator::FindObserverConfigurationPair(
139 const BitrateObserver* observer) {
Stefan Holmere5904162015-03-26 11:11:06 +0100140 for (auto it = bitrate_observers_.begin(); it != bitrate_observers_.end();
141 ++it) {
142 if (it->first == observer)
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000143 return it;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000144 }
145 return bitrate_observers_.end();
146}
147
148void BitrateAllocator::EnforceMinBitrate(bool enforce_min_bitrate) {
149 CriticalSectionScoped lock(crit_sect_.get());
150 enforce_min_bitrate_ = enforce_min_bitrate;
151}
152
Stefan Holmere5904162015-03-26 11:11:06 +0100153BitrateAllocator::ObserverBitrateMap BitrateAllocator::NormalRateAllocation(
154 uint32_t bitrate,
155 uint32_t sum_min_bitrates) {
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000156 uint32_t number_of_observers = bitrate_observers_.size();
157 uint32_t bitrate_per_observer =
158 (bitrate - sum_min_bitrates) / number_of_observers;
159 // Use map to sort list based on max bitrate.
160 ObserverSortingMap list_max_bitrates;
Stefan Holmere5904162015-03-26 11:11:06 +0100161 for (const auto& observer : bitrate_observers_) {
162 list_max_bitrates.insert(std::pair<uint32_t, ObserverConfiguration>(
163 observer.second.max_bitrate_,
164 ObserverConfiguration(observer.first, observer.second.min_bitrate_)));
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000165 }
Stefan Holmere5904162015-03-26 11:11:06 +0100166 ObserverBitrateMap allocation;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000167 ObserverSortingMap::iterator max_it = list_max_bitrates.begin();
168 while (max_it != list_max_bitrates.end()) {
169 number_of_observers--;
170 uint32_t observer_allowance =
Stefan Holmere5904162015-03-26 11:11:06 +0100171 max_it->second.min_bitrate_ + bitrate_per_observer;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000172 if (max_it->first < observer_allowance) {
173 // We have more than enough for this observer.
174 // Carry the remainder forward.
175 uint32_t remainder = observer_allowance - max_it->first;
176 if (number_of_observers != 0) {
177 bitrate_per_observer += remainder / number_of_observers;
178 }
Stefan Holmere5904162015-03-26 11:11:06 +0100179 allocation[max_it->second.observer_] = max_it->first;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000180 } else {
Stefan Holmere5904162015-03-26 11:11:06 +0100181 allocation[max_it->second.observer_] = observer_allowance;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000182 }
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000183 list_max_bitrates.erase(max_it);
184 // Prepare next iteration.
185 max_it = list_max_bitrates.begin();
186 }
Stefan Holmere5904162015-03-26 11:11:06 +0100187 return allocation;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000188}
189
Stefan Holmere5904162015-03-26 11:11:06 +0100190BitrateAllocator::ObserverBitrateMap BitrateAllocator::LowRateAllocation(
191 uint32_t bitrate) {
192 ObserverBitrateMap allocation;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000193 if (enforce_min_bitrate_) {
194 // Min bitrate to all observers.
Stefan Holmere5904162015-03-26 11:11:06 +0100195 for (const auto& observer : bitrate_observers_)
196 allocation[observer.first] = observer.second.min_bitrate_;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000197 } else {
198 // Allocate up to |min_bitrate_| to one observer at a time, until
199 // |bitrate| is depleted.
200 uint32_t remainder = bitrate;
Stefan Holmere5904162015-03-26 11:11:06 +0100201 for (const auto& observer : bitrate_observers_) {
202 uint32_t allocated_bitrate =
203 std::min(remainder, observer.second.min_bitrate_);
204 allocation[observer.first] = allocated_bitrate;
205 remainder -= allocated_bitrate;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000206 }
207 }
Stefan Holmere5904162015-03-26 11:11:06 +0100208 return allocation;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000209}
210} // namespace webrtc