blob: 1001bf4c5ea7ec11aef6640cfa1c3ee74c8ac49f [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 {
22TMMBRSet::TMMBRSet() :
hta@webrtc.org54536bb2012-05-03 14:07:23 +000023 _sizeOfSet(0),
24 _lengthOfSet(0)
niklase@google.com470e71d2011-07-07 08:21:25 +000025{
26}
27
28TMMBRSet::~TMMBRSet()
29{
hta@webrtc.org54536bb2012-05-03 14:07:23 +000030 _sizeOfSet = 0;
31 _lengthOfSet = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000032}
33
34void
pbos@webrtc.org2f446732013-04-08 11:08:41 +000035TMMBRSet::VerifyAndAllocateSet(uint32_t minimumSize)
niklase@google.com470e71d2011-07-07 08:21:25 +000036{
hta@webrtc.org54536bb2012-05-03 14:07:23 +000037 if(minimumSize > _sizeOfSet)
niklase@google.com470e71d2011-07-07 08:21:25 +000038 {
39 // make sure that our buffers are big enough
hta@webrtc.org54536bb2012-05-03 14:07:23 +000040 _data.resize(minimumSize);
41 _sizeOfSet = minimumSize;
niklase@google.com470e71d2011-07-07 08:21:25 +000042 }
43 // reset memory
pbos@webrtc.org2f446732013-04-08 11:08:41 +000044 for(uint32_t i = 0; i < _sizeOfSet; i++)
niklase@google.com470e71d2011-07-07 08:21:25 +000045 {
hta@webrtc.org54536bb2012-05-03 14:07:23 +000046 _data.at(i).tmmbr = 0;
47 _data.at(i).packet_oh = 0;
48 _data.at(i).ssrc = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000049 }
hta@webrtc.org54536bb2012-05-03 14:07:23 +000050 _lengthOfSet = 0;
51}
52
53void
pbos@webrtc.org2f446732013-04-08 11:08:41 +000054TMMBRSet::VerifyAndAllocateSetKeepingData(uint32_t minimumSize)
hta@webrtc.org54536bb2012-05-03 14:07:23 +000055{
56 if(minimumSize > _sizeOfSet)
57 {
58 {
59 _data.resize(minimumSize);
60 }
61 _sizeOfSet = minimumSize;
62 }
63}
64
65void TMMBRSet::SetEntry(unsigned int i,
pbos@webrtc.org2f446732013-04-08 11:08:41 +000066 uint32_t tmmbrSet,
67 uint32_t packetOHSet,
68 uint32_t ssrcSet) {
hta@webrtc.org54536bb2012-05-03 14:07:23 +000069 assert(i < _sizeOfSet);
70 _data.at(i).tmmbr = tmmbrSet;
71 _data.at(i).packet_oh = packetOHSet;
72 _data.at(i).ssrc = ssrcSet;
73 if (i >= _lengthOfSet) {
74 _lengthOfSet = i + 1;
75 }
76}
77
pbos@webrtc.org2f446732013-04-08 11:08:41 +000078void TMMBRSet::AddEntry(uint32_t tmmbrSet,
79 uint32_t packetOHSet,
80 uint32_t ssrcSet) {
hta@webrtc.org54536bb2012-05-03 14:07:23 +000081 assert(_lengthOfSet < _sizeOfSet);
82 SetEntry(_lengthOfSet, tmmbrSet, packetOHSet, ssrcSet);
83}
84
pbos@webrtc.org2f446732013-04-08 11:08:41 +000085void TMMBRSet::RemoveEntry(uint32_t sourceIdx) {
hta@webrtc.org54536bb2012-05-03 14:07:23 +000086 assert(sourceIdx < _lengthOfSet);
87 _data.erase(_data.begin() + sourceIdx);
88 _lengthOfSet--;
89 _data.resize(_sizeOfSet); // Ensure that size remains the same.
90}
91
pbos@webrtc.org2f446732013-04-08 11:08:41 +000092void TMMBRSet::SwapEntries(uint32_t i, uint32_t j) {
hta@webrtc.org54536bb2012-05-03 14:07:23 +000093 SetElement temp;
94 temp = _data[i];
95 _data[i] = _data[j];
96 _data[j] = temp;
97}
98
pbos@webrtc.org2f446732013-04-08 11:08:41 +000099void TMMBRSet::ClearEntry(uint32_t idx) {
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000100 SetEntry(idx, 0, 0, 0);
niklase@google.com470e71d2011-07-07 08:21:25 +0000101}
102
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +0000103TMMBRHelp::TMMBRHelp()
104 : _criticalSection(CriticalSectionWrapper::CreateCriticalSection()),
105 _candidateSet(),
106 _boundingSet(),
107 _boundingSetToSend(),
108 _ptrIntersectionBoundingSet(NULL),
109 _ptrMaxPRBoundingSet(NULL) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000110}
111
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +0000112TMMBRHelp::~TMMBRHelp() {
113 delete [] _ptrIntersectionBoundingSet;
114 delete [] _ptrMaxPRBoundingSet;
115 _ptrIntersectionBoundingSet = 0;
116 _ptrMaxPRBoundingSet = 0;
117 delete _criticalSection;
niklase@google.com470e71d2011-07-07 08:21:25 +0000118}
119
120TMMBRSet*
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000121TMMBRHelp::VerifyAndAllocateBoundingSet(uint32_t minimumSize)
niklase@google.com470e71d2011-07-07 08:21:25 +0000122{
123 CriticalSectionScoped lock(_criticalSection);
124
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000125 if(minimumSize > _boundingSet.sizeOfSet())
niklase@google.com470e71d2011-07-07 08:21:25 +0000126 {
127 // make sure that our buffers are big enough
128 if(_ptrIntersectionBoundingSet)
129 {
130 delete [] _ptrIntersectionBoundingSet;
131 delete [] _ptrMaxPRBoundingSet;
132 }
133 _ptrIntersectionBoundingSet = new float[minimumSize];
134 _ptrMaxPRBoundingSet = new float[minimumSize];
135 }
136 _boundingSet.VerifyAndAllocateSet(minimumSize);
137 return &_boundingSet;
138}
139
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +0000140TMMBRSet* TMMBRHelp::BoundingSet() {
141 return &_boundingSet;
niklase@google.com470e71d2011-07-07 08:21:25 +0000142}
143
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000144int32_t
Peter Boström9d0c4322016-02-16 17:59:27 +0100145TMMBRHelp::SetTMMBRBoundingSetToSend(const TMMBRSet* boundingSetToSend)
niklase@google.com470e71d2011-07-07 08:21:25 +0000146{
147 CriticalSectionScoped lock(_criticalSection);
148
149 if (boundingSetToSend == NULL)
150 {
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000151 _boundingSetToSend.clearSet();
niklase@google.com470e71d2011-07-07 08:21:25 +0000152 return 0;
153 }
154
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000155 VerifyAndAllocateBoundingSetToSend(boundingSetToSend->lengthOfSet());
156 _boundingSetToSend.clearSet();
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000157 for (uint32_t i = 0; i < boundingSetToSend->lengthOfSet(); i++)
niklase@google.com470e71d2011-07-07 08:21:25 +0000158 {
159 // cap at our configured max bitrate
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000160 uint32_t bitrate = boundingSetToSend->Tmmbr(i);
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000161 _boundingSetToSend.SetEntry(i, bitrate,
162 boundingSetToSend->PacketOH(i),
163 boundingSetToSend->Ssrc(i));
niklase@google.com470e71d2011-07-07 08:21:25 +0000164 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000165 return 0;
166}
167
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000168int32_t
169TMMBRHelp::VerifyAndAllocateBoundingSetToSend(uint32_t minimumSize)
niklase@google.com470e71d2011-07-07 08:21:25 +0000170{
171 CriticalSectionScoped lock(_criticalSection);
172
173 _boundingSetToSend.VerifyAndAllocateSet(minimumSize);
174 return 0;
175}
176
177TMMBRSet*
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000178TMMBRHelp::VerifyAndAllocateCandidateSet(uint32_t minimumSize)
niklase@google.com470e71d2011-07-07 08:21:25 +0000179{
180 CriticalSectionScoped lock(_criticalSection);
181
182 _candidateSet.VerifyAndAllocateSet(minimumSize);
183 return &_candidateSet;
184}
185
186TMMBRSet*
187TMMBRHelp::CandidateSet()
188{
189 return &_candidateSet;
190}
191
192TMMBRSet*
193TMMBRHelp::BoundingSetToSend()
194{
195 return &_boundingSetToSend;
196}
197
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000198int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000199TMMBRHelp::FindTMMBRBoundingSet(TMMBRSet*& boundingSet)
200{
201 CriticalSectionScoped lock(_criticalSection);
202
203 // Work on local variable, will be modified
204 TMMBRSet candidateSet;
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000205 candidateSet.VerifyAndAllocateSet(_candidateSet.sizeOfSet());
niklase@google.com470e71d2011-07-07 08:21:25 +0000206
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000207 // TODO(hta) Figure out if this should be lengthOfSet instead.
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000208 for (uint32_t i = 0; i < _candidateSet.sizeOfSet(); i++)
niklase@google.com470e71d2011-07-07 08:21:25 +0000209 {
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000210 if(_candidateSet.Tmmbr(i))
niklase@google.com470e71d2011-07-07 08:21:25 +0000211 {
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000212 candidateSet.AddEntry(_candidateSet.Tmmbr(i),
213 _candidateSet.PacketOH(i),
214 _candidateSet.Ssrc(i));
niklase@google.com470e71d2011-07-07 08:21:25 +0000215 }
216 else
217 {
218 // make sure this is zero if tmmbr = 0
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000219 assert(_candidateSet.PacketOH(i) == 0);
220 // Old code:
221 // _candidateSet.ptrPacketOHSet[i] = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000222 }
223 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000224
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000225 // Number of set candidates
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000226 int32_t numSetCandidates = candidateSet.lengthOfSet();
niklase@google.com470e71d2011-07-07 08:21:25 +0000227 // Find bounding set
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000228 uint32_t numBoundingSet = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000229 if (numSetCandidates > 0)
230 {
231 numBoundingSet = FindTMMBRBoundingSet(numSetCandidates, candidateSet);
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000232 if(numBoundingSet < 1 || (numBoundingSet > _candidateSet.sizeOfSet()))
niklase@google.com470e71d2011-07-07 08:21:25 +0000233 {
234 return -1;
235 }
236 boundingSet = &_boundingSet;
237 }
238 return numBoundingSet;
239}
240
241
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000242int32_t
243TMMBRHelp::FindTMMBRBoundingSet(int32_t numCandidates, TMMBRSet& candidateSet)
niklase@google.com470e71d2011-07-07 08:21:25 +0000244{
245 CriticalSectionScoped lock(_criticalSection);
246
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000247 uint32_t numBoundingSet = 0;
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000248 VerifyAndAllocateBoundingSet(candidateSet.sizeOfSet());
niklase@google.com470e71d2011-07-07 08:21:25 +0000249
250 if (numCandidates == 1)
251 {
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000252 // TODO(hta): lengthOfSet instead of sizeOfSet?
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000253 for (uint32_t i = 0; i < candidateSet.sizeOfSet(); i++)
niklase@google.com470e71d2011-07-07 08:21:25 +0000254 {
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000255 if (candidateSet.Tmmbr(i) > 0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000256 {
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000257 _boundingSet.AddEntry(candidateSet.Tmmbr(i),
258 candidateSet.PacketOH(i),
259 candidateSet.Ssrc(i));
niklase@google.com470e71d2011-07-07 08:21:25 +0000260 numBoundingSet++;
261 }
262 }
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +0000263 return (numBoundingSet == 1) ? 1 : -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000264 }
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +0000265
266 // 1. Sort by increasing packetOH
267 for (int i = candidateSet.sizeOfSet() - 1; i >= 0; i--)
268 {
269 for (int j = 1; j <= i; j++)
270 {
271 if (candidateSet.PacketOH(j-1) > candidateSet.PacketOH(j))
272 {
273 candidateSet.SwapEntries(j-1, j);
274 }
275 }
276 }
277 // 2. For tuples with same OH, keep the one w/ the lowest bitrate
278 for (uint32_t i = 0; i < candidateSet.sizeOfSet(); i++)
279 {
280 if (candidateSet.Tmmbr(i) > 0)
281 {
282 // get min bitrate for packets w/ same OH
283 uint32_t currentPacketOH = candidateSet.PacketOH(i);
284 uint32_t currentMinTMMBR = candidateSet.Tmmbr(i);
285 uint32_t currentMinIndexTMMBR = i;
286 for (uint32_t j = i+1; j < candidateSet.sizeOfSet(); j++)
287 {
288 if(candidateSet.PacketOH(j) == currentPacketOH)
289 {
290 if(candidateSet.Tmmbr(j) < currentMinTMMBR)
291 {
292 currentMinTMMBR = candidateSet.Tmmbr(j);
293 currentMinIndexTMMBR = j;
294 }
295 }
296 }
297 // keep lowest bitrate
298 for (uint32_t j = 0; j < candidateSet.sizeOfSet(); j++)
299 {
300 if(candidateSet.PacketOH(j) == currentPacketOH
301 && j != currentMinIndexTMMBR)
302 {
303 candidateSet.ClearEntry(j);
danilchapf6ff9712016-02-24 09:23:37 -0800304 numCandidates--;
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +0000305 }
306 }
307 }
308 }
309 // 3. Select and remove tuple w/ lowest tmmbr.
310 // (If more than 1, choose the one w/ highest OH).
311 uint32_t minTMMBR = 0;
312 uint32_t minIndexTMMBR = 0;
313 for (uint32_t i = 0; i < candidateSet.sizeOfSet(); i++)
314 {
315 if (candidateSet.Tmmbr(i) > 0)
316 {
317 minTMMBR = candidateSet.Tmmbr(i);
318 minIndexTMMBR = i;
319 break;
320 }
321 }
322
323 for (uint32_t i = 0; i < candidateSet.sizeOfSet(); i++)
324 {
325 if (candidateSet.Tmmbr(i) > 0 && candidateSet.Tmmbr(i) <= minTMMBR)
326 {
327 // get min bitrate
328 minTMMBR = candidateSet.Tmmbr(i);
329 minIndexTMMBR = i;
330 }
331 }
332 // first member of selected list
333 _boundingSet.SetEntry(numBoundingSet,
334 candidateSet.Tmmbr(minIndexTMMBR),
335 candidateSet.PacketOH(minIndexTMMBR),
336 candidateSet.Ssrc(minIndexTMMBR));
337
338 // set intersection value
339 _ptrIntersectionBoundingSet[numBoundingSet] = 0;
340 // calculate its maximum packet rate (where its line crosses x-axis)
danilchapf6ff9712016-02-24 09:23:37 -0800341 uint32_t packet_overhead_bits = 8 * _boundingSet.PacketOH(numBoundingSet);
342 if (packet_overhead_bits == 0) {
343 // Avoid division by zero.
344 _ptrMaxPRBoundingSet[numBoundingSet] = std::numeric_limits<float>::max();
345 } else {
346 _ptrMaxPRBoundingSet[numBoundingSet] =
347 _boundingSet.Tmmbr(numBoundingSet) * 1000 /
348 static_cast<float>(packet_overhead_bits);
349 }
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +0000350 numBoundingSet++;
351 // remove from candidate list
352 candidateSet.ClearEntry(minIndexTMMBR);
353 numCandidates--;
354
355 // 4. Discard from candidate list all tuple w/ lower OH
356 // (next tuple must be steeper)
357 for (uint32_t i = 0; i < candidateSet.sizeOfSet(); i++)
358 {
359 if(candidateSet.Tmmbr(i) > 0
360 && candidateSet.PacketOH(i) < _boundingSet.PacketOH(0))
361 {
362 candidateSet.ClearEntry(i);
363 numCandidates--;
364 }
365 }
366
367 if (numCandidates == 0)
368 {
369 // Should be true already:_boundingSet.lengthOfSet = numBoundingSet;
370 assert(_boundingSet.lengthOfSet() == numBoundingSet);
371 return numBoundingSet;
372 }
373
374 bool getNewCandidate = true;
danilchapf6ff9712016-02-24 09:23:37 -0800375 uint32_t curCandidateTMMBR = 0;
376 size_t curCandidateIndex = 0;
377 uint32_t curCandidatePacketOH = 0;
378 uint32_t curCandidateSSRC = 0;
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +0000379 do
380 {
381 if (getNewCandidate)
382 {
383 // 5. Remove first remaining tuple from candidate list
384 for (uint32_t i = 0; i < candidateSet.sizeOfSet(); i++)
385 {
386 if (candidateSet.Tmmbr(i) > 0)
387 {
388 curCandidateTMMBR = candidateSet.Tmmbr(i);
389 curCandidatePacketOH = candidateSet.PacketOH(i);
390 curCandidateSSRC = candidateSet.Ssrc(i);
391 curCandidateIndex = i;
392 candidateSet.ClearEntry(curCandidateIndex);
393 break;
394 }
395 }
396 }
397
398 // 6. Calculate packet rate and intersection of the current
399 // line with line of last tuple in selected list
danilchapf6ff9712016-02-24 09:23:37 -0800400 RTC_DCHECK_NE(curCandidatePacketOH,
401 _boundingSet.PacketOH(numBoundingSet - 1));
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +0000402 float packetRate
403 = float(curCandidateTMMBR
404 - _boundingSet.Tmmbr(numBoundingSet-1))*1000
405 / (8*(curCandidatePacketOH
406 - _boundingSet.PacketOH(numBoundingSet-1)));
407
408 // 7. If the packet rate is equal or lower than intersection of
409 // last tuple in selected list,
410 // remove last tuple in selected list & go back to step 6
411 if(packetRate <= _ptrIntersectionBoundingSet[numBoundingSet-1])
412 {
413 // remove last tuple and goto step 6
414 numBoundingSet--;
415 _boundingSet.ClearEntry(numBoundingSet);
416 _ptrIntersectionBoundingSet[numBoundingSet] = 0;
417 _ptrMaxPRBoundingSet[numBoundingSet] = 0;
418 getNewCandidate = false;
419 } else
420 {
421 // 8. If packet rate is lower than maximum packet rate of
422 // last tuple in selected list, add current tuple to selected
423 // list
424 if (packetRate < _ptrMaxPRBoundingSet[numBoundingSet-1])
425 {
426 _boundingSet.SetEntry(numBoundingSet,
427 curCandidateTMMBR,
428 curCandidatePacketOH,
429 curCandidateSSRC);
430 _ptrIntersectionBoundingSet[numBoundingSet] = packetRate;
danilchapf6ff9712016-02-24 09:23:37 -0800431 float packet_overhead_bits =
432 8 * _boundingSet.PacketOH(numBoundingSet);
433 RTC_DCHECK_NE(packet_overhead_bits, 0.0f);
434 _ptrMaxPRBoundingSet[numBoundingSet] =
435 _boundingSet.Tmmbr(numBoundingSet) * 1000 /
436 packet_overhead_bits;
tommi@webrtc.orgeec6ecd2014-07-11 19:09:59 +0000437 numBoundingSet++;
438 }
439 numCandidates--;
440 getNewCandidate = true;
441 }
442
443 // 9. Go back to step 5 if any tuple remains in candidate list
444 } while (numCandidates > 0);
445
niklase@google.com470e71d2011-07-07 08:21:25 +0000446 return numBoundingSet;
447}
448
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000449bool TMMBRHelp::IsOwner(const uint32_t ssrc,
450 const uint32_t length) const {
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +0000451 CriticalSectionScoped lock(_criticalSection);
niklase@google.com470e71d2011-07-07 08:21:25 +0000452
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +0000453 if (length == 0) {
454 // Empty bounding set.
henrike@webrtc.org0ad51862012-03-30 16:54:13 +0000455 return false;
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +0000456 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000457 for(uint32_t i = 0;
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000458 (i < length) && (i < _boundingSet.sizeOfSet()); ++i) {
459 if(_boundingSet.Ssrc(i) == ssrc) {
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +0000460 return true;
461 }
462 }
463 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000464}
465
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000466bool TMMBRHelp::CalcMinBitRate( uint32_t* minBitrateKbit) const {
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +0000467 CriticalSectionScoped lock(_criticalSection);
niklase@google.com470e71d2011-07-07 08:21:25 +0000468
hta@webrtc.org54536bb2012-05-03 14:07:23 +0000469 if (_candidateSet.sizeOfSet() == 0) {
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +0000470 // Empty bounding set.
471 return false;
472 }
473 *minBitrateKbit = std::numeric_limits<uint32_t>::max();
474
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000475 for (uint32_t i = 0; i < _candidateSet.lengthOfSet(); ++i) {
476 uint32_t curNetBitRateKbit = _candidateSet.Tmmbr(i);
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +0000477 if (curNetBitRateKbit < MIN_VIDEO_BW_MANAGEMENT_BITRATE) {
478 curNetBitRateKbit = MIN_VIDEO_BW_MANAGEMENT_BITRATE;
niklase@google.com470e71d2011-07-07 08:21:25 +0000479 }
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +0000480 *minBitrateKbit = curNetBitRateKbit < *minBitrateKbit ?
481 curNetBitRateKbit : *minBitrateKbit;
482 }
483 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000484}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000485} // namespace webrtc