blob: 9fdb1ec8d48160154bdbc097e9a92e356d57aa75 [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"
edjee@google.com79b02892013-04-04 19:43:34 +000021#include "system_wrappers/interface/trace_event.h"
pwestin@webrtc.org741da942011-09-20 13:52:04 +000022
niklase@google.com470e71d2011-07-07 08:21:25 +000023namespace webrtc {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +000024
25using RTCPUtility::RTCPCnameInformation;
26
edjee@google.com79b02892013-04-04 19:43:34 +000027NACKStringBuilder::NACKStringBuilder() :
28 _stream(""), _count(0), _consecutive(false)
29{
30 // Empty.
31}
32
33void NACKStringBuilder::PushNACK(WebRtc_UWord16 nack)
34{
35 if (_count == 0)
36 {
37 _stream << nack;
38 } else if (nack == _prevNack + 1)
39 {
40 _consecutive = true;
41 } else
42 {
43 if (_consecutive)
44 {
45 _stream << "-" << _prevNack;
46 _consecutive = false;
47 }
48 _stream << "," << nack;
49 }
50 _count++;
51 _prevNack = nack;
52}
53
54std::string NACKStringBuilder::GetResult()
55{
56 if (_consecutive)
57 {
58 _stream << "-" << _prevNack;
59 _consecutive = false;
60 }
61 return _stream.str();
62}
63
niklase@google.com470e71d2011-07-07 08:21:25 +000064RTCPSender::RTCPSender(const WebRtc_Word32 id,
65 const bool audio,
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +000066 Clock* clock,
pwestin@webrtc.org741da942011-09-20 13:52:04 +000067 ModuleRtpRtcpImpl* owner) :
niklase@google.com470e71d2011-07-07 08:21:25 +000068 _id(id),
69 _audio(audio),
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +000070 _clock(clock),
niklase@google.com470e71d2011-07-07 08:21:25 +000071 _method(kRtcpOff),
pwestin@webrtc.org741da942011-09-20 13:52:04 +000072 _rtpRtcp(*owner),
henrike@webrtc.org65573f22011-12-13 19:17:27 +000073 _criticalSectionTransport(CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +000074 _cbTransport(NULL),
75
henrike@webrtc.org65573f22011-12-13 19:17:27 +000076 _criticalSectionRTCPSender(CriticalSectionWrapper::CreateCriticalSection()),
niklase@google.com470e71d2011-07-07 08:21:25 +000077 _usingNack(false),
78 _sending(false),
79 _sendTMMBN(false),
pwestin@webrtc.org741da942011-09-20 13:52:04 +000080 _REMB(false),
81 _sendREMB(false),
niklase@google.com470e71d2011-07-07 08:21:25 +000082 _TMMBR(false),
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +000083 _IJ(false),
niklase@google.com470e71d2011-07-07 08:21:25 +000084 _nextTimeToSendRTCP(0),
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +000085 start_timestamp_(0),
86 last_rtp_timestamp_(0),
87 last_frame_capture_time_ms_(-1),
niklase@google.com470e71d2011-07-07 08:21:25 +000088 _SSRC(0),
89 _remoteSSRC(0),
90 _CNAME(),
91 _reportBlocks(),
92 _csrcCNAMEs(),
93
94 _cameraDelayMS(0),
95
96 _lastSendReport(),
97 _lastRTCPTime(),
98
99 _CSRCs(0),
100 _CSRC(),
101 _includeCSRCs(true),
102
103 _sequenceNumberFIR(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000104
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000105 _lengthRembSSRC(0),
106 _sizeRembSSRC(0),
107 _rembSSRC(NULL),
108 _rembBitrate(0),
109
pwestin@webrtc.orgcac78782012-04-05 08:30:10 +0000110 _tmmbrHelp(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000111 _tmmbr_Send(0),
112 _packetOH_Send(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000113
114 _appSend(false),
115 _appSubType(0),
116 _appName(),
117 _appData(NULL),
118 _appLength(0),
119 _xrSendVoIPMetric(false),
edjee@google.com79b02892013-04-04 19:43:34 +0000120 _xrVoIPMetric(),
121 _nackCount(0),
122 _pliCount(0),
123 _fullIntraRequestCount(0)
niklase@google.com470e71d2011-07-07 08:21:25 +0000124{
125 memset(_CNAME, 0, sizeof(_CNAME));
126 memset(_lastSendReport, 0, sizeof(_lastSendReport));
127 memset(_lastRTCPTime, 0, sizeof(_lastRTCPTime));
128
129 WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, id, "%s created", __FUNCTION__);
130}
131
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000132RTCPSender::~RTCPSender() {
133 delete [] _rembSSRC;
134 delete [] _appData;
niklase@google.com470e71d2011-07-07 08:21:25 +0000135
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000136 while (!_reportBlocks.empty()) {
137 std::map<WebRtc_UWord32, RTCPReportBlock*>::iterator it =
138 _reportBlocks.begin();
139 delete it->second;
140 _reportBlocks.erase(it);
141 }
142 while (!_csrcCNAMEs.empty()) {
143 std::map<WebRtc_UWord32, RTCPCnameInformation*>::iterator it =
144 _csrcCNAMEs.begin();
145 delete it->second;
146 _csrcCNAMEs.erase(it);
147 }
148 delete _criticalSectionTransport;
149 delete _criticalSectionRTCPSender;
niklase@google.com470e71d2011-07-07 08:21:25 +0000150
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000151 WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, _id, "%s deleted", __FUNCTION__);
niklase@google.com470e71d2011-07-07 08:21:25 +0000152}
153
154WebRtc_Word32
155RTCPSender::Init()
156{
157 CriticalSectionScoped lock(_criticalSectionRTCPSender);
158
159 _method = kRtcpOff;
160 _cbTransport = NULL;
161 _usingNack = false;
162 _sending = false;
163 _sendTMMBN = false;
164 _TMMBR = false;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000165 _IJ = false;
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000166 _REMB = false;
167 _sendREMB = false;
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000168 last_rtp_timestamp_ = 0;
169 last_frame_capture_time_ms_ = -1;
170 start_timestamp_ = -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000171 _SSRC = 0;
172 _remoteSSRC = 0;
173 _cameraDelayMS = 0;
174 _sequenceNumberFIR = 0;
175 _tmmbr_Send = 0;
176 _packetOH_Send = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000177 _nextTimeToSendRTCP = 0;
178 _CSRCs = 0;
179 _appSend = false;
180 _appSubType = 0;
181
182 if(_appData)
183 {
184 delete [] _appData;
185 _appData = NULL;
186 }
187 _appLength = 0;
188
189 _xrSendVoIPMetric = false;
190
191 memset(&_xrVoIPMetric, 0, sizeof(_xrVoIPMetric));
192 memset(_CNAME, 0, sizeof(_CNAME));
193 memset(_lastSendReport, 0, sizeof(_lastSendReport));
194 memset(_lastRTCPTime, 0, sizeof(_lastRTCPTime));
edjee@google.com79b02892013-04-04 19:43:34 +0000195
196 _nackCount = 0;
197 _pliCount = 0;
198 _fullIntraRequestCount = 0;
199
niklase@google.com470e71d2011-07-07 08:21:25 +0000200 return 0;
201}
202
203void
204RTCPSender::ChangeUniqueId(const WebRtc_Word32 id)
205{
206 _id = id;
207}
208
209WebRtc_Word32
210RTCPSender::RegisterSendTransport(Transport* outgoingTransport)
211{
212 CriticalSectionScoped lock(_criticalSectionTransport);
213 _cbTransport = outgoingTransport;
214 return 0;
215}
216
217RTCPMethod
218RTCPSender::Status() const
219{
220 CriticalSectionScoped lock(_criticalSectionRTCPSender);
221 return _method;
222}
223
224WebRtc_Word32
225RTCPSender::SetRTCPStatus(const RTCPMethod method)
226{
227 CriticalSectionScoped lock(_criticalSectionRTCPSender);
228 if(method != kRtcpOff)
229 {
230 if(_audio)
231 {
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +0000232 _nextTimeToSendRTCP = _clock->TimeInMilliseconds() +
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000233 (RTCP_INTERVAL_AUDIO_MS/2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000234 } else
235 {
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +0000236 _nextTimeToSendRTCP = _clock->TimeInMilliseconds() +
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000237 (RTCP_INTERVAL_VIDEO_MS/2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000238 }
239 }
240 _method = method;
241 return 0;
242}
243
244bool
245RTCPSender::Sending() const
246{
247 CriticalSectionScoped lock(_criticalSectionRTCPSender);
248 return _sending;
249}
250
251WebRtc_Word32
252RTCPSender::SetSendingStatus(const bool sending)
253{
254 bool sendRTCPBye = false;
255 {
256 CriticalSectionScoped lock(_criticalSectionRTCPSender);
257
258 if(_method != kRtcpOff)
259 {
260 if(sending == false && _sending == true)
261 {
262 // Trigger RTCP bye
263 sendRTCPBye = true;
264 }
265 }
266 _sending = sending;
267 }
268 if(sendRTCPBye)
269 {
270 return SendRTCP(kRtcpBye);
271 }
272 return 0;
273}
274
275bool
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000276RTCPSender::REMB() const
277{
278 CriticalSectionScoped lock(_criticalSectionRTCPSender);
279 return _REMB;
280}
281
282WebRtc_Word32
283RTCPSender::SetREMBStatus(const bool enable)
284{
285 CriticalSectionScoped lock(_criticalSectionRTCPSender);
286 _REMB = enable;
287 return 0;
288}
289
290WebRtc_Word32
291RTCPSender::SetREMBData(const WebRtc_UWord32 bitrate,
292 const WebRtc_UWord8 numberOfSSRC,
293 const WebRtc_UWord32* SSRC)
294{
295 CriticalSectionScoped lock(_criticalSectionRTCPSender);
296 _rembBitrate = bitrate;
297
298 if(_sizeRembSSRC < numberOfSSRC)
299 {
300 delete [] _rembSSRC;
301 _rembSSRC = new WebRtc_UWord32[numberOfSSRC];
302 _sizeRembSSRC = numberOfSSRC;
303 }
304
305 _lengthRembSSRC = numberOfSSRC;
306 for (int i = 0; i < numberOfSSRC; i++)
307 {
308 _rembSSRC[i] = SSRC[i];
309 }
mflodman@webrtc.org84dc3d12011-12-22 10:26:13 +0000310 _sendREMB = true;
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000311 return 0;
312}
313
314bool
niklase@google.com470e71d2011-07-07 08:21:25 +0000315RTCPSender::TMMBR() const
316{
317 CriticalSectionScoped lock(_criticalSectionRTCPSender);
318 return _TMMBR;
319}
320
321WebRtc_Word32
322RTCPSender::SetTMMBRStatus(const bool enable)
323{
324 CriticalSectionScoped lock(_criticalSectionRTCPSender);
325 _TMMBR = enable;
326 return 0;
327}
328
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000329bool
330RTCPSender::IJ() const
331{
332 CriticalSectionScoped lock(_criticalSectionRTCPSender);
333 return _IJ;
334}
335
336WebRtc_Word32
337RTCPSender::SetIJStatus(const bool enable)
338{
339 CriticalSectionScoped lock(_criticalSectionRTCPSender);
340 _IJ = enable;
341 return 0;
342}
343
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000344void RTCPSender::SetStartTimestamp(uint32_t start_timestamp) {
345 start_timestamp_ = start_timestamp;
346}
347
348void RTCPSender::SetLastRtpTime(uint32_t rtp_timestamp,
349 int64_t capture_time_ms) {
350 last_rtp_timestamp_ = rtp_timestamp;
351 if (capture_time_ms < 0) {
352 // We don't currently get a capture time from VoiceEngine.
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +0000353 last_frame_capture_time_ms_ = _clock->TimeInMilliseconds();
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000354 } else {
355 last_frame_capture_time_ms_ = capture_time_ms;
356 }
357}
358
niklase@google.com470e71d2011-07-07 08:21:25 +0000359void
360RTCPSender::SetSSRC( const WebRtc_UWord32 ssrc)
361{
362 CriticalSectionScoped lock(_criticalSectionRTCPSender);
363
364 if(_SSRC != 0)
365 {
366 // not first SetSSRC, probably due to a collision
367 // schedule a new RTCP report
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000368 // make sure that we send a RTP packet
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +0000369 _nextTimeToSendRTCP = _clock->TimeInMilliseconds() + 100;
niklase@google.com470e71d2011-07-07 08:21:25 +0000370 }
371 _SSRC = ssrc;
372}
373
374WebRtc_Word32
375RTCPSender::SetRemoteSSRC( const WebRtc_UWord32 ssrc)
376{
377 CriticalSectionScoped lock(_criticalSectionRTCPSender);
378 _remoteSSRC = ssrc;
niklase@google.com470e71d2011-07-07 08:21:25 +0000379 return 0;
380}
381
382WebRtc_Word32
383RTCPSender::SetCameraDelay(const WebRtc_Word32 delayMS)
384{
385 CriticalSectionScoped lock(_criticalSectionRTCPSender);
386 if(delayMS > 1000 || delayMS < -1000)
387 {
388 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument, delay can't be larger than 1 sec", __FUNCTION__);
389 return -1;
390 }
391 _cameraDelayMS = delayMS;
392 return 0;
393}
394
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000395WebRtc_Word32 RTCPSender::CNAME(char cName[RTCP_CNAME_SIZE]) {
396 assert(cName);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000397 CriticalSectionScoped lock(_criticalSectionRTCPSender);
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000398 cName[RTCP_CNAME_SIZE - 1] = 0;
399 strncpy(cName, _CNAME, RTCP_CNAME_SIZE - 1);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000400 return 0;
401}
402
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000403WebRtc_Word32 RTCPSender::SetCNAME(const char cName[RTCP_CNAME_SIZE]) {
tommi@webrtc.orga990e122012-04-26 15:28:22 +0000404 if (!cName)
405 return -1;
406
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000407 CriticalSectionScoped lock(_criticalSectionRTCPSender);
408 _CNAME[RTCP_CNAME_SIZE - 1] = 0;
409 strncpy(_CNAME, cName, RTCP_CNAME_SIZE - 1);
410 return 0;
411}
412
413WebRtc_Word32 RTCPSender::AddMixedCNAME(const WebRtc_UWord32 SSRC,
414 const char cName[RTCP_CNAME_SIZE]) {
415 assert(cName);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000416 CriticalSectionScoped lock(_criticalSectionRTCPSender);
417 if (_csrcCNAMEs.size() >= kRtpCsrcSize) {
418 return -1;
419 }
420 RTCPCnameInformation* ptr = new RTCPCnameInformation();
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000421 ptr->name[RTCP_CNAME_SIZE - 1] = 0;
422 strncpy(ptr->name, cName, RTCP_CNAME_SIZE - 1);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000423 _csrcCNAMEs[SSRC] = ptr;
424 return 0;
425}
426
427WebRtc_Word32 RTCPSender::RemoveMixedCNAME(const WebRtc_UWord32 SSRC) {
428 CriticalSectionScoped lock(_criticalSectionRTCPSender);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000429 std::map<WebRtc_UWord32, RTCPCnameInformation*>::iterator it =
430 _csrcCNAMEs.find(SSRC);
431
432 if (it == _csrcCNAMEs.end()) {
433 return -1;
434 }
435 delete it->second;
436 _csrcCNAMEs.erase(it);
437 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000438}
439
440bool
441RTCPSender::TimeToSendRTCPReport(const bool sendKeyframeBeforeRTP) const
442{
443/*
444 For audio we use a fix 5 sec interval
445
446 For video we use 1 sec interval fo a BW smaller than 360 kbit/s,
447 technicaly we break the max 5% RTCP BW for video below 10 kbit/s but that should be extreamly rare
448
449
450From RFC 3550
451
452 MAX RTCP BW is 5% if the session BW
453 A send report is approximately 65 bytes inc CNAME
454 A report report is approximately 28 bytes
455
456 The RECOMMENDED value for the reduced minimum in seconds is 360
457 divided by the session bandwidth in kilobits/second. This minimum
458 is smaller than 5 seconds for bandwidths greater than 72 kb/s.
459
460 If the participant has not yet sent an RTCP packet (the variable
461 initial is true), the constant Tmin is set to 2.5 seconds, else it
462 is set to 5 seconds.
463
464 The interval between RTCP packets is varied randomly over the
465 range [0.5,1.5] times the calculated interval to avoid unintended
466 synchronization of all participants
467
468 if we send
469 If the participant is a sender (we_sent true), the constant C is
470 set to the average RTCP packet size (avg_rtcp_size) divided by 25%
471 of the RTCP bandwidth (rtcp_bw), and the constant n is set to the
472 number of senders.
473
474 if we receive only
475 If we_sent is not true, the constant C is set
476 to the average RTCP packet size divided by 75% of the RTCP
477 bandwidth. The constant n is set to the number of receivers
478 (members - senders). If the number of senders is greater than
479 25%, senders and receivers are treated together.
480
481 reconsideration NOT required for peer-to-peer
482 "timer reconsideration" is
483 employed. This algorithm implements a simple back-off mechanism
484 which causes users to hold back RTCP packet transmission if the
485 group sizes are increasing.
486
487 n = number of members
488 C = avg_size/(rtcpBW/4)
489
490 3. The deterministic calculated interval Td is set to max(Tmin, n*C).
491
492 4. The calculated interval T is set to a number uniformly distributed
493 between 0.5 and 1.5 times the deterministic calculated interval.
494
495 5. The resulting value of T is divided by e-3/2=1.21828 to compensate
496 for the fact that the timer reconsideration algorithm converges to
497 a value of the RTCP bandwidth below the intended average
498*/
499
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +0000500 WebRtc_Word64 now = _clock->TimeInMilliseconds();
xians@webrtc.org8738d272011-11-25 13:43:53 +0000501
502 CriticalSectionScoped lock(_criticalSectionRTCPSender);
503
niklase@google.com470e71d2011-07-07 08:21:25 +0000504 if(_method == kRtcpOff)
505 {
506 return false;
507 }
508
niklase@google.com470e71d2011-07-07 08:21:25 +0000509 if(!_audio && sendKeyframeBeforeRTP)
510 {
511 // for video key-frames we want to send the RTCP before the large key-frame
512 // if we have a 100 ms margin
513 now += RTCP_SEND_BEFORE_KEY_FRAME_MS;
514 }
515
516 if(now > _nextTimeToSendRTCP)
517 {
518 return true;
519
520 } else if(now < 0x0000ffff && _nextTimeToSendRTCP > 0xffff0000) // 65 sec margin
521 {
522 // wrap
523 return true;
524 }
525 return false;
526}
527
528WebRtc_UWord32
529RTCPSender::LastSendReport( WebRtc_UWord32& lastRTCPTime)
530{
531 CriticalSectionScoped lock(_criticalSectionRTCPSender);
532
533 lastRTCPTime = _lastRTCPTime[0];
534 return _lastSendReport[0];
535}
536
537WebRtc_UWord32
538RTCPSender::SendTimeOfSendReport(const WebRtc_UWord32 sendReport)
539{
540 CriticalSectionScoped lock(_criticalSectionRTCPSender);
541
542 // This is only saved when we are the sender
543 if((_lastSendReport[0] == 0) || (sendReport == 0))
544 {
545 return 0; // will be ignored
546 } else
547 {
548 for(int i = 0; i < RTCP_NUMBER_OF_SR; ++i)
549 {
550 if( _lastSendReport[i] == sendReport)
551 {
552 return _lastRTCPTime[i];
553 }
554 }
555 }
556 return 0;
557}
558
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000559WebRtc_Word32 RTCPSender::AddReportBlock(const WebRtc_UWord32 SSRC,
560 const RTCPReportBlock* reportBlock) {
561 if (reportBlock == NULL) {
562 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
563 "%s invalid argument", __FUNCTION__);
564 return -1;
565 }
566 CriticalSectionScoped lock(_criticalSectionRTCPSender);
niklase@google.com470e71d2011-07-07 08:21:25 +0000567
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000568 if (_reportBlocks.size() >= RTCP_MAX_REPORT_BLOCKS) {
569 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
570 "%s invalid argument", __FUNCTION__);
571 return -1;
572 }
stefan@webrtc.org8d0cd072012-12-03 14:01:46 +0000573 std::map<WebRtc_UWord32, RTCPReportBlock*>::iterator it =
574 _reportBlocks.find(SSRC);
575 if (it != _reportBlocks.end()) {
576 delete it->second;
577 _reportBlocks.erase(it);
578 }
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000579 RTCPReportBlock* copyReportBlock = new RTCPReportBlock();
580 memcpy(copyReportBlock, reportBlock, sizeof(RTCPReportBlock));
581 _reportBlocks[SSRC] = copyReportBlock;
582 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000583}
584
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000585WebRtc_Word32 RTCPSender::RemoveReportBlock(const WebRtc_UWord32 SSRC) {
586 CriticalSectionScoped lock(_criticalSectionRTCPSender);
niklase@google.com470e71d2011-07-07 08:21:25 +0000587
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000588 std::map<WebRtc_UWord32, RTCPReportBlock*>::iterator it =
589 _reportBlocks.find(SSRC);
590
591 if (it == _reportBlocks.end()) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000592 return -1;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000593 }
594 delete it->second;
595 _reportBlocks.erase(it);
596 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000597}
598
599WebRtc_Word32
600RTCPSender::BuildSR(WebRtc_UWord8* rtcpbuffer,
601 WebRtc_UWord32& pos,
602 const WebRtc_UWord32 NTPsec,
603 const WebRtc_UWord32 NTPfrac,
604 const RTCPReportBlock* received)
605{
606 // sanity
607 if(pos + 52 >= IP_PACKET_SIZE)
608 {
609 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", __FUNCTION__);
610 return -2;
611 }
612 WebRtc_UWord32 RTPtime;
niklase@google.com470e71d2011-07-07 08:21:25 +0000613
614 WebRtc_UWord32 posNumberOfReportBlocks = pos;
615 rtcpbuffer[pos++]=(WebRtc_UWord8)0x80;
616
617 // Sender report
618 rtcpbuffer[pos++]=(WebRtc_UWord8)200;
619
620 for(int i = (RTCP_NUMBER_OF_SR-2); i >= 0; i--)
621 {
622 // shift old
623 _lastSendReport[i+1] = _lastSendReport[i];
624 _lastRTCPTime[i+1] =_lastRTCPTime[i];
625 }
626
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000627 _lastRTCPTime[0] = ModuleRTPUtility::ConvertNTPTimeToMS(NTPsec, NTPfrac);
628 _lastSendReport[0] = (NTPsec << 16) + (NTPfrac >> 16);
niklase@google.com470e71d2011-07-07 08:21:25 +0000629
630 WebRtc_UWord32 freqHz = 90000; // For video
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000631 if(_audio) {
632 freqHz = _rtpRtcp.CurrentSendFrequencyHz();
niklase@google.com470e71d2011-07-07 08:21:25 +0000633 }
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000634 // The timestamp of this RTCP packet should be estimated as the timestamp of
635 // the frame being captured at this moment. We are calculating that
636 // timestamp as the last frame's timestamp + the time since the last frame
637 // was captured.
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000638 RTPtime = start_timestamp_ + last_rtp_timestamp_ + (
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +0000639 _clock->TimeInMilliseconds() - last_frame_capture_time_ms_) *
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +0000640 (freqHz / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +0000641
642 // Add sender data
643 // Save for our length field
644 pos++;
645 pos++;
646
647 // Add our own SSRC
648 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
649 pos += 4;
650 // NTP
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000651 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, NTPsec);
niklase@google.com470e71d2011-07-07 08:21:25 +0000652 pos += 4;
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000653 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, NTPfrac);
niklase@google.com470e71d2011-07-07 08:21:25 +0000654 pos += 4;
655 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, RTPtime);
656 pos += 4;
657
658 //sender's packet count
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000659 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _rtpRtcp.PacketCountSent());
niklase@google.com470e71d2011-07-07 08:21:25 +0000660 pos += 4;
661
662 //sender's octet count
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000663 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _rtpRtcp.ByteCountSent());
niklase@google.com470e71d2011-07-07 08:21:25 +0000664 pos += 4;
665
666 WebRtc_UWord8 numberOfReportBlocks = 0;
667 WebRtc_Word32 retVal = AddReportBlocks(rtcpbuffer, pos, numberOfReportBlocks, received, NTPsec, NTPfrac);
668 if(retVal < 0)
669 {
670 //
671 return retVal ;
672 }
673 rtcpbuffer[posNumberOfReportBlocks] += numberOfReportBlocks;
674
675 WebRtc_UWord16 len = WebRtc_UWord16((pos/4) -1);
676 ModuleRTPUtility::AssignUWord16ToBuffer(rtcpbuffer+2, len);
677 return 0;
678}
679
680
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000681WebRtc_Word32 RTCPSender::BuildSDEC(WebRtc_UWord8* rtcpbuffer,
682 WebRtc_UWord32& pos) {
683 size_t lengthCname = strlen(_CNAME);
684 assert(lengthCname < RTCP_CNAME_SIZE);
niklase@google.com470e71d2011-07-07 08:21:25 +0000685
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000686 // sanity
687 if(pos + 12 + lengthCname >= IP_PACKET_SIZE) {
688 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
689 "%s invalid argument", __FUNCTION__);
690 return -2;
691 }
692 // SDEC Source Description
niklase@google.com470e71d2011-07-07 08:21:25 +0000693
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000694 // We always need to add SDES CNAME
695 rtcpbuffer[pos++] = static_cast<WebRtc_UWord8>(0x80 + 1 + _csrcCNAMEs.size());
696 rtcpbuffer[pos++] = static_cast<WebRtc_UWord8>(202);
niklase@google.com470e71d2011-07-07 08:21:25 +0000697
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000698 // handle SDES length later on
699 WebRtc_UWord32 SDESLengthPos = pos;
700 pos++;
701 pos++;
niklase@google.com470e71d2011-07-07 08:21:25 +0000702
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000703 // Add our own SSRC
704 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
705 pos += 4;
706
707 // CNAME = 1
708 rtcpbuffer[pos++] = static_cast<WebRtc_UWord8>(1);
709
710 //
711 rtcpbuffer[pos++] = static_cast<WebRtc_UWord8>(lengthCname);
712
713 WebRtc_UWord16 SDESLength = 10;
714
715 memcpy(&rtcpbuffer[pos], _CNAME, lengthCname);
716 pos += lengthCname;
717 SDESLength += (WebRtc_UWord16)lengthCname;
718
719 WebRtc_UWord16 padding = 0;
720 // We must have a zero field even if we have an even multiple of 4 bytes
721 if ((pos % 4) == 0) {
722 padding++;
723 rtcpbuffer[pos++]=0;
724 }
725 while ((pos % 4) != 0) {
726 padding++;
727 rtcpbuffer[pos++]=0;
728 }
729 SDESLength += padding;
730
731 std::map<WebRtc_UWord32, RTCPUtility::RTCPCnameInformation*>::iterator it =
732 _csrcCNAMEs.begin();
733
734 for(; it != _csrcCNAMEs.end(); it++) {
735 RTCPCnameInformation* cname = it->second;
736 WebRtc_UWord32 SSRC = it->first;
737
738 // Add SSRC
739 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000740 pos += 4;
741
742 // CNAME = 1
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000743 rtcpbuffer[pos++] = static_cast<WebRtc_UWord8>(1);
niklase@google.com470e71d2011-07-07 08:21:25 +0000744
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000745 size_t length = strlen(cname->name);
746 assert(length < RTCP_CNAME_SIZE);
niklase@google.com470e71d2011-07-07 08:21:25 +0000747
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000748 rtcpbuffer[pos++]= static_cast<WebRtc_UWord8>(length);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000749 SDESLength += 6;
niklase@google.com470e71d2011-07-07 08:21:25 +0000750
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000751 memcpy(&rtcpbuffer[pos],cname->name, length);
niklase@google.com470e71d2011-07-07 08:21:25 +0000752
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000753 pos += length;
754 SDESLength += length;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000755 WebRtc_UWord16 padding = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000756
757 // We must have a zero field even if we have an even multiple of 4 bytes
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000758 if((pos % 4) == 0){
759 padding++;
760 rtcpbuffer[pos++]=0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000761 }
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000762 while((pos % 4) != 0){
763 padding++;
764 rtcpbuffer[pos++] = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000765 }
766 SDESLength += padding;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000767 }
768 // in 32-bit words minus one and we don't count the header
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000769 WebRtc_UWord16 buffer_length = (SDESLength / 4) - 1;
770 ModuleRTPUtility::AssignUWord16ToBuffer(rtcpbuffer + SDESLengthPos,
771 buffer_length);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000772 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000773}
774
775WebRtc_Word32
776RTCPSender::BuildRR(WebRtc_UWord8* rtcpbuffer,
777 WebRtc_UWord32& pos,
778 const WebRtc_UWord32 NTPsec,
779 const WebRtc_UWord32 NTPfrac,
780 const RTCPReportBlock* received)
781{
782 // sanity one block
783 if(pos + 32 >= IP_PACKET_SIZE)
784 {
785 return -2;
786 }
787 WebRtc_UWord32 posNumberOfReportBlocks = pos;
788
789 rtcpbuffer[pos++]=(WebRtc_UWord8)0x80;
790 rtcpbuffer[pos++]=(WebRtc_UWord8)201;
791
792 // Save for our length field
793 pos++;
794 pos++;
795
796 // Add our own SSRC
797 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
798 pos += 4;
799
800 WebRtc_UWord8 numberOfReportBlocks = 0;
801 WebRtc_Word32 retVal = AddReportBlocks(rtcpbuffer, pos, numberOfReportBlocks, received, NTPsec, NTPfrac);
802 if(retVal < 0)
803 {
804 return retVal;
805 }
806 rtcpbuffer[posNumberOfReportBlocks] += numberOfReportBlocks;
807
808 WebRtc_UWord16 len = WebRtc_UWord16((pos)/4 -1);
809 ModuleRTPUtility::AssignUWord16ToBuffer(rtcpbuffer+2, len);
810 return 0;
811}
812
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000813// From RFC 5450: Transmission Time Offsets in RTP Streams.
814// 0 1 2 3
815// 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
816// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
817// hdr |V=2|P| RC | PT=IJ=195 | length |
818// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
819// | inter-arrival jitter |
820// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
821// . .
822// . .
823// . .
824// | inter-arrival jitter |
825// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
826//
827// If present, this RTCP packet must be placed after a receiver report
828// (inside a compound RTCP packet), and MUST have the same value for RC
829// (reception report count) as the receiver report.
830
831WebRtc_Word32
832RTCPSender::BuildExtendedJitterReport(
833 WebRtc_UWord8* rtcpbuffer,
834 WebRtc_UWord32& pos,
835 const WebRtc_UWord32 jitterTransmissionTimeOffset)
836{
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000837 if (_reportBlocks.size() > 0)
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000838 {
839 WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id, "Not implemented.");
840 return 0;
841 }
842
843 // sanity
844 if(pos + 8 >= IP_PACKET_SIZE)
845 {
846 return -2;
847 }
848 // add picture loss indicator
849 WebRtc_UWord8 RC = 1;
850 rtcpbuffer[pos++]=(WebRtc_UWord8)0x80 + RC;
851 rtcpbuffer[pos++]=(WebRtc_UWord8)195;
852
853 // Used fixed length of 2
854 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
855 rtcpbuffer[pos++]=(WebRtc_UWord8)(1);
856
857 // Add inter-arrival jitter
858 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer + pos,
859 jitterTransmissionTimeOffset);
860 pos += 4;
861 return 0;
862}
863
niklase@google.com470e71d2011-07-07 08:21:25 +0000864WebRtc_Word32
865RTCPSender::BuildPLI(WebRtc_UWord8* rtcpbuffer, WebRtc_UWord32& pos)
866{
867 // sanity
868 if(pos + 12 >= IP_PACKET_SIZE)
869 {
870 return -2;
871 }
872 // add picture loss indicator
873 WebRtc_UWord8 FMT = 1;
874 rtcpbuffer[pos++]=(WebRtc_UWord8)0x80 + FMT;
875 rtcpbuffer[pos++]=(WebRtc_UWord8)206;
876
877 //Used fixed length of 2
878 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
879 rtcpbuffer[pos++]=(WebRtc_UWord8)(2);
880
881 // Add our own SSRC
882 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
883 pos += 4;
884
885 // Add the remote SSRC
886 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _remoteSSRC);
887 pos += 4;
888 return 0;
889}
890
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000891WebRtc_Word32 RTCPSender::BuildFIR(WebRtc_UWord8* rtcpbuffer,
892 WebRtc_UWord32& pos,
893 bool repeat) {
894 // sanity
895 if(pos + 20 >= IP_PACKET_SIZE) {
896 return -2;
897 }
898 if (!repeat) {
899 _sequenceNumberFIR++; // do not increase if repetition
900 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000901
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000902 // add full intra request indicator
903 WebRtc_UWord8 FMT = 4;
904 rtcpbuffer[pos++] = (WebRtc_UWord8)0x80 + FMT;
905 rtcpbuffer[pos++] = (WebRtc_UWord8)206;
niklase@google.com470e71d2011-07-07 08:21:25 +0000906
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000907 //Length of 4
908 rtcpbuffer[pos++] = (WebRtc_UWord8)0;
909 rtcpbuffer[pos++] = (WebRtc_UWord8)(4);
niklase@google.com470e71d2011-07-07 08:21:25 +0000910
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000911 // Add our own SSRC
912 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
913 pos += 4;
niklase@google.com470e71d2011-07-07 08:21:25 +0000914
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000915 // RFC 5104 4.3.1.2. Semantics
916 // SSRC of media source
917 rtcpbuffer[pos++] = (WebRtc_UWord8)0;
918 rtcpbuffer[pos++] = (WebRtc_UWord8)0;
919 rtcpbuffer[pos++] = (WebRtc_UWord8)0;
920 rtcpbuffer[pos++] = (WebRtc_UWord8)0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000921
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000922 // Additional Feedback Control Information (FCI)
923 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _remoteSSRC);
924 pos += 4;
niklase@google.com470e71d2011-07-07 08:21:25 +0000925
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000926 rtcpbuffer[pos++] = (WebRtc_UWord8)(_sequenceNumberFIR);
927 rtcpbuffer[pos++] = (WebRtc_UWord8)0;
928 rtcpbuffer[pos++] = (WebRtc_UWord8)0;
929 rtcpbuffer[pos++] = (WebRtc_UWord8)0;
930 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000931}
932
933/*
934 0 1 2 3
935 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
936 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
937 | First | Number | PictureID |
938 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
939*/
940WebRtc_Word32
941RTCPSender::BuildSLI(WebRtc_UWord8* rtcpbuffer, WebRtc_UWord32& pos, const WebRtc_UWord8 pictureID)
942{
943 // sanity
944 if(pos + 16 >= IP_PACKET_SIZE)
945 {
946 return -2;
947 }
948 // add slice loss indicator
949 WebRtc_UWord8 FMT = 2;
950 rtcpbuffer[pos++]=(WebRtc_UWord8)0x80 + FMT;
951 rtcpbuffer[pos++]=(WebRtc_UWord8)206;
952
953 //Used fixed length of 3
954 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
955 rtcpbuffer[pos++]=(WebRtc_UWord8)(3);
956
957 // Add our own SSRC
958 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
959 pos += 4;
960
961 // Add the remote SSRC
962 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _remoteSSRC);
963 pos += 4;
964
965 // Add first, number & picture ID 6 bits
966 // first = 0, 13 - bits
967 // number = 0x1fff, 13 - bits only ones for now
968 WebRtc_UWord32 sliField = (0x1fff << 6)+ (0x3f & pictureID);
969 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, sliField);
970 pos += 4;
971 return 0;
972}
973
974/*
975 0 1 2 3
976 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
977 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
978 | PB |0| Payload Type| Native RPSI bit string |
979 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
980 | defined per codec ... | Padding (0) |
981 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
982*/
983/*
984* Note: not generic made for VP8
985*/
986WebRtc_Word32
987RTCPSender::BuildRPSI(WebRtc_UWord8* rtcpbuffer,
988 WebRtc_UWord32& pos,
989 const WebRtc_UWord64 pictureID,
990 const WebRtc_UWord8 payloadType)
991{
992 // sanity
993 if(pos + 24 >= IP_PACKET_SIZE)
994 {
995 return -2;
996 }
997 // add Reference Picture Selection Indication
998 WebRtc_UWord8 FMT = 3;
999 rtcpbuffer[pos++]=(WebRtc_UWord8)0x80 + FMT;
1000 rtcpbuffer[pos++]=(WebRtc_UWord8)206;
1001
1002 // calc length
1003 WebRtc_UWord32 bitsRequired = 7;
1004 WebRtc_UWord8 bytesRequired = 1;
1005 while((pictureID>>bitsRequired) > 0)
1006 {
1007 bitsRequired += 7;
1008 bytesRequired++;
1009 }
1010
1011 WebRtc_UWord8 size = 3;
1012 if(bytesRequired > 6)
1013 {
1014 size = 5;
1015 } else if(bytesRequired > 2)
1016 {
1017 size = 4;
1018 }
1019 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1020 rtcpbuffer[pos++]=size;
1021
1022 // Add our own SSRC
1023 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
1024 pos += 4;
1025
1026 // Add the remote SSRC
1027 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _remoteSSRC);
1028 pos += 4;
1029
1030 // calc padding length
1031 WebRtc_UWord8 paddingBytes = 4-((2+bytesRequired)%4);
1032 if(paddingBytes == 4)
1033 {
1034 paddingBytes = 0;
1035 }
1036 // add padding length in bits
1037 rtcpbuffer[pos] = paddingBytes*8; // padding can be 0, 8, 16 or 24
1038 pos++;
1039
1040 // add payload type
1041 rtcpbuffer[pos] = payloadType;
1042 pos++;
1043
1044 // add picture ID
1045 for(int i = bytesRequired-1; i > 0; i--)
1046 {
1047 rtcpbuffer[pos] = 0x80 | WebRtc_UWord8(pictureID >> (i*7));
1048 pos++;
1049 }
1050 // add last byte of picture ID
1051 rtcpbuffer[pos] = WebRtc_UWord8(pictureID & 0x7f);
1052 pos++;
1053
1054 // add padding
1055 for(int j = 0; j <paddingBytes; j++)
1056 {
1057 rtcpbuffer[pos] = 0;
1058 pos++;
1059 }
1060 return 0;
1061}
1062
1063WebRtc_Word32
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001064RTCPSender::BuildREMB(WebRtc_UWord8* rtcpbuffer, WebRtc_UWord32& pos)
1065{
1066 // sanity
1067 if(pos + 20 + 4 * _lengthRembSSRC >= IP_PACKET_SIZE)
1068 {
1069 return -2;
1070 }
1071 // add application layer feedback
1072 WebRtc_UWord8 FMT = 15;
1073 rtcpbuffer[pos++]=(WebRtc_UWord8)0x80 + FMT;
1074 rtcpbuffer[pos++]=(WebRtc_UWord8)206;
1075
1076 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1077 rtcpbuffer[pos++]=_lengthRembSSRC + 4;
1078
1079 // Add our own SSRC
1080 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
1081 pos += 4;
1082
1083 // Remote SSRC must be 0
1084 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, 0);
1085 pos += 4;
1086
1087 rtcpbuffer[pos++]='R';
1088 rtcpbuffer[pos++]='E';
1089 rtcpbuffer[pos++]='M';
1090 rtcpbuffer[pos++]='B';
1091
1092 rtcpbuffer[pos++] = _lengthRembSSRC;
1093 // 6 bit Exp
1094 // 18 bit mantissa
1095 WebRtc_UWord8 brExp = 0;
1096 for(WebRtc_UWord32 i=0; i<64; i++)
1097 {
1098 if(_rembBitrate <= ((WebRtc_UWord32)262143 << i))
1099 {
1100 brExp = i;
1101 break;
1102 }
1103 }
1104 const WebRtc_UWord32 brMantissa = (_rembBitrate >> brExp);
1105 rtcpbuffer[pos++]=(WebRtc_UWord8)((brExp << 2) + ((brMantissa >> 16) & 0x03));
1106 rtcpbuffer[pos++]=(WebRtc_UWord8)(brMantissa >> 8);
1107 rtcpbuffer[pos++]=(WebRtc_UWord8)(brMantissa);
1108
1109 for (int i = 0; i < _lengthRembSSRC; i++)
1110 {
1111 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _rembSSRC[i]);
1112 pos += 4;
1113 }
edjee@google.com79b02892013-04-04 19:43:34 +00001114 TRACE_COUNTER1("webrtc_rtcp", "Remb", _rembBitrate);
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001115 return 0;
1116}
1117
stefan@webrtc.org9354cc92012-06-07 08:10:14 +00001118void
1119RTCPSender::SetTargetBitrate(unsigned int target_bitrate)
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001120{
mflodman@webrtc.org117c1192012-01-13 08:52:58 +00001121 CriticalSectionScoped lock(_criticalSectionRTCPSender);
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001122 _tmmbr_Send = target_bitrate / 1000;
mflodman@webrtc.org117c1192012-01-13 08:52:58 +00001123}
1124
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001125WebRtc_Word32
1126RTCPSender::BuildTMMBR(WebRtc_UWord8* rtcpbuffer, WebRtc_UWord32& pos)
niklase@google.com470e71d2011-07-07 08:21:25 +00001127{
1128 // Before sending the TMMBR check the received TMMBN, only an owner is allowed to raise the bitrate
1129 // If the sender is an owner of the TMMBN -> send TMMBR
1130 // If not an owner but the TMMBR would enter the TMMBN -> send TMMBR
1131
niklase@google.com470e71d2011-07-07 08:21:25 +00001132 // get current bounding set from RTCP receiver
1133 bool tmmbrOwner = false;
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001134 // store in candidateSet, allocates one extra slot
1135 TMMBRSet* candidateSet = _tmmbrHelp.CandidateSet();
niklase@google.com470e71d2011-07-07 08:21:25 +00001136
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001137 // holding _criticalSectionRTCPSender while calling RTCPreceiver which
1138 // will accuire _criticalSectionRTCPReceiver is a potental deadlock but
1139 // since RTCPreceiver is not doing the reverse we should be fine
1140 WebRtc_Word32 lengthOfBoundingSet
1141 = _rtpRtcp.BoundingSet(tmmbrOwner, candidateSet);
niklase@google.com470e71d2011-07-07 08:21:25 +00001142
1143 if(lengthOfBoundingSet > 0)
1144 {
1145 for (WebRtc_Word32 i = 0; i < lengthOfBoundingSet; i++)
1146 {
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001147 if( candidateSet->Tmmbr(i) == _tmmbr_Send &&
1148 candidateSet->PacketOH(i) == _packetOH_Send)
niklase@google.com470e71d2011-07-07 08:21:25 +00001149 {
1150 // do not send the same tuple
1151 return 0;
1152 }
1153 }
1154 if(!tmmbrOwner)
1155 {
1156 // use received bounding set as candidate set
1157 // add current tuple
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001158 candidateSet->SetEntry(lengthOfBoundingSet,
1159 _tmmbr_Send,
1160 _packetOH_Send,
1161 _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001162 int numCandidates = lengthOfBoundingSet+ 1;
1163
1164 // find bounding set
1165 TMMBRSet* boundingSet = NULL;
1166 int numBoundingSet = _tmmbrHelp.FindTMMBRBoundingSet(boundingSet);
1167 if(numBoundingSet > 0 || numBoundingSet <= numCandidates)
1168 {
1169 tmmbrOwner = _tmmbrHelp.IsOwner(_SSRC, numBoundingSet);
1170 }
1171 if(!tmmbrOwner)
1172 {
1173 // did not enter bounding set, no meaning to send this request
1174 return 0;
1175 }
1176 }
1177 }
1178
1179 if(_tmmbr_Send)
1180 {
1181 // sanity
1182 if(pos + 20 >= IP_PACKET_SIZE)
1183 {
1184 return -2;
1185 }
1186 // add TMMBR indicator
1187 WebRtc_UWord8 FMT = 3;
1188 rtcpbuffer[pos++]=(WebRtc_UWord8)0x80 + FMT;
1189 rtcpbuffer[pos++]=(WebRtc_UWord8)205;
1190
1191 //Length of 4
1192 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1193 rtcpbuffer[pos++]=(WebRtc_UWord8)(4);
1194
1195 // Add our own SSRC
1196 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
1197 pos += 4;
1198
1199 // RFC 5104 4.2.1.2. Semantics
1200
1201 // SSRC of media source
1202 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1203 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1204 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1205 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1206
1207 // Additional Feedback Control Information (FCI)
1208 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _remoteSSRC);
1209 pos += 4;
1210
1211 WebRtc_UWord32 bitRate = _tmmbr_Send*1000;
1212 WebRtc_UWord32 mmbrExp = 0;
1213 for(WebRtc_UWord32 i=0;i<64;i++)
1214 {
1215 if(bitRate <= ((WebRtc_UWord32)131071 << i))
1216 {
1217 mmbrExp = i;
1218 break;
1219 }
1220 }
1221 WebRtc_UWord32 mmbrMantissa = (bitRate >> mmbrExp);
1222
1223 rtcpbuffer[pos++]=(WebRtc_UWord8)((mmbrExp << 2) + ((mmbrMantissa >> 15) & 0x03));
1224 rtcpbuffer[pos++]=(WebRtc_UWord8)(mmbrMantissa >> 7);
1225 rtcpbuffer[pos++]=(WebRtc_UWord8)((mmbrMantissa << 1) + ((_packetOH_Send >> 8)& 0x01));
1226 rtcpbuffer[pos++]=(WebRtc_UWord8)(_packetOH_Send);
1227 }
1228 return 0;
1229}
1230
1231WebRtc_Word32
1232RTCPSender::BuildTMMBN(WebRtc_UWord8* rtcpbuffer, WebRtc_UWord32& pos)
1233{
1234 TMMBRSet* boundingSet = _tmmbrHelp.BoundingSetToSend();
1235 if(boundingSet == NULL)
1236 {
1237 return -1;
1238 }
1239 // sanity
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001240 if(pos + 12 + boundingSet->lengthOfSet()*8 >= IP_PACKET_SIZE)
niklase@google.com470e71d2011-07-07 08:21:25 +00001241 {
1242 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", __FUNCTION__);
1243 return -2;
1244 }
1245 WebRtc_UWord8 FMT = 4;
1246 // add TMMBN indicator
1247 rtcpbuffer[pos++]=(WebRtc_UWord8)0x80 + FMT;
1248 rtcpbuffer[pos++]=(WebRtc_UWord8)205;
1249
1250 //Add length later
1251 int posLength = pos;
1252 pos++;
1253 pos++;
1254
1255 // Add our own SSRC
1256 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
1257 pos += 4;
1258
1259 // RFC 5104 4.2.2.2. Semantics
1260
1261 // SSRC of media source
1262 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1263 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1264 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1265 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1266
1267 // Additional Feedback Control Information (FCI)
1268 int numBoundingSet = 0;
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001269 for(WebRtc_UWord32 n=0; n< boundingSet->lengthOfSet(); n++)
niklase@google.com470e71d2011-07-07 08:21:25 +00001270 {
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001271 if (boundingSet->Tmmbr(n) > 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001272 {
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001273 WebRtc_UWord32 tmmbrSSRC = boundingSet->Ssrc(n);
niklase@google.com470e71d2011-07-07 08:21:25 +00001274 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, tmmbrSSRC);
1275 pos += 4;
1276
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001277 WebRtc_UWord32 bitRate = boundingSet->Tmmbr(n) * 1000;
niklase@google.com470e71d2011-07-07 08:21:25 +00001278 WebRtc_UWord32 mmbrExp = 0;
1279 for(int i=0; i<64; i++)
1280 {
1281 if(bitRate <= ((WebRtc_UWord32)131071 << i))
1282 {
1283 mmbrExp = i;
1284 break;
1285 }
1286 }
1287 WebRtc_UWord32 mmbrMantissa = (bitRate >> mmbrExp);
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001288 WebRtc_UWord32 measuredOH = boundingSet->PacketOH(n);
niklase@google.com470e71d2011-07-07 08:21:25 +00001289
1290 rtcpbuffer[pos++]=(WebRtc_UWord8)((mmbrExp << 2) + ((mmbrMantissa >> 15) & 0x03));
1291 rtcpbuffer[pos++]=(WebRtc_UWord8)(mmbrMantissa >> 7);
1292 rtcpbuffer[pos++]=(WebRtc_UWord8)((mmbrMantissa << 1) + ((measuredOH >> 8)& 0x01));
1293 rtcpbuffer[pos++]=(WebRtc_UWord8)(measuredOH);
1294 numBoundingSet++;
1295 }
1296 }
1297 WebRtc_UWord16 length= (WebRtc_UWord16)(2+2*numBoundingSet);
1298 rtcpbuffer[posLength++]=(WebRtc_UWord8)(length>>8);
1299 rtcpbuffer[posLength]=(WebRtc_UWord8)(length);
1300 return 0;
1301}
1302
1303WebRtc_Word32
1304RTCPSender::BuildAPP(WebRtc_UWord8* rtcpbuffer, WebRtc_UWord32& pos)
1305{
1306 // sanity
1307 if(_appData == NULL)
1308 {
1309 WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id, "%s invalid state", __FUNCTION__);
1310 return -1;
1311 }
1312 if(pos + 12 + _appLength >= IP_PACKET_SIZE)
1313 {
1314 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", __FUNCTION__);
1315 return -2;
1316 }
1317 rtcpbuffer[pos++]=(WebRtc_UWord8)0x80 + _appSubType;
1318
1319 // Add APP ID
1320 rtcpbuffer[pos++]=(WebRtc_UWord8)204;
1321
1322 WebRtc_UWord16 length = (_appLength>>2) + 2; // include SSRC and name
1323 rtcpbuffer[pos++]=(WebRtc_UWord8)(length>>8);
1324 rtcpbuffer[pos++]=(WebRtc_UWord8)(length);
1325
1326 // Add our own SSRC
1327 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
1328 pos += 4;
1329
1330 // Add our application name
1331 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _appName);
1332 pos += 4;
1333
1334 // Add the data
1335 memcpy(rtcpbuffer +pos, _appData,_appLength);
1336 pos += _appLength;
1337 return 0;
1338}
1339
1340WebRtc_Word32
1341RTCPSender::BuildNACK(WebRtc_UWord8* rtcpbuffer,
1342 WebRtc_UWord32& pos,
1343 const WebRtc_Word32 nackSize,
edjee@google.com79b02892013-04-04 19:43:34 +00001344 const WebRtc_UWord16* nackList,
1345 std::string* nackString)
niklase@google.com470e71d2011-07-07 08:21:25 +00001346{
1347 // sanity
1348 if(pos + 16 >= IP_PACKET_SIZE)
1349 {
1350 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", __FUNCTION__);
1351 return -2;
1352 }
1353
1354 // int size, WebRtc_UWord16* nackList
1355 // add nack list
1356 WebRtc_UWord8 FMT = 1;
1357 rtcpbuffer[pos++]=(WebRtc_UWord8)0x80 + FMT;
1358 rtcpbuffer[pos++]=(WebRtc_UWord8)205;
1359
1360 rtcpbuffer[pos++]=(WebRtc_UWord8) 0;
1361 int nackSizePos = pos;
1362 rtcpbuffer[pos++]=(WebRtc_UWord8)(3); //setting it to one kNACK signal as default
1363
1364 // Add our own SSRC
1365 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
1366 pos += 4;
1367
1368 // Add the remote SSRC
1369 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _remoteSSRC);
1370 pos += 4;
1371
1372 // add the list
1373 int i = 0;
1374 int numOfNackFields = 0;
edjee@google.com79b02892013-04-04 19:43:34 +00001375 NACKStringBuilder stringBuilder;
stefan@webrtc.orga2710702013-03-05 09:02:06 +00001376 while (nackSize > i && numOfNackFields < kRtcpMaxNackFields)
niklase@google.com470e71d2011-07-07 08:21:25 +00001377 {
1378 WebRtc_UWord16 nack = nackList[i];
1379 // put dow our sequence number
1380 ModuleRTPUtility::AssignUWord16ToBuffer(rtcpbuffer+pos, nack);
1381 pos += 2;
edjee@google.com79b02892013-04-04 19:43:34 +00001382 stringBuilder.PushNACK(nack);
niklase@google.com470e71d2011-07-07 08:21:25 +00001383
1384 i++;
1385 numOfNackFields++;
1386 if(nackSize > i)
1387 {
1388 bool moreThan16Away = (WebRtc_UWord16(nack+16) < nackList[i])?true: false;
1389 if(!moreThan16Away)
1390 {
1391 // check for a wrap
1392 if(WebRtc_UWord16(nack+16) > 0xff00 && nackList[i] < 0x0fff)
1393 {
1394 // wrap
1395 moreThan16Away = true;
1396 }
1397 }
1398 if(moreThan16Away)
1399 {
1400 // next is more than 16 away
1401 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1402 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1403 } else
1404 {
1405 // build our bitmask
1406 WebRtc_UWord16 bitmask = 0;
1407
1408 bool within16Away = (WebRtc_UWord16(nack+16) > nackList[i])?true: false;
1409 if(within16Away)
1410 {
1411 // check for a wrap
1412 if(WebRtc_UWord16(nack+16) > 0xff00 && nackList[i] < 0x0fff)
1413 {
1414 // wrap
1415 within16Away = false;
1416 }
1417 }
1418
1419 while( nackSize > i && within16Away)
1420 {
1421 WebRtc_Word16 shift = (nackList[i]-nack)-1;
1422 assert(!(shift > 15) && !(shift < 0));
1423
1424 bitmask += (1<< shift);
edjee@google.com79b02892013-04-04 19:43:34 +00001425 stringBuilder.PushNACK(nackList[i]);
niklase@google.com470e71d2011-07-07 08:21:25 +00001426 i++;
1427 if(nackSize > i)
1428 {
1429 within16Away = (WebRtc_UWord16(nack+16) > nackList[i])?true: false;
1430 if(within16Away)
1431 {
1432 // check for a wrap
1433 if(WebRtc_UWord16(nack+16) > 0xff00 && nackList[i] < 0x0fff)
1434 {
1435 // wrap
1436 within16Away = false;
1437 }
1438 }
1439 }
1440 }
1441 ModuleRTPUtility::AssignUWord16ToBuffer(rtcpbuffer+pos, bitmask);
1442 pos += 2;
1443 }
1444 // sanity do we have room from one more 4 byte block?
1445 if(pos + 4 >= IP_PACKET_SIZE)
1446 {
1447 return -2;
1448 }
1449 } else
1450 {
1451 // no more in the list
1452 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1453 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1454 }
1455 }
1456 rtcpbuffer[nackSizePos]=(WebRtc_UWord8)(2+numOfNackFields);
edjee@google.com79b02892013-04-04 19:43:34 +00001457 *nackString = stringBuilder.GetResult();
niklase@google.com470e71d2011-07-07 08:21:25 +00001458 return 0;
1459}
1460
1461WebRtc_Word32
1462RTCPSender::BuildBYE(WebRtc_UWord8* rtcpbuffer, WebRtc_UWord32& pos)
1463{
1464 // sanity
1465 if(pos + 8 >= IP_PACKET_SIZE)
1466 {
1467 return -2;
1468 }
1469 if(_includeCSRCs)
1470 {
1471 // Add a bye packet
1472 rtcpbuffer[pos++]=(WebRtc_UWord8)0x80 + 1 + _CSRCs; // number of SSRC+CSRCs
1473 rtcpbuffer[pos++]=(WebRtc_UWord8)203;
1474
1475 // length
1476 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1477 rtcpbuffer[pos++]=(WebRtc_UWord8)(1 + _CSRCs);
1478
1479 // Add our own SSRC
1480 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
1481 pos += 4;
1482
1483 // add CSRCs
1484 for(int i = 0; i < _CSRCs; i++)
1485 {
1486 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _CSRC[i]);
1487 pos += 4;
1488 }
1489 } else
1490 {
1491 // Add a bye packet
1492 rtcpbuffer[pos++]=(WebRtc_UWord8)0x80 + 1; // number of SSRC+CSRCs
1493 rtcpbuffer[pos++]=(WebRtc_UWord8)203;
1494
1495 // length
1496 rtcpbuffer[pos++]=(WebRtc_UWord8)0;
1497 rtcpbuffer[pos++]=(WebRtc_UWord8)1;
1498
1499 // Add our own SSRC
1500 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
1501 pos += 4;
1502 }
1503 return 0;
1504}
1505
1506WebRtc_Word32
1507RTCPSender::BuildVoIPMetric(WebRtc_UWord8* rtcpbuffer, WebRtc_UWord32& pos)
1508{
1509 // sanity
1510 if(pos + 44 >= IP_PACKET_SIZE)
1511 {
1512 return -2;
1513 }
1514
1515 // Add XR header
1516 rtcpbuffer[pos++]=(WebRtc_UWord8)0x80;
1517 rtcpbuffer[pos++]=(WebRtc_UWord8)207;
1518
1519 WebRtc_UWord32 XRLengthPos = pos;
1520
1521 // handle length later on
1522 pos++;
1523 pos++;
1524
1525 // Add our own SSRC
1526 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
1527 pos += 4;
1528
1529 // Add a VoIP metrics block
1530 rtcpbuffer[pos++]=7;
1531 rtcpbuffer[pos++]=0;
1532 rtcpbuffer[pos++]=0;
1533 rtcpbuffer[pos++]=8;
1534
1535 // Add the remote SSRC
1536 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _remoteSSRC);
1537 pos += 4;
1538
1539 rtcpbuffer[pos++] = _xrVoIPMetric.lossRate;
1540 rtcpbuffer[pos++] = _xrVoIPMetric.discardRate;
1541 rtcpbuffer[pos++] = _xrVoIPMetric.burstDensity;
1542 rtcpbuffer[pos++] = _xrVoIPMetric.gapDensity;
1543
1544 rtcpbuffer[pos++] = (WebRtc_UWord8)(_xrVoIPMetric.burstDuration >> 8);
1545 rtcpbuffer[pos++] = (WebRtc_UWord8)(_xrVoIPMetric.burstDuration);
1546 rtcpbuffer[pos++] = (WebRtc_UWord8)(_xrVoIPMetric.gapDuration >> 8);
1547 rtcpbuffer[pos++] = (WebRtc_UWord8)(_xrVoIPMetric.gapDuration);
1548
1549 rtcpbuffer[pos++] = (WebRtc_UWord8)(_xrVoIPMetric.roundTripDelay >> 8);
1550 rtcpbuffer[pos++] = (WebRtc_UWord8)(_xrVoIPMetric.roundTripDelay);
1551 rtcpbuffer[pos++] = (WebRtc_UWord8)(_xrVoIPMetric.endSystemDelay >> 8);
1552 rtcpbuffer[pos++] = (WebRtc_UWord8)(_xrVoIPMetric.endSystemDelay);
1553
1554 rtcpbuffer[pos++] = _xrVoIPMetric.signalLevel;
1555 rtcpbuffer[pos++] = _xrVoIPMetric.noiseLevel;
1556 rtcpbuffer[pos++] = _xrVoIPMetric.RERL;
1557 rtcpbuffer[pos++] = _xrVoIPMetric.Gmin;
1558
1559 rtcpbuffer[pos++] = _xrVoIPMetric.Rfactor;
1560 rtcpbuffer[pos++] = _xrVoIPMetric.extRfactor;
1561 rtcpbuffer[pos++] = _xrVoIPMetric.MOSLQ;
1562 rtcpbuffer[pos++] = _xrVoIPMetric.MOSCQ;
1563
1564 rtcpbuffer[pos++] = _xrVoIPMetric.RXconfig;
1565 rtcpbuffer[pos++] = 0; // reserved
1566 rtcpbuffer[pos++] = (WebRtc_UWord8)(_xrVoIPMetric.JBnominal >> 8);
1567 rtcpbuffer[pos++] = (WebRtc_UWord8)(_xrVoIPMetric.JBnominal);
1568
1569 rtcpbuffer[pos++] = (WebRtc_UWord8)(_xrVoIPMetric.JBmax >> 8);
1570 rtcpbuffer[pos++] = (WebRtc_UWord8)(_xrVoIPMetric.JBmax);
1571 rtcpbuffer[pos++] = (WebRtc_UWord8)(_xrVoIPMetric.JBabsMax >> 8);
1572 rtcpbuffer[pos++] = (WebRtc_UWord8)(_xrVoIPMetric.JBabsMax);
1573
1574 rtcpbuffer[XRLengthPos]=(WebRtc_UWord8)(0);
1575 rtcpbuffer[XRLengthPos+1]=(WebRtc_UWord8)(10);
1576 return 0;
1577}
1578
1579WebRtc_Word32
1580RTCPSender::SendRTCP(const WebRtc_UWord32 packetTypeFlags,
1581 const WebRtc_Word32 nackSize, // NACK
1582 const WebRtc_UWord16* nackList, // NACK
pwestin@webrtc.org5e954812012-02-10 12:13:12 +00001583 const bool repeat, // FIR
niklase@google.com470e71d2011-07-07 08:21:25 +00001584 const WebRtc_UWord64 pictureID) // SLI & RPSI
1585{
1586 WebRtc_UWord32 rtcpPacketTypeFlags = packetTypeFlags;
1587 WebRtc_UWord32 pos = 0;
1588 WebRtc_UWord8 rtcpbuffer[IP_PACKET_SIZE];
1589
niklase@google.com470e71d2011-07-07 08:21:25 +00001590 do // only to be able to use break :) (and the critsect must be inside its own scope)
1591 {
1592 // collect the received information
1593 RTCPReportBlock received;
1594 bool hasReceived = false;
1595 WebRtc_UWord32 NTPsec = 0;
1596 WebRtc_UWord32 NTPfrac = 0;
xians@webrtc.org8738d272011-11-25 13:43:53 +00001597 bool rtcpCompound = false;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +00001598 WebRtc_UWord32 jitterTransmissionOffset = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001599
xians@webrtc.org8738d272011-11-25 13:43:53 +00001600 {
1601 CriticalSectionScoped lock(_criticalSectionRTCPSender);
1602 if(_method == kRtcpOff)
1603 {
1604 WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id,
1605 "%s invalid state", __FUNCTION__);
1606 return -1;
1607 }
1608 rtcpCompound = (_method == kRtcpCompound) ? true : false;
1609 }
1610
1611 if (rtcpCompound ||
niklase@google.com470e71d2011-07-07 08:21:25 +00001612 rtcpPacketTypeFlags & kRtcpReport ||
1613 rtcpPacketTypeFlags & kRtcpSr ||
1614 rtcpPacketTypeFlags & kRtcpRr)
1615 {
1616 // get statistics from our RTPreceiver outside critsect
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001617 if(_rtpRtcp.ReportBlockStatistics(&received.fractionLost,
1618 &received.cumulativeLost,
1619 &received.extendedHighSeqNum,
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +00001620 &received.jitter,
1621 &jitterTransmissionOffset) == 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001622 {
1623 hasReceived = true;
1624
1625 WebRtc_UWord32 lastReceivedRRNTPsecs = 0;
1626 WebRtc_UWord32 lastReceivedRRNTPfrac = 0;
1627 WebRtc_UWord32 remoteSR = 0;
1628
1629 // ok even if we have not received a SR, we will send 0 in that case
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001630 _rtpRtcp.LastReceivedNTP(lastReceivedRRNTPsecs,
1631 lastReceivedRRNTPfrac,
1632 remoteSR);
niklase@google.com470e71d2011-07-07 08:21:25 +00001633
1634 // get our NTP as late as possible to avoid a race
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +00001635 _clock->CurrentNtp(NTPsec, NTPfrac);
niklase@google.com470e71d2011-07-07 08:21:25 +00001636
1637 // Delay since last received report
1638 WebRtc_UWord32 delaySinceLastReceivedSR = 0;
1639 if((lastReceivedRRNTPsecs !=0) || (lastReceivedRRNTPfrac !=0))
1640 {
1641 // get the 16 lowest bits of seconds and the 16 higest bits of fractions
1642 WebRtc_UWord32 now=NTPsec&0x0000FFFF;
1643 now <<=16;
1644 now += (NTPfrac&0xffff0000)>>16;
1645
1646 WebRtc_UWord32 receiveTime = lastReceivedRRNTPsecs&0x0000FFFF;
1647 receiveTime <<=16;
1648 receiveTime += (lastReceivedRRNTPfrac&0xffff0000)>>16;
1649
1650 delaySinceLastReceivedSR = now-receiveTime;
1651 }
1652 received.delaySinceLastSR = delaySinceLastReceivedSR;
1653 received.lastSR = remoteSR;
1654 } else
1655 {
1656 // we need to send our NTP even if we dont have received any reports
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +00001657 _clock->CurrentNtp(NTPsec, NTPfrac);
niklase@google.com470e71d2011-07-07 08:21:25 +00001658 }
1659 }
1660
1661 CriticalSectionScoped lock(_criticalSectionRTCPSender);
1662
1663 if(_TMMBR ) // attach TMMBR to send and receive reports
1664 {
1665 rtcpPacketTypeFlags |= kRtcpTmmbr;
1666 }
1667 if(_appSend)
1668 {
1669 rtcpPacketTypeFlags |= kRtcpApp;
1670 _appSend = false;
1671 }
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001672 if(_REMB && _sendREMB)
1673 {
mflodman@webrtc.org84dc3d12011-12-22 10:26:13 +00001674 // Always attach REMB to SR if that is configured. Note that REMB is
1675 // only sent on one of the RTP modules in the REMB group.
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001676 rtcpPacketTypeFlags |= kRtcpRemb;
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001677 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001678 if(_xrSendVoIPMetric)
1679 {
1680 rtcpPacketTypeFlags |= kRtcpXrVoipMetric;
1681 _xrSendVoIPMetric = false;
1682 }
1683 if(_sendTMMBN) // set when having received a TMMBR
1684 {
1685 rtcpPacketTypeFlags |= kRtcpTmmbn;
1686 _sendTMMBN = false;
1687 }
1688
1689 if(_method == kRtcpCompound)
1690 {
1691 if(_sending)
1692 {
1693 rtcpPacketTypeFlags |= kRtcpSr;
1694 } else
1695 {
1696 rtcpPacketTypeFlags |= kRtcpRr;
1697 }
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +00001698 if (_IJ && hasReceived)
1699 {
1700 rtcpPacketTypeFlags |= kRtcpTransmissionTimeOffset;
1701 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001702 } else if(_method == kRtcpNonCompound)
1703 {
1704 if(rtcpPacketTypeFlags & kRtcpReport)
1705 {
1706 if(_sending)
1707 {
1708 rtcpPacketTypeFlags |= kRtcpSr;
1709 } else
1710 {
1711 rtcpPacketTypeFlags |= kRtcpRr;
1712 }
1713 }
1714 }
1715 if( rtcpPacketTypeFlags & kRtcpRr ||
1716 rtcpPacketTypeFlags & kRtcpSr)
1717 {
1718 // generate next time to send a RTCP report
1719 // seeded from RTP constructor
1720 WebRtc_Word32 random = rand() % 1000;
1721 WebRtc_Word32 timeToNext = RTCP_INTERVAL_AUDIO_MS;
1722
1723 if(_audio)
1724 {
1725 timeToNext = (RTCP_INTERVAL_AUDIO_MS/2) + (RTCP_INTERVAL_AUDIO_MS*random/1000);
1726 }else
1727 {
1728 WebRtc_UWord32 minIntervalMs = RTCP_INTERVAL_AUDIO_MS;
1729 if(_sending)
1730 {
1731 // calc bw for video 360/sendBW in kbit/s
stefan@webrtc.orgd0bdab02011-10-14 14:24:54 +00001732 WebRtc_UWord32 sendBitrateKbit = 0;
stefan@webrtc.orgfbea4e52011-10-27 16:08:29 +00001733 WebRtc_UWord32 videoRate = 0;
stefan@webrtc.orgd0bdab02011-10-14 14:24:54 +00001734 WebRtc_UWord32 fecRate = 0;
1735 WebRtc_UWord32 nackRate = 0;
1736 _rtpRtcp.BitrateSent(&sendBitrateKbit,
stefan@webrtc.orgfbea4e52011-10-27 16:08:29 +00001737 &videoRate,
stefan@webrtc.orgd0bdab02011-10-14 14:24:54 +00001738 &fecRate,
1739 &nackRate);
1740 sendBitrateKbit /= 1000;
niklase@google.com470e71d2011-07-07 08:21:25 +00001741 if(sendBitrateKbit != 0)
1742 {
1743 minIntervalMs = 360000/sendBitrateKbit;
1744 }
1745 }
1746 if(minIntervalMs > RTCP_INTERVAL_VIDEO_MS)
1747 {
1748 minIntervalMs = RTCP_INTERVAL_VIDEO_MS;
1749 }
1750 timeToNext = (minIntervalMs/2) + (minIntervalMs*random/1000);
1751 }
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +00001752 _nextTimeToSendRTCP = _clock->TimeInMilliseconds() + timeToNext;
niklase@google.com470e71d2011-07-07 08:21:25 +00001753 }
1754
1755 // if the data does not fitt in the packet we fill it as much as possible
1756 WebRtc_Word32 buildVal = 0;
1757
1758 if(rtcpPacketTypeFlags & kRtcpSr)
1759 {
1760 if(hasReceived)
1761 {
1762 buildVal = BuildSR(rtcpbuffer, pos, NTPsec, NTPfrac, &received);
1763 } else
1764 {
1765 buildVal = BuildSR(rtcpbuffer, pos, NTPsec, NTPfrac);
1766 }
1767 if(buildVal == -1)
1768 {
1769 return -1; // error
1770
1771 }else if(buildVal == -2)
1772 {
1773 break; // out of buffer
1774 }
1775 buildVal = BuildSDEC(rtcpbuffer, pos);
1776 if(buildVal == -1)
1777 {
1778 return -1; // error
1779
1780 }else if(buildVal == -2)
1781 {
1782 break; // out of buffer
1783 }
1784
1785 }else if(rtcpPacketTypeFlags & kRtcpRr)
1786 {
1787 if(hasReceived)
1788 {
1789 buildVal = BuildRR(rtcpbuffer, pos, NTPsec, NTPfrac,&received);
1790 }else
1791 {
1792 buildVal = BuildRR(rtcpbuffer, pos, NTPsec, NTPfrac);
1793 }
1794 if(buildVal == -1)
1795 {
1796 return -1; // error
1797
1798 }else if(buildVal == -2)
1799 {
1800 break; // out of buffer
1801 }
1802 // only of set
1803 if(_CNAME[0] != 0)
1804 {
1805 buildVal = BuildSDEC(rtcpbuffer, pos);
1806 if(buildVal == -1)
1807 {
1808 return -1; // error
1809 }
1810 }
1811 }
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +00001812 if(rtcpPacketTypeFlags & kRtcpTransmissionTimeOffset)
1813 {
1814 // If present, this RTCP packet must be placed after a
1815 // receiver report.
1816 buildVal = BuildExtendedJitterReport(rtcpbuffer,
1817 pos,
1818 jitterTransmissionOffset);
1819 if(buildVal == -1)
1820 {
1821 return -1; // error
1822 }
1823 else if(buildVal == -2)
1824 {
1825 break; // out of buffer
1826 }
1827 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001828 if(rtcpPacketTypeFlags & kRtcpPli)
1829 {
1830 buildVal = BuildPLI(rtcpbuffer, pos);
1831 if(buildVal == -1)
1832 {
1833 return -1; // error
1834
1835 }else if(buildVal == -2)
1836 {
1837 break; // out of buffer
1838 }
edjee@google.com79b02892013-04-04 19:43:34 +00001839 TRACE_EVENT_INSTANT1("webrtc_rtcp", "SendRTCP", "type", "pli");
1840 _pliCount++;
1841 TRACE_COUNTER1("webrtc_rtcp", "PLI Count", _pliCount);
niklase@google.com470e71d2011-07-07 08:21:25 +00001842 }
1843 if(rtcpPacketTypeFlags & kRtcpFir)
1844 {
pwestin@webrtc.org5e954812012-02-10 12:13:12 +00001845 buildVal = BuildFIR(rtcpbuffer, pos, repeat);
niklase@google.com470e71d2011-07-07 08:21:25 +00001846 if(buildVal == -1)
1847 {
1848 return -1; // error
1849
1850 }else if(buildVal == -2)
1851 {
1852 break; // out of buffer
1853 }
edjee@google.com79b02892013-04-04 19:43:34 +00001854 TRACE_EVENT_INSTANT1("webrtc_rtcp", "SendRTCP", "type", "fir");
1855 _fullIntraRequestCount++;
1856 TRACE_COUNTER1("webrtc_rtcp", "FIR Count", _fullIntraRequestCount);
niklase@google.com470e71d2011-07-07 08:21:25 +00001857 }
1858 if(rtcpPacketTypeFlags & kRtcpSli)
1859 {
1860 buildVal = BuildSLI(rtcpbuffer, pos, (WebRtc_UWord8)pictureID);
1861 if(buildVal == -1)
1862 {
1863 return -1; // error
1864
1865 }else if(buildVal == -2)
1866 {
1867 break; // out of buffer
1868 }
1869 }
1870 if(rtcpPacketTypeFlags & kRtcpRpsi)
1871 {
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001872 const WebRtc_Word8 payloadType = _rtpRtcp.SendPayloadType();
niklase@google.com470e71d2011-07-07 08:21:25 +00001873 if(payloadType == -1)
1874 {
1875 return -1;
1876 }
1877 buildVal = BuildRPSI(rtcpbuffer, pos, pictureID, (WebRtc_UWord8)payloadType);
1878 if(buildVal == -1)
1879 {
1880 return -1; // error
1881
1882 }else if(buildVal == -2)
1883 {
1884 break; // out of buffer
1885 }
1886 }
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001887 if(rtcpPacketTypeFlags & kRtcpRemb)
1888 {
1889 buildVal = BuildREMB(rtcpbuffer, pos);
1890 if(buildVal == -1)
1891 {
1892 return -1; // error
1893
1894 }else if(buildVal == -2)
1895 {
1896 break; // out of buffer
1897 }
edjee@google.com79b02892013-04-04 19:43:34 +00001898 TRACE_EVENT_INSTANT2("webrtc_rtcp", "SendRTCP", "type", "remb",
1899 "bitrate", _rembBitrate);
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001900 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001901 if(rtcpPacketTypeFlags & kRtcpBye)
1902 {
1903 buildVal = BuildBYE(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 if(rtcpPacketTypeFlags & kRtcpApp)
1914 {
1915 buildVal = BuildAPP(rtcpbuffer, pos);
1916 if(buildVal == -1)
1917 {
1918 return -1; // error
1919
1920 }else if(buildVal == -2)
1921 {
1922 break; // out of buffer
1923 }
1924 }
1925 if(rtcpPacketTypeFlags & kRtcpTmmbr)
1926 {
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001927 buildVal = BuildTMMBR(rtcpbuffer, pos);
niklase@google.com470e71d2011-07-07 08:21:25 +00001928 if(buildVal == -1)
1929 {
1930 return -1; // error
1931
1932 }else if(buildVal == -2)
1933 {
1934 break; // out of buffer
1935 }
1936 }
1937 if(rtcpPacketTypeFlags & kRtcpTmmbn)
1938 {
1939 buildVal = BuildTMMBN(rtcpbuffer, pos);
1940 if(buildVal == -1)
1941 {
1942 return -1; // error
1943
1944 }else if(buildVal == -2)
1945 {
1946 break; // out of buffer
1947 }
1948 }
1949 if(rtcpPacketTypeFlags & kRtcpNack)
1950 {
edjee@google.com79b02892013-04-04 19:43:34 +00001951 std::string nackString;
1952 buildVal = BuildNACK(rtcpbuffer, pos, nackSize, nackList,
1953 &nackString);
niklase@google.com470e71d2011-07-07 08:21:25 +00001954 if(buildVal == -1)
1955 {
1956 return -1; // error
1957
1958 }else if(buildVal == -2)
1959 {
1960 break; // out of buffer
1961 }
edjee@google.com79b02892013-04-04 19:43:34 +00001962 TRACE_EVENT_INSTANT2("webrtc_rtcp", "SendRTCP", "type", "nack",
1963 "list", TRACE_STR_COPY(nackString.c_str()));
1964 _nackCount++;
1965 TRACE_COUNTER1("webrtc_rtcp", "Nacks", _nackCount);
niklase@google.com470e71d2011-07-07 08:21:25 +00001966 }
1967 if(rtcpPacketTypeFlags & kRtcpXrVoipMetric)
1968 {
1969 buildVal = BuildVoIPMetric(rtcpbuffer, pos);
1970 if(buildVal == -1)
1971 {
1972 return -1; // error
1973
1974 }else if(buildVal == -2)
1975 {
1976 break; // out of buffer
1977 }
1978 }
1979 }while (false);
pwestin@webrtc.org8edb39d2011-12-22 07:40:33 +00001980 // Sanity don't send empty packets.
1981 if (pos == 0)
1982 {
1983 return -1;
1984 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001985 return SendToNetwork(rtcpbuffer, (WebRtc_UWord16)pos);
1986}
1987
1988WebRtc_Word32
1989RTCPSender::SendToNetwork(const WebRtc_UWord8* dataBuffer,
1990 const WebRtc_UWord16 length)
1991{
1992 CriticalSectionScoped lock(_criticalSectionTransport);
1993 if(_cbTransport)
1994 {
1995 if(_cbTransport->SendRTCPPacket(_id, dataBuffer, length) > 0)
1996 {
1997 return 0;
1998 }
1999 }
2000 return -1;
2001}
2002
2003WebRtc_Word32
2004RTCPSender::SetCSRCStatus(const bool include)
2005{
2006 _includeCSRCs = include;
2007 return 0;
2008}
2009
2010WebRtc_Word32
2011RTCPSender::SetCSRCs(const WebRtc_UWord32 arrOfCSRC[kRtpCsrcSize],
2012 const WebRtc_UWord8 arrLength)
2013{
2014 if(arrLength > kRtpCsrcSize)
2015 {
2016 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", __FUNCTION__);
2017 assert(false);
2018 return -1;
2019 }
2020
2021 CriticalSectionScoped lock(_criticalSectionRTCPSender);
2022
2023 for(int i = 0; i < arrLength;i++)
2024 {
2025 _CSRC[i] = arrOfCSRC[i];
2026 }
2027 _CSRCs = arrLength;
2028 return 0;
2029}
2030
2031WebRtc_Word32
2032RTCPSender::SetApplicationSpecificData(const WebRtc_UWord8 subType,
2033 const WebRtc_UWord32 name,
2034 const WebRtc_UWord8* data,
2035 const WebRtc_UWord16 length)
2036{
2037 if(length %4 != 0)
2038 {
2039 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", __FUNCTION__);
2040 return -1;
2041 }
2042 CriticalSectionScoped lock(_criticalSectionRTCPSender);
2043
2044 if(_appData)
2045 {
2046 delete [] _appData;
2047 }
2048
2049 _appSend = true;
2050 _appSubType = subType;
2051 _appName = name;
2052 _appData = new WebRtc_UWord8[length];
2053 _appLength = length;
2054 memcpy(_appData, data, length);
2055 return 0;
2056}
2057
2058WebRtc_Word32
2059RTCPSender::SetRTCPVoIPMetrics(const RTCPVoIPMetric* VoIPMetric)
2060{
2061 CriticalSectionScoped lock(_criticalSectionRTCPSender);
2062 memcpy(&_xrVoIPMetric, VoIPMetric, sizeof(RTCPVoIPMetric));
2063
2064 _xrSendVoIPMetric = true;
2065 return 0;
2066}
2067
2068// called under critsect _criticalSectionRTCPSender
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002069WebRtc_Word32 RTCPSender::AddReportBlocks(WebRtc_UWord8* rtcpbuffer,
2070 WebRtc_UWord32& pos,
2071 WebRtc_UWord8& numberOfReportBlocks,
2072 const RTCPReportBlock* received,
2073 const WebRtc_UWord32 NTPsec,
2074 const WebRtc_UWord32 NTPfrac) {
2075 // sanity one block
2076 if(pos + 24 >= IP_PACKET_SIZE) {
2077 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
2078 "%s invalid argument", __FUNCTION__);
2079 return -1;
2080 }
2081 numberOfReportBlocks = _reportBlocks.size();
2082 if (received) {
2083 // add our multiple RR to numberOfReportBlocks
2084 numberOfReportBlocks++;
2085 }
2086 if (received) {
2087 // answer to the one that sends to me
2088 _lastRTCPTime[0] = ModuleRTPUtility::ConvertNTPTimeToMS(NTPsec, NTPfrac);
2089
2090 // Remote SSRC
2091 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _remoteSSRC);
2092 pos += 4;
2093
2094 // fraction lost
2095 rtcpbuffer[pos++]=received->fractionLost;
2096
2097 // cumulative loss
2098 ModuleRTPUtility::AssignUWord24ToBuffer(rtcpbuffer+pos,
2099 received->cumulativeLost);
2100 pos += 3;
2101 // extended highest seq_no, contain the highest sequence number received
2102 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos,
2103 received->extendedHighSeqNum);
2104 pos += 4;
2105
2106 //Jitter
2107 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, received->jitter);
2108 pos += 4;
2109
2110 // Last SR timestamp, our NTP time when we received the last report
2111 // This is the value that we read from the send report packet not when we
2112 // received it...
2113 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, received->lastSR);
2114 pos += 4;
2115
2116 // Delay since last received report,time since we received the report
2117 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos,
2118 received->delaySinceLastSR);
2119 pos += 4;
2120 }
2121 if ((pos + _reportBlocks.size() * 24) >= IP_PACKET_SIZE) {
2122 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
2123 "%s invalid argument", __FUNCTION__);
2124 return -1;
2125 }
2126 std::map<WebRtc_UWord32, RTCPReportBlock*>::iterator it =
2127 _reportBlocks.begin();
2128
2129 for (; it != _reportBlocks.end(); it++) {
2130 // we can have multiple report block in a conference
2131 WebRtc_UWord32 remoteSSRC = it->first;
2132 RTCPReportBlock* reportBlock = it->second;
2133 if (reportBlock) {
2134 // Remote SSRC
2135 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, remoteSSRC);
2136 pos += 4;
2137
2138 // fraction lost
2139 rtcpbuffer[pos++] = reportBlock->fractionLost;
2140
2141 // cumulative loss
2142 ModuleRTPUtility::AssignUWord24ToBuffer(rtcpbuffer+pos,
2143 reportBlock->cumulativeLost);
2144 pos += 3;
2145
2146 // extended highest seq_no, contain the highest sequence number received
2147 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos,
2148 reportBlock->extendedHighSeqNum);
2149 pos += 4;
2150
2151 //Jitter
2152 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos,
2153 reportBlock->jitter);
2154 pos += 4;
2155
2156 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos,
2157 reportBlock->lastSR);
2158 pos += 4;
2159
2160 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos,
2161 reportBlock->delaySinceLastSR);
2162 pos += 4;
niklase@google.com470e71d2011-07-07 08:21:25 +00002163 }
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002164 }
2165 return pos;
niklase@google.com470e71d2011-07-07 08:21:25 +00002166}
2167
2168// no callbacks allowed inside this function
2169WebRtc_Word32
2170RTCPSender::SetTMMBN(const TMMBRSet* boundingSet,
2171 const WebRtc_UWord32 maxBitrateKbit)
2172{
2173 CriticalSectionScoped lock(_criticalSectionRTCPSender);
2174
2175 if (0 == _tmmbrHelp.SetTMMBRBoundingSetToSend(boundingSet, maxBitrateKbit))
2176 {
2177 _sendTMMBN = true;
2178 return 0;
2179 }
2180 return -1;
2181}
niklase@google.com470e71d2011-07-07 08:21:25 +00002182} // namespace webrtc