blob: 5d598e03ab2d4629623baef76000c1984090bdd8 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +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
11#include "rtcp_sender.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
stefan@webrtc.org9354cc92012-06-07 08:10:14 +000013#include <cassert> // assert
14#include <cstdlib> // rand
15#include <string.h> // memcpy
niklase@google.com470e71d2011-07-07 08:21:25 +000016
niklase@google.com470e71d2011-07-07 08:21:25 +000017#include "common_types.h"
stefan@webrtc.org9354cc92012-06-07 08:10:14 +000018#include "modules/rtp_rtcp/source/rtp_rtcp_impl.h"
19#include "system_wrappers/interface/critical_section_wrapper.h"
20#include "system_wrappers/interface/trace.h"
pwestin@webrtc.org741da942011-09-20 13:52:04 +000021
niklase@google.com470e71d2011-07-07 08:21:25 +000022namespace webrtc {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +000023
24using RTCPUtility::RTCPCnameInformation;
25
niklase@google.com470e71d2011-07-07 08:21:25 +000026RTCPSender::RTCPSender(const WebRtc_Word32 id,
27 const bool audio,
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +000028 Clock* clock,
pwestin@webrtc.org741da942011-09-20 13:52:04 +000029 ModuleRtpRtcpImpl* owner) :
niklase@google.com470e71d2011-07-07 08:21:25 +000030 _id(id),
31 _audio(audio),
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +000032 _clock(clock),
niklase@google.com470e71d2011-07-07 08:21:25 +000033 _method(kRtcpOff),
pwestin@webrtc.org741da942011-09-20 13:52:04 +000034 _rtpRtcp(*owner),
henrike@webrtc.org65573f22011-12-13 19:17:27 +000035 _criticalSectionTransport(CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +000036 _cbTransport(NULL),
37
henrike@webrtc.org65573f22011-12-13 19:17:27 +000038 _criticalSectionRTCPSender(CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +000039 _usingNack(false),
40 _sending(false),
41 _sendTMMBN(false),
pwestin@webrtc.org741da942011-09-20 13:52:04 +000042 _REMB(false),
43 _sendREMB(false),
niklase@google.com470e71d2011-07-07 08:21:25 +000044 _TMMBR(false),
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +000045 _IJ(false),
niklase@google.com470e71d2011-07-07 08:21:25 +000046 _nextTimeToSendRTCP(0),
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000047 start_timestamp_(0),
48 last_rtp_timestamp_(0),
49 last_frame_capture_time_ms_(-1),
niklase@google.com470e71d2011-07-07 08:21:25 +000050 _SSRC(0),
51 _remoteSSRC(0),
52 _CNAME(),
53 _reportBlocks(),
54 _csrcCNAMEs(),
55
56 _cameraDelayMS(0),
57
58 _lastSendReport(),
59 _lastRTCPTime(),
60
61 _CSRCs(0),
62 _CSRC(),
63 _includeCSRCs(true),
64
65 _sequenceNumberFIR(0),
niklase@google.com470e71d2011-07-07 08:21:25 +000066
pwestin@webrtc.org741da942011-09-20 13:52:04 +000067 _lengthRembSSRC(0),
68 _sizeRembSSRC(0),
69 _rembSSRC(NULL),
70 _rembBitrate(0),
71
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +000072 _tmmbrHelp(),
niklase@google.com470e71d2011-07-07 08:21:25 +000073 _tmmbr_Send(0),
74 _packetOH_Send(0),
niklase@google.com470e71d2011-07-07 08:21:25 +000075
76 _appSend(false),
77 _appSubType(0),
78 _appName(),
79 _appData(NULL),
80 _appLength(0),
81 _xrSendVoIPMetric(false),
82 _xrVoIPMetric()
83{
84 memset(_CNAME, 0, sizeof(_CNAME));
85 memset(_lastSendReport, 0, sizeof(_lastSendReport));
86 memset(_lastRTCPTime, 0, sizeof(_lastRTCPTime));
87
88 WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, id, "%s created", __FUNCTION__);
89}
90
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +000091RTCPSender::~RTCPSender() {
92 delete [] _rembSSRC;
93 delete [] _appData;
niklase@google.com470e71d2011-07-07 08:21:25 +000094
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +000095 while (!_reportBlocks.empty()) {
96 std::map<WebRtc_UWord32, RTCPReportBlock*>::iterator it =
97 _reportBlocks.begin();
98 delete it->second;
99 _reportBlocks.erase(it);
100 }
101 while (!_csrcCNAMEs.empty()) {
102 std::map<WebRtc_UWord32, RTCPCnameInformation*>::iterator it =
103 _csrcCNAMEs.begin();
104 delete it->second;
105 _csrcCNAMEs.erase(it);
106 }
107 delete _criticalSectionTransport;
108 delete _criticalSectionRTCPSender;
niklase@google.com470e71d2011-07-07 08:21:25 +0000109
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000110 WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, _id, "%s deleted", __FUNCTION__);
niklase@google.com470e71d2011-07-07 08:21:25 +0000111}
112
113WebRtc_Word32
114RTCPSender::Init()
115{
116 CriticalSectionScoped lock(_criticalSectionRTCPSender);
117
118 _method = kRtcpOff;
119 _cbTransport = NULL;
120 _usingNack = false;
121 _sending = false;
122 _sendTMMBN = false;
123 _TMMBR = false;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000124 _IJ = false;
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000125 _REMB = false;
126 _sendREMB = false;
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000127 last_rtp_timestamp_ = 0;
128 last_frame_capture_time_ms_ = -1;
129 start_timestamp_ = -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000130 _SSRC = 0;
131 _remoteSSRC = 0;
132 _cameraDelayMS = 0;
133 _sequenceNumberFIR = 0;
134 _tmmbr_Send = 0;
135 _packetOH_Send = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000136 _nextTimeToSendRTCP = 0;
137 _CSRCs = 0;
138 _appSend = false;
139 _appSubType = 0;
140
141 if(_appData)
142 {
143 delete [] _appData;
144 _appData = NULL;
145 }
146 _appLength = 0;
147
148 _xrSendVoIPMetric = false;
149
150 memset(&_xrVoIPMetric, 0, sizeof(_xrVoIPMetric));
151 memset(_CNAME, 0, sizeof(_CNAME));
152 memset(_lastSendReport, 0, sizeof(_lastSendReport));
153 memset(_lastRTCPTime, 0, sizeof(_lastRTCPTime));
154 return 0;
155}
156
157void
158RTCPSender::ChangeUniqueId(const WebRtc_Word32 id)
159{
160 _id = id;
161}
162
163WebRtc_Word32
164RTCPSender::RegisterSendTransport(Transport* outgoingTransport)
165{
166 CriticalSectionScoped lock(_criticalSectionTransport);
167 _cbTransport = outgoingTransport;
168 return 0;
169}
170
171RTCPMethod
172RTCPSender::Status() const
173{
174 CriticalSectionScoped lock(_criticalSectionRTCPSender);
175 return _method;
176}
177
178WebRtc_Word32
179RTCPSender::SetRTCPStatus(const RTCPMethod method)
180{
181 CriticalSectionScoped lock(_criticalSectionRTCPSender);
182 if(method != kRtcpOff)
183 {
184 if(_audio)
185 {
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +0000186 _nextTimeToSendRTCP = _clock->TimeInMilliseconds() +
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000187 (RTCP_INTERVAL_AUDIO_MS/2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000188 } else
189 {
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +0000190 _nextTimeToSendRTCP = _clock->TimeInMilliseconds() +
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000191 (RTCP_INTERVAL_VIDEO_MS/2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000192 }
193 }
194 _method = method;
195 return 0;
196}
197
198bool
199RTCPSender::Sending() const
200{
201 CriticalSectionScoped lock(_criticalSectionRTCPSender);
202 return _sending;
203}
204
205WebRtc_Word32
206RTCPSender::SetSendingStatus(const bool sending)
207{
208 bool sendRTCPBye = false;
209 {
210 CriticalSectionScoped lock(_criticalSectionRTCPSender);
211
212 if(_method != kRtcpOff)
213 {
214 if(sending == false && _sending == true)
215 {
216 // Trigger RTCP bye
217 sendRTCPBye = true;
218 }
219 }
220 _sending = sending;
221 }
222 if(sendRTCPBye)
223 {
224 return SendRTCP(kRtcpBye);
225 }
226 return 0;
227}
228
229bool
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000230RTCPSender::REMB() const
231{
232 CriticalSectionScoped lock(_criticalSectionRTCPSender);
233 return _REMB;
234}
235
236WebRtc_Word32
237RTCPSender::SetREMBStatus(const bool enable)
238{
239 CriticalSectionScoped lock(_criticalSectionRTCPSender);
240 _REMB = enable;
241 return 0;
242}
243
244WebRtc_Word32
245RTCPSender::SetREMBData(const WebRtc_UWord32 bitrate,
246 const WebRtc_UWord8 numberOfSSRC,
247 const WebRtc_UWord32* SSRC)
248{
249 CriticalSectionScoped lock(_criticalSectionRTCPSender);
250 _rembBitrate = bitrate;
251
252 if(_sizeRembSSRC < numberOfSSRC)
253 {
254 delete [] _rembSSRC;
255 _rembSSRC = new WebRtc_UWord32[numberOfSSRC];
256 _sizeRembSSRC = numberOfSSRC;
257 }
258
259 _lengthRembSSRC = numberOfSSRC;
260 for (int i = 0; i < numberOfSSRC; i++)
261 {
262 _rembSSRC[i] = SSRC[i];
263 }
mflodman@webrtc.org84dc3d12011-12-22 10:26:13 +0000264 _sendREMB = true;
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000265 return 0;
266}
267
268bool
niklase@google.com470e71d2011-07-07 08:21:25 +0000269RTCPSender::TMMBR() const
270{
271 CriticalSectionScoped lock(_criticalSectionRTCPSender);
272 return _TMMBR;
273}
274
275WebRtc_Word32
276RTCPSender::SetTMMBRStatus(const bool enable)
277{
278 CriticalSectionScoped lock(_criticalSectionRTCPSender);
279 _TMMBR = enable;
280 return 0;
281}
282
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000283bool
284RTCPSender::IJ() const
285{
286 CriticalSectionScoped lock(_criticalSectionRTCPSender);
287 return _IJ;
288}
289
290WebRtc_Word32
291RTCPSender::SetIJStatus(const bool enable)
292{
293 CriticalSectionScoped lock(_criticalSectionRTCPSender);
294 _IJ = enable;
295 return 0;
296}
297
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000298void RTCPSender::SetStartTimestamp(uint32_t start_timestamp) {
299 start_timestamp_ = start_timestamp;
300}
301
302void RTCPSender::SetLastRtpTime(uint32_t rtp_timestamp,
303 int64_t capture_time_ms) {
304 last_rtp_timestamp_ = rtp_timestamp;
305 if (capture_time_ms < 0) {
306 // We don't currently get a capture time from VoiceEngine.
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +0000307 last_frame_capture_time_ms_ = _clock->TimeInMilliseconds();
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000308 } else {
309 last_frame_capture_time_ms_ = capture_time_ms;
310 }
311}
312
niklase@google.com470e71d2011-07-07 08:21:25 +0000313void
314RTCPSender::SetSSRC( const WebRtc_UWord32 ssrc)
315{
316 CriticalSectionScoped lock(_criticalSectionRTCPSender);
317
318 if(_SSRC != 0)
319 {
320 // not first SetSSRC, probably due to a collision
321 // schedule a new RTCP report
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000322 // make sure that we send a RTP packet
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +0000323 _nextTimeToSendRTCP = _clock->TimeInMilliseconds() + 100;
niklase@google.com470e71d2011-07-07 08:21:25 +0000324 }
325 _SSRC = ssrc;
326}
327
328WebRtc_Word32
329RTCPSender::SetRemoteSSRC( const WebRtc_UWord32 ssrc)
330{
331 CriticalSectionScoped lock(_criticalSectionRTCPSender);
332 _remoteSSRC = ssrc;
niklase@google.com470e71d2011-07-07 08:21:25 +0000333 return 0;
334}
335
336WebRtc_Word32
337RTCPSender::SetCameraDelay(const WebRtc_Word32 delayMS)
338{
339 CriticalSectionScoped lock(_criticalSectionRTCPSender);
340 if(delayMS > 1000 || delayMS < -1000)
341 {
342 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument, delay can't be larger than 1 sec", __FUNCTION__);
343 return -1;
344 }
345 _cameraDelayMS = delayMS;
346 return 0;
347}
348
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000349WebRtc_Word32 RTCPSender::CNAME(char cName[RTCP_CNAME_SIZE]) {
350 assert(cName);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000351 CriticalSectionScoped lock(_criticalSectionRTCPSender);
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000352 cName[RTCP_CNAME_SIZE - 1] = 0;
353 strncpy(cName, _CNAME, RTCP_CNAME_SIZE - 1);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000354 return 0;
355}
356
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000357WebRtc_Word32 RTCPSender::SetCNAME(const char cName[RTCP_CNAME_SIZE]) {
tommi@webrtc.orga990e122012-04-26 15:28:22 +0000358 if (!cName)
359 return -1;
360
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000361 CriticalSectionScoped lock(_criticalSectionRTCPSender);
362 _CNAME[RTCP_CNAME_SIZE - 1] = 0;
363 strncpy(_CNAME, cName, RTCP_CNAME_SIZE - 1);
364 return 0;
365}
366
367WebRtc_Word32 RTCPSender::AddMixedCNAME(const WebRtc_UWord32 SSRC,
368 const char cName[RTCP_CNAME_SIZE]) {
369 assert(cName);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000370 CriticalSectionScoped lock(_criticalSectionRTCPSender);
371 if (_csrcCNAMEs.size() >= kRtpCsrcSize) {
372 return -1;
373 }
374 RTCPCnameInformation* ptr = new RTCPCnameInformation();
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000375 ptr->name[RTCP_CNAME_SIZE - 1] = 0;
376 strncpy(ptr->name, cName, RTCP_CNAME_SIZE - 1);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000377 _csrcCNAMEs[SSRC] = ptr;
378 return 0;
379}
380
381WebRtc_Word32 RTCPSender::RemoveMixedCNAME(const WebRtc_UWord32 SSRC) {
382 CriticalSectionScoped lock(_criticalSectionRTCPSender);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000383 std::map<WebRtc_UWord32, RTCPCnameInformation*>::iterator it =
384 _csrcCNAMEs.find(SSRC);
385
386 if (it == _csrcCNAMEs.end()) {
387 return -1;
388 }
389 delete it->second;
390 _csrcCNAMEs.erase(it);
391 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000392}
393
394bool
395RTCPSender::TimeToSendRTCPReport(const bool sendKeyframeBeforeRTP) const
396{
397/*
398 For audio we use a fix 5 sec interval
399
400 For video we use 1 sec interval fo a BW smaller than 360 kbit/s,
401 technicaly we break the max 5% RTCP BW for video below 10 kbit/s but that should be extreamly rare
402
403
404From RFC 3550
405
406 MAX RTCP BW is 5% if the session BW
407 A send report is approximately 65 bytes inc CNAME
408 A report report is approximately 28 bytes
409
410 The RECOMMENDED value for the reduced minimum in seconds is 360
411 divided by the session bandwidth in kilobits/second. This minimum
412 is smaller than 5 seconds for bandwidths greater than 72 kb/s.
413
414 If the participant has not yet sent an RTCP packet (the variable
415 initial is true), the constant Tmin is set to 2.5 seconds, else it
416 is set to 5 seconds.
417
418 The interval between RTCP packets is varied randomly over the
419 range [0.5,1.5] times the calculated interval to avoid unintended
420 synchronization of all participants
421
422 if we send
423 If the participant is a sender (we_sent true), the constant C is
424 set to the average RTCP packet size (avg_rtcp_size) divided by 25%
425 of the RTCP bandwidth (rtcp_bw), and the constant n is set to the
426 number of senders.
427
428 if we receive only
429 If we_sent is not true, the constant C is set
430 to the average RTCP packet size divided by 75% of the RTCP
431 bandwidth. The constant n is set to the number of receivers
432 (members - senders). If the number of senders is greater than
433 25%, senders and receivers are treated together.
434
435 reconsideration NOT required for peer-to-peer
436 "timer reconsideration" is
437 employed. This algorithm implements a simple back-off mechanism
438 which causes users to hold back RTCP packet transmission if the
439 group sizes are increasing.
440
441 n = number of members
442 C = avg_size/(rtcpBW/4)
443
444 3. The deterministic calculated interval Td is set to max(Tmin, n*C).
445
446 4. The calculated interval T is set to a number uniformly distributed
447 between 0.5 and 1.5 times the deterministic calculated interval.
448
449 5. The resulting value of T is divided by e-3/2=1.21828 to compensate
450 for the fact that the timer reconsideration algorithm converges to
451 a value of the RTCP bandwidth below the intended average
452*/
453
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +0000454 WebRtc_Word64 now = _clock->TimeInMilliseconds();
xians@webrtc.org8738d272011-11-25 13:43:53 +0000455
456 CriticalSectionScoped lock(_criticalSectionRTCPSender);
457
niklase@google.com470e71d2011-07-07 08:21:25 +0000458 if(_method == kRtcpOff)
459 {
460 return false;
461 }
462
niklase@google.com470e71d2011-07-07 08:21:25 +0000463 if(!_audio && sendKeyframeBeforeRTP)
464 {
465 // for video key-frames we want to send the RTCP before the large key-frame
466 // if we have a 100 ms margin
467 now += RTCP_SEND_BEFORE_KEY_FRAME_MS;
468 }
469
470 if(now > _nextTimeToSendRTCP)
471 {
472 return true;
473
474 } else if(now < 0x0000ffff && _nextTimeToSendRTCP > 0xffff0000) // 65 sec margin
475 {
476 // wrap
477 return true;
478 }
479 return false;
480}
481
482WebRtc_UWord32
483RTCPSender::LastSendReport( WebRtc_UWord32& lastRTCPTime)
484{
485 CriticalSectionScoped lock(_criticalSectionRTCPSender);
486
487 lastRTCPTime = _lastRTCPTime[0];
488 return _lastSendReport[0];
489}
490
491WebRtc_UWord32
492RTCPSender::SendTimeOfSendReport(const WebRtc_UWord32 sendReport)
493{
494 CriticalSectionScoped lock(_criticalSectionRTCPSender);
495
496 // This is only saved when we are the sender
497 if((_lastSendReport[0] == 0) || (sendReport == 0))
498 {
499 return 0; // will be ignored
500 } else
501 {
502 for(int i = 0; i < RTCP_NUMBER_OF_SR; ++i)
503 {
504 if( _lastSendReport[i] == sendReport)
505 {
506 return _lastRTCPTime[i];
507 }
508 }
509 }
510 return 0;
511}
512
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000513WebRtc_Word32 RTCPSender::AddReportBlock(const WebRtc_UWord32 SSRC,
514 const RTCPReportBlock* reportBlock) {
515 if (reportBlock == NULL) {
516 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
517 "%s invalid argument", __FUNCTION__);
518 return -1;
519 }
520 CriticalSectionScoped lock(_criticalSectionRTCPSender);
niklase@google.com470e71d2011-07-07 08:21:25 +0000521
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000522 if (_reportBlocks.size() >= RTCP_MAX_REPORT_BLOCKS) {
523 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
524 "%s invalid argument", __FUNCTION__);
525 return -1;
526 }
stefan@webrtc.org8d0cd072012-12-03 14:01:46 +0000527 std::map<WebRtc_UWord32, RTCPReportBlock*>::iterator it =
528 _reportBlocks.find(SSRC);
529 if (it != _reportBlocks.end()) {
530 delete it->second;
531 _reportBlocks.erase(it);
532 }
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000533 RTCPReportBlock* copyReportBlock = new RTCPReportBlock();
534 memcpy(copyReportBlock, reportBlock, sizeof(RTCPReportBlock));
535 _reportBlocks[SSRC] = copyReportBlock;
536 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000537}
538
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000539WebRtc_Word32 RTCPSender::RemoveReportBlock(const WebRtc_UWord32 SSRC) {
540 CriticalSectionScoped lock(_criticalSectionRTCPSender);
niklase@google.com470e71d2011-07-07 08:21:25 +0000541
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000542 std::map<WebRtc_UWord32, RTCPReportBlock*>::iterator it =
543 _reportBlocks.find(SSRC);
544
545 if (it == _reportBlocks.end()) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000546 return -1;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000547 }
548 delete it->second;
549 _reportBlocks.erase(it);
550 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000551}
552
553WebRtc_Word32
554RTCPSender::BuildSR(WebRtc_UWord8* rtcpbuffer,
555 WebRtc_UWord32& pos,
556 const WebRtc_UWord32 NTPsec,
557 const WebRtc_UWord32 NTPfrac,
558 const RTCPReportBlock* received)
559{
560 // sanity
561 if(pos + 52 >= IP_PACKET_SIZE)
562 {
563 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", __FUNCTION__);
564 return -2;
565 }
566 WebRtc_UWord32 RTPtime;
niklase@google.com470e71d2011-07-07 08:21:25 +0000567
568 WebRtc_UWord32 posNumberOfReportBlocks = pos;
569 rtcpbuffer[pos++]=(WebRtc_UWord8)0x80;
570
571 // Sender report
572 rtcpbuffer[pos++]=(WebRtc_UWord8)200;
573
574 for(int i = (RTCP_NUMBER_OF_SR-2); i >= 0; i--)
575 {
576 // shift old
577 _lastSendReport[i+1] = _lastSendReport[i];
578 _lastRTCPTime[i+1] =_lastRTCPTime[i];
579 }
580
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000581 _lastRTCPTime[0] = ModuleRTPUtility::ConvertNTPTimeToMS(NTPsec, NTPfrac);
582 _lastSendReport[0] = (NTPsec << 16) + (NTPfrac >> 16);
niklase@google.com470e71d2011-07-07 08:21:25 +0000583
584 WebRtc_UWord32 freqHz = 90000; // For video
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000585 if(_audio) {
586 freqHz = _rtpRtcp.CurrentSendFrequencyHz();
niklase@google.com470e71d2011-07-07 08:21:25 +0000587 }
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000588 // The timestamp of this RTCP packet should be estimated as the timestamp of
589 // the frame being captured at this moment. We are calculating that
590 // timestamp as the last frame's timestamp + the time since the last frame
591 // was captured.
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000592 RTPtime = start_timestamp_ + last_rtp_timestamp_ + (
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +0000593 _clock->TimeInMilliseconds() - last_frame_capture_time_ms_) *
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000594 (freqHz / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +0000595
596 // Add sender data
597 // Save for our length field
598 pos++;
599 pos++;
600
601 // Add our own SSRC
602 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
603 pos += 4;
604 // NTP
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000605 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, NTPsec);
niklase@google.com470e71d2011-07-07 08:21:25 +0000606 pos += 4;
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000607 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, NTPfrac);
niklase@google.com470e71d2011-07-07 08:21:25 +0000608 pos += 4;
609 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, RTPtime);
610 pos += 4;
611
612 //sender's packet count
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000613 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _rtpRtcp.PacketCountSent());
niklase@google.com470e71d2011-07-07 08:21:25 +0000614 pos += 4;
615
616 //sender's octet count
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000617 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _rtpRtcp.ByteCountSent());
niklase@google.com470e71d2011-07-07 08:21:25 +0000618 pos += 4;
619
620 WebRtc_UWord8 numberOfReportBlocks = 0;
621 WebRtc_Word32 retVal = AddReportBlocks(rtcpbuffer, pos, numberOfReportBlocks, received, NTPsec, NTPfrac);
622 if(retVal < 0)
623 {
624 //
625 return retVal ;
626 }
627 rtcpbuffer[posNumberOfReportBlocks] += numberOfReportBlocks;
628
629 WebRtc_UWord16 len = WebRtc_UWord16((pos/4) -1);
630 ModuleRTPUtility::AssignUWord16ToBuffer(rtcpbuffer+2, len);
631 return 0;
632}
633
634
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000635WebRtc_Word32 RTCPSender::BuildSDEC(WebRtc_UWord8* rtcpbuffer,
636 WebRtc_UWord32& pos) {
637 size_t lengthCname = strlen(_CNAME);
638 assert(lengthCname < RTCP_CNAME_SIZE);
niklase@google.com470e71d2011-07-07 08:21:25 +0000639
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000640 // sanity
641 if(pos + 12 + lengthCname >= IP_PACKET_SIZE) {
642 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
643 "%s invalid argument", __FUNCTION__);
644 return -2;
645 }
646 // SDEC Source Description
niklase@google.com470e71d2011-07-07 08:21:25 +0000647
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000648 // We always need to add SDES CNAME
649 rtcpbuffer[pos++] = static_cast<WebRtc_UWord8>(0x80 + 1 + _csrcCNAMEs.size());
650 rtcpbuffer[pos++] = static_cast<WebRtc_UWord8>(202);
niklase@google.com470e71d2011-07-07 08:21:25 +0000651
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000652 // handle SDES length later on
653 WebRtc_UWord32 SDESLengthPos = pos;
654 pos++;
655 pos++;
niklase@google.com470e71d2011-07-07 08:21:25 +0000656
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000657 // Add our own SSRC
658 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
659 pos += 4;
660
661 // CNAME = 1
662 rtcpbuffer[pos++] = static_cast<WebRtc_UWord8>(1);
663
664 //
665 rtcpbuffer[pos++] = static_cast<WebRtc_UWord8>(lengthCname);
666
667 WebRtc_UWord16 SDESLength = 10;
668
669 memcpy(&rtcpbuffer[pos], _CNAME, lengthCname);
670 pos += lengthCname;
671 SDESLength += (WebRtc_UWord16)lengthCname;
672
673 WebRtc_UWord16 padding = 0;
674 // We must have a zero field even if we have an even multiple of 4 bytes
675 if ((pos % 4) == 0) {
676 padding++;
677 rtcpbuffer[pos++]=0;
678 }
679 while ((pos % 4) != 0) {
680 padding++;
681 rtcpbuffer[pos++]=0;
682 }
683 SDESLength += padding;
684
685 std::map<WebRtc_UWord32, RTCPUtility::RTCPCnameInformation*>::iterator it =
686 _csrcCNAMEs.begin();
687
688 for(; it != _csrcCNAMEs.end(); it++) {
689 RTCPCnameInformation* cname = it->second;
690 WebRtc_UWord32 SSRC = it->first;
691
692 // Add SSRC
693 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000694 pos += 4;
695
696 // CNAME = 1
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000697 rtcpbuffer[pos++] = static_cast<WebRtc_UWord8>(1);
niklase@google.com470e71d2011-07-07 08:21:25 +0000698
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000699 size_t length = strlen(cname->name);
700 assert(length < RTCP_CNAME_SIZE);
niklase@google.com470e71d2011-07-07 08:21:25 +0000701
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000702 rtcpbuffer[pos++]= static_cast<WebRtc_UWord8>(length);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000703 SDESLength += 6;
niklase@google.com470e71d2011-07-07 08:21:25 +0000704
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000705 memcpy(&rtcpbuffer[pos],cname->name, length);
niklase@google.com470e71d2011-07-07 08:21:25 +0000706
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000707 pos += length;
708 SDESLength += length;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000709 WebRtc_UWord16 padding = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000710
711 // We must have a zero field even if we have an even multiple of 4 bytes
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000712 if((pos % 4) == 0){
713 padding++;
714 rtcpbuffer[pos++]=0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000715 }
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000716 while((pos % 4) != 0){
717 padding++;
718 rtcpbuffer[pos++] = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000719 }
720 SDESLength += padding;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000721 }
722 // in 32-bit words minus one and we don't count the header
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000723 WebRtc_UWord16 buffer_length = (SDESLength / 4) - 1;
724 ModuleRTPUtility::AssignUWord16ToBuffer(rtcpbuffer + SDESLengthPos,
725 buffer_length);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000726 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000727}
728
729WebRtc_Word32
730RTCPSender::BuildRR(WebRtc_UWord8* rtcpbuffer,
731 WebRtc_UWord32& pos,
732 const WebRtc_UWord32 NTPsec,
733 const WebRtc_UWord32 NTPfrac,
734 const RTCPReportBlock* received)
735{
736 // sanity one block
737 if(pos + 32 >= IP_PACKET_SIZE)
738 {
739 return -2;
740 }
741 WebRtc_UWord32 posNumberOfReportBlocks = pos;
742
743 rtcpbuffer[pos++]=(WebRtc_UWord8)0x80;
744 rtcpbuffer[pos++]=(WebRtc_UWord8)201;
745
746 // Save for our length field
747 pos++;
748 pos++;
749
750 // Add our own SSRC
751 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
752 pos += 4;
753
754 WebRtc_UWord8 numberOfReportBlocks = 0;
755 WebRtc_Word32 retVal = AddReportBlocks(rtcpbuffer, pos, numberOfReportBlocks, received, NTPsec, NTPfrac);
756 if(retVal < 0)
757 {
758 return retVal;
759 }
760 rtcpbuffer[posNumberOfReportBlocks] += numberOfReportBlocks;
761
762 WebRtc_UWord16 len = WebRtc_UWord16((pos)/4 -1);
763 ModuleRTPUtility::AssignUWord16ToBuffer(rtcpbuffer+2, len);
764 return 0;
765}
766
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000767// From RFC 5450: Transmission Time Offsets in RTP Streams.
768// 0 1 2 3
769// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
770// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
771// hdr |V=2|P| RC | PT=IJ=195 | length |
772// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
773// | inter-arrival jitter |
774// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
775// . .
776// . .
777// . .
778// | inter-arrival jitter |
779// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
780//
781// If present, this RTCP packet must be placed after a receiver report
782// (inside a compound RTCP packet), and MUST have the same value for RC
783// (reception report count) as the receiver report.
784
785WebRtc_Word32
786RTCPSender::BuildExtendedJitterReport(
787 WebRtc_UWord8* rtcpbuffer,
788 WebRtc_UWord32& pos,
789 const WebRtc_UWord32 jitterTransmissionTimeOffset)
790{
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000791 if (_reportBlocks.size() > 0)
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000792 {
793 WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id, "Not implemented.");
794 return 0;
795 }
796
797 // sanity
798 if(pos + 8 >= IP_PACKET_SIZE)
799 {
800 return -2;
801 }
802 // add picture loss indicator
803 WebRtc_UWord8 RC = 1;
804 rtcpbuffer[pos++]=(WebRtc_UWord8)0x80 + RC;
805 rtcpbuffer[pos++]=(WebRtc_UWord8)195;
806
807 // Used fixed length of 2
808 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
809 rtcpbuffer[pos++]=(WebRtc_UWord8)(1);
810
811 // Add inter-arrival jitter
812 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer + pos,
813 jitterTransmissionTimeOffset);
814 pos += 4;
815 return 0;
816}
817
niklase@google.com470e71d2011-07-07 08:21:25 +0000818WebRtc_Word32
819RTCPSender::BuildPLI(WebRtc_UWord8* rtcpbuffer, WebRtc_UWord32& pos)
820{
821 // sanity
822 if(pos + 12 >= IP_PACKET_SIZE)
823 {
824 return -2;
825 }
826 // add picture loss indicator
827 WebRtc_UWord8 FMT = 1;
828 rtcpbuffer[pos++]=(WebRtc_UWord8)0x80 + FMT;
829 rtcpbuffer[pos++]=(WebRtc_UWord8)206;
830
831 //Used fixed length of 2
832 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
833 rtcpbuffer[pos++]=(WebRtc_UWord8)(2);
834
835 // Add our own SSRC
836 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
837 pos += 4;
838
839 // Add the remote SSRC
840 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _remoteSSRC);
841 pos += 4;
842 return 0;
843}
844
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000845WebRtc_Word32 RTCPSender::BuildFIR(WebRtc_UWord8* rtcpbuffer,
846 WebRtc_UWord32& pos,
847 bool repeat) {
848 // sanity
849 if(pos + 20 >= IP_PACKET_SIZE) {
850 return -2;
851 }
852 if (!repeat) {
853 _sequenceNumberFIR++; // do not increase if repetition
854 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000855
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000856 // add full intra request indicator
857 WebRtc_UWord8 FMT = 4;
858 rtcpbuffer[pos++] = (WebRtc_UWord8)0x80 + FMT;
859 rtcpbuffer[pos++] = (WebRtc_UWord8)206;
niklase@google.com470e71d2011-07-07 08:21:25 +0000860
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000861 //Length of 4
862 rtcpbuffer[pos++] = (WebRtc_UWord8)0;
863 rtcpbuffer[pos++] = (WebRtc_UWord8)(4);
niklase@google.com470e71d2011-07-07 08:21:25 +0000864
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000865 // Add our own SSRC
866 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
867 pos += 4;
niklase@google.com470e71d2011-07-07 08:21:25 +0000868
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000869 // RFC 5104 4.3.1.2. Semantics
870 // SSRC of media source
871 rtcpbuffer[pos++] = (WebRtc_UWord8)0;
872 rtcpbuffer[pos++] = (WebRtc_UWord8)0;
873 rtcpbuffer[pos++] = (WebRtc_UWord8)0;
874 rtcpbuffer[pos++] = (WebRtc_UWord8)0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000875
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000876 // Additional Feedback Control Information (FCI)
877 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _remoteSSRC);
878 pos += 4;
niklase@google.com470e71d2011-07-07 08:21:25 +0000879
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000880 rtcpbuffer[pos++] = (WebRtc_UWord8)(_sequenceNumberFIR);
881 rtcpbuffer[pos++] = (WebRtc_UWord8)0;
882 rtcpbuffer[pos++] = (WebRtc_UWord8)0;
883 rtcpbuffer[pos++] = (WebRtc_UWord8)0;
884 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000885}
886
887/*
888 0 1 2 3
889 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
890 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
891 | First | Number | PictureID |
892 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
893*/
894WebRtc_Word32
895RTCPSender::BuildSLI(WebRtc_UWord8* rtcpbuffer, WebRtc_UWord32& pos, const WebRtc_UWord8 pictureID)
896{
897 // sanity
898 if(pos + 16 >= IP_PACKET_SIZE)
899 {
900 return -2;
901 }
902 // add slice loss indicator
903 WebRtc_UWord8 FMT = 2;
904 rtcpbuffer[pos++]=(WebRtc_UWord8)0x80 + FMT;
905 rtcpbuffer[pos++]=(WebRtc_UWord8)206;
906
907 //Used fixed length of 3
908 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
909 rtcpbuffer[pos++]=(WebRtc_UWord8)(3);
910
911 // Add our own SSRC
912 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
913 pos += 4;
914
915 // Add the remote SSRC
916 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _remoteSSRC);
917 pos += 4;
918
919 // Add first, number & picture ID 6 bits
920 // first = 0, 13 - bits
921 // number = 0x1fff, 13 - bits only ones for now
922 WebRtc_UWord32 sliField = (0x1fff << 6)+ (0x3f & pictureID);
923 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, sliField);
924 pos += 4;
925 return 0;
926}
927
928/*
929 0 1 2 3
930 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
931 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
932 | PB |0| Payload Type| Native RPSI bit string |
933 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
934 | defined per codec ... | Padding (0) |
935 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
936*/
937/*
938* Note: not generic made for VP8
939*/
940WebRtc_Word32
941RTCPSender::BuildRPSI(WebRtc_UWord8* rtcpbuffer,
942 WebRtc_UWord32& pos,
943 const WebRtc_UWord64 pictureID,
944 const WebRtc_UWord8 payloadType)
945{
946 // sanity
947 if(pos + 24 >= IP_PACKET_SIZE)
948 {
949 return -2;
950 }
951 // add Reference Picture Selection Indication
952 WebRtc_UWord8 FMT = 3;
953 rtcpbuffer[pos++]=(WebRtc_UWord8)0x80 + FMT;
954 rtcpbuffer[pos++]=(WebRtc_UWord8)206;
955
956 // calc length
957 WebRtc_UWord32 bitsRequired = 7;
958 WebRtc_UWord8 bytesRequired = 1;
959 while((pictureID>>bitsRequired) > 0)
960 {
961 bitsRequired += 7;
962 bytesRequired++;
963 }
964
965 WebRtc_UWord8 size = 3;
966 if(bytesRequired > 6)
967 {
968 size = 5;
969 } else if(bytesRequired > 2)
970 {
971 size = 4;
972 }
973 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
974 rtcpbuffer[pos++]=size;
975
976 // Add our own SSRC
977 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
978 pos += 4;
979
980 // Add the remote SSRC
981 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _remoteSSRC);
982 pos += 4;
983
984 // calc padding length
985 WebRtc_UWord8 paddingBytes = 4-((2+bytesRequired)%4);
986 if(paddingBytes == 4)
987 {
988 paddingBytes = 0;
989 }
990 // add padding length in bits
991 rtcpbuffer[pos] = paddingBytes*8; // padding can be 0, 8, 16 or 24
992 pos++;
993
994 // add payload type
995 rtcpbuffer[pos] = payloadType;
996 pos++;
997
998 // add picture ID
999 for(int i = bytesRequired-1; i > 0; i--)
1000 {
1001 rtcpbuffer[pos] = 0x80 | WebRtc_UWord8(pictureID >> (i*7));
1002 pos++;
1003 }
1004 // add last byte of picture ID
1005 rtcpbuffer[pos] = WebRtc_UWord8(pictureID & 0x7f);
1006 pos++;
1007
1008 // add padding
1009 for(int j = 0; j <paddingBytes; j++)
1010 {
1011 rtcpbuffer[pos] = 0;
1012 pos++;
1013 }
1014 return 0;
1015}
1016
1017WebRtc_Word32
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001018RTCPSender::BuildREMB(WebRtc_UWord8* rtcpbuffer, WebRtc_UWord32& pos)
1019{
1020 // sanity
1021 if(pos + 20 + 4 * _lengthRembSSRC >= IP_PACKET_SIZE)
1022 {
1023 return -2;
1024 }
1025 // add application layer feedback
1026 WebRtc_UWord8 FMT = 15;
1027 rtcpbuffer[pos++]=(WebRtc_UWord8)0x80 + FMT;
1028 rtcpbuffer[pos++]=(WebRtc_UWord8)206;
1029
1030 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1031 rtcpbuffer[pos++]=_lengthRembSSRC + 4;
1032
1033 // Add our own SSRC
1034 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
1035 pos += 4;
1036
1037 // Remote SSRC must be 0
1038 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, 0);
1039 pos += 4;
1040
1041 rtcpbuffer[pos++]='R';
1042 rtcpbuffer[pos++]='E';
1043 rtcpbuffer[pos++]='M';
1044 rtcpbuffer[pos++]='B';
1045
1046 rtcpbuffer[pos++] = _lengthRembSSRC;
1047 // 6 bit Exp
1048 // 18 bit mantissa
1049 WebRtc_UWord8 brExp = 0;
1050 for(WebRtc_UWord32 i=0; i<64; i++)
1051 {
1052 if(_rembBitrate <= ((WebRtc_UWord32)262143 << i))
1053 {
1054 brExp = i;
1055 break;
1056 }
1057 }
1058 const WebRtc_UWord32 brMantissa = (_rembBitrate >> brExp);
1059 rtcpbuffer[pos++]=(WebRtc_UWord8)((brExp << 2) + ((brMantissa >> 16) & 0x03));
1060 rtcpbuffer[pos++]=(WebRtc_UWord8)(brMantissa >> 8);
1061 rtcpbuffer[pos++]=(WebRtc_UWord8)(brMantissa);
1062
1063 for (int i = 0; i < _lengthRembSSRC; i++)
1064 {
1065 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _rembSSRC[i]);
1066 pos += 4;
1067 }
1068 return 0;
1069}
1070
stefan@webrtc.org9354cc92012-06-07 08:10:14 +00001071void
1072RTCPSender::SetTargetBitrate(unsigned int target_bitrate)
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001073{
mflodman@webrtc.org117c1192012-01-13 08:52:58 +00001074 CriticalSectionScoped lock(_criticalSectionRTCPSender);
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001075 _tmmbr_Send = target_bitrate / 1000;
mflodman@webrtc.org117c1192012-01-13 08:52:58 +00001076}
1077
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001078WebRtc_Word32
1079RTCPSender::BuildTMMBR(WebRtc_UWord8* rtcpbuffer, WebRtc_UWord32& pos)
niklase@google.com470e71d2011-07-07 08:21:25 +00001080{
1081 // Before sending the TMMBR check the received TMMBN, only an owner is allowed to raise the bitrate
1082 // If the sender is an owner of the TMMBN -> send TMMBR
1083 // If not an owner but the TMMBR would enter the TMMBN -> send TMMBR
1084
niklase@google.com470e71d2011-07-07 08:21:25 +00001085 // get current bounding set from RTCP receiver
1086 bool tmmbrOwner = false;
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001087 // store in candidateSet, allocates one extra slot
1088 TMMBRSet* candidateSet = _tmmbrHelp.CandidateSet();
niklase@google.com470e71d2011-07-07 08:21:25 +00001089
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001090 // holding _criticalSectionRTCPSender while calling RTCPreceiver which
1091 // will accuire _criticalSectionRTCPReceiver is a potental deadlock but
1092 // since RTCPreceiver is not doing the reverse we should be fine
1093 WebRtc_Word32 lengthOfBoundingSet
1094 = _rtpRtcp.BoundingSet(tmmbrOwner, candidateSet);
niklase@google.com470e71d2011-07-07 08:21:25 +00001095
1096 if(lengthOfBoundingSet > 0)
1097 {
1098 for (WebRtc_Word32 i = 0; i < lengthOfBoundingSet; i++)
1099 {
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001100 if( candidateSet->Tmmbr(i) == _tmmbr_Send &&
1101 candidateSet->PacketOH(i) == _packetOH_Send)
niklase@google.com470e71d2011-07-07 08:21:25 +00001102 {
1103 // do not send the same tuple
1104 return 0;
1105 }
1106 }
1107 if(!tmmbrOwner)
1108 {
1109 // use received bounding set as candidate set
1110 // add current tuple
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001111 candidateSet->SetEntry(lengthOfBoundingSet,
1112 _tmmbr_Send,
1113 _packetOH_Send,
1114 _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001115 int numCandidates = lengthOfBoundingSet+ 1;
1116
1117 // find bounding set
1118 TMMBRSet* boundingSet = NULL;
1119 int numBoundingSet = _tmmbrHelp.FindTMMBRBoundingSet(boundingSet);
1120 if(numBoundingSet > 0 || numBoundingSet <= numCandidates)
1121 {
1122 tmmbrOwner = _tmmbrHelp.IsOwner(_SSRC, numBoundingSet);
1123 }
1124 if(!tmmbrOwner)
1125 {
1126 // did not enter bounding set, no meaning to send this request
1127 return 0;
1128 }
1129 }
1130 }
1131
1132 if(_tmmbr_Send)
1133 {
1134 // sanity
1135 if(pos + 20 >= IP_PACKET_SIZE)
1136 {
1137 return -2;
1138 }
1139 // add TMMBR indicator
1140 WebRtc_UWord8 FMT = 3;
1141 rtcpbuffer[pos++]=(WebRtc_UWord8)0x80 + FMT;
1142 rtcpbuffer[pos++]=(WebRtc_UWord8)205;
1143
1144 //Length of 4
1145 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1146 rtcpbuffer[pos++]=(WebRtc_UWord8)(4);
1147
1148 // Add our own SSRC
1149 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
1150 pos += 4;
1151
1152 // RFC 5104 4.2.1.2. Semantics
1153
1154 // SSRC of media source
1155 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1156 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1157 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1158 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1159
1160 // Additional Feedback Control Information (FCI)
1161 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _remoteSSRC);
1162 pos += 4;
1163
1164 WebRtc_UWord32 bitRate = _tmmbr_Send*1000;
1165 WebRtc_UWord32 mmbrExp = 0;
1166 for(WebRtc_UWord32 i=0;i<64;i++)
1167 {
1168 if(bitRate <= ((WebRtc_UWord32)131071 << i))
1169 {
1170 mmbrExp = i;
1171 break;
1172 }
1173 }
1174 WebRtc_UWord32 mmbrMantissa = (bitRate >> mmbrExp);
1175
1176 rtcpbuffer[pos++]=(WebRtc_UWord8)((mmbrExp << 2) + ((mmbrMantissa >> 15) & 0x03));
1177 rtcpbuffer[pos++]=(WebRtc_UWord8)(mmbrMantissa >> 7);
1178 rtcpbuffer[pos++]=(WebRtc_UWord8)((mmbrMantissa << 1) + ((_packetOH_Send >> 8)& 0x01));
1179 rtcpbuffer[pos++]=(WebRtc_UWord8)(_packetOH_Send);
1180 }
1181 return 0;
1182}
1183
1184WebRtc_Word32
1185RTCPSender::BuildTMMBN(WebRtc_UWord8* rtcpbuffer, WebRtc_UWord32& pos)
1186{
1187 TMMBRSet* boundingSet = _tmmbrHelp.BoundingSetToSend();
1188 if(boundingSet == NULL)
1189 {
1190 return -1;
1191 }
1192 // sanity
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001193 if(pos + 12 + boundingSet->lengthOfSet()*8 >= IP_PACKET_SIZE)
niklase@google.com470e71d2011-07-07 08:21:25 +00001194 {
1195 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", __FUNCTION__);
1196 return -2;
1197 }
1198 WebRtc_UWord8 FMT = 4;
1199 // add TMMBN indicator
1200 rtcpbuffer[pos++]=(WebRtc_UWord8)0x80 + FMT;
1201 rtcpbuffer[pos++]=(WebRtc_UWord8)205;
1202
1203 //Add length later
1204 int posLength = pos;
1205 pos++;
1206 pos++;
1207
1208 // Add our own SSRC
1209 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
1210 pos += 4;
1211
1212 // RFC 5104 4.2.2.2. Semantics
1213
1214 // SSRC of media source
1215 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1216 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1217 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1218 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1219
1220 // Additional Feedback Control Information (FCI)
1221 int numBoundingSet = 0;
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001222 for(WebRtc_UWord32 n=0; n< boundingSet->lengthOfSet(); n++)
niklase@google.com470e71d2011-07-07 08:21:25 +00001223 {
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001224 if (boundingSet->Tmmbr(n) > 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001225 {
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001226 WebRtc_UWord32 tmmbrSSRC = boundingSet->Ssrc(n);
niklase@google.com470e71d2011-07-07 08:21:25 +00001227 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, tmmbrSSRC);
1228 pos += 4;
1229
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001230 WebRtc_UWord32 bitRate = boundingSet->Tmmbr(n) * 1000;
niklase@google.com470e71d2011-07-07 08:21:25 +00001231 WebRtc_UWord32 mmbrExp = 0;
1232 for(int i=0; i<64; i++)
1233 {
1234 if(bitRate <= ((WebRtc_UWord32)131071 << i))
1235 {
1236 mmbrExp = i;
1237 break;
1238 }
1239 }
1240 WebRtc_UWord32 mmbrMantissa = (bitRate >> mmbrExp);
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001241 WebRtc_UWord32 measuredOH = boundingSet->PacketOH(n);
niklase@google.com470e71d2011-07-07 08:21:25 +00001242
1243 rtcpbuffer[pos++]=(WebRtc_UWord8)((mmbrExp << 2) + ((mmbrMantissa >> 15) & 0x03));
1244 rtcpbuffer[pos++]=(WebRtc_UWord8)(mmbrMantissa >> 7);
1245 rtcpbuffer[pos++]=(WebRtc_UWord8)((mmbrMantissa << 1) + ((measuredOH >> 8)& 0x01));
1246 rtcpbuffer[pos++]=(WebRtc_UWord8)(measuredOH);
1247 numBoundingSet++;
1248 }
1249 }
1250 WebRtc_UWord16 length= (WebRtc_UWord16)(2+2*numBoundingSet);
1251 rtcpbuffer[posLength++]=(WebRtc_UWord8)(length>>8);
1252 rtcpbuffer[posLength]=(WebRtc_UWord8)(length);
1253 return 0;
1254}
1255
1256WebRtc_Word32
1257RTCPSender::BuildAPP(WebRtc_UWord8* rtcpbuffer, WebRtc_UWord32& pos)
1258{
1259 // sanity
1260 if(_appData == NULL)
1261 {
1262 WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id, "%s invalid state", __FUNCTION__);
1263 return -1;
1264 }
1265 if(pos + 12 + _appLength >= IP_PACKET_SIZE)
1266 {
1267 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", __FUNCTION__);
1268 return -2;
1269 }
1270 rtcpbuffer[pos++]=(WebRtc_UWord8)0x80 + _appSubType;
1271
1272 // Add APP ID
1273 rtcpbuffer[pos++]=(WebRtc_UWord8)204;
1274
1275 WebRtc_UWord16 length = (_appLength>>2) + 2; // include SSRC and name
1276 rtcpbuffer[pos++]=(WebRtc_UWord8)(length>>8);
1277 rtcpbuffer[pos++]=(WebRtc_UWord8)(length);
1278
1279 // Add our own SSRC
1280 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
1281 pos += 4;
1282
1283 // Add our application name
1284 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _appName);
1285 pos += 4;
1286
1287 // Add the data
1288 memcpy(rtcpbuffer +pos, _appData,_appLength);
1289 pos += _appLength;
1290 return 0;
1291}
1292
1293WebRtc_Word32
1294RTCPSender::BuildNACK(WebRtc_UWord8* rtcpbuffer,
1295 WebRtc_UWord32& pos,
1296 const WebRtc_Word32 nackSize,
1297 const WebRtc_UWord16* nackList)
1298{
1299 // sanity
1300 if(pos + 16 >= IP_PACKET_SIZE)
1301 {
1302 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", __FUNCTION__);
1303 return -2;
1304 }
1305
1306 // int size, WebRtc_UWord16* nackList
1307 // add nack list
1308 WebRtc_UWord8 FMT = 1;
1309 rtcpbuffer[pos++]=(WebRtc_UWord8)0x80 + FMT;
1310 rtcpbuffer[pos++]=(WebRtc_UWord8)205;
1311
1312 rtcpbuffer[pos++]=(WebRtc_UWord8) 0;
1313 int nackSizePos = pos;
1314 rtcpbuffer[pos++]=(WebRtc_UWord8)(3); //setting it to one kNACK signal as default
1315
1316 // Add our own SSRC
1317 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
1318 pos += 4;
1319
1320 // Add the remote SSRC
1321 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _remoteSSRC);
1322 pos += 4;
1323
1324 // add the list
1325 int i = 0;
1326 int numOfNackFields = 0;
stefan@webrtc.orga2710702013-03-05 09:02:06 +00001327 while (nackSize > i && numOfNackFields < kRtcpMaxNackFields)
niklase@google.com470e71d2011-07-07 08:21:25 +00001328 {
1329 WebRtc_UWord16 nack = nackList[i];
1330 // put dow our sequence number
1331 ModuleRTPUtility::AssignUWord16ToBuffer(rtcpbuffer+pos, nack);
1332 pos += 2;
1333
1334 i++;
1335 numOfNackFields++;
1336 if(nackSize > i)
1337 {
1338 bool moreThan16Away = (WebRtc_UWord16(nack+16) < nackList[i])?true: false;
1339 if(!moreThan16Away)
1340 {
1341 // check for a wrap
1342 if(WebRtc_UWord16(nack+16) > 0xff00 && nackList[i] < 0x0fff)
1343 {
1344 // wrap
1345 moreThan16Away = true;
1346 }
1347 }
1348 if(moreThan16Away)
1349 {
1350 // next is more than 16 away
1351 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1352 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1353 } else
1354 {
1355 // build our bitmask
1356 WebRtc_UWord16 bitmask = 0;
1357
1358 bool within16Away = (WebRtc_UWord16(nack+16) > nackList[i])?true: false;
1359 if(within16Away)
1360 {
1361 // check for a wrap
1362 if(WebRtc_UWord16(nack+16) > 0xff00 && nackList[i] < 0x0fff)
1363 {
1364 // wrap
1365 within16Away = false;
1366 }
1367 }
1368
1369 while( nackSize > i && within16Away)
1370 {
1371 WebRtc_Word16 shift = (nackList[i]-nack)-1;
1372 assert(!(shift > 15) && !(shift < 0));
1373
1374 bitmask += (1<< shift);
1375 i++;
1376 if(nackSize > i)
1377 {
1378 within16Away = (WebRtc_UWord16(nack+16) > nackList[i])?true: false;
1379 if(within16Away)
1380 {
1381 // check for a wrap
1382 if(WebRtc_UWord16(nack+16) > 0xff00 && nackList[i] < 0x0fff)
1383 {
1384 // wrap
1385 within16Away = false;
1386 }
1387 }
1388 }
1389 }
1390 ModuleRTPUtility::AssignUWord16ToBuffer(rtcpbuffer+pos, bitmask);
1391 pos += 2;
1392 }
1393 // sanity do we have room from one more 4 byte block?
1394 if(pos + 4 >= IP_PACKET_SIZE)
1395 {
1396 return -2;
1397 }
1398 } else
1399 {
1400 // no more in the list
1401 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1402 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1403 }
1404 }
1405 rtcpbuffer[nackSizePos]=(WebRtc_UWord8)(2+numOfNackFields);
1406 return 0;
1407}
1408
1409WebRtc_Word32
1410RTCPSender::BuildBYE(WebRtc_UWord8* rtcpbuffer, WebRtc_UWord32& pos)
1411{
1412 // sanity
1413 if(pos + 8 >= IP_PACKET_SIZE)
1414 {
1415 return -2;
1416 }
1417 if(_includeCSRCs)
1418 {
1419 // Add a bye packet
1420 rtcpbuffer[pos++]=(WebRtc_UWord8)0x80 + 1 + _CSRCs; // number of SSRC+CSRCs
1421 rtcpbuffer[pos++]=(WebRtc_UWord8)203;
1422
1423 // length
1424 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1425 rtcpbuffer[pos++]=(WebRtc_UWord8)(1 + _CSRCs);
1426
1427 // Add our own SSRC
1428 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
1429 pos += 4;
1430
1431 // add CSRCs
1432 for(int i = 0; i < _CSRCs; i++)
1433 {
1434 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _CSRC[i]);
1435 pos += 4;
1436 }
1437 } else
1438 {
1439 // Add a bye packet
1440 rtcpbuffer[pos++]=(WebRtc_UWord8)0x80 + 1; // number of SSRC+CSRCs
1441 rtcpbuffer[pos++]=(WebRtc_UWord8)203;
1442
1443 // length
1444 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1445 rtcpbuffer[pos++]=(WebRtc_UWord8)1;
1446
1447 // Add our own SSRC
1448 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
1449 pos += 4;
1450 }
1451 return 0;
1452}
1453
1454WebRtc_Word32
1455RTCPSender::BuildVoIPMetric(WebRtc_UWord8* rtcpbuffer, WebRtc_UWord32& pos)
1456{
1457 // sanity
1458 if(pos + 44 >= IP_PACKET_SIZE)
1459 {
1460 return -2;
1461 }
1462
1463 // Add XR header
1464 rtcpbuffer[pos++]=(WebRtc_UWord8)0x80;
1465 rtcpbuffer[pos++]=(WebRtc_UWord8)207;
1466
1467 WebRtc_UWord32 XRLengthPos = pos;
1468
1469 // handle length later on
1470 pos++;
1471 pos++;
1472
1473 // Add our own SSRC
1474 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
1475 pos += 4;
1476
1477 // Add a VoIP metrics block
1478 rtcpbuffer[pos++]=7;
1479 rtcpbuffer[pos++]=0;
1480 rtcpbuffer[pos++]=0;
1481 rtcpbuffer[pos++]=8;
1482
1483 // Add the remote SSRC
1484 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _remoteSSRC);
1485 pos += 4;
1486
1487 rtcpbuffer[pos++] = _xrVoIPMetric.lossRate;
1488 rtcpbuffer[pos++] = _xrVoIPMetric.discardRate;
1489 rtcpbuffer[pos++] = _xrVoIPMetric.burstDensity;
1490 rtcpbuffer[pos++] = _xrVoIPMetric.gapDensity;
1491
1492 rtcpbuffer[pos++] = (WebRtc_UWord8)(_xrVoIPMetric.burstDuration >> 8);
1493 rtcpbuffer[pos++] = (WebRtc_UWord8)(_xrVoIPMetric.burstDuration);
1494 rtcpbuffer[pos++] = (WebRtc_UWord8)(_xrVoIPMetric.gapDuration >> 8);
1495 rtcpbuffer[pos++] = (WebRtc_UWord8)(_xrVoIPMetric.gapDuration);
1496
1497 rtcpbuffer[pos++] = (WebRtc_UWord8)(_xrVoIPMetric.roundTripDelay >> 8);
1498 rtcpbuffer[pos++] = (WebRtc_UWord8)(_xrVoIPMetric.roundTripDelay);
1499 rtcpbuffer[pos++] = (WebRtc_UWord8)(_xrVoIPMetric.endSystemDelay >> 8);
1500 rtcpbuffer[pos++] = (WebRtc_UWord8)(_xrVoIPMetric.endSystemDelay);
1501
1502 rtcpbuffer[pos++] = _xrVoIPMetric.signalLevel;
1503 rtcpbuffer[pos++] = _xrVoIPMetric.noiseLevel;
1504 rtcpbuffer[pos++] = _xrVoIPMetric.RERL;
1505 rtcpbuffer[pos++] = _xrVoIPMetric.Gmin;
1506
1507 rtcpbuffer[pos++] = _xrVoIPMetric.Rfactor;
1508 rtcpbuffer[pos++] = _xrVoIPMetric.extRfactor;
1509 rtcpbuffer[pos++] = _xrVoIPMetric.MOSLQ;
1510 rtcpbuffer[pos++] = _xrVoIPMetric.MOSCQ;
1511
1512 rtcpbuffer[pos++] = _xrVoIPMetric.RXconfig;
1513 rtcpbuffer[pos++] = 0; // reserved
1514 rtcpbuffer[pos++] = (WebRtc_UWord8)(_xrVoIPMetric.JBnominal >> 8);
1515 rtcpbuffer[pos++] = (WebRtc_UWord8)(_xrVoIPMetric.JBnominal);
1516
1517 rtcpbuffer[pos++] = (WebRtc_UWord8)(_xrVoIPMetric.JBmax >> 8);
1518 rtcpbuffer[pos++] = (WebRtc_UWord8)(_xrVoIPMetric.JBmax);
1519 rtcpbuffer[pos++] = (WebRtc_UWord8)(_xrVoIPMetric.JBabsMax >> 8);
1520 rtcpbuffer[pos++] = (WebRtc_UWord8)(_xrVoIPMetric.JBabsMax);
1521
1522 rtcpbuffer[XRLengthPos]=(WebRtc_UWord8)(0);
1523 rtcpbuffer[XRLengthPos+1]=(WebRtc_UWord8)(10);
1524 return 0;
1525}
1526
1527WebRtc_Word32
1528RTCPSender::SendRTCP(const WebRtc_UWord32 packetTypeFlags,
1529 const WebRtc_Word32 nackSize, // NACK
1530 const WebRtc_UWord16* nackList, // NACK
pwestin@webrtc.org5e954812012-02-10 12:13:12 +00001531 const bool repeat, // FIR
niklase@google.com470e71d2011-07-07 08:21:25 +00001532 const WebRtc_UWord64 pictureID) // SLI & RPSI
1533{
1534 WebRtc_UWord32 rtcpPacketTypeFlags = packetTypeFlags;
1535 WebRtc_UWord32 pos = 0;
1536 WebRtc_UWord8 rtcpbuffer[IP_PACKET_SIZE];
1537
niklase@google.com470e71d2011-07-07 08:21:25 +00001538 do // only to be able to use break :) (and the critsect must be inside its own scope)
1539 {
1540 // collect the received information
1541 RTCPReportBlock received;
1542 bool hasReceived = false;
1543 WebRtc_UWord32 NTPsec = 0;
1544 WebRtc_UWord32 NTPfrac = 0;
xians@webrtc.org8738d272011-11-25 13:43:53 +00001545 bool rtcpCompound = false;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +00001546 WebRtc_UWord32 jitterTransmissionOffset = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001547
xians@webrtc.org8738d272011-11-25 13:43:53 +00001548 {
1549 CriticalSectionScoped lock(_criticalSectionRTCPSender);
1550 if(_method == kRtcpOff)
1551 {
1552 WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id,
1553 "%s invalid state", __FUNCTION__);
1554 return -1;
1555 }
1556 rtcpCompound = (_method == kRtcpCompound) ? true : false;
1557 }
1558
1559 if (rtcpCompound ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001560 rtcpPacketTypeFlags & kRtcpReport ||
1561 rtcpPacketTypeFlags & kRtcpSr ||
1562 rtcpPacketTypeFlags & kRtcpRr)
1563 {
1564 // get statistics from our RTPreceiver outside critsect
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001565 if(_rtpRtcp.ReportBlockStatistics(&received.fractionLost,
1566 &received.cumulativeLost,
1567 &received.extendedHighSeqNum,
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +00001568 &received.jitter,
1569 &jitterTransmissionOffset) == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001570 {
1571 hasReceived = true;
1572
1573 WebRtc_UWord32 lastReceivedRRNTPsecs = 0;
1574 WebRtc_UWord32 lastReceivedRRNTPfrac = 0;
1575 WebRtc_UWord32 remoteSR = 0;
1576
1577 // ok even if we have not received a SR, we will send 0 in that case
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001578 _rtpRtcp.LastReceivedNTP(lastReceivedRRNTPsecs,
1579 lastReceivedRRNTPfrac,
1580 remoteSR);
niklase@google.com470e71d2011-07-07 08:21:25 +00001581
1582 // get our NTP as late as possible to avoid a race
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +00001583 _clock->CurrentNtp(NTPsec, NTPfrac);
niklase@google.com470e71d2011-07-07 08:21:25 +00001584
1585 // Delay since last received report
1586 WebRtc_UWord32 delaySinceLastReceivedSR = 0;
1587 if((lastReceivedRRNTPsecs !=0) || (lastReceivedRRNTPfrac !=0))
1588 {
1589 // get the 16 lowest bits of seconds and the 16 higest bits of fractions
1590 WebRtc_UWord32 now=NTPsec&0x0000FFFF;
1591 now <<=16;
1592 now += (NTPfrac&0xffff0000)>>16;
1593
1594 WebRtc_UWord32 receiveTime = lastReceivedRRNTPsecs&0x0000FFFF;
1595 receiveTime <<=16;
1596 receiveTime += (lastReceivedRRNTPfrac&0xffff0000)>>16;
1597
1598 delaySinceLastReceivedSR = now-receiveTime;
1599 }
1600 received.delaySinceLastSR = delaySinceLastReceivedSR;
1601 received.lastSR = remoteSR;
1602 } else
1603 {
1604 // we need to send our NTP even if we dont have received any reports
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +00001605 _clock->CurrentNtp(NTPsec, NTPfrac);
niklase@google.com470e71d2011-07-07 08:21:25 +00001606 }
1607 }
1608
1609 CriticalSectionScoped lock(_criticalSectionRTCPSender);
1610
1611 if(_TMMBR ) // attach TMMBR to send and receive reports
1612 {
1613 rtcpPacketTypeFlags |= kRtcpTmmbr;
1614 }
1615 if(_appSend)
1616 {
1617 rtcpPacketTypeFlags |= kRtcpApp;
1618 _appSend = false;
1619 }
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001620 if(_REMB && _sendREMB)
1621 {
mflodman@webrtc.org84dc3d12011-12-22 10:26:13 +00001622 // Always attach REMB to SR if that is configured. Note that REMB is
1623 // only sent on one of the RTP modules in the REMB group.
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001624 rtcpPacketTypeFlags |= kRtcpRemb;
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001625 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001626 if(_xrSendVoIPMetric)
1627 {
1628 rtcpPacketTypeFlags |= kRtcpXrVoipMetric;
1629 _xrSendVoIPMetric = false;
1630 }
1631 if(_sendTMMBN) // set when having received a TMMBR
1632 {
1633 rtcpPacketTypeFlags |= kRtcpTmmbn;
1634 _sendTMMBN = false;
1635 }
1636
1637 if(_method == kRtcpCompound)
1638 {
1639 if(_sending)
1640 {
1641 rtcpPacketTypeFlags |= kRtcpSr;
1642 } else
1643 {
1644 rtcpPacketTypeFlags |= kRtcpRr;
1645 }
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +00001646 if (_IJ && hasReceived)
1647 {
1648 rtcpPacketTypeFlags |= kRtcpTransmissionTimeOffset;
1649 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001650 } else if(_method == kRtcpNonCompound)
1651 {
1652 if(rtcpPacketTypeFlags & kRtcpReport)
1653 {
1654 if(_sending)
1655 {
1656 rtcpPacketTypeFlags |= kRtcpSr;
1657 } else
1658 {
1659 rtcpPacketTypeFlags |= kRtcpRr;
1660 }
1661 }
1662 }
1663 if( rtcpPacketTypeFlags & kRtcpRr ||
1664 rtcpPacketTypeFlags & kRtcpSr)
1665 {
1666 // generate next time to send a RTCP report
1667 // seeded from RTP constructor
1668 WebRtc_Word32 random = rand() % 1000;
1669 WebRtc_Word32 timeToNext = RTCP_INTERVAL_AUDIO_MS;
1670
1671 if(_audio)
1672 {
1673 timeToNext = (RTCP_INTERVAL_AUDIO_MS/2) + (RTCP_INTERVAL_AUDIO_MS*random/1000);
1674 }else
1675 {
1676 WebRtc_UWord32 minIntervalMs = RTCP_INTERVAL_AUDIO_MS;
1677 if(_sending)
1678 {
1679 // calc bw for video 360/sendBW in kbit/s
stefan@webrtc.orgd0bdab02011-10-14 14:24:54 +00001680 WebRtc_UWord32 sendBitrateKbit = 0;
stefan@webrtc.orgfbea4e52011-10-27 16:08:29 +00001681 WebRtc_UWord32 videoRate = 0;
stefan@webrtc.orgd0bdab02011-10-14 14:24:54 +00001682 WebRtc_UWord32 fecRate = 0;
1683 WebRtc_UWord32 nackRate = 0;
1684 _rtpRtcp.BitrateSent(&sendBitrateKbit,
stefan@webrtc.orgfbea4e52011-10-27 16:08:29 +00001685 &videoRate,
stefan@webrtc.orgd0bdab02011-10-14 14:24:54 +00001686 &fecRate,
1687 &nackRate);
1688 sendBitrateKbit /= 1000;
niklase@google.com470e71d2011-07-07 08:21:25 +00001689 if(sendBitrateKbit != 0)
1690 {
1691 minIntervalMs = 360000/sendBitrateKbit;
1692 }
1693 }
1694 if(minIntervalMs > RTCP_INTERVAL_VIDEO_MS)
1695 {
1696 minIntervalMs = RTCP_INTERVAL_VIDEO_MS;
1697 }
1698 timeToNext = (minIntervalMs/2) + (minIntervalMs*random/1000);
1699 }
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +00001700 _nextTimeToSendRTCP = _clock->TimeInMilliseconds() + timeToNext;
niklase@google.com470e71d2011-07-07 08:21:25 +00001701 }
1702
1703 // if the data does not fitt in the packet we fill it as much as possible
1704 WebRtc_Word32 buildVal = 0;
1705
1706 if(rtcpPacketTypeFlags & kRtcpSr)
1707 {
1708 if(hasReceived)
1709 {
1710 buildVal = BuildSR(rtcpbuffer, pos, NTPsec, NTPfrac, &received);
1711 } else
1712 {
1713 buildVal = BuildSR(rtcpbuffer, pos, NTPsec, NTPfrac);
1714 }
1715 if(buildVal == -1)
1716 {
1717 return -1; // error
1718
1719 }else if(buildVal == -2)
1720 {
1721 break; // out of buffer
1722 }
1723 buildVal = BuildSDEC(rtcpbuffer, pos);
1724 if(buildVal == -1)
1725 {
1726 return -1; // error
1727
1728 }else if(buildVal == -2)
1729 {
1730 break; // out of buffer
1731 }
1732
1733 }else if(rtcpPacketTypeFlags & kRtcpRr)
1734 {
1735 if(hasReceived)
1736 {
1737 buildVal = BuildRR(rtcpbuffer, pos, NTPsec, NTPfrac,&received);
1738 }else
1739 {
1740 buildVal = BuildRR(rtcpbuffer, pos, NTPsec, NTPfrac);
1741 }
1742 if(buildVal == -1)
1743 {
1744 return -1; // error
1745
1746 }else if(buildVal == -2)
1747 {
1748 break; // out of buffer
1749 }
1750 // only of set
1751 if(_CNAME[0] != 0)
1752 {
1753 buildVal = BuildSDEC(rtcpbuffer, pos);
1754 if(buildVal == -1)
1755 {
1756 return -1; // error
1757 }
1758 }
1759 }
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +00001760 if(rtcpPacketTypeFlags & kRtcpTransmissionTimeOffset)
1761 {
1762 // If present, this RTCP packet must be placed after a
1763 // receiver report.
1764 buildVal = BuildExtendedJitterReport(rtcpbuffer,
1765 pos,
1766 jitterTransmissionOffset);
1767 if(buildVal == -1)
1768 {
1769 return -1; // error
1770 }
1771 else if(buildVal == -2)
1772 {
1773 break; // out of buffer
1774 }
1775 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001776 if(rtcpPacketTypeFlags & kRtcpPli)
1777 {
1778 buildVal = BuildPLI(rtcpbuffer, pos);
1779 if(buildVal == -1)
1780 {
1781 return -1; // error
1782
1783 }else if(buildVal == -2)
1784 {
1785 break; // out of buffer
1786 }
1787 }
1788 if(rtcpPacketTypeFlags & kRtcpFir)
1789 {
pwestin@webrtc.org5e954812012-02-10 12:13:12 +00001790 buildVal = BuildFIR(rtcpbuffer, pos, repeat);
niklase@google.com470e71d2011-07-07 08:21:25 +00001791 if(buildVal == -1)
1792 {
1793 return -1; // error
1794
1795 }else if(buildVal == -2)
1796 {
1797 break; // out of buffer
1798 }
1799 }
1800 if(rtcpPacketTypeFlags & kRtcpSli)
1801 {
1802 buildVal = BuildSLI(rtcpbuffer, pos, (WebRtc_UWord8)pictureID);
1803 if(buildVal == -1)
1804 {
1805 return -1; // error
1806
1807 }else if(buildVal == -2)
1808 {
1809 break; // out of buffer
1810 }
1811 }
1812 if(rtcpPacketTypeFlags & kRtcpRpsi)
1813 {
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001814 const WebRtc_Word8 payloadType = _rtpRtcp.SendPayloadType();
niklase@google.com470e71d2011-07-07 08:21:25 +00001815 if(payloadType == -1)
1816 {
1817 return -1;
1818 }
1819 buildVal = BuildRPSI(rtcpbuffer, pos, pictureID, (WebRtc_UWord8)payloadType);
1820 if(buildVal == -1)
1821 {
1822 return -1; // error
1823
1824 }else if(buildVal == -2)
1825 {
1826 break; // out of buffer
1827 }
1828 }
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001829 if(rtcpPacketTypeFlags & kRtcpRemb)
1830 {
1831 buildVal = BuildREMB(rtcpbuffer, pos);
1832 if(buildVal == -1)
1833 {
1834 return -1; // error
1835
1836 }else if(buildVal == -2)
1837 {
1838 break; // out of buffer
1839 }
1840 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001841 if(rtcpPacketTypeFlags & kRtcpBye)
1842 {
1843 buildVal = BuildBYE(rtcpbuffer, pos);
1844 if(buildVal == -1)
1845 {
1846 return -1; // error
1847
1848 }else if(buildVal == -2)
1849 {
1850 break; // out of buffer
1851 }
1852 }
1853 if(rtcpPacketTypeFlags & kRtcpApp)
1854 {
1855 buildVal = BuildAPP(rtcpbuffer, pos);
1856 if(buildVal == -1)
1857 {
1858 return -1; // error
1859
1860 }else if(buildVal == -2)
1861 {
1862 break; // out of buffer
1863 }
1864 }
1865 if(rtcpPacketTypeFlags & kRtcpTmmbr)
1866 {
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001867 buildVal = BuildTMMBR(rtcpbuffer, pos);
niklase@google.com470e71d2011-07-07 08:21:25 +00001868 if(buildVal == -1)
1869 {
1870 return -1; // error
1871
1872 }else if(buildVal == -2)
1873 {
1874 break; // out of buffer
1875 }
1876 }
1877 if(rtcpPacketTypeFlags & kRtcpTmmbn)
1878 {
1879 buildVal = BuildTMMBN(rtcpbuffer, pos);
1880 if(buildVal == -1)
1881 {
1882 return -1; // error
1883
1884 }else if(buildVal == -2)
1885 {
1886 break; // out of buffer
1887 }
1888 }
1889 if(rtcpPacketTypeFlags & kRtcpNack)
1890 {
1891 buildVal = BuildNACK(rtcpbuffer, pos, nackSize, nackList);
1892 if(buildVal == -1)
1893 {
1894 return -1; // error
1895
1896 }else if(buildVal == -2)
1897 {
1898 break; // out of buffer
1899 }
1900 }
1901 if(rtcpPacketTypeFlags & kRtcpXrVoipMetric)
1902 {
1903 buildVal = BuildVoIPMetric(rtcpbuffer, pos);
1904 if(buildVal == -1)
1905 {
1906 return -1; // error
1907
1908 }else if(buildVal == -2)
1909 {
1910 break; // out of buffer
1911 }
1912 }
1913 }while (false);
pwestin@webrtc.org8edb39d2011-12-22 07:40:33 +00001914 // Sanity don't send empty packets.
1915 if (pos == 0)
1916 {
1917 return -1;
1918 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001919 return SendToNetwork(rtcpbuffer, (WebRtc_UWord16)pos);
1920}
1921
1922WebRtc_Word32
1923RTCPSender::SendToNetwork(const WebRtc_UWord8* dataBuffer,
1924 const WebRtc_UWord16 length)
1925{
1926 CriticalSectionScoped lock(_criticalSectionTransport);
1927 if(_cbTransport)
1928 {
1929 if(_cbTransport->SendRTCPPacket(_id, dataBuffer, length) > 0)
1930 {
1931 return 0;
1932 }
1933 }
1934 return -1;
1935}
1936
1937WebRtc_Word32
1938RTCPSender::SetCSRCStatus(const bool include)
1939{
1940 _includeCSRCs = include;
1941 return 0;
1942}
1943
1944WebRtc_Word32
1945RTCPSender::SetCSRCs(const WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize],
1946 const WebRtc_UWord8 arrLength)
1947{
1948 if(arrLength > kRtpCsrcSize)
1949 {
1950 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", __FUNCTION__);
1951 assert(false);
1952 return -1;
1953 }
1954
1955 CriticalSectionScoped lock(_criticalSectionRTCPSender);
1956
1957 for(int i = 0; i < arrLength;i++)
1958 {
1959 _CSRC[i] = arrOfCSRC[i];
1960 }
1961 _CSRCs = arrLength;
1962 return 0;
1963}
1964
1965WebRtc_Word32
1966RTCPSender::SetApplicationSpecificData(const WebRtc_UWord8 subType,
1967 const WebRtc_UWord32 name,
1968 const WebRtc_UWord8* data,
1969 const WebRtc_UWord16 length)
1970{
1971 if(length %4 != 0)
1972 {
1973 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", __FUNCTION__);
1974 return -1;
1975 }
1976 CriticalSectionScoped lock(_criticalSectionRTCPSender);
1977
1978 if(_appData)
1979 {
1980 delete [] _appData;
1981 }
1982
1983 _appSend = true;
1984 _appSubType = subType;
1985 _appName = name;
1986 _appData = new WebRtc_UWord8[length];
1987 _appLength = length;
1988 memcpy(_appData, data, length);
1989 return 0;
1990}
1991
1992WebRtc_Word32
1993RTCPSender::SetRTCPVoIPMetrics(const RTCPVoIPMetric* VoIPMetric)
1994{
1995 CriticalSectionScoped lock(_criticalSectionRTCPSender);
1996 memcpy(&_xrVoIPMetric, VoIPMetric, sizeof(RTCPVoIPMetric));
1997
1998 _xrSendVoIPMetric = true;
1999 return 0;
2000}
2001
2002// called under critsect _criticalSectionRTCPSender
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002003WebRtc_Word32 RTCPSender::AddReportBlocks(WebRtc_UWord8* rtcpbuffer,
2004 WebRtc_UWord32& pos,
2005 WebRtc_UWord8& numberOfReportBlocks,
2006 const RTCPReportBlock* received,
2007 const WebRtc_UWord32 NTPsec,
2008 const WebRtc_UWord32 NTPfrac) {
2009 // sanity one block
2010 if(pos + 24 >= IP_PACKET_SIZE) {
2011 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
2012 "%s invalid argument", __FUNCTION__);
2013 return -1;
2014 }
2015 numberOfReportBlocks = _reportBlocks.size();
2016 if (received) {
2017 // add our multiple RR to numberOfReportBlocks
2018 numberOfReportBlocks++;
2019 }
2020 if (received) {
2021 // answer to the one that sends to me
2022 _lastRTCPTime[0] = ModuleRTPUtility::ConvertNTPTimeToMS(NTPsec, NTPfrac);
2023
2024 // Remote SSRC
2025 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _remoteSSRC);
2026 pos += 4;
2027
2028 // fraction lost
2029 rtcpbuffer[pos++]=received->fractionLost;
2030
2031 // cumulative loss
2032 ModuleRTPUtility::AssignUWord24ToBuffer(rtcpbuffer+pos,
2033 received->cumulativeLost);
2034 pos += 3;
2035 // extended highest seq_no, contain the highest sequence number received
2036 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos,
2037 received->extendedHighSeqNum);
2038 pos += 4;
2039
2040 //Jitter
2041 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, received->jitter);
2042 pos += 4;
2043
2044 // Last SR timestamp, our NTP time when we received the last report
2045 // This is the value that we read from the send report packet not when we
2046 // received it...
2047 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, received->lastSR);
2048 pos += 4;
2049
2050 // Delay since last received report,time since we received the report
2051 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos,
2052 received->delaySinceLastSR);
2053 pos += 4;
2054 }
2055 if ((pos + _reportBlocks.size() * 24) >= IP_PACKET_SIZE) {
2056 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
2057 "%s invalid argument", __FUNCTION__);
2058 return -1;
2059 }
2060 std::map<WebRtc_UWord32, RTCPReportBlock*>::iterator it =
2061 _reportBlocks.begin();
2062
2063 for (; it != _reportBlocks.end(); it++) {
2064 // we can have multiple report block in a conference
2065 WebRtc_UWord32 remoteSSRC = it->first;
2066 RTCPReportBlock* reportBlock = it->second;
2067 if (reportBlock) {
2068 // Remote SSRC
2069 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, remoteSSRC);
2070 pos += 4;
2071
2072 // fraction lost
2073 rtcpbuffer[pos++] = reportBlock->fractionLost;
2074
2075 // cumulative loss
2076 ModuleRTPUtility::AssignUWord24ToBuffer(rtcpbuffer+pos,
2077 reportBlock->cumulativeLost);
2078 pos += 3;
2079
2080 // extended highest seq_no, contain the highest sequence number received
2081 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos,
2082 reportBlock->extendedHighSeqNum);
2083 pos += 4;
2084
2085 //Jitter
2086 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos,
2087 reportBlock->jitter);
2088 pos += 4;
2089
2090 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos,
2091 reportBlock->lastSR);
2092 pos += 4;
2093
2094 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos,
2095 reportBlock->delaySinceLastSR);
2096 pos += 4;
niklase@google.com470e71d2011-07-07 08:21:25 +00002097 }
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002098 }
2099 return pos;
niklase@google.com470e71d2011-07-07 08:21:25 +00002100}
2101
2102// no callbacks allowed inside this function
2103WebRtc_Word32
2104RTCPSender::SetTMMBN(const TMMBRSet* boundingSet,
2105 const WebRtc_UWord32 maxBitrateKbit)
2106{
2107 CriticalSectionScoped lock(_criticalSectionRTCPSender);
2108
2109 if (0 == _tmmbrHelp.SetTMMBRBoundingSetToSend(boundingSet, maxBitrateKbit))
2110 {
2111 _sendTMMBN = true;
2112 return 0;
2113 }
2114 return -1;
2115}
niklase@google.com470e71d2011-07-07 08:21:25 +00002116} // namespace webrtc