blob: 5b1d07ee040cb21862de253931d9daaa7928c702 [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
mflodman0e7e2592015-11-12 21:02:42 -080012#include "webrtc/call/bitrate_allocator.h"
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000013
14#include <algorithm>
15#include <utility>
16
mflodman2ebe5b12016-05-13 01:43:51 -070017#include "webrtc/base/checks.h"
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000018#include "webrtc/modules/bitrate_controller/include/bitrate_controller.h"
19
20namespace webrtc {
21
Stefan Holmere5904162015-03-26 11:11:06 +010022// Allow packets to be transmitted in up to 2 times max video bitrate if the
23// bandwidth estimate allows it.
24const int kTransmissionMaxBitrateMultiplier = 2;
25const int kDefaultBitrateBps = 300000;
26
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000027BitrateAllocator::BitrateAllocator()
mflodman2ebe5b12016-05-13 01:43:51 -070028 : bitrate_observer_configs_(),
Stefan Holmere5904162015-03-26 11:11:06 +010029 enforce_min_bitrate_(true),
30 last_bitrate_bps_(kDefaultBitrateBps),
31 last_fraction_loss_(0),
sprang2f48d942015-11-05 04:25:49 -080032 last_rtt_(0) {}
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000033
sprang2f48d942015-11-05 04:25:49 -080034uint32_t BitrateAllocator::OnNetworkChanged(uint32_t bitrate,
35 uint8_t fraction_loss,
36 int64_t rtt) {
tommi63cb4342016-01-20 02:32:54 -080037 rtc::CritScope lock(&crit_sect_);
Stefan Holmere5904162015-03-26 11:11:06 +010038 last_bitrate_bps_ = bitrate;
39 last_fraction_loss_ = fraction_loss;
40 last_rtt_ = rtt;
mflodman2ebe5b12016-05-13 01:43:51 -070041
sprang2f48d942015-11-05 04:25:49 -080042 uint32_t allocated_bitrate_bps = 0;
mflodman2ebe5b12016-05-13 01:43:51 -070043 ObserverAllocation allocation = AllocateBitrates();
sprang2f48d942015-11-05 04:25:49 -080044 for (const auto& kv : allocation) {
mflodman86aabb22016-03-11 15:44:32 +010045 kv.first->OnBitrateUpdated(kv.second, last_fraction_loss_, last_rtt_);
sprang2f48d942015-11-05 04:25:49 -080046 allocated_bitrate_bps += kv.second;
47 }
48 return allocated_bitrate_bps;
Stefan Holmere5904162015-03-26 11:11:06 +010049}
50
mflodman86aabb22016-03-11 15:44:32 +010051int BitrateAllocator::AddObserver(BitrateAllocatorObserver* observer,
52 uint32_t min_bitrate_bps,
mflodman2ebe5b12016-05-13 01:43:51 -070053 uint32_t max_bitrate_bps,
54 bool enforce_min_bitrate) {
tommi63cb4342016-01-20 02:32:54 -080055 rtc::CritScope lock(&crit_sect_);
mflodman2ebe5b12016-05-13 01:43:51 -070056 // TODO(mflodman): Enforce this per observer.
57 EnforceMinBitrate(enforce_min_bitrate);
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000058
mflodman2ebe5b12016-05-13 01:43:51 -070059 auto it = FindObserverConfig(observer);
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000060
Stefan Holmere5904162015-03-26 11:11:06 +010061 // Allow the max bitrate to be exceeded for FEC and retransmissions.
62 // TODO(holmer): We have to get rid of this hack as it makes it difficult to
63 // properly allocate bitrate. The allocator should instead distribute any
64 // extra bitrate after all streams have maxed out.
65 max_bitrate_bps *= kTransmissionMaxBitrateMultiplier;
mflodman2ebe5b12016-05-13 01:43:51 -070066 if (it != bitrate_observer_configs_.end()) {
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000067 // Update current configuration.
mflodman2ebe5b12016-05-13 01:43:51 -070068 it->min_bitrate_bps = min_bitrate_bps;
69 it->max_bitrate_bps = max_bitrate_bps;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000070 } else {
71 // Add new settings.
mflodman2ebe5b12016-05-13 01:43:51 -070072 bitrate_observer_configs_.push_back(ObserverConfig(
73 observer, min_bitrate_bps, max_bitrate_bps, enforce_min_bitrate));
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000074 }
Stefan Holmere5904162015-03-26 11:11:06 +010075
mflodman2ebe5b12016-05-13 01:43:51 -070076 ObserverAllocation allocation = AllocateBitrates();
Peter Boström8e4e8b02015-09-15 15:08:03 +020077 int new_observer_bitrate_bps = 0;
Stefan Holmere5904162015-03-26 11:11:06 +010078 for (auto& kv : allocation) {
mflodman86aabb22016-03-11 15:44:32 +010079 kv.first->OnBitrateUpdated(kv.second, last_fraction_loss_, last_rtt_);
Stefan Holmere5904162015-03-26 11:11:06 +010080 if (kv.first == observer)
Peter Boström8e4e8b02015-09-15 15:08:03 +020081 new_observer_bitrate_bps = kv.second;
Stefan Holmere5904162015-03-26 11:11:06 +010082 }
Peter Boström8e4e8b02015-09-15 15:08:03 +020083 return new_observer_bitrate_bps;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000084}
85
mflodman86aabb22016-03-11 15:44:32 +010086void BitrateAllocator::RemoveObserver(BitrateAllocatorObserver* observer) {
tommi63cb4342016-01-20 02:32:54 -080087 rtc::CritScope lock(&crit_sect_);
mflodman2ebe5b12016-05-13 01:43:51 -070088 auto it = FindObserverConfig(observer);
89 if (it != bitrate_observer_configs_.end()) {
90 bitrate_observer_configs_.erase(it);
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000091 }
92}
93
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000094void BitrateAllocator::EnforceMinBitrate(bool enforce_min_bitrate) {
stefan@webrtc.org792f1a12015-03-04 12:24:26 +000095 enforce_min_bitrate_ = enforce_min_bitrate;
96}
97
mflodman2ebe5b12016-05-13 01:43:51 -070098BitrateAllocator::ObserverConfigList::iterator
99BitrateAllocator::FindObserverConfig(
100 const BitrateAllocatorObserver* observer) {
101 for (auto it = bitrate_observer_configs_.begin();
102 it != bitrate_observer_configs_.end(); ++it) {
103 if (it->observer == observer)
104 return it;
105 }
106 return bitrate_observer_configs_.end();
107}
108
109BitrateAllocator::ObserverAllocation BitrateAllocator::AllocateBitrates() {
110 if (bitrate_observer_configs_.empty())
111 return ObserverAllocation();
112
113 if (last_bitrate_bps_ == 0)
114 return ZeroRateAllocation();
115
116 uint32_t sum_min_bitrates = 0;
117 for (const auto& observer_config : bitrate_observer_configs_)
118 sum_min_bitrates += observer_config.min_bitrate_bps;
119 if (last_bitrate_bps_ <= sum_min_bitrates)
120 return LowRateAllocation(last_bitrate_bps_);
121
122 return NormalRateAllocation(last_bitrate_bps_, sum_min_bitrates);
123}
124
125BitrateAllocator::ObserverAllocation BitrateAllocator::NormalRateAllocation(
Stefan Holmere5904162015-03-26 11:11:06 +0100126 uint32_t bitrate,
127 uint32_t sum_min_bitrates) {
mflodman2ebe5b12016-05-13 01:43:51 -0700128 uint32_t num_remaining_observers =
129 static_cast<uint32_t>(bitrate_observer_configs_.size());
130 RTC_DCHECK_GT(num_remaining_observers, 0u);
131
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000132 uint32_t bitrate_per_observer =
mflodman2ebe5b12016-05-13 01:43:51 -0700133 (bitrate - sum_min_bitrates) / num_remaining_observers;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000134 // Use map to sort list based on max bitrate.
135 ObserverSortingMap list_max_bitrates;
mflodman2ebe5b12016-05-13 01:43:51 -0700136 for (const auto& config : bitrate_observer_configs_) {
137 list_max_bitrates.insert(std::pair<uint32_t, const ObserverConfig*>(
138 config.max_bitrate_bps, &config));
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000139 }
mflodman2ebe5b12016-05-13 01:43:51 -0700140
141 ObserverAllocation allocation;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000142 ObserverSortingMap::iterator max_it = list_max_bitrates.begin();
143 while (max_it != list_max_bitrates.end()) {
mflodman2ebe5b12016-05-13 01:43:51 -0700144 num_remaining_observers--;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000145 uint32_t observer_allowance =
mflodman2ebe5b12016-05-13 01:43:51 -0700146 max_it->second->min_bitrate_bps + bitrate_per_observer;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000147 if (max_it->first < observer_allowance) {
148 // We have more than enough for this observer.
149 // Carry the remainder forward.
150 uint32_t remainder = observer_allowance - max_it->first;
mflodman2ebe5b12016-05-13 01:43:51 -0700151 if (num_remaining_observers != 0)
152 bitrate_per_observer += remainder / num_remaining_observers;
153 allocation[max_it->second->observer] = max_it->first;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000154 } else {
mflodman2ebe5b12016-05-13 01:43:51 -0700155 allocation[max_it->second->observer] = observer_allowance;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000156 }
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000157 list_max_bitrates.erase(max_it);
158 // Prepare next iteration.
159 max_it = list_max_bitrates.begin();
160 }
Stefan Holmere5904162015-03-26 11:11:06 +0100161 return allocation;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000162}
163
mflodman2ebe5b12016-05-13 01:43:51 -0700164BitrateAllocator::ObserverAllocation BitrateAllocator::ZeroRateAllocation() {
165 ObserverAllocation allocation;
perkjec81bcd2016-05-11 06:01:13 -0700166 // Zero bitrate to all observers.
mflodman2ebe5b12016-05-13 01:43:51 -0700167 for (const auto& observer_config : bitrate_observer_configs_)
168 allocation[observer_config.observer] = 0;
perkjec81bcd2016-05-11 06:01:13 -0700169 return allocation;
170}
171
mflodman2ebe5b12016-05-13 01:43:51 -0700172BitrateAllocator::ObserverAllocation BitrateAllocator::LowRateAllocation(
Stefan Holmere5904162015-03-26 11:11:06 +0100173 uint32_t bitrate) {
mflodman2ebe5b12016-05-13 01:43:51 -0700174 ObserverAllocation allocation;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000175 if (enforce_min_bitrate_) {
176 // Min bitrate to all observers.
mflodman2ebe5b12016-05-13 01:43:51 -0700177 for (const auto& observer_config : bitrate_observer_configs_)
178 allocation[observer_config.observer] = observer_config.min_bitrate_bps;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000179 } else {
mflodman2ebe5b12016-05-13 01:43:51 -0700180 // Allocate up to |min_bitrate_bps| to one observer at a time, until
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000181 // |bitrate| is depleted.
182 uint32_t remainder = bitrate;
mflodman2ebe5b12016-05-13 01:43:51 -0700183 for (const auto& observer_config : bitrate_observer_configs_) {
Stefan Holmere5904162015-03-26 11:11:06 +0100184 uint32_t allocated_bitrate =
mflodman2ebe5b12016-05-13 01:43:51 -0700185 std::min(remainder, observer_config.min_bitrate_bps);
186 allocation[observer_config.observer] = allocated_bitrate;
Stefan Holmere5904162015-03-26 11:11:06 +0100187 remainder -= allocated_bitrate;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000188 }
189 }
Stefan Holmere5904162015-03-26 11:11:06 +0100190 return allocation;
stefan@webrtc.org792f1a12015-03-04 12:24:26 +0000191}
192} // namespace webrtc