blob: cd904207daee5347fea45de4f57c46eea2231ed4 [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
21BitrateAllocator::BitrateAllocator()
22 : crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
23 bitrate_observers_(),
24 enforce_min_bitrate_(true) {
25}
26
27BitrateAllocator::~BitrateAllocator() {
28 for (auto& kv : bitrate_observers_)
29 delete kv.second;
30}
31
32void BitrateAllocator::OnNetworkChanged(uint32_t bitrate,
33 uint8_t fraction_loss,
34 int64_t rtt) {
35 CriticalSectionScoped lock(crit_sect_.get());
36 // Sanity check.
37 if (bitrate_observers_.empty())
38 return;
39
40 uint32_t sum_min_bitrates = 0;
41 BitrateObserverConfList::iterator it;
42 for (auto& kv : bitrate_observers_)
43 sum_min_bitrates += kv.second->min_bitrate_;
44 if (bitrate <= sum_min_bitrates)
45 return LowRateAllocation(bitrate, fraction_loss, rtt, sum_min_bitrates);
46 else
47 return NormalRateAllocation(bitrate, fraction_loss, rtt, sum_min_bitrates);
48}
49
50int BitrateAllocator::AddBitrateObserver(BitrateObserver* observer,
51 uint32_t start_bitrate,
52 uint32_t min_bitrate,
53 uint32_t max_bitrate) {
54 CriticalSectionScoped lock(crit_sect_.get());
55
56 BitrateObserverConfList::iterator it =
57 FindObserverConfigurationPair(observer);
58
59 int new_bwe_candidate_bps = -1;
60 if (it != bitrate_observers_.end()) {
61 // Update current configuration.
62 it->second->start_bitrate_ = start_bitrate;
63 it->second->min_bitrate_ = min_bitrate;
64 it->second->max_bitrate_ = max_bitrate;
65 // Set the send-side bandwidth to the max of the sum of start bitrates and
66 // the current estimate, so that if the user wants to immediately use more
67 // bandwidth, that can be enforced.
68 new_bwe_candidate_bps = 0;
69 for (auto& kv : bitrate_observers_)
70 new_bwe_candidate_bps += kv.second->start_bitrate_;
71 } else {
72 // Add new settings.
73 bitrate_observers_.push_back(BitrateObserverConfiguration(
74 observer,
75 new BitrateConfiguration(start_bitrate, min_bitrate, max_bitrate)));
76 bitrate_observers_modified_ = true;
77
78 // TODO(andresp): This is a ugly way to set start bitrate.
79 //
80 // Only change start bitrate if we have exactly one observer. By definition
81 // you can only have one start bitrate, once we have our first estimate we
82 // will adapt from there.
83 if (bitrate_observers_.size() == 1)
84 new_bwe_candidate_bps = start_bitrate;
85 }
86 return new_bwe_candidate_bps;
87}
88
89void BitrateAllocator::RemoveBitrateObserver(BitrateObserver* observer) {
90 CriticalSectionScoped lock(crit_sect_.get());
91 BitrateObserverConfList::iterator it =
92 FindObserverConfigurationPair(observer);
93 if (it != bitrate_observers_.end()) {
94 delete it->second;
95 bitrate_observers_.erase(it);
96 bitrate_observers_modified_ = true;
97 }
98}
99
100void BitrateAllocator::GetMinMaxBitrateSumBps(int* min_bitrate_sum_bps,
101 int* max_bitrate_sum_bps) const {
102 *min_bitrate_sum_bps = 0;
103 *max_bitrate_sum_bps = 0;
104
105 CriticalSectionScoped lock(crit_sect_.get());
106 BitrateObserverConfList::const_iterator it;
107 for (it = bitrate_observers_.begin(); it != bitrate_observers_.end(); ++it) {
108 *min_bitrate_sum_bps += it->second->min_bitrate_;
109 *max_bitrate_sum_bps += it->second->max_bitrate_;
110 }
111 if (*max_bitrate_sum_bps == 0) {
112 // No max configured use 1Gbit/s.
113 *max_bitrate_sum_bps = 1000000000;
114 }
115 // TODO(holmer): Enforcing a min bitrate should be per stream, allowing some
116 // streams to auto-mute while others keep sending.
117 if (!enforce_min_bitrate_) {
118 // If not enforcing min bitrate, allow the bandwidth estimation to
119 // go as low as 10 kbps.
120 *min_bitrate_sum_bps = std::min(*min_bitrate_sum_bps, 10000);
121 }
122}
123
124BitrateAllocator::BitrateObserverConfList::iterator
125BitrateAllocator::FindObserverConfigurationPair(
126 const BitrateObserver* observer) {
127 BitrateObserverConfList::iterator it = bitrate_observers_.begin();
128 for (; it != bitrate_observers_.end(); ++it) {
129 if (it->first == observer) {
130 return it;
131 }
132 }
133 return bitrate_observers_.end();
134}
135
136void BitrateAllocator::EnforceMinBitrate(bool enforce_min_bitrate) {
137 CriticalSectionScoped lock(crit_sect_.get());
138 enforce_min_bitrate_ = enforce_min_bitrate;
139}
140
141void BitrateAllocator::NormalRateAllocation(uint32_t bitrate,
142 uint8_t fraction_loss,
143 int64_t rtt,
144 uint32_t sum_min_bitrates) {
145 uint32_t number_of_observers = bitrate_observers_.size();
146 uint32_t bitrate_per_observer =
147 (bitrate - sum_min_bitrates) / number_of_observers;
148 // Use map to sort list based on max bitrate.
149 ObserverSortingMap list_max_bitrates;
150 BitrateObserverConfList::iterator it;
151 for (it = bitrate_observers_.begin(); it != bitrate_observers_.end(); ++it) {
152 list_max_bitrates.insert(std::pair<uint32_t, ObserverConfiguration*>(
153 it->second->max_bitrate_,
154 new ObserverConfiguration(it->first, it->second->min_bitrate_)));
155 }
156 ObserverSortingMap::iterator max_it = list_max_bitrates.begin();
157 while (max_it != list_max_bitrates.end()) {
158 number_of_observers--;
159 uint32_t observer_allowance =
160 max_it->second->min_bitrate_ + bitrate_per_observer;
161 if (max_it->first < observer_allowance) {
162 // We have more than enough for this observer.
163 // Carry the remainder forward.
164 uint32_t remainder = observer_allowance - max_it->first;
165 if (number_of_observers != 0) {
166 bitrate_per_observer += remainder / number_of_observers;
167 }
168 max_it->second->observer_->OnNetworkChanged(max_it->first, fraction_loss,
169 rtt);
170 } else {
171 max_it->second->observer_->OnNetworkChanged(observer_allowance,
172 fraction_loss, rtt);
173 }
174 delete max_it->second;
175 list_max_bitrates.erase(max_it);
176 // Prepare next iteration.
177 max_it = list_max_bitrates.begin();
178 }
179}
180
181void BitrateAllocator::LowRateAllocation(uint32_t bitrate,
182 uint8_t fraction_loss,
183 int64_t rtt,
184 uint32_t sum_min_bitrates) {
185 if (enforce_min_bitrate_) {
186 // Min bitrate to all observers.
187 BitrateObserverConfList::iterator it;
188 for (it = bitrate_observers_.begin(); it != bitrate_observers_.end();
189 ++it) {
190 it->first->OnNetworkChanged(it->second->min_bitrate_, fraction_loss, rtt);
191 }
192 } else {
193 // Allocate up to |min_bitrate_| to one observer at a time, until
194 // |bitrate| is depleted.
195 uint32_t remainder = bitrate;
196 BitrateObserverConfList::iterator it;
197 for (it = bitrate_observers_.begin(); it != bitrate_observers_.end();
198 ++it) {
199 uint32_t allocation = std::min(remainder, it->second->min_bitrate_);
200 it->first->OnNetworkChanged(allocation, fraction_loss, rtt);
201 remainder -= allocation;
202 }
203 }
204}
205} // namespace webrtc