xref: /aosp_15_r20/external/webrtc/call/bitrate_allocator.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker  *
4*d9f75844SAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker  *
10*d9f75844SAndroid Build Coastguard Worker  */
11*d9f75844SAndroid Build Coastguard Worker 
12*d9f75844SAndroid Build Coastguard Worker #include "call/bitrate_allocator.h"
13*d9f75844SAndroid Build Coastguard Worker 
14*d9f75844SAndroid Build Coastguard Worker #include <algorithm>
15*d9f75844SAndroid Build Coastguard Worker #include <cmath>
16*d9f75844SAndroid Build Coastguard Worker #include <memory>
17*d9f75844SAndroid Build Coastguard Worker #include <utility>
18*d9f75844SAndroid Build Coastguard Worker 
19*d9f75844SAndroid Build Coastguard Worker #include "absl/algorithm/container.h"
20*d9f75844SAndroid Build Coastguard Worker #include "api/units/data_rate.h"
21*d9f75844SAndroid Build Coastguard Worker #include "api/units/time_delta.h"
22*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
23*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/logging.h"
24*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/numerics/safe_minmax.h"
25*d9f75844SAndroid Build Coastguard Worker #include "system_wrappers/include/clock.h"
26*d9f75844SAndroid Build Coastguard Worker #include "system_wrappers/include/metrics.h"
27*d9f75844SAndroid Build Coastguard Worker 
28*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
29*d9f75844SAndroid Build Coastguard Worker 
30*d9f75844SAndroid Build Coastguard Worker namespace {
31*d9f75844SAndroid Build Coastguard Worker using bitrate_allocator_impl::AllocatableTrack;
32*d9f75844SAndroid Build Coastguard Worker 
33*d9f75844SAndroid Build Coastguard Worker // Allow packets to be transmitted in up to 2 times max video bitrate if the
34*d9f75844SAndroid Build Coastguard Worker // bandwidth estimate allows it.
35*d9f75844SAndroid Build Coastguard Worker const uint8_t kTransmissionMaxBitrateMultiplier = 2;
36*d9f75844SAndroid Build Coastguard Worker const int kDefaultBitrateBps = 300000;
37*d9f75844SAndroid Build Coastguard Worker 
38*d9f75844SAndroid Build Coastguard Worker // Require a bitrate increase of max(10%, 20kbps) to resume paused streams.
39*d9f75844SAndroid Build Coastguard Worker const double kToggleFactor = 0.1;
40*d9f75844SAndroid Build Coastguard Worker const uint32_t kMinToggleBitrateBps = 20000;
41*d9f75844SAndroid Build Coastguard Worker 
42*d9f75844SAndroid Build Coastguard Worker const int64_t kBweLogIntervalMs = 5000;
43*d9f75844SAndroid Build Coastguard Worker 
MediaRatio(uint32_t allocated_bitrate,uint32_t protection_bitrate)44*d9f75844SAndroid Build Coastguard Worker double MediaRatio(uint32_t allocated_bitrate, uint32_t protection_bitrate) {
45*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_GT(allocated_bitrate, 0);
46*d9f75844SAndroid Build Coastguard Worker   if (protection_bitrate == 0)
47*d9f75844SAndroid Build Coastguard Worker     return 1.0;
48*d9f75844SAndroid Build Coastguard Worker 
49*d9f75844SAndroid Build Coastguard Worker   uint32_t media_bitrate = allocated_bitrate - protection_bitrate;
50*d9f75844SAndroid Build Coastguard Worker   return media_bitrate / static_cast<double>(allocated_bitrate);
51*d9f75844SAndroid Build Coastguard Worker }
52*d9f75844SAndroid Build Coastguard Worker 
EnoughBitrateForAllObservers(const std::vector<AllocatableTrack> & allocatable_tracks,uint32_t bitrate,uint32_t sum_min_bitrates)53*d9f75844SAndroid Build Coastguard Worker bool EnoughBitrateForAllObservers(
54*d9f75844SAndroid Build Coastguard Worker     const std::vector<AllocatableTrack>& allocatable_tracks,
55*d9f75844SAndroid Build Coastguard Worker     uint32_t bitrate,
56*d9f75844SAndroid Build Coastguard Worker     uint32_t sum_min_bitrates) {
57*d9f75844SAndroid Build Coastguard Worker   if (bitrate < sum_min_bitrates)
58*d9f75844SAndroid Build Coastguard Worker     return false;
59*d9f75844SAndroid Build Coastguard Worker 
60*d9f75844SAndroid Build Coastguard Worker   uint32_t extra_bitrate_per_observer =
61*d9f75844SAndroid Build Coastguard Worker       (bitrate - sum_min_bitrates) /
62*d9f75844SAndroid Build Coastguard Worker       static_cast<uint32_t>(allocatable_tracks.size());
63*d9f75844SAndroid Build Coastguard Worker   for (const auto& observer_config : allocatable_tracks) {
64*d9f75844SAndroid Build Coastguard Worker     if (observer_config.config.min_bitrate_bps + extra_bitrate_per_observer <
65*d9f75844SAndroid Build Coastguard Worker         observer_config.MinBitrateWithHysteresis()) {
66*d9f75844SAndroid Build Coastguard Worker       return false;
67*d9f75844SAndroid Build Coastguard Worker     }
68*d9f75844SAndroid Build Coastguard Worker   }
69*d9f75844SAndroid Build Coastguard Worker   return true;
70*d9f75844SAndroid Build Coastguard Worker }
71*d9f75844SAndroid Build Coastguard Worker 
72*d9f75844SAndroid Build Coastguard Worker // Splits `bitrate` evenly to observers already in `allocation`.
73*d9f75844SAndroid Build Coastguard Worker // `include_zero_allocations` decides if zero allocations should be part of
74*d9f75844SAndroid Build Coastguard Worker // the distribution or not. The allowed max bitrate is `max_multiplier` x
75*d9f75844SAndroid Build Coastguard Worker // observer max bitrate.
DistributeBitrateEvenly(const std::vector<AllocatableTrack> & allocatable_tracks,uint32_t bitrate,bool include_zero_allocations,int max_multiplier,std::map<BitrateAllocatorObserver *,int> * allocation)76*d9f75844SAndroid Build Coastguard Worker void DistributeBitrateEvenly(
77*d9f75844SAndroid Build Coastguard Worker     const std::vector<AllocatableTrack>& allocatable_tracks,
78*d9f75844SAndroid Build Coastguard Worker     uint32_t bitrate,
79*d9f75844SAndroid Build Coastguard Worker     bool include_zero_allocations,
80*d9f75844SAndroid Build Coastguard Worker     int max_multiplier,
81*d9f75844SAndroid Build Coastguard Worker     std::map<BitrateAllocatorObserver*, int>* allocation) {
82*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_EQ(allocation->size(), allocatable_tracks.size());
83*d9f75844SAndroid Build Coastguard Worker 
84*d9f75844SAndroid Build Coastguard Worker   std::multimap<uint32_t, const AllocatableTrack*> list_max_bitrates;
85*d9f75844SAndroid Build Coastguard Worker   for (const auto& observer_config : allocatable_tracks) {
86*d9f75844SAndroid Build Coastguard Worker     if (include_zero_allocations ||
87*d9f75844SAndroid Build Coastguard Worker         allocation->at(observer_config.observer) != 0) {
88*d9f75844SAndroid Build Coastguard Worker       list_max_bitrates.insert(
89*d9f75844SAndroid Build Coastguard Worker           {observer_config.config.max_bitrate_bps, &observer_config});
90*d9f75844SAndroid Build Coastguard Worker     }
91*d9f75844SAndroid Build Coastguard Worker   }
92*d9f75844SAndroid Build Coastguard Worker   auto it = list_max_bitrates.begin();
93*d9f75844SAndroid Build Coastguard Worker   while (it != list_max_bitrates.end()) {
94*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_GT(bitrate, 0);
95*d9f75844SAndroid Build Coastguard Worker     uint32_t extra_allocation =
96*d9f75844SAndroid Build Coastguard Worker         bitrate / static_cast<uint32_t>(list_max_bitrates.size());
97*d9f75844SAndroid Build Coastguard Worker     uint32_t total_allocation =
98*d9f75844SAndroid Build Coastguard Worker         extra_allocation + allocation->at(it->second->observer);
99*d9f75844SAndroid Build Coastguard Worker     bitrate -= extra_allocation;
100*d9f75844SAndroid Build Coastguard Worker     if (total_allocation > max_multiplier * it->first) {
101*d9f75844SAndroid Build Coastguard Worker       // There is more than we can fit for this observer, carry over to the
102*d9f75844SAndroid Build Coastguard Worker       // remaining observers.
103*d9f75844SAndroid Build Coastguard Worker       bitrate += total_allocation - max_multiplier * it->first;
104*d9f75844SAndroid Build Coastguard Worker       total_allocation = max_multiplier * it->first;
105*d9f75844SAndroid Build Coastguard Worker     }
106*d9f75844SAndroid Build Coastguard Worker     // Finally, update the allocation for this observer.
107*d9f75844SAndroid Build Coastguard Worker     allocation->at(it->second->observer) = total_allocation;
108*d9f75844SAndroid Build Coastguard Worker     it = list_max_bitrates.erase(it);
109*d9f75844SAndroid Build Coastguard Worker   }
110*d9f75844SAndroid Build Coastguard Worker }
111*d9f75844SAndroid Build Coastguard Worker 
112*d9f75844SAndroid Build Coastguard Worker // From the available `bitrate`, each observer will be allocated a
113*d9f75844SAndroid Build Coastguard Worker // proportional amount based upon its bitrate priority. If that amount is
114*d9f75844SAndroid Build Coastguard Worker // more than the observer's capacity, it will be allocated its capacity, and
115*d9f75844SAndroid Build Coastguard Worker // the excess bitrate is still allocated proportionally to other observers.
116*d9f75844SAndroid Build Coastguard Worker // Allocating the proportional amount means an observer with twice the
117*d9f75844SAndroid Build Coastguard Worker // bitrate_priority of another will be allocated twice the bitrate.
DistributeBitrateRelatively(const std::vector<AllocatableTrack> & allocatable_tracks,uint32_t remaining_bitrate,const std::map<BitrateAllocatorObserver *,int> & observers_capacities,std::map<BitrateAllocatorObserver *,int> * allocation)118*d9f75844SAndroid Build Coastguard Worker void DistributeBitrateRelatively(
119*d9f75844SAndroid Build Coastguard Worker     const std::vector<AllocatableTrack>& allocatable_tracks,
120*d9f75844SAndroid Build Coastguard Worker     uint32_t remaining_bitrate,
121*d9f75844SAndroid Build Coastguard Worker     const std::map<BitrateAllocatorObserver*, int>& observers_capacities,
122*d9f75844SAndroid Build Coastguard Worker     std::map<BitrateAllocatorObserver*, int>* allocation) {
123*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_EQ(allocation->size(), allocatable_tracks.size());
124*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_EQ(observers_capacities.size(), allocatable_tracks.size());
125*d9f75844SAndroid Build Coastguard Worker 
126*d9f75844SAndroid Build Coastguard Worker   struct PriorityRateObserverConfig {
127*d9f75844SAndroid Build Coastguard Worker     BitrateAllocatorObserver* allocation_key;
128*d9f75844SAndroid Build Coastguard Worker     // The amount of bitrate bps that can be allocated to this observer.
129*d9f75844SAndroid Build Coastguard Worker     int capacity_bps;
130*d9f75844SAndroid Build Coastguard Worker     double bitrate_priority;
131*d9f75844SAndroid Build Coastguard Worker   };
132*d9f75844SAndroid Build Coastguard Worker 
133*d9f75844SAndroid Build Coastguard Worker   double bitrate_priority_sum = 0;
134*d9f75844SAndroid Build Coastguard Worker   std::vector<PriorityRateObserverConfig> priority_rate_observers;
135*d9f75844SAndroid Build Coastguard Worker   for (const auto& observer_config : allocatable_tracks) {
136*d9f75844SAndroid Build Coastguard Worker     priority_rate_observers.push_back(PriorityRateObserverConfig{
137*d9f75844SAndroid Build Coastguard Worker         observer_config.observer,
138*d9f75844SAndroid Build Coastguard Worker         observers_capacities.at(observer_config.observer),
139*d9f75844SAndroid Build Coastguard Worker         observer_config.config.bitrate_priority});
140*d9f75844SAndroid Build Coastguard Worker     bitrate_priority_sum += observer_config.config.bitrate_priority;
141*d9f75844SAndroid Build Coastguard Worker   }
142*d9f75844SAndroid Build Coastguard Worker 
143*d9f75844SAndroid Build Coastguard Worker   // Iterate in the order observers can be allocated their full capacity.
144*d9f75844SAndroid Build Coastguard Worker 
145*d9f75844SAndroid Build Coastguard Worker   // We want to sort by which observers will be allocated their full capacity
146*d9f75844SAndroid Build Coastguard Worker   // first. By dividing each observer's capacity by its bitrate priority we
147*d9f75844SAndroid Build Coastguard Worker   // are "normalizing" the capacity of an observer by the rate it will be
148*d9f75844SAndroid Build Coastguard Worker   // filled. This is because the amount allocated is based upon bitrate
149*d9f75844SAndroid Build Coastguard Worker   // priority. We allocate twice as much bitrate to an observer with twice the
150*d9f75844SAndroid Build Coastguard Worker   // bitrate priority of another.
151*d9f75844SAndroid Build Coastguard Worker   absl::c_sort(priority_rate_observers, [](const auto& a, const auto& b) {
152*d9f75844SAndroid Build Coastguard Worker     return a.capacity_bps / a.bitrate_priority <
153*d9f75844SAndroid Build Coastguard Worker            b.capacity_bps / b.bitrate_priority;
154*d9f75844SAndroid Build Coastguard Worker   });
155*d9f75844SAndroid Build Coastguard Worker   size_t i;
156*d9f75844SAndroid Build Coastguard Worker   for (i = 0; i < priority_rate_observers.size(); ++i) {
157*d9f75844SAndroid Build Coastguard Worker     const auto& priority_rate_observer = priority_rate_observers[i];
158*d9f75844SAndroid Build Coastguard Worker     // We allocate the full capacity to an observer only if its relative
159*d9f75844SAndroid Build Coastguard Worker     // portion from the remaining bitrate is sufficient to allocate its full
160*d9f75844SAndroid Build Coastguard Worker     // capacity. This means we aren't greedily allocating the full capacity, but
161*d9f75844SAndroid Build Coastguard Worker     // that it is only done when there is also enough bitrate to allocate the
162*d9f75844SAndroid Build Coastguard Worker     // proportional amounts to all other observers.
163*d9f75844SAndroid Build Coastguard Worker     double observer_share =
164*d9f75844SAndroid Build Coastguard Worker         priority_rate_observer.bitrate_priority / bitrate_priority_sum;
165*d9f75844SAndroid Build Coastguard Worker     double allocation_bps = observer_share * remaining_bitrate;
166*d9f75844SAndroid Build Coastguard Worker     bool enough_bitrate = allocation_bps >= priority_rate_observer.capacity_bps;
167*d9f75844SAndroid Build Coastguard Worker     if (!enough_bitrate)
168*d9f75844SAndroid Build Coastguard Worker       break;
169*d9f75844SAndroid Build Coastguard Worker     allocation->at(priority_rate_observer.allocation_key) +=
170*d9f75844SAndroid Build Coastguard Worker         priority_rate_observer.capacity_bps;
171*d9f75844SAndroid Build Coastguard Worker     remaining_bitrate -= priority_rate_observer.capacity_bps;
172*d9f75844SAndroid Build Coastguard Worker     bitrate_priority_sum -= priority_rate_observer.bitrate_priority;
173*d9f75844SAndroid Build Coastguard Worker   }
174*d9f75844SAndroid Build Coastguard Worker 
175*d9f75844SAndroid Build Coastguard Worker   // From the remaining bitrate, allocate the proportional amounts to the
176*d9f75844SAndroid Build Coastguard Worker   // observers that aren't allocated their max capacity.
177*d9f75844SAndroid Build Coastguard Worker   for (; i < priority_rate_observers.size(); ++i) {
178*d9f75844SAndroid Build Coastguard Worker     const auto& priority_rate_observer = priority_rate_observers[i];
179*d9f75844SAndroid Build Coastguard Worker     double fraction_allocated =
180*d9f75844SAndroid Build Coastguard Worker         priority_rate_observer.bitrate_priority / bitrate_priority_sum;
181*d9f75844SAndroid Build Coastguard Worker     allocation->at(priority_rate_observer.allocation_key) +=
182*d9f75844SAndroid Build Coastguard Worker         fraction_allocated * remaining_bitrate;
183*d9f75844SAndroid Build Coastguard Worker   }
184*d9f75844SAndroid Build Coastguard Worker }
185*d9f75844SAndroid Build Coastguard Worker 
186*d9f75844SAndroid Build Coastguard Worker // Allocates bitrate to observers when there isn't enough to allocate the
187*d9f75844SAndroid Build Coastguard Worker // minimum to all observers.
LowRateAllocation(const std::vector<AllocatableTrack> & allocatable_tracks,uint32_t bitrate)188*d9f75844SAndroid Build Coastguard Worker std::map<BitrateAllocatorObserver*, int> LowRateAllocation(
189*d9f75844SAndroid Build Coastguard Worker     const std::vector<AllocatableTrack>& allocatable_tracks,
190*d9f75844SAndroid Build Coastguard Worker     uint32_t bitrate) {
191*d9f75844SAndroid Build Coastguard Worker   std::map<BitrateAllocatorObserver*, int> allocation;
192*d9f75844SAndroid Build Coastguard Worker   // Start by allocating bitrate to observers enforcing a min bitrate, hence
193*d9f75844SAndroid Build Coastguard Worker   // remaining_bitrate might turn negative.
194*d9f75844SAndroid Build Coastguard Worker   int64_t remaining_bitrate = bitrate;
195*d9f75844SAndroid Build Coastguard Worker   for (const auto& observer_config : allocatable_tracks) {
196*d9f75844SAndroid Build Coastguard Worker     int32_t allocated_bitrate = 0;
197*d9f75844SAndroid Build Coastguard Worker     if (observer_config.config.enforce_min_bitrate)
198*d9f75844SAndroid Build Coastguard Worker       allocated_bitrate = observer_config.config.min_bitrate_bps;
199*d9f75844SAndroid Build Coastguard Worker 
200*d9f75844SAndroid Build Coastguard Worker     allocation[observer_config.observer] = allocated_bitrate;
201*d9f75844SAndroid Build Coastguard Worker     remaining_bitrate -= allocated_bitrate;
202*d9f75844SAndroid Build Coastguard Worker   }
203*d9f75844SAndroid Build Coastguard Worker 
204*d9f75844SAndroid Build Coastguard Worker   // Allocate bitrate to all previously active streams.
205*d9f75844SAndroid Build Coastguard Worker   if (remaining_bitrate > 0) {
206*d9f75844SAndroid Build Coastguard Worker     for (const auto& observer_config : allocatable_tracks) {
207*d9f75844SAndroid Build Coastguard Worker       if (observer_config.config.enforce_min_bitrate ||
208*d9f75844SAndroid Build Coastguard Worker           observer_config.LastAllocatedBitrate() == 0)
209*d9f75844SAndroid Build Coastguard Worker         continue;
210*d9f75844SAndroid Build Coastguard Worker 
211*d9f75844SAndroid Build Coastguard Worker       uint32_t required_bitrate = observer_config.MinBitrateWithHysteresis();
212*d9f75844SAndroid Build Coastguard Worker       if (remaining_bitrate >= required_bitrate) {
213*d9f75844SAndroid Build Coastguard Worker         allocation[observer_config.observer] = required_bitrate;
214*d9f75844SAndroid Build Coastguard Worker         remaining_bitrate -= required_bitrate;
215*d9f75844SAndroid Build Coastguard Worker       }
216*d9f75844SAndroid Build Coastguard Worker     }
217*d9f75844SAndroid Build Coastguard Worker   }
218*d9f75844SAndroid Build Coastguard Worker 
219*d9f75844SAndroid Build Coastguard Worker   // Allocate bitrate to previously paused streams.
220*d9f75844SAndroid Build Coastguard Worker   if (remaining_bitrate > 0) {
221*d9f75844SAndroid Build Coastguard Worker     for (const auto& observer_config : allocatable_tracks) {
222*d9f75844SAndroid Build Coastguard Worker       if (observer_config.LastAllocatedBitrate() != 0)
223*d9f75844SAndroid Build Coastguard Worker         continue;
224*d9f75844SAndroid Build Coastguard Worker 
225*d9f75844SAndroid Build Coastguard Worker       // Add a hysteresis to avoid toggling.
226*d9f75844SAndroid Build Coastguard Worker       uint32_t required_bitrate = observer_config.MinBitrateWithHysteresis();
227*d9f75844SAndroid Build Coastguard Worker       if (remaining_bitrate >= required_bitrate) {
228*d9f75844SAndroid Build Coastguard Worker         allocation[observer_config.observer] = required_bitrate;
229*d9f75844SAndroid Build Coastguard Worker         remaining_bitrate -= required_bitrate;
230*d9f75844SAndroid Build Coastguard Worker       }
231*d9f75844SAndroid Build Coastguard Worker     }
232*d9f75844SAndroid Build Coastguard Worker   }
233*d9f75844SAndroid Build Coastguard Worker 
234*d9f75844SAndroid Build Coastguard Worker   // Split a possible remainder evenly on all streams with an allocation.
235*d9f75844SAndroid Build Coastguard Worker   if (remaining_bitrate > 0)
236*d9f75844SAndroid Build Coastguard Worker     DistributeBitrateEvenly(allocatable_tracks, remaining_bitrate, false, 1,
237*d9f75844SAndroid Build Coastguard Worker                             &allocation);
238*d9f75844SAndroid Build Coastguard Worker 
239*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_EQ(allocation.size(), allocatable_tracks.size());
240*d9f75844SAndroid Build Coastguard Worker   return allocation;
241*d9f75844SAndroid Build Coastguard Worker }
242*d9f75844SAndroid Build Coastguard Worker 
243*d9f75844SAndroid Build Coastguard Worker // Allocates bitrate to all observers when the available bandwidth is enough
244*d9f75844SAndroid Build Coastguard Worker // to allocate the minimum to all observers but not enough to allocate the
245*d9f75844SAndroid Build Coastguard Worker // max bitrate of each observer.
246*d9f75844SAndroid Build Coastguard Worker 
247*d9f75844SAndroid Build Coastguard Worker // Allocates the bitrate based on the bitrate priority of each observer. This
248*d9f75844SAndroid Build Coastguard Worker // bitrate priority defines the priority for bitrate to be allocated to that
249*d9f75844SAndroid Build Coastguard Worker // observer in relation to other observers. For example with two observers, if
250*d9f75844SAndroid Build Coastguard Worker // observer 1 had a bitrate_priority = 1.0, and observer 2 has a
251*d9f75844SAndroid Build Coastguard Worker // bitrate_priority = 2.0, the expected behavior is that observer 2 will be
252*d9f75844SAndroid Build Coastguard Worker // allocated twice the bitrate as observer 1 above the each observer's
253*d9f75844SAndroid Build Coastguard Worker // min_bitrate_bps values, until one of the observers hits its max_bitrate_bps.
NormalRateAllocation(const std::vector<AllocatableTrack> & allocatable_tracks,uint32_t bitrate,uint32_t sum_min_bitrates)254*d9f75844SAndroid Build Coastguard Worker std::map<BitrateAllocatorObserver*, int> NormalRateAllocation(
255*d9f75844SAndroid Build Coastguard Worker     const std::vector<AllocatableTrack>& allocatable_tracks,
256*d9f75844SAndroid Build Coastguard Worker     uint32_t bitrate,
257*d9f75844SAndroid Build Coastguard Worker     uint32_t sum_min_bitrates) {
258*d9f75844SAndroid Build Coastguard Worker   std::map<BitrateAllocatorObserver*, int> allocation;
259*d9f75844SAndroid Build Coastguard Worker   std::map<BitrateAllocatorObserver*, int> observers_capacities;
260*d9f75844SAndroid Build Coastguard Worker   for (const auto& observer_config : allocatable_tracks) {
261*d9f75844SAndroid Build Coastguard Worker     allocation[observer_config.observer] =
262*d9f75844SAndroid Build Coastguard Worker         observer_config.config.min_bitrate_bps;
263*d9f75844SAndroid Build Coastguard Worker     observers_capacities[observer_config.observer] =
264*d9f75844SAndroid Build Coastguard Worker         observer_config.config.max_bitrate_bps -
265*d9f75844SAndroid Build Coastguard Worker         observer_config.config.min_bitrate_bps;
266*d9f75844SAndroid Build Coastguard Worker   }
267*d9f75844SAndroid Build Coastguard Worker 
268*d9f75844SAndroid Build Coastguard Worker   bitrate -= sum_min_bitrates;
269*d9f75844SAndroid Build Coastguard Worker 
270*d9f75844SAndroid Build Coastguard Worker   // TODO(srte): Implement fair sharing between prioritized streams, currently
271*d9f75844SAndroid Build Coastguard Worker   // they are treated on a first come first serve basis.
272*d9f75844SAndroid Build Coastguard Worker   for (const auto& observer_config : allocatable_tracks) {
273*d9f75844SAndroid Build Coastguard Worker     int64_t priority_margin = observer_config.config.priority_bitrate_bps -
274*d9f75844SAndroid Build Coastguard Worker                               allocation[observer_config.observer];
275*d9f75844SAndroid Build Coastguard Worker     if (priority_margin > 0 && bitrate > 0) {
276*d9f75844SAndroid Build Coastguard Worker       int64_t extra_bitrate = std::min<int64_t>(priority_margin, bitrate);
277*d9f75844SAndroid Build Coastguard Worker       allocation[observer_config.observer] +=
278*d9f75844SAndroid Build Coastguard Worker           rtc::dchecked_cast<int>(extra_bitrate);
279*d9f75844SAndroid Build Coastguard Worker       observers_capacities[observer_config.observer] -= extra_bitrate;
280*d9f75844SAndroid Build Coastguard Worker       bitrate -= extra_bitrate;
281*d9f75844SAndroid Build Coastguard Worker     }
282*d9f75844SAndroid Build Coastguard Worker   }
283*d9f75844SAndroid Build Coastguard Worker 
284*d9f75844SAndroid Build Coastguard Worker   // From the remaining bitrate, allocate a proportional amount to each observer
285*d9f75844SAndroid Build Coastguard Worker   // above the min bitrate already allocated.
286*d9f75844SAndroid Build Coastguard Worker   if (bitrate > 0)
287*d9f75844SAndroid Build Coastguard Worker     DistributeBitrateRelatively(allocatable_tracks, bitrate,
288*d9f75844SAndroid Build Coastguard Worker                                 observers_capacities, &allocation);
289*d9f75844SAndroid Build Coastguard Worker 
290*d9f75844SAndroid Build Coastguard Worker   return allocation;
291*d9f75844SAndroid Build Coastguard Worker }
292*d9f75844SAndroid Build Coastguard Worker 
293*d9f75844SAndroid Build Coastguard Worker // Allocates bitrate to observers when there is enough available bandwidth
294*d9f75844SAndroid Build Coastguard Worker // for all observers to be allocated their max bitrate.
MaxRateAllocation(const std::vector<AllocatableTrack> & allocatable_tracks,uint32_t bitrate,uint32_t sum_max_bitrates)295*d9f75844SAndroid Build Coastguard Worker std::map<BitrateAllocatorObserver*, int> MaxRateAllocation(
296*d9f75844SAndroid Build Coastguard Worker     const std::vector<AllocatableTrack>& allocatable_tracks,
297*d9f75844SAndroid Build Coastguard Worker     uint32_t bitrate,
298*d9f75844SAndroid Build Coastguard Worker     uint32_t sum_max_bitrates) {
299*d9f75844SAndroid Build Coastguard Worker   std::map<BitrateAllocatorObserver*, int> allocation;
300*d9f75844SAndroid Build Coastguard Worker 
301*d9f75844SAndroid Build Coastguard Worker   for (const auto& observer_config : allocatable_tracks) {
302*d9f75844SAndroid Build Coastguard Worker     allocation[observer_config.observer] =
303*d9f75844SAndroid Build Coastguard Worker         observer_config.config.max_bitrate_bps;
304*d9f75844SAndroid Build Coastguard Worker     bitrate -= observer_config.config.max_bitrate_bps;
305*d9f75844SAndroid Build Coastguard Worker   }
306*d9f75844SAndroid Build Coastguard Worker   DistributeBitrateEvenly(allocatable_tracks, bitrate, true,
307*d9f75844SAndroid Build Coastguard Worker                           kTransmissionMaxBitrateMultiplier, &allocation);
308*d9f75844SAndroid Build Coastguard Worker   return allocation;
309*d9f75844SAndroid Build Coastguard Worker }
310*d9f75844SAndroid Build Coastguard Worker 
311*d9f75844SAndroid Build Coastguard Worker // Allocates zero bitrate to all observers.
ZeroRateAllocation(const std::vector<AllocatableTrack> & allocatable_tracks)312*d9f75844SAndroid Build Coastguard Worker std::map<BitrateAllocatorObserver*, int> ZeroRateAllocation(
313*d9f75844SAndroid Build Coastguard Worker     const std::vector<AllocatableTrack>& allocatable_tracks) {
314*d9f75844SAndroid Build Coastguard Worker   std::map<BitrateAllocatorObserver*, int> allocation;
315*d9f75844SAndroid Build Coastguard Worker   for (const auto& observer_config : allocatable_tracks)
316*d9f75844SAndroid Build Coastguard Worker     allocation[observer_config.observer] = 0;
317*d9f75844SAndroid Build Coastguard Worker   return allocation;
318*d9f75844SAndroid Build Coastguard Worker }
319*d9f75844SAndroid Build Coastguard Worker 
AllocateBitrates(const std::vector<AllocatableTrack> & allocatable_tracks,uint32_t bitrate)320*d9f75844SAndroid Build Coastguard Worker std::map<BitrateAllocatorObserver*, int> AllocateBitrates(
321*d9f75844SAndroid Build Coastguard Worker     const std::vector<AllocatableTrack>& allocatable_tracks,
322*d9f75844SAndroid Build Coastguard Worker     uint32_t bitrate) {
323*d9f75844SAndroid Build Coastguard Worker   if (allocatable_tracks.empty())
324*d9f75844SAndroid Build Coastguard Worker     return std::map<BitrateAllocatorObserver*, int>();
325*d9f75844SAndroid Build Coastguard Worker 
326*d9f75844SAndroid Build Coastguard Worker   if (bitrate == 0)
327*d9f75844SAndroid Build Coastguard Worker     return ZeroRateAllocation(allocatable_tracks);
328*d9f75844SAndroid Build Coastguard Worker 
329*d9f75844SAndroid Build Coastguard Worker   uint32_t sum_min_bitrates = 0;
330*d9f75844SAndroid Build Coastguard Worker   uint32_t sum_max_bitrates = 0;
331*d9f75844SAndroid Build Coastguard Worker   for (const auto& observer_config : allocatable_tracks) {
332*d9f75844SAndroid Build Coastguard Worker     sum_min_bitrates += observer_config.config.min_bitrate_bps;
333*d9f75844SAndroid Build Coastguard Worker     sum_max_bitrates += observer_config.config.max_bitrate_bps;
334*d9f75844SAndroid Build Coastguard Worker   }
335*d9f75844SAndroid Build Coastguard Worker 
336*d9f75844SAndroid Build Coastguard Worker   // Not enough for all observers to get an allocation, allocate according to:
337*d9f75844SAndroid Build Coastguard Worker   // enforced min bitrate -> allocated bitrate previous round -> restart paused
338*d9f75844SAndroid Build Coastguard Worker   // streams.
339*d9f75844SAndroid Build Coastguard Worker   if (!EnoughBitrateForAllObservers(allocatable_tracks, bitrate,
340*d9f75844SAndroid Build Coastguard Worker                                     sum_min_bitrates))
341*d9f75844SAndroid Build Coastguard Worker     return LowRateAllocation(allocatable_tracks, bitrate);
342*d9f75844SAndroid Build Coastguard Worker 
343*d9f75844SAndroid Build Coastguard Worker   // All observers will get their min bitrate plus a share of the rest. This
344*d9f75844SAndroid Build Coastguard Worker   // share is allocated to each observer based on its bitrate_priority.
345*d9f75844SAndroid Build Coastguard Worker   if (bitrate <= sum_max_bitrates)
346*d9f75844SAndroid Build Coastguard Worker     return NormalRateAllocation(allocatable_tracks, bitrate, sum_min_bitrates);
347*d9f75844SAndroid Build Coastguard Worker 
348*d9f75844SAndroid Build Coastguard Worker   // All observers will get up to transmission_max_bitrate_multiplier_ x max.
349*d9f75844SAndroid Build Coastguard Worker   return MaxRateAllocation(allocatable_tracks, bitrate, sum_max_bitrates);
350*d9f75844SAndroid Build Coastguard Worker }
351*d9f75844SAndroid Build Coastguard Worker 
352*d9f75844SAndroid Build Coastguard Worker }  // namespace
353*d9f75844SAndroid Build Coastguard Worker 
BitrateAllocator(LimitObserver * limit_observer)354*d9f75844SAndroid Build Coastguard Worker BitrateAllocator::BitrateAllocator(LimitObserver* limit_observer)
355*d9f75844SAndroid Build Coastguard Worker     : limit_observer_(limit_observer),
356*d9f75844SAndroid Build Coastguard Worker       last_target_bps_(0),
357*d9f75844SAndroid Build Coastguard Worker       last_stable_target_bps_(0),
358*d9f75844SAndroid Build Coastguard Worker       last_non_zero_bitrate_bps_(kDefaultBitrateBps),
359*d9f75844SAndroid Build Coastguard Worker       last_fraction_loss_(0),
360*d9f75844SAndroid Build Coastguard Worker       last_rtt_(0),
361*d9f75844SAndroid Build Coastguard Worker       last_bwe_period_ms_(1000),
362*d9f75844SAndroid Build Coastguard Worker       num_pause_events_(0),
363*d9f75844SAndroid Build Coastguard Worker       last_bwe_log_time_(0) {
364*d9f75844SAndroid Build Coastguard Worker   sequenced_checker_.Detach();
365*d9f75844SAndroid Build Coastguard Worker }
366*d9f75844SAndroid Build Coastguard Worker 
~BitrateAllocator()367*d9f75844SAndroid Build Coastguard Worker BitrateAllocator::~BitrateAllocator() {
368*d9f75844SAndroid Build Coastguard Worker   RTC_HISTOGRAM_COUNTS_100("WebRTC.Call.NumberOfPauseEvents",
369*d9f75844SAndroid Build Coastguard Worker                            num_pause_events_);
370*d9f75844SAndroid Build Coastguard Worker }
371*d9f75844SAndroid Build Coastguard Worker 
UpdateStartRate(uint32_t start_rate_bps)372*d9f75844SAndroid Build Coastguard Worker void BitrateAllocator::UpdateStartRate(uint32_t start_rate_bps) {
373*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(&sequenced_checker_);
374*d9f75844SAndroid Build Coastguard Worker   last_non_zero_bitrate_bps_ = start_rate_bps;
375*d9f75844SAndroid Build Coastguard Worker }
376*d9f75844SAndroid Build Coastguard Worker 
OnNetworkEstimateChanged(TargetTransferRate msg)377*d9f75844SAndroid Build Coastguard Worker void BitrateAllocator::OnNetworkEstimateChanged(TargetTransferRate msg) {
378*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(&sequenced_checker_);
379*d9f75844SAndroid Build Coastguard Worker   last_target_bps_ = msg.target_rate.bps();
380*d9f75844SAndroid Build Coastguard Worker   last_stable_target_bps_ = msg.stable_target_rate.bps();
381*d9f75844SAndroid Build Coastguard Worker   last_non_zero_bitrate_bps_ =
382*d9f75844SAndroid Build Coastguard Worker       last_target_bps_ > 0 ? last_target_bps_ : last_non_zero_bitrate_bps_;
383*d9f75844SAndroid Build Coastguard Worker 
384*d9f75844SAndroid Build Coastguard Worker   int loss_ratio_255 = msg.network_estimate.loss_rate_ratio * 255;
385*d9f75844SAndroid Build Coastguard Worker   last_fraction_loss_ =
386*d9f75844SAndroid Build Coastguard Worker       rtc::dchecked_cast<uint8_t>(rtc::SafeClamp(loss_ratio_255, 0, 255));
387*d9f75844SAndroid Build Coastguard Worker   last_rtt_ = msg.network_estimate.round_trip_time.ms();
388*d9f75844SAndroid Build Coastguard Worker   last_bwe_period_ms_ = msg.network_estimate.bwe_period.ms();
389*d9f75844SAndroid Build Coastguard Worker 
390*d9f75844SAndroid Build Coastguard Worker   // Periodically log the incoming BWE.
391*d9f75844SAndroid Build Coastguard Worker   int64_t now = msg.at_time.ms();
392*d9f75844SAndroid Build Coastguard Worker   if (now > last_bwe_log_time_ + kBweLogIntervalMs) {
393*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_INFO) << "Current BWE " << last_target_bps_;
394*d9f75844SAndroid Build Coastguard Worker     last_bwe_log_time_ = now;
395*d9f75844SAndroid Build Coastguard Worker   }
396*d9f75844SAndroid Build Coastguard Worker 
397*d9f75844SAndroid Build Coastguard Worker   auto allocation = AllocateBitrates(allocatable_tracks_, last_target_bps_);
398*d9f75844SAndroid Build Coastguard Worker   auto stable_bitrate_allocation =
399*d9f75844SAndroid Build Coastguard Worker       AllocateBitrates(allocatable_tracks_, last_stable_target_bps_);
400*d9f75844SAndroid Build Coastguard Worker 
401*d9f75844SAndroid Build Coastguard Worker   for (auto& config : allocatable_tracks_) {
402*d9f75844SAndroid Build Coastguard Worker     uint32_t allocated_bitrate = allocation[config.observer];
403*d9f75844SAndroid Build Coastguard Worker     uint32_t allocated_stable_target_rate =
404*d9f75844SAndroid Build Coastguard Worker         stable_bitrate_allocation[config.observer];
405*d9f75844SAndroid Build Coastguard Worker     BitrateAllocationUpdate update;
406*d9f75844SAndroid Build Coastguard Worker     update.target_bitrate = DataRate::BitsPerSec(allocated_bitrate);
407*d9f75844SAndroid Build Coastguard Worker     update.stable_target_bitrate =
408*d9f75844SAndroid Build Coastguard Worker         DataRate::BitsPerSec(allocated_stable_target_rate);
409*d9f75844SAndroid Build Coastguard Worker     update.packet_loss_ratio = last_fraction_loss_ / 256.0;
410*d9f75844SAndroid Build Coastguard Worker     update.round_trip_time = TimeDelta::Millis(last_rtt_);
411*d9f75844SAndroid Build Coastguard Worker     update.bwe_period = TimeDelta::Millis(last_bwe_period_ms_);
412*d9f75844SAndroid Build Coastguard Worker     update.cwnd_reduce_ratio = msg.cwnd_reduce_ratio;
413*d9f75844SAndroid Build Coastguard Worker     uint32_t protection_bitrate = config.observer->OnBitrateUpdated(update);
414*d9f75844SAndroid Build Coastguard Worker 
415*d9f75844SAndroid Build Coastguard Worker     if (allocated_bitrate == 0 && config.allocated_bitrate_bps > 0) {
416*d9f75844SAndroid Build Coastguard Worker       if (last_target_bps_ > 0)
417*d9f75844SAndroid Build Coastguard Worker         ++num_pause_events_;
418*d9f75844SAndroid Build Coastguard Worker       // The protection bitrate is an estimate based on the ratio between media
419*d9f75844SAndroid Build Coastguard Worker       // and protection used before this observer was muted.
420*d9f75844SAndroid Build Coastguard Worker       uint32_t predicted_protection_bps =
421*d9f75844SAndroid Build Coastguard Worker           (1.0 - config.media_ratio) * config.config.min_bitrate_bps;
422*d9f75844SAndroid Build Coastguard Worker       RTC_LOG(LS_INFO) << "Pausing observer " << config.observer
423*d9f75844SAndroid Build Coastguard Worker                        << " with configured min bitrate "
424*d9f75844SAndroid Build Coastguard Worker                        << config.config.min_bitrate_bps
425*d9f75844SAndroid Build Coastguard Worker                        << " and current estimate of " << last_target_bps_
426*d9f75844SAndroid Build Coastguard Worker                        << " and protection bitrate "
427*d9f75844SAndroid Build Coastguard Worker                        << predicted_protection_bps;
428*d9f75844SAndroid Build Coastguard Worker     } else if (allocated_bitrate > 0 && config.allocated_bitrate_bps == 0) {
429*d9f75844SAndroid Build Coastguard Worker       if (last_target_bps_ > 0)
430*d9f75844SAndroid Build Coastguard Worker         ++num_pause_events_;
431*d9f75844SAndroid Build Coastguard Worker       RTC_LOG(LS_INFO) << "Resuming observer " << config.observer
432*d9f75844SAndroid Build Coastguard Worker                        << ", configured min bitrate "
433*d9f75844SAndroid Build Coastguard Worker                        << config.config.min_bitrate_bps
434*d9f75844SAndroid Build Coastguard Worker                        << ", current allocation " << allocated_bitrate
435*d9f75844SAndroid Build Coastguard Worker                        << " and protection bitrate " << protection_bitrate;
436*d9f75844SAndroid Build Coastguard Worker     }
437*d9f75844SAndroid Build Coastguard Worker 
438*d9f75844SAndroid Build Coastguard Worker     // Only update the media ratio if the observer got an allocation.
439*d9f75844SAndroid Build Coastguard Worker     if (allocated_bitrate > 0)
440*d9f75844SAndroid Build Coastguard Worker       config.media_ratio = MediaRatio(allocated_bitrate, protection_bitrate);
441*d9f75844SAndroid Build Coastguard Worker     config.allocated_bitrate_bps = allocated_bitrate;
442*d9f75844SAndroid Build Coastguard Worker   }
443*d9f75844SAndroid Build Coastguard Worker   UpdateAllocationLimits();
444*d9f75844SAndroid Build Coastguard Worker }
445*d9f75844SAndroid Build Coastguard Worker 
AddObserver(BitrateAllocatorObserver * observer,MediaStreamAllocationConfig config)446*d9f75844SAndroid Build Coastguard Worker void BitrateAllocator::AddObserver(BitrateAllocatorObserver* observer,
447*d9f75844SAndroid Build Coastguard Worker                                    MediaStreamAllocationConfig config) {
448*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(&sequenced_checker_);
449*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_GT(config.bitrate_priority, 0);
450*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(std::isnormal(config.bitrate_priority));
451*d9f75844SAndroid Build Coastguard Worker   auto it = absl::c_find_if(
452*d9f75844SAndroid Build Coastguard Worker       allocatable_tracks_,
453*d9f75844SAndroid Build Coastguard Worker       [observer](const auto& config) { return config.observer == observer; });
454*d9f75844SAndroid Build Coastguard Worker   // Update settings if the observer already exists, create a new one otherwise.
455*d9f75844SAndroid Build Coastguard Worker   if (it != allocatable_tracks_.end()) {
456*d9f75844SAndroid Build Coastguard Worker     it->config = config;
457*d9f75844SAndroid Build Coastguard Worker   } else {
458*d9f75844SAndroid Build Coastguard Worker     allocatable_tracks_.push_back(AllocatableTrack(observer, config));
459*d9f75844SAndroid Build Coastguard Worker   }
460*d9f75844SAndroid Build Coastguard Worker 
461*d9f75844SAndroid Build Coastguard Worker   if (last_target_bps_ > 0) {
462*d9f75844SAndroid Build Coastguard Worker     // Calculate a new allocation and update all observers.
463*d9f75844SAndroid Build Coastguard Worker 
464*d9f75844SAndroid Build Coastguard Worker     auto allocation = AllocateBitrates(allocatable_tracks_, last_target_bps_);
465*d9f75844SAndroid Build Coastguard Worker     auto stable_bitrate_allocation =
466*d9f75844SAndroid Build Coastguard Worker         AllocateBitrates(allocatable_tracks_, last_stable_target_bps_);
467*d9f75844SAndroid Build Coastguard Worker     for (auto& config : allocatable_tracks_) {
468*d9f75844SAndroid Build Coastguard Worker       uint32_t allocated_bitrate = allocation[config.observer];
469*d9f75844SAndroid Build Coastguard Worker       uint32_t allocated_stable_bitrate =
470*d9f75844SAndroid Build Coastguard Worker           stable_bitrate_allocation[config.observer];
471*d9f75844SAndroid Build Coastguard Worker       BitrateAllocationUpdate update;
472*d9f75844SAndroid Build Coastguard Worker       update.target_bitrate = DataRate::BitsPerSec(allocated_bitrate);
473*d9f75844SAndroid Build Coastguard Worker       update.stable_target_bitrate =
474*d9f75844SAndroid Build Coastguard Worker           DataRate::BitsPerSec(allocated_stable_bitrate);
475*d9f75844SAndroid Build Coastguard Worker       update.packet_loss_ratio = last_fraction_loss_ / 256.0;
476*d9f75844SAndroid Build Coastguard Worker       update.round_trip_time = TimeDelta::Millis(last_rtt_);
477*d9f75844SAndroid Build Coastguard Worker       update.bwe_period = TimeDelta::Millis(last_bwe_period_ms_);
478*d9f75844SAndroid Build Coastguard Worker       uint32_t protection_bitrate = config.observer->OnBitrateUpdated(update);
479*d9f75844SAndroid Build Coastguard Worker       config.allocated_bitrate_bps = allocated_bitrate;
480*d9f75844SAndroid Build Coastguard Worker       if (allocated_bitrate > 0)
481*d9f75844SAndroid Build Coastguard Worker         config.media_ratio = MediaRatio(allocated_bitrate, protection_bitrate);
482*d9f75844SAndroid Build Coastguard Worker     }
483*d9f75844SAndroid Build Coastguard Worker   } else {
484*d9f75844SAndroid Build Coastguard Worker     // Currently, an encoder is not allowed to produce frames.
485*d9f75844SAndroid Build Coastguard Worker     // But we still have to return the initial config bitrate + let the
486*d9f75844SAndroid Build Coastguard Worker     // observer know that it can not produce frames.
487*d9f75844SAndroid Build Coastguard Worker 
488*d9f75844SAndroid Build Coastguard Worker     BitrateAllocationUpdate update;
489*d9f75844SAndroid Build Coastguard Worker     update.target_bitrate = DataRate::Zero();
490*d9f75844SAndroid Build Coastguard Worker     update.stable_target_bitrate = DataRate::Zero();
491*d9f75844SAndroid Build Coastguard Worker     update.packet_loss_ratio = last_fraction_loss_ / 256.0;
492*d9f75844SAndroid Build Coastguard Worker     update.round_trip_time = TimeDelta::Millis(last_rtt_);
493*d9f75844SAndroid Build Coastguard Worker     update.bwe_period = TimeDelta::Millis(last_bwe_period_ms_);
494*d9f75844SAndroid Build Coastguard Worker     observer->OnBitrateUpdated(update);
495*d9f75844SAndroid Build Coastguard Worker   }
496*d9f75844SAndroid Build Coastguard Worker   UpdateAllocationLimits();
497*d9f75844SAndroid Build Coastguard Worker }
498*d9f75844SAndroid Build Coastguard Worker 
UpdateAllocationLimits()499*d9f75844SAndroid Build Coastguard Worker void BitrateAllocator::UpdateAllocationLimits() {
500*d9f75844SAndroid Build Coastguard Worker   BitrateAllocationLimits limits;
501*d9f75844SAndroid Build Coastguard Worker   for (const auto& config : allocatable_tracks_) {
502*d9f75844SAndroid Build Coastguard Worker     uint32_t stream_padding = config.config.pad_up_bitrate_bps;
503*d9f75844SAndroid Build Coastguard Worker     if (config.config.enforce_min_bitrate) {
504*d9f75844SAndroid Build Coastguard Worker       limits.min_allocatable_rate +=
505*d9f75844SAndroid Build Coastguard Worker           DataRate::BitsPerSec(config.config.min_bitrate_bps);
506*d9f75844SAndroid Build Coastguard Worker     } else if (config.allocated_bitrate_bps == 0) {
507*d9f75844SAndroid Build Coastguard Worker       stream_padding =
508*d9f75844SAndroid Build Coastguard Worker           std::max(config.MinBitrateWithHysteresis(), stream_padding);
509*d9f75844SAndroid Build Coastguard Worker     }
510*d9f75844SAndroid Build Coastguard Worker     limits.max_padding_rate += DataRate::BitsPerSec(stream_padding);
511*d9f75844SAndroid Build Coastguard Worker     limits.max_allocatable_rate +=
512*d9f75844SAndroid Build Coastguard Worker         DataRate::BitsPerSec(config.config.max_bitrate_bps);
513*d9f75844SAndroid Build Coastguard Worker   }
514*d9f75844SAndroid Build Coastguard Worker 
515*d9f75844SAndroid Build Coastguard Worker   if (limits.min_allocatable_rate == current_limits_.min_allocatable_rate &&
516*d9f75844SAndroid Build Coastguard Worker       limits.max_allocatable_rate == current_limits_.max_allocatable_rate &&
517*d9f75844SAndroid Build Coastguard Worker       limits.max_padding_rate == current_limits_.max_padding_rate) {
518*d9f75844SAndroid Build Coastguard Worker     return;
519*d9f75844SAndroid Build Coastguard Worker   }
520*d9f75844SAndroid Build Coastguard Worker   current_limits_ = limits;
521*d9f75844SAndroid Build Coastguard Worker 
522*d9f75844SAndroid Build Coastguard Worker   RTC_LOG(LS_INFO) << "UpdateAllocationLimits : total_requested_min_bitrate: "
523*d9f75844SAndroid Build Coastguard Worker                    << ToString(limits.min_allocatable_rate)
524*d9f75844SAndroid Build Coastguard Worker                    << ", total_requested_padding_bitrate: "
525*d9f75844SAndroid Build Coastguard Worker                    << ToString(limits.max_padding_rate)
526*d9f75844SAndroid Build Coastguard Worker                    << ", total_requested_max_bitrate: "
527*d9f75844SAndroid Build Coastguard Worker                    << ToString(limits.max_allocatable_rate);
528*d9f75844SAndroid Build Coastguard Worker 
529*d9f75844SAndroid Build Coastguard Worker   limit_observer_->OnAllocationLimitsChanged(limits);
530*d9f75844SAndroid Build Coastguard Worker }
531*d9f75844SAndroid Build Coastguard Worker 
RemoveObserver(BitrateAllocatorObserver * observer)532*d9f75844SAndroid Build Coastguard Worker void BitrateAllocator::RemoveObserver(BitrateAllocatorObserver* observer) {
533*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(&sequenced_checker_);
534*d9f75844SAndroid Build Coastguard Worker   for (auto it = allocatable_tracks_.begin(); it != allocatable_tracks_.end();
535*d9f75844SAndroid Build Coastguard Worker        ++it) {
536*d9f75844SAndroid Build Coastguard Worker     if (it->observer == observer) {
537*d9f75844SAndroid Build Coastguard Worker       allocatable_tracks_.erase(it);
538*d9f75844SAndroid Build Coastguard Worker       break;
539*d9f75844SAndroid Build Coastguard Worker     }
540*d9f75844SAndroid Build Coastguard Worker   }
541*d9f75844SAndroid Build Coastguard Worker 
542*d9f75844SAndroid Build Coastguard Worker   UpdateAllocationLimits();
543*d9f75844SAndroid Build Coastguard Worker }
544*d9f75844SAndroid Build Coastguard Worker 
GetStartBitrate(BitrateAllocatorObserver * observer) const545*d9f75844SAndroid Build Coastguard Worker int BitrateAllocator::GetStartBitrate(
546*d9f75844SAndroid Build Coastguard Worker     BitrateAllocatorObserver* observer) const {
547*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(&sequenced_checker_);
548*d9f75844SAndroid Build Coastguard Worker   auto it = absl::c_find_if(
549*d9f75844SAndroid Build Coastguard Worker       allocatable_tracks_,
550*d9f75844SAndroid Build Coastguard Worker       [observer](const auto& config) { return config.observer == observer; });
551*d9f75844SAndroid Build Coastguard Worker   if (it == allocatable_tracks_.end()) {
552*d9f75844SAndroid Build Coastguard Worker     // This observer hasn't been added yet, just give it its fair share.
553*d9f75844SAndroid Build Coastguard Worker     return last_non_zero_bitrate_bps_ /
554*d9f75844SAndroid Build Coastguard Worker            static_cast<int>((allocatable_tracks_.size() + 1));
555*d9f75844SAndroid Build Coastguard Worker   } else if (it->allocated_bitrate_bps == -1) {
556*d9f75844SAndroid Build Coastguard Worker     // This observer hasn't received an allocation yet, so do the same.
557*d9f75844SAndroid Build Coastguard Worker     return last_non_zero_bitrate_bps_ /
558*d9f75844SAndroid Build Coastguard Worker            static_cast<int>(allocatable_tracks_.size());
559*d9f75844SAndroid Build Coastguard Worker   } else {
560*d9f75844SAndroid Build Coastguard Worker     // This observer already has an allocation.
561*d9f75844SAndroid Build Coastguard Worker     return it->allocated_bitrate_bps;
562*d9f75844SAndroid Build Coastguard Worker   }
563*d9f75844SAndroid Build Coastguard Worker }
564*d9f75844SAndroid Build Coastguard Worker 
LastAllocatedBitrate() const565*d9f75844SAndroid Build Coastguard Worker uint32_t bitrate_allocator_impl::AllocatableTrack::LastAllocatedBitrate()
566*d9f75844SAndroid Build Coastguard Worker     const {
567*d9f75844SAndroid Build Coastguard Worker   // Return the configured minimum bitrate for newly added observers, to avoid
568*d9f75844SAndroid Build Coastguard Worker   // requiring an extra high bitrate for the observer to get an allocated
569*d9f75844SAndroid Build Coastguard Worker   // bitrate.
570*d9f75844SAndroid Build Coastguard Worker   return allocated_bitrate_bps == -1 ? config.min_bitrate_bps
571*d9f75844SAndroid Build Coastguard Worker                                      : allocated_bitrate_bps;
572*d9f75844SAndroid Build Coastguard Worker }
573*d9f75844SAndroid Build Coastguard Worker 
MinBitrateWithHysteresis() const574*d9f75844SAndroid Build Coastguard Worker uint32_t bitrate_allocator_impl::AllocatableTrack::MinBitrateWithHysteresis()
575*d9f75844SAndroid Build Coastguard Worker     const {
576*d9f75844SAndroid Build Coastguard Worker   uint32_t min_bitrate = config.min_bitrate_bps;
577*d9f75844SAndroid Build Coastguard Worker   if (LastAllocatedBitrate() == 0) {
578*d9f75844SAndroid Build Coastguard Worker     min_bitrate += std::max(static_cast<uint32_t>(kToggleFactor * min_bitrate),
579*d9f75844SAndroid Build Coastguard Worker                             kMinToggleBitrateBps);
580*d9f75844SAndroid Build Coastguard Worker   }
581*d9f75844SAndroid Build Coastguard Worker   // Account for protection bitrate used by this observer in the previous
582*d9f75844SAndroid Build Coastguard Worker   // allocation.
583*d9f75844SAndroid Build Coastguard Worker   // Note: the ratio will only be updated when the stream is active, meaning a
584*d9f75844SAndroid Build Coastguard Worker   // paused stream won't get any ratio updates. This might lead to waiting a bit
585*d9f75844SAndroid Build Coastguard Worker   // longer than necessary if the network condition improves, but this is to
586*d9f75844SAndroid Build Coastguard Worker   // avoid too much toggling.
587*d9f75844SAndroid Build Coastguard Worker   if (media_ratio > 0.0 && media_ratio < 1.0)
588*d9f75844SAndroid Build Coastguard Worker     min_bitrate += min_bitrate * (1.0 - media_ratio);
589*d9f75844SAndroid Build Coastguard Worker 
590*d9f75844SAndroid Build Coastguard Worker   return min_bitrate;
591*d9f75844SAndroid Build Coastguard Worker }
592*d9f75844SAndroid Build Coastguard Worker 
593*d9f75844SAndroid Build Coastguard Worker }  // namespace webrtc
594