blob: da43204b0938b420898bc937810a9adaf9fd94f5 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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
pbos@webrtc.orga048d7c2013-05-29 14:27:38 +000011#include "webrtc/modules/rtp_rtcp/source/tmmbr_help.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
hta@webrtc.org54536bb2012-05-03 14:07:23 +000013#include <assert.h>
hta@webrtc.org54536bb2012-05-03 14:07:23 +000014#include <string.h>
danilchapb8b6fbb2015-12-10 05:05:27 -080015
16#include <limits>
17
danilchapf6ff9712016-02-24 09:23:37 -080018#include "webrtc/base/checks.h"
pbos@webrtc.orga048d7c2013-05-29 14:27:38 +000019#include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_config.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000020
21namespace webrtc {
niklase@google.com470e71d2011-07-07 08:21:25 +000022void
pbos@webrtc.org2f446732013-04-08 11:08:41 +000023TMMBRSet::VerifyAndAllocateSet(uint32_t minimumSize)
niklase@google.com470e71d2011-07-07 08:21:25 +000024{
danilchapa4f31bd2016-02-29 05:26:01 -080025 clear();
26 reserve(minimumSize);
hta@webrtc.org54536bb2012-05-03 14:07:23 +000027}
28
29void
pbos@webrtc.org2f446732013-04-08 11:08:41 +000030TMMBRSet::VerifyAndAllocateSetKeepingData(uint32_t minimumSize)
hta@webrtc.org54536bb2012-05-03 14:07:23 +000031{
danilchapa4f31bd2016-02-29 05:26:01 -080032 reserve(minimumSize);
hta@webrtc.org54536bb2012-05-03 14:07:23 +000033}
34
35void TMMBRSet::SetEntry(unsigned int i,
pbos@webrtc.org2f446732013-04-08 11:08:41 +000036 uint32_t tmmbrSet,
37 uint32_t packetOHSet,
38 uint32_t ssrcSet) {
danilchapa4f31bd2016-02-29 05:26:01 -080039 RTC_DCHECK_LT(i, capacity());
40 if (i >= size()) {
41 resize(i+1);
hta@webrtc.org54536bb2012-05-03 14:07:23 +000042 }
danilchapa4f31bd2016-02-29 05:26:01 -080043 (*this)[i].set_bitrate_bps(tmmbrSet * 1000);
44 (*this)[i].set_packet_overhead(packetOHSet);
45 (*this)[i].set_ssrc(ssrcSet);
hta@webrtc.org54536bb2012-05-03 14:07:23 +000046}
47
pbos@webrtc.org2f446732013-04-08 11:08:41 +000048void TMMBRSet::AddEntry(uint32_t tmmbrSet,
49 uint32_t packetOHSet,
50 uint32_t ssrcSet) {
danilchapa4f31bd2016-02-29 05:26:01 -080051 RTC_DCHECK_LT(size(), capacity());
52 SetEntry(size(), tmmbrSet, packetOHSet, ssrcSet);
hta@webrtc.org54536bb2012-05-03 14:07:23 +000053}
54
pbos@webrtc.org2f446732013-04-08 11:08:41 +000055void TMMBRSet::RemoveEntry(uint32_t sourceIdx) {
danilchapa4f31bd2016-02-29 05:26:01 -080056 RTC_DCHECK_LT(sourceIdx, size());
57 erase(begin() + sourceIdx);
hta@webrtc.org54536bb2012-05-03 14:07:23 +000058}
59
pbos@webrtc.org2f446732013-04-08 11:08:41 +000060void TMMBRSet::SwapEntries(uint32_t i, uint32_t j) {
danilchapa4f31bd2016-02-29 05:26:01 -080061 using std::swap;
62 swap((*this)[i], (*this)[j]);
hta@webrtc.org54536bb2012-05-03 14:07:23 +000063}
64
pbos@webrtc.org2f446732013-04-08 11:08:41 +000065void TMMBRSet::ClearEntry(uint32_t idx) {
hta@webrtc.org54536bb2012-05-03 14:07:23 +000066 SetEntry(idx, 0, 0, 0);
niklase@google.com470e71d2011-07-07 08:21:25 +000067}
68
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +000069TMMBRHelp::TMMBRHelp()
70 : _criticalSection(CriticalSectionWrapper::CreateCriticalSection()),
71 _candidateSet(),
72 _boundingSet(),
73 _boundingSetToSend(),
74 _ptrIntersectionBoundingSet(NULL),
75 _ptrMaxPRBoundingSet(NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +000076}
77
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +000078TMMBRHelp::~TMMBRHelp() {
79 delete [] _ptrIntersectionBoundingSet;
80 delete [] _ptrMaxPRBoundingSet;
81 _ptrIntersectionBoundingSet = 0;
82 _ptrMaxPRBoundingSet = 0;
83 delete _criticalSection;
niklase@google.com470e71d2011-07-07 08:21:25 +000084}
85
86TMMBRSet*
pbos@webrtc.org2f446732013-04-08 11:08:41 +000087TMMBRHelp::VerifyAndAllocateBoundingSet(uint32_t minimumSize)
niklase@google.com470e71d2011-07-07 08:21:25 +000088{
89 CriticalSectionScoped lock(_criticalSection);
90
danilchapa4f31bd2016-02-29 05:26:01 -080091 if(minimumSize > _boundingSet.capacity())
niklase@google.com470e71d2011-07-07 08:21:25 +000092 {
93 // make sure that our buffers are big enough
94 if(_ptrIntersectionBoundingSet)
95 {
96 delete [] _ptrIntersectionBoundingSet;
97 delete [] _ptrMaxPRBoundingSet;
98 }
99 _ptrIntersectionBoundingSet = new float[minimumSize];
100 _ptrMaxPRBoundingSet = new float[minimumSize];
101 }
102 _boundingSet.VerifyAndAllocateSet(minimumSize);
103 return &_boundingSet;
104}
105
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +0000106TMMBRSet* TMMBRHelp::BoundingSet() {
107 return &_boundingSet;
niklase@google.com470e71d2011-07-07 08:21:25 +0000108}
109
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000110int32_t
Peter Boström9d0c4322016-02-16 17:59:27 +0100111TMMBRHelp::SetTMMBRBoundingSetToSend(const TMMBRSet* boundingSetToSend)
niklase@google.com470e71d2011-07-07 08:21:25 +0000112{
113 CriticalSectionScoped lock(_criticalSection);
114
115 if (boundingSetToSend == NULL)
116 {
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000117 _boundingSetToSend.clearSet();
niklase@google.com470e71d2011-07-07 08:21:25 +0000118 return 0;
119 }
120
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000121 VerifyAndAllocateBoundingSetToSend(boundingSetToSend->lengthOfSet());
122 _boundingSetToSend.clearSet();
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000123 for (uint32_t i = 0; i < boundingSetToSend->lengthOfSet(); i++)
niklase@google.com470e71d2011-07-07 08:21:25 +0000124 {
125 // cap at our configured max bitrate
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000126 uint32_t bitrate = boundingSetToSend->Tmmbr(i);
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000127 _boundingSetToSend.SetEntry(i, bitrate,
128 boundingSetToSend->PacketOH(i),
129 boundingSetToSend->Ssrc(i));
niklase@google.com470e71d2011-07-07 08:21:25 +0000130 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000131 return 0;
132}
133
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000134int32_t
135TMMBRHelp::VerifyAndAllocateBoundingSetToSend(uint32_t minimumSize)
niklase@google.com470e71d2011-07-07 08:21:25 +0000136{
137 CriticalSectionScoped lock(_criticalSection);
138
139 _boundingSetToSend.VerifyAndAllocateSet(minimumSize);
140 return 0;
141}
142
143TMMBRSet*
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000144TMMBRHelp::VerifyAndAllocateCandidateSet(uint32_t minimumSize)
niklase@google.com470e71d2011-07-07 08:21:25 +0000145{
146 CriticalSectionScoped lock(_criticalSection);
147
148 _candidateSet.VerifyAndAllocateSet(minimumSize);
149 return &_candidateSet;
150}
151
152TMMBRSet*
153TMMBRHelp::CandidateSet()
154{
155 return &_candidateSet;
156}
157
158TMMBRSet*
159TMMBRHelp::BoundingSetToSend()
160{
161 return &_boundingSetToSend;
162}
163
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000164int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000165TMMBRHelp::FindTMMBRBoundingSet(TMMBRSet*& boundingSet)
166{
167 CriticalSectionScoped lock(_criticalSection);
168
169 // Work on local variable, will be modified
170 TMMBRSet candidateSet;
danilchapa4f31bd2016-02-29 05:26:01 -0800171 candidateSet.VerifyAndAllocateSet(_candidateSet.capacity());
niklase@google.com470e71d2011-07-07 08:21:25 +0000172
danilchapa4f31bd2016-02-29 05:26:01 -0800173 for (uint32_t i = 0; i < _candidateSet.size(); i++)
niklase@google.com470e71d2011-07-07 08:21:25 +0000174 {
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000175 if(_candidateSet.Tmmbr(i))
niklase@google.com470e71d2011-07-07 08:21:25 +0000176 {
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000177 candidateSet.AddEntry(_candidateSet.Tmmbr(i),
178 _candidateSet.PacketOH(i),
179 _candidateSet.Ssrc(i));
niklase@google.com470e71d2011-07-07 08:21:25 +0000180 }
181 else
182 {
183 // make sure this is zero if tmmbr = 0
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000184 assert(_candidateSet.PacketOH(i) == 0);
185 // Old code:
186 // _candidateSet.ptrPacketOHSet[i] = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000187 }
188 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000189
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000190 // Number of set candidates
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000191 int32_t numSetCandidates = candidateSet.lengthOfSet();
niklase@google.com470e71d2011-07-07 08:21:25 +0000192 // Find bounding set
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000193 uint32_t numBoundingSet = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000194 if (numSetCandidates > 0)
195 {
196 numBoundingSet = FindTMMBRBoundingSet(numSetCandidates, candidateSet);
danilchapa4f31bd2016-02-29 05:26:01 -0800197 if(numBoundingSet < 1 || (numBoundingSet > _candidateSet.size()))
niklase@google.com470e71d2011-07-07 08:21:25 +0000198 {
199 return -1;
200 }
201 boundingSet = &_boundingSet;
202 }
203 return numBoundingSet;
204}
205
206
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000207int32_t
208TMMBRHelp::FindTMMBRBoundingSet(int32_t numCandidates, TMMBRSet& candidateSet)
niklase@google.com470e71d2011-07-07 08:21:25 +0000209{
210 CriticalSectionScoped lock(_criticalSection);
211
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000212 uint32_t numBoundingSet = 0;
danilchapa4f31bd2016-02-29 05:26:01 -0800213 VerifyAndAllocateBoundingSet(candidateSet.capacity());
niklase@google.com470e71d2011-07-07 08:21:25 +0000214
215 if (numCandidates == 1)
216 {
danilchapa4f31bd2016-02-29 05:26:01 -0800217 for (uint32_t i = 0; i < candidateSet.size(); i++)
niklase@google.com470e71d2011-07-07 08:21:25 +0000218 {
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000219 if (candidateSet.Tmmbr(i) > 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000220 {
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000221 _boundingSet.AddEntry(candidateSet.Tmmbr(i),
222 candidateSet.PacketOH(i),
223 candidateSet.Ssrc(i));
niklase@google.com470e71d2011-07-07 08:21:25 +0000224 numBoundingSet++;
225 }
226 }
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +0000227 return (numBoundingSet == 1) ? 1 : -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000228 }
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +0000229
230 // 1. Sort by increasing packetOH
danilchapa4f31bd2016-02-29 05:26:01 -0800231 for (int i = candidateSet.size() - 1; i >= 0; i--)
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +0000232 {
233 for (int j = 1; j <= i; j++)
234 {
235 if (candidateSet.PacketOH(j-1) > candidateSet.PacketOH(j))
236 {
237 candidateSet.SwapEntries(j-1, j);
238 }
239 }
240 }
241 // 2. For tuples with same OH, keep the one w/ the lowest bitrate
danilchapa4f31bd2016-02-29 05:26:01 -0800242 for (uint32_t i = 0; i < candidateSet.size(); i++)
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +0000243 {
244 if (candidateSet.Tmmbr(i) > 0)
245 {
246 // get min bitrate for packets w/ same OH
247 uint32_t currentPacketOH = candidateSet.PacketOH(i);
248 uint32_t currentMinTMMBR = candidateSet.Tmmbr(i);
249 uint32_t currentMinIndexTMMBR = i;
danilchapa4f31bd2016-02-29 05:26:01 -0800250 for (uint32_t j = i+1; j < candidateSet.size(); j++)
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +0000251 {
252 if(candidateSet.PacketOH(j) == currentPacketOH)
253 {
254 if(candidateSet.Tmmbr(j) < currentMinTMMBR)
255 {
256 currentMinTMMBR = candidateSet.Tmmbr(j);
257 currentMinIndexTMMBR = j;
258 }
259 }
260 }
261 // keep lowest bitrate
danilchapa4f31bd2016-02-29 05:26:01 -0800262 for (uint32_t j = 0; j < candidateSet.size(); j++)
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +0000263 {
264 if(candidateSet.PacketOH(j) == currentPacketOH
265 && j != currentMinIndexTMMBR)
266 {
267 candidateSet.ClearEntry(j);
danilchapf6ff9712016-02-24 09:23:37 -0800268 numCandidates--;
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +0000269 }
270 }
271 }
272 }
273 // 3. Select and remove tuple w/ lowest tmmbr.
274 // (If more than 1, choose the one w/ highest OH).
275 uint32_t minTMMBR = 0;
276 uint32_t minIndexTMMBR = 0;
danilchapa4f31bd2016-02-29 05:26:01 -0800277 for (uint32_t i = 0; i < candidateSet.size(); i++)
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +0000278 {
279 if (candidateSet.Tmmbr(i) > 0)
280 {
281 minTMMBR = candidateSet.Tmmbr(i);
282 minIndexTMMBR = i;
283 break;
284 }
285 }
286
danilchapa4f31bd2016-02-29 05:26:01 -0800287 for (uint32_t i = 0; i < candidateSet.size(); i++)
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +0000288 {
289 if (candidateSet.Tmmbr(i) > 0 && candidateSet.Tmmbr(i) <= minTMMBR)
290 {
291 // get min bitrate
292 minTMMBR = candidateSet.Tmmbr(i);
293 minIndexTMMBR = i;
294 }
295 }
296 // first member of selected list
297 _boundingSet.SetEntry(numBoundingSet,
298 candidateSet.Tmmbr(minIndexTMMBR),
299 candidateSet.PacketOH(minIndexTMMBR),
300 candidateSet.Ssrc(minIndexTMMBR));
301
302 // set intersection value
303 _ptrIntersectionBoundingSet[numBoundingSet] = 0;
304 // calculate its maximum packet rate (where its line crosses x-axis)
danilchapf6ff9712016-02-24 09:23:37 -0800305 uint32_t packet_overhead_bits = 8 * _boundingSet.PacketOH(numBoundingSet);
306 if (packet_overhead_bits == 0) {
307 // Avoid division by zero.
308 _ptrMaxPRBoundingSet[numBoundingSet] = std::numeric_limits<float>::max();
309 } else {
310 _ptrMaxPRBoundingSet[numBoundingSet] =
311 _boundingSet.Tmmbr(numBoundingSet) * 1000 /
312 static_cast<float>(packet_overhead_bits);
313 }
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +0000314 numBoundingSet++;
315 // remove from candidate list
316 candidateSet.ClearEntry(minIndexTMMBR);
317 numCandidates--;
318
319 // 4. Discard from candidate list all tuple w/ lower OH
320 // (next tuple must be steeper)
danilchapa4f31bd2016-02-29 05:26:01 -0800321 for (uint32_t i = 0; i < candidateSet.size(); i++)
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +0000322 {
323 if(candidateSet.Tmmbr(i) > 0
324 && candidateSet.PacketOH(i) < _boundingSet.PacketOH(0))
325 {
326 candidateSet.ClearEntry(i);
327 numCandidates--;
328 }
329 }
330
331 if (numCandidates == 0)
332 {
333 // Should be true already:_boundingSet.lengthOfSet = numBoundingSet;
334 assert(_boundingSet.lengthOfSet() == numBoundingSet);
335 return numBoundingSet;
336 }
337
338 bool getNewCandidate = true;
danilchapf6ff9712016-02-24 09:23:37 -0800339 uint32_t curCandidateTMMBR = 0;
340 size_t curCandidateIndex = 0;
341 uint32_t curCandidatePacketOH = 0;
342 uint32_t curCandidateSSRC = 0;
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +0000343 do
344 {
345 if (getNewCandidate)
346 {
347 // 5. Remove first remaining tuple from candidate list
danilchapa4f31bd2016-02-29 05:26:01 -0800348 for (uint32_t i = 0; i < candidateSet.size(); i++)
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +0000349 {
350 if (candidateSet.Tmmbr(i) > 0)
351 {
352 curCandidateTMMBR = candidateSet.Tmmbr(i);
353 curCandidatePacketOH = candidateSet.PacketOH(i);
354 curCandidateSSRC = candidateSet.Ssrc(i);
355 curCandidateIndex = i;
356 candidateSet.ClearEntry(curCandidateIndex);
357 break;
358 }
359 }
360 }
361
362 // 6. Calculate packet rate and intersection of the current
363 // line with line of last tuple in selected list
danilchapf6ff9712016-02-24 09:23:37 -0800364 RTC_DCHECK_NE(curCandidatePacketOH,
365 _boundingSet.PacketOH(numBoundingSet - 1));
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +0000366 float packetRate
367 = float(curCandidateTMMBR
368 - _boundingSet.Tmmbr(numBoundingSet-1))*1000
369 / (8*(curCandidatePacketOH
370 - _boundingSet.PacketOH(numBoundingSet-1)));
371
372 // 7. If the packet rate is equal or lower than intersection of
373 // last tuple in selected list,
374 // remove last tuple in selected list & go back to step 6
375 if(packetRate <= _ptrIntersectionBoundingSet[numBoundingSet-1])
376 {
377 // remove last tuple and goto step 6
378 numBoundingSet--;
379 _boundingSet.ClearEntry(numBoundingSet);
380 _ptrIntersectionBoundingSet[numBoundingSet] = 0;
381 _ptrMaxPRBoundingSet[numBoundingSet] = 0;
382 getNewCandidate = false;
383 } else
384 {
385 // 8. If packet rate is lower than maximum packet rate of
386 // last tuple in selected list, add current tuple to selected
387 // list
388 if (packetRate < _ptrMaxPRBoundingSet[numBoundingSet-1])
389 {
390 _boundingSet.SetEntry(numBoundingSet,
391 curCandidateTMMBR,
392 curCandidatePacketOH,
393 curCandidateSSRC);
394 _ptrIntersectionBoundingSet[numBoundingSet] = packetRate;
danilchapf6ff9712016-02-24 09:23:37 -0800395 float packet_overhead_bits =
396 8 * _boundingSet.PacketOH(numBoundingSet);
397 RTC_DCHECK_NE(packet_overhead_bits, 0.0f);
398 _ptrMaxPRBoundingSet[numBoundingSet] =
399 _boundingSet.Tmmbr(numBoundingSet) * 1000 /
400 packet_overhead_bits;
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +0000401 numBoundingSet++;
402 }
403 numCandidates--;
404 getNewCandidate = true;
405 }
406
407 // 9. Go back to step 5 if any tuple remains in candidate list
408 } while (numCandidates > 0);
409
niklase@google.com470e71d2011-07-07 08:21:25 +0000410 return numBoundingSet;
411}
412
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000413bool TMMBRHelp::IsOwner(const uint32_t ssrc,
414 const uint32_t length) const {
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +0000415 CriticalSectionScoped lock(_criticalSection);
niklase@google.com470e71d2011-07-07 08:21:25 +0000416
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +0000417 if (length == 0) {
418 // Empty bounding set.
henrike@webrtc.org0ad51862012-03-30 16:54:13 +0000419 return false;
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +0000420 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000421 for(uint32_t i = 0;
danilchapa4f31bd2016-02-29 05:26:01 -0800422 (i < length) && (i < _boundingSet.size()); ++i) {
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000423 if(_boundingSet.Ssrc(i) == ssrc) {
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +0000424 return true;
425 }
426 }
427 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000428}
429
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000430bool TMMBRHelp::CalcMinBitRate( uint32_t* minBitrateKbit) const {
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +0000431 CriticalSectionScoped lock(_criticalSection);
niklase@google.com470e71d2011-07-07 08:21:25 +0000432
danilchapa4f31bd2016-02-29 05:26:01 -0800433 if (_candidateSet.size() == 0) {
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +0000434 // Empty bounding set.
435 return false;
436 }
437 *minBitrateKbit = std::numeric_limits<uint32_t>::max();
438
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000439 for (uint32_t i = 0; i < _candidateSet.lengthOfSet(); ++i) {
440 uint32_t curNetBitRateKbit = _candidateSet.Tmmbr(i);
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +0000441 if (curNetBitRateKbit < MIN_VIDEO_BW_MANAGEMENT_BITRATE) {
442 curNetBitRateKbit = MIN_VIDEO_BW_MANAGEMENT_BITRATE;
niklase@google.com470e71d2011-07-07 08:21:25 +0000443 }
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +0000444 *minBitrateKbit = curNetBitRateKbit < *minBitrateKbit ?
445 curNetBitRateKbit : *minBitrateKbit;
446 }
447 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000448}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000449} // namespace webrtc