blob: 8cac9969a58683ff8e0a591bb917e8d735512cdb [file] [log] [blame]
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001/*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
pbos@webrtc.orgcbd78ae2013-05-29 14:27:38 +000011#include "webrtc/modules/rtp_rtcp/source/rtcp_sender.h"
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000012
pbos@webrtc.org3f45c2e2013-08-05 16:22:53 +000013#include <assert.h> // assert
14#include <stdlib.h> // rand
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000015#include <string.h> // memcpy
16
pbos@webrtc.org3f45c2e2013-08-05 16:22:53 +000017#include <algorithm> // min
18
pbos@webrtc.orgcbd78ae2013-05-29 14:27:38 +000019#include "webrtc/common_types.h"
20#include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h"
21#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
22#include "webrtc/system_wrappers/interface/trace.h"
23#include "webrtc/system_wrappers/interface/trace_event.h"
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000024
25namespace webrtc {
26
27using RTCPUtility::RTCPCnameInformation;
28
edjee@google.comdded2062013-04-04 19:43:34 +000029NACKStringBuilder::NACKStringBuilder() :
30 _stream(""), _count(0), _consecutive(false)
31{
32 // Empty.
33}
34
pbos@webrtc.org9d71e282013-07-31 15:17:19 +000035NACKStringBuilder::~NACKStringBuilder() {}
36
pbos@webrtc.orgb57da652013-04-08 11:08:41 +000037void NACKStringBuilder::PushNACK(uint16_t nack)
edjee@google.comdded2062013-04-04 19:43:34 +000038{
39 if (_count == 0)
40 {
41 _stream << nack;
42 } else if (nack == _prevNack + 1)
43 {
44 _consecutive = true;
45 } else
46 {
47 if (_consecutive)
48 {
49 _stream << "-" << _prevNack;
50 _consecutive = false;
51 }
52 _stream << "," << nack;
53 }
54 _count++;
55 _prevNack = nack;
56}
57
58std::string NACKStringBuilder::GetResult()
59{
60 if (_consecutive)
61 {
62 _stream << "-" << _prevNack;
63 _consecutive = false;
64 }
65 return _stream.str();
66}
67
pbos@webrtc.org4e7777b2013-09-09 16:02:19 +000068RTCPSender::FeedbackState::FeedbackState(ModuleRtpRtcpImpl* module)
69 : send_payload_type(module->SendPayloadType()),
70 frequency_hz(module->CurrentSendFrequencyHz()),
71 packet_count_sent(module->PacketCountSent()),
72 byte_count_sent(module->ByteCountSent()),
73 module(module) {
74 uint32_t last_ntp_secs = 0, last_ntp_frac = 0, last_remote_sr = 0;
75 module->LastReceivedNTP(last_ntp_secs, last_ntp_frac, last_remote_sr);
76 last_rr_ntp_secs = last_ntp_secs;
77 last_rr_ntp_frac = last_ntp_frac;
78 remote_sr = last_remote_sr;
79
asapersson@webrtc.orgd6da2392013-10-02 13:15:34 +000080 has_last_xr_rr = module->LastReceivedXrReferenceTimeInfo(&last_xr_rr);
81
pbos@webrtc.org4e7777b2013-09-09 16:02:19 +000082 uint32_t send_bitrate = 0, tmp;
83 module->BitrateSent(&send_bitrate, &tmp, &tmp, &tmp);
84 this->send_bitrate = send_bitrate;
85}
86
87RTCPSender::FeedbackState::FeedbackState()
88 : send_payload_type(0),
89 frequency_hz(0),
90 packet_count_sent(0),
91 byte_count_sent(0),
92 send_bitrate(0),
93 last_rr_ntp_secs(0),
94 last_rr_ntp_frac(0),
asapersson@webrtc.orgd6da2392013-10-02 13:15:34 +000095 remote_sr(0),
96 has_last_xr_rr(false) {}
pbos@webrtc.org4e7777b2013-09-09 16:02:19 +000097
pbos@webrtc.orgb57da652013-04-08 11:08:41 +000098RTCPSender::RTCPSender(const int32_t id,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +000099 const bool audio,
stefan@webrtc.org9858fc82013-01-17 14:01:20 +0000100 Clock* clock,
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +0000101 ReceiveStatistics* receive_statistics) :
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000102 _id(id),
103 _audio(audio),
stefan@webrtc.org1bb21462013-01-21 07:42:11 +0000104 _clock(clock),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000105 _method(kRtcpOff),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000106 _criticalSectionTransport(CriticalSectionWrapper::CreateCriticalSection()),
107 _cbTransport(NULL),
108
109 _criticalSectionRTCPSender(CriticalSectionWrapper::CreateCriticalSection()),
110 _usingNack(false),
111 _sending(false),
112 _sendTMMBN(false),
113 _REMB(false),
114 _sendREMB(false),
115 _TMMBR(false),
116 _IJ(false),
117 _nextTimeToSendRTCP(0),
118 start_timestamp_(0),
119 last_rtp_timestamp_(0),
120 last_frame_capture_time_ms_(-1),
121 _SSRC(0),
122 _remoteSSRC(0),
123 _CNAME(),
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +0000124 receive_statistics_(receive_statistics),
125 internal_report_blocks_(),
126 external_report_blocks_(),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000127 _csrcCNAMEs(),
128
stefan@webrtc.org73ebe672013-04-09 14:56:29 +0000129 _cameraDelayMS(0),
130
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000131 _lastSendReport(),
132 _lastRTCPTime(),
133
asapersson@webrtc.orgd6da2392013-10-02 13:15:34 +0000134 last_xr_rr_(),
135
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000136 _CSRCs(0),
137 _CSRC(),
138 _includeCSRCs(true),
139
140 _sequenceNumberFIR(0),
141
142 _lengthRembSSRC(0),
143 _sizeRembSSRC(0),
144 _rembSSRC(NULL),
145 _rembBitrate(0),
146
147 _tmmbrHelp(),
148 _tmmbr_Send(0),
149 _packetOH_Send(0),
150
151 _appSend(false),
152 _appSubType(0),
153 _appName(),
154 _appData(NULL),
155 _appLength(0),
asapersson@webrtc.orgd6da2392013-10-02 13:15:34 +0000156
157 xrSendReceiverReferenceTimeEnabled_(false),
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000158 _xrSendVoIPMetric(false),
edjee@google.comdded2062013-04-04 19:43:34 +0000159 _xrVoIPMetric(),
160 _nackCount(0),
161 _pliCount(0),
162 _fullIntraRequestCount(0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000163{
164 memset(_CNAME, 0, sizeof(_CNAME));
165 memset(_lastSendReport, 0, sizeof(_lastSendReport));
166 memset(_lastRTCPTime, 0, sizeof(_lastRTCPTime));
167
168 WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, id, "%s created", __FUNCTION__);
169}
170
171RTCPSender::~RTCPSender() {
172 delete [] _rembSSRC;
173 delete [] _appData;
174
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +0000175 while (!internal_report_blocks_.empty()) {
176 delete internal_report_blocks_.begin()->second;
177 internal_report_blocks_.erase(internal_report_blocks_.begin());
178 }
179 while (!external_report_blocks_.empty()) {
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000180 std::map<uint32_t, RTCPReportBlock*>::iterator it =
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +0000181 external_report_blocks_.begin();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000182 delete it->second;
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +0000183 external_report_blocks_.erase(it);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000184 }
185 while (!_csrcCNAMEs.empty()) {
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000186 std::map<uint32_t, RTCPCnameInformation*>::iterator it =
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000187 _csrcCNAMEs.begin();
188 delete it->second;
189 _csrcCNAMEs.erase(it);
190 }
191 delete _criticalSectionTransport;
192 delete _criticalSectionRTCPSender;
193
194 WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, _id, "%s deleted", __FUNCTION__);
195}
196
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000197int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000198RTCPSender::Init()
199{
200 CriticalSectionScoped lock(_criticalSectionRTCPSender);
201
202 _method = kRtcpOff;
203 _cbTransport = NULL;
204 _usingNack = false;
205 _sending = false;
206 _sendTMMBN = false;
207 _TMMBR = false;
208 _IJ = false;
209 _REMB = false;
210 _sendREMB = false;
211 last_rtp_timestamp_ = 0;
212 last_frame_capture_time_ms_ = -1;
213 start_timestamp_ = -1;
214 _SSRC = 0;
215 _remoteSSRC = 0;
stefan@webrtc.org73ebe672013-04-09 14:56:29 +0000216 _cameraDelayMS = 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000217 _sequenceNumberFIR = 0;
218 _tmmbr_Send = 0;
219 _packetOH_Send = 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000220 _nextTimeToSendRTCP = 0;
221 _CSRCs = 0;
222 _appSend = false;
223 _appSubType = 0;
224
225 if(_appData)
226 {
227 delete [] _appData;
228 _appData = NULL;
229 }
230 _appLength = 0;
231
asapersson@webrtc.orgd6da2392013-10-02 13:15:34 +0000232 xrSendReceiverReferenceTimeEnabled_ = false;
233
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000234 _xrSendVoIPMetric = false;
235
236 memset(&_xrVoIPMetric, 0, sizeof(_xrVoIPMetric));
237 memset(_CNAME, 0, sizeof(_CNAME));
238 memset(_lastSendReport, 0, sizeof(_lastSendReport));
239 memset(_lastRTCPTime, 0, sizeof(_lastRTCPTime));
asapersson@webrtc.orgd6da2392013-10-02 13:15:34 +0000240 last_xr_rr_.clear();
edjee@google.comdded2062013-04-04 19:43:34 +0000241
242 _nackCount = 0;
243 _pliCount = 0;
244 _fullIntraRequestCount = 0;
245
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000246 return 0;
247}
248
249void
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000250RTCPSender::ChangeUniqueId(const int32_t id)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000251{
252 _id = id;
253}
254
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000255int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000256RTCPSender::RegisterSendTransport(Transport* outgoingTransport)
257{
258 CriticalSectionScoped lock(_criticalSectionTransport);
259 _cbTransport = outgoingTransport;
260 return 0;
261}
262
263RTCPMethod
264RTCPSender::Status() const
265{
266 CriticalSectionScoped lock(_criticalSectionRTCPSender);
267 return _method;
268}
269
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000270int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000271RTCPSender::SetRTCPStatus(const RTCPMethod method)
272{
273 CriticalSectionScoped lock(_criticalSectionRTCPSender);
274 if(method != kRtcpOff)
275 {
276 if(_audio)
277 {
stefan@webrtc.org1bb21462013-01-21 07:42:11 +0000278 _nextTimeToSendRTCP = _clock->TimeInMilliseconds() +
stefan@webrtc.org9858fc82013-01-17 14:01:20 +0000279 (RTCP_INTERVAL_AUDIO_MS/2);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000280 } else
281 {
stefan@webrtc.org1bb21462013-01-21 07:42:11 +0000282 _nextTimeToSendRTCP = _clock->TimeInMilliseconds() +
stefan@webrtc.org9858fc82013-01-17 14:01:20 +0000283 (RTCP_INTERVAL_VIDEO_MS/2);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000284 }
285 }
286 _method = method;
287 return 0;
288}
289
290bool
291RTCPSender::Sending() const
292{
293 CriticalSectionScoped lock(_criticalSectionRTCPSender);
294 return _sending;
295}
296
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000297int32_t
pbos@webrtc.org4e7777b2013-09-09 16:02:19 +0000298RTCPSender::SetSendingStatus(const FeedbackState& feedback_state, bool sending)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000299{
300 bool sendRTCPBye = false;
301 {
302 CriticalSectionScoped lock(_criticalSectionRTCPSender);
303
304 if(_method != kRtcpOff)
305 {
306 if(sending == false && _sending == true)
307 {
308 // Trigger RTCP bye
309 sendRTCPBye = true;
310 }
311 }
312 _sending = sending;
313 }
314 if(sendRTCPBye)
315 {
pbos@webrtc.org4e7777b2013-09-09 16:02:19 +0000316 return SendRTCP(feedback_state, kRtcpBye);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000317 }
318 return 0;
319}
320
321bool
322RTCPSender::REMB() const
323{
324 CriticalSectionScoped lock(_criticalSectionRTCPSender);
325 return _REMB;
326}
327
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000328int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000329RTCPSender::SetREMBStatus(const bool enable)
330{
331 CriticalSectionScoped lock(_criticalSectionRTCPSender);
332 _REMB = enable;
333 return 0;
334}
335
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000336int32_t
337RTCPSender::SetREMBData(const uint32_t bitrate,
338 const uint8_t numberOfSSRC,
339 const uint32_t* SSRC)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000340{
341 CriticalSectionScoped lock(_criticalSectionRTCPSender);
342 _rembBitrate = bitrate;
343
344 if(_sizeRembSSRC < numberOfSSRC)
345 {
346 delete [] _rembSSRC;
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000347 _rembSSRC = new uint32_t[numberOfSSRC];
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000348 _sizeRembSSRC = numberOfSSRC;
349 }
350
351 _lengthRembSSRC = numberOfSSRC;
352 for (int i = 0; i < numberOfSSRC; i++)
353 {
354 _rembSSRC[i] = SSRC[i];
355 }
356 _sendREMB = true;
357 return 0;
358}
359
360bool
361RTCPSender::TMMBR() const
362{
363 CriticalSectionScoped lock(_criticalSectionRTCPSender);
364 return _TMMBR;
365}
366
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000367int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000368RTCPSender::SetTMMBRStatus(const bool enable)
369{
370 CriticalSectionScoped lock(_criticalSectionRTCPSender);
371 _TMMBR = enable;
372 return 0;
373}
374
375bool
376RTCPSender::IJ() const
377{
378 CriticalSectionScoped lock(_criticalSectionRTCPSender);
379 return _IJ;
380}
381
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000382int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000383RTCPSender::SetIJStatus(const bool enable)
384{
385 CriticalSectionScoped lock(_criticalSectionRTCPSender);
386 _IJ = enable;
387 return 0;
388}
389
390void RTCPSender::SetStartTimestamp(uint32_t start_timestamp) {
391 start_timestamp_ = start_timestamp;
392}
393
394void RTCPSender::SetLastRtpTime(uint32_t rtp_timestamp,
395 int64_t capture_time_ms) {
henrika@webrtc.org1d25eac2013-04-05 14:34:57 +0000396 CriticalSectionScoped lock(_criticalSectionRTCPSender);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000397 last_rtp_timestamp_ = rtp_timestamp;
398 if (capture_time_ms < 0) {
399 // We don't currently get a capture time from VoiceEngine.
stefan@webrtc.org73ebe672013-04-09 14:56:29 +0000400 last_frame_capture_time_ms_ = _clock->TimeInMilliseconds();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000401 } else {
402 last_frame_capture_time_ms_ = capture_time_ms;
403 }
404}
405
406void
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000407RTCPSender::SetSSRC( const uint32_t ssrc)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000408{
409 CriticalSectionScoped lock(_criticalSectionRTCPSender);
410
411 if(_SSRC != 0)
412 {
413 // not first SetSSRC, probably due to a collision
414 // schedule a new RTCP report
415 // make sure that we send a RTP packet
stefan@webrtc.org1bb21462013-01-21 07:42:11 +0000416 _nextTimeToSendRTCP = _clock->TimeInMilliseconds() + 100;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000417 }
418 _SSRC = ssrc;
419}
420
wu@webrtc.org7fc75bb2013-08-15 23:38:54 +0000421void RTCPSender::SetRemoteSSRC(uint32_t ssrc)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000422{
423 CriticalSectionScoped lock(_criticalSectionRTCPSender);
424 _remoteSSRC = ssrc;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000425}
426
stefan@webrtc.org73ebe672013-04-09 14:56:29 +0000427int32_t
428RTCPSender::SetCameraDelay(const int32_t delayMS)
429{
430 CriticalSectionScoped lock(_criticalSectionRTCPSender);
431 if(delayMS > 1000 || delayMS < -1000)
432 {
433 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument, delay can't be larger than 1 sec", __FUNCTION__);
434 return -1;
435 }
436 _cameraDelayMS = delayMS;
437 return 0;
438}
439
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000440int32_t RTCPSender::CNAME(char cName[RTCP_CNAME_SIZE]) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000441 assert(cName);
442 CriticalSectionScoped lock(_criticalSectionRTCPSender);
443 cName[RTCP_CNAME_SIZE - 1] = 0;
444 strncpy(cName, _CNAME, RTCP_CNAME_SIZE - 1);
445 return 0;
446}
447
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000448int32_t RTCPSender::SetCNAME(const char cName[RTCP_CNAME_SIZE]) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000449 if (!cName)
450 return -1;
451
452 CriticalSectionScoped lock(_criticalSectionRTCPSender);
453 _CNAME[RTCP_CNAME_SIZE - 1] = 0;
454 strncpy(_CNAME, cName, RTCP_CNAME_SIZE - 1);
455 return 0;
456}
457
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000458int32_t RTCPSender::AddMixedCNAME(const uint32_t SSRC,
459 const char cName[RTCP_CNAME_SIZE]) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000460 assert(cName);
461 CriticalSectionScoped lock(_criticalSectionRTCPSender);
462 if (_csrcCNAMEs.size() >= kRtpCsrcSize) {
463 return -1;
464 }
465 RTCPCnameInformation* ptr = new RTCPCnameInformation();
466 ptr->name[RTCP_CNAME_SIZE - 1] = 0;
467 strncpy(ptr->name, cName, RTCP_CNAME_SIZE - 1);
468 _csrcCNAMEs[SSRC] = ptr;
469 return 0;
470}
471
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000472int32_t RTCPSender::RemoveMixedCNAME(const uint32_t SSRC) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000473 CriticalSectionScoped lock(_criticalSectionRTCPSender);
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000474 std::map<uint32_t, RTCPCnameInformation*>::iterator it =
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000475 _csrcCNAMEs.find(SSRC);
476
477 if (it == _csrcCNAMEs.end()) {
478 return -1;
479 }
480 delete it->second;
481 _csrcCNAMEs.erase(it);
482 return 0;
483}
484
485bool
486RTCPSender::TimeToSendRTCPReport(const bool sendKeyframeBeforeRTP) const
487{
488/*
489 For audio we use a fix 5 sec interval
490
491 For video we use 1 sec interval fo a BW smaller than 360 kbit/s,
492 technicaly we break the max 5% RTCP BW for video below 10 kbit/s but that should be extreamly rare
493
494
495From RFC 3550
496
497 MAX RTCP BW is 5% if the session BW
498 A send report is approximately 65 bytes inc CNAME
499 A report report is approximately 28 bytes
500
501 The RECOMMENDED value for the reduced minimum in seconds is 360
502 divided by the session bandwidth in kilobits/second. This minimum
503 is smaller than 5 seconds for bandwidths greater than 72 kb/s.
504
505 If the participant has not yet sent an RTCP packet (the variable
506 initial is true), the constant Tmin is set to 2.5 seconds, else it
507 is set to 5 seconds.
508
509 The interval between RTCP packets is varied randomly over the
510 range [0.5,1.5] times the calculated interval to avoid unintended
511 synchronization of all participants
512
513 if we send
514 If the participant is a sender (we_sent true), the constant C is
515 set to the average RTCP packet size (avg_rtcp_size) divided by 25%
516 of the RTCP bandwidth (rtcp_bw), and the constant n is set to the
517 number of senders.
518
519 if we receive only
520 If we_sent is not true, the constant C is set
521 to the average RTCP packet size divided by 75% of the RTCP
522 bandwidth. The constant n is set to the number of receivers
523 (members - senders). If the number of senders is greater than
524 25%, senders and receivers are treated together.
525
526 reconsideration NOT required for peer-to-peer
527 "timer reconsideration" is
528 employed. This algorithm implements a simple back-off mechanism
529 which causes users to hold back RTCP packet transmission if the
530 group sizes are increasing.
531
532 n = number of members
533 C = avg_size/(rtcpBW/4)
534
535 3. The deterministic calculated interval Td is set to max(Tmin, n*C).
536
537 4. The calculated interval T is set to a number uniformly distributed
538 between 0.5 and 1.5 times the deterministic calculated interval.
539
540 5. The resulting value of T is divided by e-3/2=1.21828 to compensate
541 for the fact that the timer reconsideration algorithm converges to
542 a value of the RTCP bandwidth below the intended average
543*/
544
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000545 int64_t now = _clock->TimeInMilliseconds();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000546
547 CriticalSectionScoped lock(_criticalSectionRTCPSender);
548
549 if(_method == kRtcpOff)
550 {
551 return false;
552 }
553
554 if(!_audio && sendKeyframeBeforeRTP)
555 {
556 // for video key-frames we want to send the RTCP before the large key-frame
557 // if we have a 100 ms margin
558 now += RTCP_SEND_BEFORE_KEY_FRAME_MS;
559 }
560
561 if(now > _nextTimeToSendRTCP)
562 {
563 return true;
564
565 } else if(now < 0x0000ffff && _nextTimeToSendRTCP > 0xffff0000) // 65 sec margin
566 {
567 // wrap
568 return true;
569 }
570 return false;
571}
572
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000573uint32_t
574RTCPSender::LastSendReport( uint32_t& lastRTCPTime)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000575{
576 CriticalSectionScoped lock(_criticalSectionRTCPSender);
577
578 lastRTCPTime = _lastRTCPTime[0];
579 return _lastSendReport[0];
580}
581
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000582uint32_t
583RTCPSender::SendTimeOfSendReport(const uint32_t sendReport)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000584{
585 CriticalSectionScoped lock(_criticalSectionRTCPSender);
586
587 // This is only saved when we are the sender
588 if((_lastSendReport[0] == 0) || (sendReport == 0))
589 {
590 return 0; // will be ignored
591 } else
592 {
593 for(int i = 0; i < RTCP_NUMBER_OF_SR; ++i)
594 {
595 if( _lastSendReport[i] == sendReport)
596 {
597 return _lastRTCPTime[i];
598 }
599 }
600 }
601 return 0;
602}
603
asapersson@webrtc.orgd6da2392013-10-02 13:15:34 +0000604bool RTCPSender::SendTimeOfXrRrReport(uint32_t mid_ntp,
605 int64_t* time_ms) const {
606 CriticalSectionScoped lock(_criticalSectionRTCPSender);
607
608 if (last_xr_rr_.empty()) {
609 return false;
610 }
611 std::map<uint32_t, int64_t>::const_iterator it = last_xr_rr_.find(mid_ntp);
612 if (it == last_xr_rr_.end()) {
613 return false;
614 }
615 *time_ms = it->second;
616 return true;
617}
618
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +0000619int32_t RTCPSender::AddExternalReportBlock(
620 uint32_t SSRC,
621 const RTCPReportBlock* reportBlock) {
622 CriticalSectionScoped lock(_criticalSectionRTCPSender);
623 return AddReportBlock(SSRC, &external_report_blocks_, reportBlock);
624}
625
626int32_t RTCPSender::AddReportBlock(
627 uint32_t SSRC,
628 std::map<uint32_t, RTCPReportBlock*>* report_blocks,
629 const RTCPReportBlock* reportBlock) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000630 if (reportBlock == NULL) {
631 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
632 "%s invalid argument", __FUNCTION__);
633 return -1;
634 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000635
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +0000636 if (report_blocks->size() >= RTCP_MAX_REPORT_BLOCKS) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000637 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
638 "%s invalid argument", __FUNCTION__);
639 return -1;
640 }
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000641 std::map<uint32_t, RTCPReportBlock*>::iterator it =
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +0000642 report_blocks->find(SSRC);
643 if (it != report_blocks->end()) {
stefan@webrtc.orgcf4441c2012-12-03 14:01:46 +0000644 delete it->second;
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +0000645 report_blocks->erase(it);
stefan@webrtc.orgcf4441c2012-12-03 14:01:46 +0000646 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000647 RTCPReportBlock* copyReportBlock = new RTCPReportBlock();
648 memcpy(copyReportBlock, reportBlock, sizeof(RTCPReportBlock));
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +0000649 (*report_blocks)[SSRC] = copyReportBlock;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000650 return 0;
651}
652
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +0000653int32_t RTCPSender::RemoveExternalReportBlock(uint32_t SSRC) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000654 CriticalSectionScoped lock(_criticalSectionRTCPSender);
655
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000656 std::map<uint32_t, RTCPReportBlock*>::iterator it =
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +0000657 external_report_blocks_.find(SSRC);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000658
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +0000659 if (it == external_report_blocks_.end()) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000660 return -1;
661 }
662 delete it->second;
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +0000663 external_report_blocks_.erase(it);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000664 return 0;
665}
666
pbos@webrtc.org4e7777b2013-09-09 16:02:19 +0000667int32_t RTCPSender::BuildSR(const FeedbackState& feedback_state,
668 uint8_t* rtcpbuffer,
669 int& pos,
670 uint32_t NTPsec,
671 uint32_t NTPfrac)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000672{
673 // sanity
674 if(pos + 52 >= IP_PACKET_SIZE)
675 {
676 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", __FUNCTION__);
677 return -2;
678 }
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000679 uint32_t RTPtime;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000680
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000681 uint32_t posNumberOfReportBlocks = pos;
682 rtcpbuffer[pos++]=(uint8_t)0x80;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000683
684 // Sender report
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000685 rtcpbuffer[pos++]=(uint8_t)200;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000686
687 for(int i = (RTCP_NUMBER_OF_SR-2); i >= 0; i--)
688 {
689 // shift old
690 _lastSendReport[i+1] = _lastSendReport[i];
691 _lastRTCPTime[i+1] =_lastRTCPTime[i];
692 }
693
stefan@webrtc.org9b531522013-04-12 11:56:23 +0000694 _lastRTCPTime[0] = Clock::NtpToMs(NTPsec, NTPfrac);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000695 _lastSendReport[0] = (NTPsec << 16) + (NTPfrac >> 16);
696
stefan@webrtc.org73ebe672013-04-09 14:56:29 +0000697 // The timestamp of this RTCP packet should be estimated as the timestamp of
698 // the frame being captured at this moment. We are calculating that
699 // timestamp as the last frame's timestamp + the time since the last frame
700 // was captured.
701 {
702 // Needs protection since this method is called on the process thread.
703 CriticalSectionScoped lock(_criticalSectionRTCPSender);
704 RTPtime = start_timestamp_ + last_rtp_timestamp_ + (
705 _clock->TimeInMilliseconds() - last_frame_capture_time_ms_) *
pbos@webrtc.org4e7777b2013-09-09 16:02:19 +0000706 (feedback_state.frequency_hz / 1000);
stefan@webrtc.org73ebe672013-04-09 14:56:29 +0000707 }
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000708
709 // Add sender data
710 // Save for our length field
711 pos++;
712 pos++;
713
714 // Add our own SSRC
715 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
716 pos += 4;
717 // NTP
718 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, NTPsec);
719 pos += 4;
720 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, NTPfrac);
721 pos += 4;
722 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, RTPtime);
723 pos += 4;
724
725 //sender's packet count
pbos@webrtc.org4e7777b2013-09-09 16:02:19 +0000726 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos,
727 feedback_state.packet_count_sent);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000728 pos += 4;
729
730 //sender's octet count
pbos@webrtc.org4e7777b2013-09-09 16:02:19 +0000731 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos,
732 feedback_state.byte_count_sent);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000733 pos += 4;
734
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000735 uint8_t numberOfReportBlocks = 0;
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +0000736 int32_t retVal = WriteAllReportBlocksToBuffer(rtcpbuffer, pos,
737 numberOfReportBlocks,
738 NTPsec, NTPfrac);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000739 if(retVal < 0)
740 {
741 //
742 return retVal ;
743 }
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +0000744 pos = retVal;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000745 rtcpbuffer[posNumberOfReportBlocks] += numberOfReportBlocks;
746
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000747 uint16_t len = uint16_t((pos/4) -1);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000748 ModuleRTPUtility::AssignUWord16ToBuffer(rtcpbuffer+2, len);
749 return 0;
750}
751
752
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +0000753int32_t RTCPSender::BuildSDEC(uint8_t* rtcpbuffer, int& pos) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000754 size_t lengthCname = strlen(_CNAME);
755 assert(lengthCname < RTCP_CNAME_SIZE);
756
757 // sanity
758 if(pos + 12 + lengthCname >= IP_PACKET_SIZE) {
759 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
760 "%s invalid argument", __FUNCTION__);
761 return -2;
762 }
763 // SDEC Source Description
764
765 // We always need to add SDES CNAME
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000766 rtcpbuffer[pos++] = static_cast<uint8_t>(0x80 + 1 + _csrcCNAMEs.size());
767 rtcpbuffer[pos++] = static_cast<uint8_t>(202);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000768
769 // handle SDES length later on
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000770 uint32_t SDESLengthPos = pos;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000771 pos++;
772 pos++;
773
774 // Add our own SSRC
775 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
776 pos += 4;
777
778 // CNAME = 1
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000779 rtcpbuffer[pos++] = static_cast<uint8_t>(1);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000780
781 //
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000782 rtcpbuffer[pos++] = static_cast<uint8_t>(lengthCname);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000783
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000784 uint16_t SDESLength = 10;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000785
786 memcpy(&rtcpbuffer[pos], _CNAME, lengthCname);
787 pos += lengthCname;
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000788 SDESLength += (uint16_t)lengthCname;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000789
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000790 uint16_t padding = 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000791 // We must have a zero field even if we have an even multiple of 4 bytes
792 if ((pos % 4) == 0) {
793 padding++;
794 rtcpbuffer[pos++]=0;
795 }
796 while ((pos % 4) != 0) {
797 padding++;
798 rtcpbuffer[pos++]=0;
799 }
800 SDESLength += padding;
801
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000802 std::map<uint32_t, RTCPUtility::RTCPCnameInformation*>::iterator it =
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000803 _csrcCNAMEs.begin();
804
805 for(; it != _csrcCNAMEs.end(); it++) {
806 RTCPCnameInformation* cname = it->second;
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000807 uint32_t SSRC = it->first;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000808
809 // Add SSRC
810 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, SSRC);
811 pos += 4;
812
813 // CNAME = 1
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000814 rtcpbuffer[pos++] = static_cast<uint8_t>(1);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000815
816 size_t length = strlen(cname->name);
817 assert(length < RTCP_CNAME_SIZE);
818
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000819 rtcpbuffer[pos++]= static_cast<uint8_t>(length);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000820 SDESLength += 6;
821
822 memcpy(&rtcpbuffer[pos],cname->name, length);
823
824 pos += length;
825 SDESLength += length;
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000826 uint16_t padding = 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000827
828 // We must have a zero field even if we have an even multiple of 4 bytes
829 if((pos % 4) == 0){
830 padding++;
831 rtcpbuffer[pos++]=0;
832 }
833 while((pos % 4) != 0){
834 padding++;
835 rtcpbuffer[pos++] = 0;
836 }
837 SDESLength += padding;
838 }
839 // in 32-bit words minus one and we don't count the header
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000840 uint16_t buffer_length = (SDESLength / 4) - 1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000841 ModuleRTPUtility::AssignUWord16ToBuffer(rtcpbuffer + SDESLengthPos,
842 buffer_length);
843 return 0;
844}
845
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000846int32_t
847RTCPSender::BuildRR(uint8_t* rtcpbuffer,
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +0000848 int& pos,
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000849 const uint32_t NTPsec,
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +0000850 const uint32_t NTPfrac)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000851{
852 // sanity one block
853 if(pos + 32 >= IP_PACKET_SIZE)
854 {
855 return -2;
856 }
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000857 uint32_t posNumberOfReportBlocks = pos;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000858
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000859 rtcpbuffer[pos++]=(uint8_t)0x80;
860 rtcpbuffer[pos++]=(uint8_t)201;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000861
862 // Save for our length field
863 pos++;
864 pos++;
865
866 // Add our own SSRC
867 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
868 pos += 4;
869
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000870 uint8_t numberOfReportBlocks = 0;
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +0000871 int retVal = WriteAllReportBlocksToBuffer(rtcpbuffer, pos,
872 numberOfReportBlocks,
873 NTPsec, NTPfrac);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000874 if(retVal < 0)
875 {
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +0000876 return pos;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000877 }
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +0000878 pos = retVal;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000879 rtcpbuffer[posNumberOfReportBlocks] += numberOfReportBlocks;
880
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000881 uint16_t len = uint16_t((pos)/4 -1);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000882 ModuleRTPUtility::AssignUWord16ToBuffer(rtcpbuffer+2, len);
883 return 0;
884}
885
886// From RFC 5450: Transmission Time Offsets in RTP Streams.
887// 0 1 2 3
888// 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
889// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
890// hdr |V=2|P| RC | PT=IJ=195 | length |
891// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
892// | inter-arrival jitter |
893// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
894// . .
895// . .
896// . .
897// | inter-arrival jitter |
898// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
899//
900// If present, this RTCP packet must be placed after a receiver report
901// (inside a compound RTCP packet), and MUST have the same value for RC
902// (reception report count) as the receiver report.
903
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000904int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000905RTCPSender::BuildExtendedJitterReport(
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000906 uint8_t* rtcpbuffer,
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +0000907 int& pos,
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000908 const uint32_t jitterTransmissionTimeOffset)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000909{
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +0000910 if (external_report_blocks_.size() > 0)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000911 {
912 WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id, "Not implemented.");
913 return 0;
914 }
915
916 // sanity
917 if(pos + 8 >= IP_PACKET_SIZE)
918 {
919 return -2;
920 }
921 // add picture loss indicator
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000922 uint8_t RC = 1;
923 rtcpbuffer[pos++]=(uint8_t)0x80 + RC;
924 rtcpbuffer[pos++]=(uint8_t)195;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000925
926 // Used fixed length of 2
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000927 rtcpbuffer[pos++]=(uint8_t)0;
928 rtcpbuffer[pos++]=(uint8_t)(1);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000929
930 // Add inter-arrival jitter
931 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer + pos,
932 jitterTransmissionTimeOffset);
933 pos += 4;
934 return 0;
935}
936
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000937int32_t
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +0000938RTCPSender::BuildPLI(uint8_t* rtcpbuffer, int& pos)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000939{
940 // sanity
941 if(pos + 12 >= IP_PACKET_SIZE)
942 {
943 return -2;
944 }
945 // add picture loss indicator
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000946 uint8_t FMT = 1;
947 rtcpbuffer[pos++]=(uint8_t)0x80 + FMT;
948 rtcpbuffer[pos++]=(uint8_t)206;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000949
950 //Used fixed length of 2
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000951 rtcpbuffer[pos++]=(uint8_t)0;
952 rtcpbuffer[pos++]=(uint8_t)(2);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000953
954 // Add our own SSRC
955 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
956 pos += 4;
957
958 // Add the remote SSRC
959 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _remoteSSRC);
960 pos += 4;
961 return 0;
962}
963
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000964int32_t RTCPSender::BuildFIR(uint8_t* rtcpbuffer,
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +0000965 int& pos,
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000966 bool repeat) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000967 // sanity
968 if(pos + 20 >= IP_PACKET_SIZE) {
969 return -2;
970 }
971 if (!repeat) {
972 _sequenceNumberFIR++; // do not increase if repetition
973 }
974
975 // add full intra request indicator
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000976 uint8_t FMT = 4;
977 rtcpbuffer[pos++] = (uint8_t)0x80 + FMT;
978 rtcpbuffer[pos++] = (uint8_t)206;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000979
980 //Length of 4
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000981 rtcpbuffer[pos++] = (uint8_t)0;
982 rtcpbuffer[pos++] = (uint8_t)(4);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000983
984 // Add our own SSRC
985 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
986 pos += 4;
987
988 // RFC 5104 4.3.1.2. Semantics
989 // SSRC of media source
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000990 rtcpbuffer[pos++] = (uint8_t)0;
991 rtcpbuffer[pos++] = (uint8_t)0;
992 rtcpbuffer[pos++] = (uint8_t)0;
993 rtcpbuffer[pos++] = (uint8_t)0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +0000994
995 // Additional Feedback Control Information (FCI)
996 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _remoteSSRC);
997 pos += 4;
998
pbos@webrtc.orgb57da652013-04-08 11:08:41 +0000999 rtcpbuffer[pos++] = (uint8_t)(_sequenceNumberFIR);
1000 rtcpbuffer[pos++] = (uint8_t)0;
1001 rtcpbuffer[pos++] = (uint8_t)0;
1002 rtcpbuffer[pos++] = (uint8_t)0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001003 return 0;
1004}
1005
1006/*
1007 0 1 2 3
1008 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
1009 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1010 | First | Number | PictureID |
1011 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1012*/
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001013int32_t
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00001014RTCPSender::BuildSLI(uint8_t* rtcpbuffer, int& pos, const uint8_t pictureID)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001015{
1016 // sanity
1017 if(pos + 16 >= IP_PACKET_SIZE)
1018 {
1019 return -2;
1020 }
1021 // add slice loss indicator
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001022 uint8_t FMT = 2;
1023 rtcpbuffer[pos++]=(uint8_t)0x80 + FMT;
1024 rtcpbuffer[pos++]=(uint8_t)206;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001025
1026 //Used fixed length of 3
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001027 rtcpbuffer[pos++]=(uint8_t)0;
1028 rtcpbuffer[pos++]=(uint8_t)(3);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001029
1030 // Add our own SSRC
1031 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
1032 pos += 4;
1033
1034 // Add the remote SSRC
1035 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _remoteSSRC);
1036 pos += 4;
1037
1038 // Add first, number & picture ID 6 bits
1039 // first = 0, 13 - bits
1040 // number = 0x1fff, 13 - bits only ones for now
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001041 uint32_t sliField = (0x1fff << 6)+ (0x3f & pictureID);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001042 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, sliField);
1043 pos += 4;
1044 return 0;
1045}
1046
1047/*
1048 0 1 2 3
1049 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
1050 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1051 | PB |0| Payload Type| Native RPSI bit string |
1052 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1053 | defined per codec ... | Padding (0) |
1054 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1055*/
1056/*
1057* Note: not generic made for VP8
1058*/
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001059int32_t
1060RTCPSender::BuildRPSI(uint8_t* rtcpbuffer,
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00001061 int& pos,
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001062 const uint64_t pictureID,
1063 const uint8_t payloadType)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001064{
1065 // sanity
1066 if(pos + 24 >= IP_PACKET_SIZE)
1067 {
1068 return -2;
1069 }
1070 // add Reference Picture Selection Indication
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001071 uint8_t FMT = 3;
1072 rtcpbuffer[pos++]=(uint8_t)0x80 + FMT;
1073 rtcpbuffer[pos++]=(uint8_t)206;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001074
1075 // calc length
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001076 uint32_t bitsRequired = 7;
1077 uint8_t bytesRequired = 1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001078 while((pictureID>>bitsRequired) > 0)
1079 {
1080 bitsRequired += 7;
1081 bytesRequired++;
1082 }
1083
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001084 uint8_t size = 3;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001085 if(bytesRequired > 6)
1086 {
1087 size = 5;
1088 } else if(bytesRequired > 2)
1089 {
1090 size = 4;
1091 }
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001092 rtcpbuffer[pos++]=(uint8_t)0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001093 rtcpbuffer[pos++]=size;
1094
1095 // Add our own SSRC
1096 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
1097 pos += 4;
1098
1099 // Add the remote SSRC
1100 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _remoteSSRC);
1101 pos += 4;
1102
1103 // calc padding length
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001104 uint8_t paddingBytes = 4-((2+bytesRequired)%4);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001105 if(paddingBytes == 4)
1106 {
1107 paddingBytes = 0;
1108 }
1109 // add padding length in bits
1110 rtcpbuffer[pos] = paddingBytes*8; // padding can be 0, 8, 16 or 24
1111 pos++;
1112
1113 // add payload type
1114 rtcpbuffer[pos] = payloadType;
1115 pos++;
1116
1117 // add picture ID
1118 for(int i = bytesRequired-1; i > 0; i--)
1119 {
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001120 rtcpbuffer[pos] = 0x80 | uint8_t(pictureID >> (i*7));
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001121 pos++;
1122 }
1123 // add last byte of picture ID
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001124 rtcpbuffer[pos] = uint8_t(pictureID & 0x7f);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001125 pos++;
1126
1127 // add padding
1128 for(int j = 0; j <paddingBytes; j++)
1129 {
1130 rtcpbuffer[pos] = 0;
1131 pos++;
1132 }
1133 return 0;
1134}
1135
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001136int32_t
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00001137RTCPSender::BuildREMB(uint8_t* rtcpbuffer, int& pos)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001138{
1139 // sanity
1140 if(pos + 20 + 4 * _lengthRembSSRC >= IP_PACKET_SIZE)
1141 {
1142 return -2;
1143 }
1144 // add application layer feedback
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001145 uint8_t FMT = 15;
1146 rtcpbuffer[pos++]=(uint8_t)0x80 + FMT;
1147 rtcpbuffer[pos++]=(uint8_t)206;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001148
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001149 rtcpbuffer[pos++]=(uint8_t)0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001150 rtcpbuffer[pos++]=_lengthRembSSRC + 4;
1151
1152 // Add our own SSRC
1153 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
1154 pos += 4;
1155
1156 // Remote SSRC must be 0
1157 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, 0);
1158 pos += 4;
1159
1160 rtcpbuffer[pos++]='R';
1161 rtcpbuffer[pos++]='E';
1162 rtcpbuffer[pos++]='M';
1163 rtcpbuffer[pos++]='B';
1164
1165 rtcpbuffer[pos++] = _lengthRembSSRC;
1166 // 6 bit Exp
1167 // 18 bit mantissa
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001168 uint8_t brExp = 0;
1169 for(uint32_t i=0; i<64; i++)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001170 {
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001171 if(_rembBitrate <= ((uint32_t)262143 << i))
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001172 {
1173 brExp = i;
1174 break;
1175 }
1176 }
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001177 const uint32_t brMantissa = (_rembBitrate >> brExp);
1178 rtcpbuffer[pos++]=(uint8_t)((brExp << 2) + ((brMantissa >> 16) & 0x03));
1179 rtcpbuffer[pos++]=(uint8_t)(brMantissa >> 8);
1180 rtcpbuffer[pos++]=(uint8_t)(brMantissa);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001181
1182 for (int i = 0; i < _lengthRembSSRC; i++)
1183 {
1184 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _rembSSRC[i]);
1185 pos += 4;
1186 }
1187 return 0;
1188}
1189
1190void
1191RTCPSender::SetTargetBitrate(unsigned int target_bitrate)
1192{
1193 CriticalSectionScoped lock(_criticalSectionRTCPSender);
1194 _tmmbr_Send = target_bitrate / 1000;
1195}
1196
pbos@webrtc.org4e7777b2013-09-09 16:02:19 +00001197int32_t RTCPSender::BuildTMMBR(ModuleRtpRtcpImpl* rtp_rtcp_module,
1198 uint8_t* rtcpbuffer,
1199 int& pos) {
1200 if (rtp_rtcp_module == NULL)
1201 return -1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001202 // Before sending the TMMBR check the received TMMBN, only an owner is allowed to raise the bitrate
1203 // If the sender is an owner of the TMMBN -> send TMMBR
1204 // If not an owner but the TMMBR would enter the TMMBN -> send TMMBR
1205
1206 // get current bounding set from RTCP receiver
1207 bool tmmbrOwner = false;
1208 // store in candidateSet, allocates one extra slot
1209 TMMBRSet* candidateSet = _tmmbrHelp.CandidateSet();
1210
1211 // holding _criticalSectionRTCPSender while calling RTCPreceiver which
1212 // will accuire _criticalSectionRTCPReceiver is a potental deadlock but
1213 // since RTCPreceiver is not doing the reverse we should be fine
pbos@webrtc.org4e7777b2013-09-09 16:02:19 +00001214 int32_t lengthOfBoundingSet =
1215 rtp_rtcp_module->BoundingSet(tmmbrOwner, candidateSet);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001216
1217 if(lengthOfBoundingSet > 0)
1218 {
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001219 for (int32_t i = 0; i < lengthOfBoundingSet; i++)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001220 {
1221 if( candidateSet->Tmmbr(i) == _tmmbr_Send &&
1222 candidateSet->PacketOH(i) == _packetOH_Send)
1223 {
1224 // do not send the same tuple
1225 return 0;
1226 }
1227 }
1228 if(!tmmbrOwner)
1229 {
1230 // use received bounding set as candidate set
1231 // add current tuple
1232 candidateSet->SetEntry(lengthOfBoundingSet,
1233 _tmmbr_Send,
1234 _packetOH_Send,
1235 _SSRC);
1236 int numCandidates = lengthOfBoundingSet+ 1;
1237
1238 // find bounding set
1239 TMMBRSet* boundingSet = NULL;
1240 int numBoundingSet = _tmmbrHelp.FindTMMBRBoundingSet(boundingSet);
1241 if(numBoundingSet > 0 || numBoundingSet <= numCandidates)
1242 {
1243 tmmbrOwner = _tmmbrHelp.IsOwner(_SSRC, numBoundingSet);
1244 }
1245 if(!tmmbrOwner)
1246 {
1247 // did not enter bounding set, no meaning to send this request
1248 return 0;
1249 }
1250 }
1251 }
1252
1253 if(_tmmbr_Send)
1254 {
1255 // sanity
1256 if(pos + 20 >= IP_PACKET_SIZE)
1257 {
1258 return -2;
1259 }
1260 // add TMMBR indicator
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001261 uint8_t FMT = 3;
1262 rtcpbuffer[pos++]=(uint8_t)0x80 + FMT;
1263 rtcpbuffer[pos++]=(uint8_t)205;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001264
1265 //Length of 4
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001266 rtcpbuffer[pos++]=(uint8_t)0;
1267 rtcpbuffer[pos++]=(uint8_t)(4);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001268
1269 // Add our own SSRC
1270 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
1271 pos += 4;
1272
1273 // RFC 5104 4.2.1.2. Semantics
1274
1275 // SSRC of media source
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001276 rtcpbuffer[pos++]=(uint8_t)0;
1277 rtcpbuffer[pos++]=(uint8_t)0;
1278 rtcpbuffer[pos++]=(uint8_t)0;
1279 rtcpbuffer[pos++]=(uint8_t)0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001280
1281 // Additional Feedback Control Information (FCI)
1282 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _remoteSSRC);
1283 pos += 4;
1284
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001285 uint32_t bitRate = _tmmbr_Send*1000;
1286 uint32_t mmbrExp = 0;
1287 for(uint32_t i=0;i<64;i++)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001288 {
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001289 if(bitRate <= ((uint32_t)131071 << i))
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001290 {
1291 mmbrExp = i;
1292 break;
1293 }
1294 }
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001295 uint32_t mmbrMantissa = (bitRate >> mmbrExp);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001296
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001297 rtcpbuffer[pos++]=(uint8_t)((mmbrExp << 2) + ((mmbrMantissa >> 15) & 0x03));
1298 rtcpbuffer[pos++]=(uint8_t)(mmbrMantissa >> 7);
1299 rtcpbuffer[pos++]=(uint8_t)((mmbrMantissa << 1) + ((_packetOH_Send >> 8)& 0x01));
1300 rtcpbuffer[pos++]=(uint8_t)(_packetOH_Send);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001301 }
1302 return 0;
1303}
1304
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001305int32_t
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00001306RTCPSender::BuildTMMBN(uint8_t* rtcpbuffer, int& pos)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001307{
1308 TMMBRSet* boundingSet = _tmmbrHelp.BoundingSetToSend();
1309 if(boundingSet == NULL)
1310 {
1311 return -1;
1312 }
1313 // sanity
1314 if(pos + 12 + boundingSet->lengthOfSet()*8 >= IP_PACKET_SIZE)
1315 {
1316 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", __FUNCTION__);
1317 return -2;
1318 }
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001319 uint8_t FMT = 4;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001320 // add TMMBN indicator
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001321 rtcpbuffer[pos++]=(uint8_t)0x80 + FMT;
1322 rtcpbuffer[pos++]=(uint8_t)205;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001323
1324 //Add length later
1325 int posLength = pos;
1326 pos++;
1327 pos++;
1328
1329 // Add our own SSRC
1330 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
1331 pos += 4;
1332
1333 // RFC 5104 4.2.2.2. Semantics
1334
1335 // SSRC of media source
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001336 rtcpbuffer[pos++]=(uint8_t)0;
1337 rtcpbuffer[pos++]=(uint8_t)0;
1338 rtcpbuffer[pos++]=(uint8_t)0;
1339 rtcpbuffer[pos++]=(uint8_t)0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001340
1341 // Additional Feedback Control Information (FCI)
1342 int numBoundingSet = 0;
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001343 for(uint32_t n=0; n< boundingSet->lengthOfSet(); n++)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001344 {
1345 if (boundingSet->Tmmbr(n) > 0)
1346 {
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001347 uint32_t tmmbrSSRC = boundingSet->Ssrc(n);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001348 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, tmmbrSSRC);
1349 pos += 4;
1350
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001351 uint32_t bitRate = boundingSet->Tmmbr(n) * 1000;
1352 uint32_t mmbrExp = 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001353 for(int i=0; i<64; i++)
1354 {
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001355 if(bitRate <= ((uint32_t)131071 << i))
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001356 {
1357 mmbrExp = i;
1358 break;
1359 }
1360 }
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001361 uint32_t mmbrMantissa = (bitRate >> mmbrExp);
1362 uint32_t measuredOH = boundingSet->PacketOH(n);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001363
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001364 rtcpbuffer[pos++]=(uint8_t)((mmbrExp << 2) + ((mmbrMantissa >> 15) & 0x03));
1365 rtcpbuffer[pos++]=(uint8_t)(mmbrMantissa >> 7);
1366 rtcpbuffer[pos++]=(uint8_t)((mmbrMantissa << 1) + ((measuredOH >> 8)& 0x01));
1367 rtcpbuffer[pos++]=(uint8_t)(measuredOH);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001368 numBoundingSet++;
1369 }
1370 }
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001371 uint16_t length= (uint16_t)(2+2*numBoundingSet);
1372 rtcpbuffer[posLength++]=(uint8_t)(length>>8);
1373 rtcpbuffer[posLength]=(uint8_t)(length);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001374 return 0;
1375}
1376
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001377int32_t
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00001378RTCPSender::BuildAPP(uint8_t* rtcpbuffer, int& pos)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001379{
1380 // sanity
1381 if(_appData == NULL)
1382 {
1383 WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id, "%s invalid state", __FUNCTION__);
1384 return -1;
1385 }
1386 if(pos + 12 + _appLength >= IP_PACKET_SIZE)
1387 {
1388 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", __FUNCTION__);
1389 return -2;
1390 }
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001391 rtcpbuffer[pos++]=(uint8_t)0x80 + _appSubType;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001392
1393 // Add APP ID
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001394 rtcpbuffer[pos++]=(uint8_t)204;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001395
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001396 uint16_t length = (_appLength>>2) + 2; // include SSRC and name
1397 rtcpbuffer[pos++]=(uint8_t)(length>>8);
1398 rtcpbuffer[pos++]=(uint8_t)(length);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001399
1400 // Add our own SSRC
1401 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
1402 pos += 4;
1403
1404 // Add our application name
1405 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _appName);
1406 pos += 4;
1407
1408 // Add the data
1409 memcpy(rtcpbuffer +pos, _appData,_appLength);
1410 pos += _appLength;
1411 return 0;
1412}
1413
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001414int32_t
1415RTCPSender::BuildNACK(uint8_t* rtcpbuffer,
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00001416 int& pos,
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001417 const int32_t nackSize,
1418 const uint16_t* nackList,
edjee@google.comdded2062013-04-04 19:43:34 +00001419 std::string* nackString)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001420{
1421 // sanity
1422 if(pos + 16 >= IP_PACKET_SIZE)
1423 {
1424 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", __FUNCTION__);
1425 return -2;
1426 }
1427
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001428 // int size, uint16_t* nackList
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001429 // add nack list
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001430 uint8_t FMT = 1;
1431 rtcpbuffer[pos++]=(uint8_t)0x80 + FMT;
1432 rtcpbuffer[pos++]=(uint8_t)205;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001433
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001434 rtcpbuffer[pos++]=(uint8_t) 0;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001435 int nackSizePos = pos;
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001436 rtcpbuffer[pos++]=(uint8_t)(3); //setting it to one kNACK signal as default
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001437
1438 // Add our own SSRC
1439 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
1440 pos += 4;
1441
1442 // Add the remote SSRC
1443 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _remoteSSRC);
1444 pos += 4;
1445
edjee@google.comdded2062013-04-04 19:43:34 +00001446 NACKStringBuilder stringBuilder;
andresp@webrtc.orgbda02e42013-04-11 11:30:39 +00001447 // Build NACK bitmasks and write them to the RTCP message.
1448 // The nack list should be sorted and not contain duplicates if one
1449 // wants to build the smallest rtcp nack packet.
1450 int numOfNackFields = 0;
1451 int maxNackFields = std::min<int>(kRtcpMaxNackFields,
1452 (IP_PACKET_SIZE - pos) / 4);
1453 int i = 0;
1454 while (i < nackSize && numOfNackFields < maxNackFields) {
1455 stringBuilder.PushNACK(nackList[i]);
1456 uint16_t nack = nackList[i++];
1457 uint16_t bitmask = 0;
1458 while (i < nackSize) {
1459 int shift = static_cast<uint16_t>(nackList[i] - nack) - 1;
1460 if (shift >= 0 && shift <= 15) {
1461 stringBuilder.PushNACK(nackList[i]);
1462 bitmask |= (1 << shift);
1463 ++i;
1464 } else {
1465 break;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001466 }
andresp@webrtc.orgbda02e42013-04-11 11:30:39 +00001467 }
1468 // Write the sequence number and the bitmask to the packet.
1469 assert(pos + 4 < IP_PACKET_SIZE);
1470 ModuleRTPUtility::AssignUWord16ToBuffer(rtcpbuffer + pos, nack);
1471 pos += 2;
1472 ModuleRTPUtility::AssignUWord16ToBuffer(rtcpbuffer + pos, bitmask);
1473 pos += 2;
1474 numOfNackFields++;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001475 }
andresp@webrtc.orgbda02e42013-04-11 11:30:39 +00001476 if (i != nackSize) {
1477 WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id,
1478 "Nack list to large for one packet.");
1479 }
1480 rtcpbuffer[nackSizePos] = static_cast<uint8_t>(2 + numOfNackFields);
edjee@google.comdded2062013-04-04 19:43:34 +00001481 *nackString = stringBuilder.GetResult();
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001482 return 0;
1483}
1484
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001485int32_t
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00001486RTCPSender::BuildBYE(uint8_t* rtcpbuffer, int& pos)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001487{
1488 // sanity
1489 if(pos + 8 >= IP_PACKET_SIZE)
1490 {
1491 return -2;
1492 }
1493 if(_includeCSRCs)
1494 {
1495 // Add a bye packet
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001496 rtcpbuffer[pos++]=(uint8_t)0x80 + 1 + _CSRCs; // number of SSRC+CSRCs
1497 rtcpbuffer[pos++]=(uint8_t)203;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001498
1499 // length
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001500 rtcpbuffer[pos++]=(uint8_t)0;
1501 rtcpbuffer[pos++]=(uint8_t)(1 + _CSRCs);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001502
1503 // Add our own SSRC
1504 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
1505 pos += 4;
1506
1507 // add CSRCs
1508 for(int i = 0; i < _CSRCs; i++)
1509 {
1510 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _CSRC[i]);
1511 pos += 4;
1512 }
1513 } else
1514 {
1515 // Add a bye packet
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001516 rtcpbuffer[pos++]=(uint8_t)0x80 + 1; // number of SSRC+CSRCs
1517 rtcpbuffer[pos++]=(uint8_t)203;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001518
1519 // length
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001520 rtcpbuffer[pos++]=(uint8_t)0;
1521 rtcpbuffer[pos++]=(uint8_t)1;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001522
1523 // Add our own SSRC
1524 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
1525 pos += 4;
1526 }
1527 return 0;
1528}
1529
asapersson@webrtc.orgd6da2392013-10-02 13:15:34 +00001530int32_t RTCPSender::BuildReceiverReferenceTime(uint8_t* buffer,
1531 int& pos,
1532 uint32_t ntp_sec,
1533 uint32_t ntp_frac) {
1534 const int kRrTimeBlockLength = 20;
1535 if (pos + kRrTimeBlockLength >= IP_PACKET_SIZE) {
1536 return -2;
1537 }
1538
1539 if (last_xr_rr_.size() >= RTCP_NUMBER_OF_SR) {
1540 last_xr_rr_.erase(last_xr_rr_.begin());
1541 }
1542 last_xr_rr_.insert(std::pair<uint32_t, int64_t>(
1543 RTCPUtility::MidNtp(ntp_sec, ntp_frac),
1544 Clock::NtpToMs(ntp_sec, ntp_frac)));
1545
1546 // Add XR header.
1547 buffer[pos++] = 0x80;
1548 buffer[pos++] = 207;
1549 buffer[pos++] = 0; // XR packet length.
1550 buffer[pos++] = 4; // XR packet length.
1551
1552 // Add our own SSRC.
1553 ModuleRTPUtility::AssignUWord32ToBuffer(buffer + pos, _SSRC);
1554 pos += 4;
1555
1556 // 0 1 2 3
1557 // 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
1558 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1559 // | BT=4 | reserved | block length = 2 |
1560 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1561 // | NTP timestamp, most significant word |
1562 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1563 // | NTP timestamp, least significant word |
1564 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1565
1566 // Add Receiver Reference Time Report block.
1567 buffer[pos++] = 4; // BT.
1568 buffer[pos++] = 0; // Reserved.
1569 buffer[pos++] = 0; // Block length.
1570 buffer[pos++] = 2; // Block length.
1571
1572 // NTP timestamp.
1573 ModuleRTPUtility::AssignUWord32ToBuffer(buffer + pos, ntp_sec);
1574 pos += 4;
1575 ModuleRTPUtility::AssignUWord32ToBuffer(buffer + pos, ntp_frac);
1576 pos += 4;
1577
1578 return 0;
1579}
1580
1581int32_t RTCPSender::BuildDlrr(uint8_t* buffer,
1582 int& pos,
1583 const RtcpReceiveTimeInfo& info) {
1584 const int kDlrrBlockLength = 24;
1585 if (pos + kDlrrBlockLength >= IP_PACKET_SIZE) {
1586 return -2;
1587 }
1588
1589 // Add XR header.
1590 buffer[pos++] = 0x80;
1591 buffer[pos++] = 207;
1592 buffer[pos++] = 0; // XR packet length.
1593 buffer[pos++] = 5; // XR packet length.
1594
1595 // Add our own SSRC.
1596 ModuleRTPUtility::AssignUWord32ToBuffer(buffer + pos, _SSRC);
1597 pos += 4;
1598
1599 // 0 1 2 3
1600 // 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
1601 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1602 // | BT=5 | reserved | block length |
1603 // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
1604 // | SSRC_1 (SSRC of first receiver) | sub-
1605 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
1606 // | last RR (LRR) | 1
1607 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1608 // | delay since last RR (DLRR) |
1609 // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
1610 // | SSRC_2 (SSRC of second receiver) | sub-
1611 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
1612 // : ... : 2
1613
1614 // Add DLRR sub block.
1615 buffer[pos++] = 5; // BT.
1616 buffer[pos++] = 0; // Reserved.
1617 buffer[pos++] = 0; // Block length.
1618 buffer[pos++] = 3; // Block length.
1619
1620 // NTP timestamp.
1621 ModuleRTPUtility::AssignUWord32ToBuffer(buffer + pos, info.sourceSSRC);
1622 pos += 4;
1623 ModuleRTPUtility::AssignUWord32ToBuffer(buffer + pos, info.lastRR);
1624 pos += 4;
1625 ModuleRTPUtility::AssignUWord32ToBuffer(buffer + pos, info.delaySinceLastRR);
1626 pos += 4;
1627
1628 return 0;
1629}
1630
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001631int32_t
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00001632RTCPSender::BuildVoIPMetric(uint8_t* rtcpbuffer, int& pos)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001633{
1634 // sanity
1635 if(pos + 44 >= IP_PACKET_SIZE)
1636 {
1637 return -2;
1638 }
1639
1640 // Add XR header
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001641 rtcpbuffer[pos++]=(uint8_t)0x80;
1642 rtcpbuffer[pos++]=(uint8_t)207;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001643
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001644 uint32_t XRLengthPos = pos;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001645
1646 // handle length later on
1647 pos++;
1648 pos++;
1649
1650 // Add our own SSRC
1651 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _SSRC);
1652 pos += 4;
1653
1654 // Add a VoIP metrics block
1655 rtcpbuffer[pos++]=7;
1656 rtcpbuffer[pos++]=0;
1657 rtcpbuffer[pos++]=0;
1658 rtcpbuffer[pos++]=8;
1659
1660 // Add the remote SSRC
1661 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+pos, _remoteSSRC);
1662 pos += 4;
1663
1664 rtcpbuffer[pos++] = _xrVoIPMetric.lossRate;
1665 rtcpbuffer[pos++] = _xrVoIPMetric.discardRate;
1666 rtcpbuffer[pos++] = _xrVoIPMetric.burstDensity;
1667 rtcpbuffer[pos++] = _xrVoIPMetric.gapDensity;
1668
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001669 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.burstDuration >> 8);
1670 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.burstDuration);
1671 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.gapDuration >> 8);
1672 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.gapDuration);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001673
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001674 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.roundTripDelay >> 8);
1675 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.roundTripDelay);
1676 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.endSystemDelay >> 8);
1677 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.endSystemDelay);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001678
1679 rtcpbuffer[pos++] = _xrVoIPMetric.signalLevel;
1680 rtcpbuffer[pos++] = _xrVoIPMetric.noiseLevel;
1681 rtcpbuffer[pos++] = _xrVoIPMetric.RERL;
1682 rtcpbuffer[pos++] = _xrVoIPMetric.Gmin;
1683
1684 rtcpbuffer[pos++] = _xrVoIPMetric.Rfactor;
1685 rtcpbuffer[pos++] = _xrVoIPMetric.extRfactor;
1686 rtcpbuffer[pos++] = _xrVoIPMetric.MOSLQ;
1687 rtcpbuffer[pos++] = _xrVoIPMetric.MOSCQ;
1688
1689 rtcpbuffer[pos++] = _xrVoIPMetric.RXconfig;
1690 rtcpbuffer[pos++] = 0; // reserved
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001691 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.JBnominal >> 8);
1692 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.JBnominal);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001693
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001694 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.JBmax >> 8);
1695 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.JBmax);
1696 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.JBabsMax >> 8);
1697 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.JBabsMax);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001698
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00001699 rtcpbuffer[XRLengthPos]=(uint8_t)(0);
1700 rtcpbuffer[XRLengthPos+1]=(uint8_t)(10);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001701 return 0;
1702}
1703
pbos@webrtc.org4e7777b2013-09-09 16:02:19 +00001704int32_t RTCPSender::SendRTCP(const FeedbackState& feedback_state,
1705 uint32_t packetTypeFlags,
1706 int32_t nackSize,
1707 const uint16_t* nackList,
1708 bool repeat,
1709 uint64_t pictureID) {
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00001710 {
1711 CriticalSectionScoped lock(_criticalSectionRTCPSender);
1712 if(_method == kRtcpOff)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001713 {
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00001714 WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id,
1715 "%s invalid state", __FUNCTION__);
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00001716 return -1;
1717 }
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00001718 }
1719 uint8_t rtcp_buffer[IP_PACKET_SIZE];
pbos@webrtc.org4e7777b2013-09-09 16:02:19 +00001720 int rtcp_length = PrepareRTCP(feedback_state,
1721 packetTypeFlags,
1722 nackSize,
1723 nackList,
1724 repeat,
1725 pictureID,
1726 rtcp_buffer,
1727 IP_PACKET_SIZE);
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00001728 if (rtcp_length < 0) {
1729 return -1;
1730 }
1731 // Sanity don't send empty packets.
1732 if (rtcp_length == 0)
1733 {
1734 return -1;
1735 }
1736 return SendToNetwork(rtcp_buffer, static_cast<uint16_t>(rtcp_length));
1737}
1738
pbos@webrtc.org4e7777b2013-09-09 16:02:19 +00001739int RTCPSender::PrepareRTCP(const FeedbackState& feedback_state,
1740 uint32_t packetTypeFlags,
1741 int32_t nackSize,
1742 const uint16_t* nackList,
1743 bool repeat,
1744 uint64_t pictureID,
1745 uint8_t* rtcp_buffer,
1746 int buffer_size) {
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00001747 uint32_t rtcpPacketTypeFlags = packetTypeFlags;
1748 // Collect the received information.
1749 uint32_t NTPsec = 0;
1750 uint32_t NTPfrac = 0;
1751 uint32_t jitterTransmissionOffset = 0;
1752 int position = 0;
1753
1754 CriticalSectionScoped lock(_criticalSectionRTCPSender);
1755
1756 if(_TMMBR ) // Attach TMMBR to send and receive reports.
1757 {
1758 rtcpPacketTypeFlags |= kRtcpTmmbr;
1759 }
1760 if(_appSend)
1761 {
1762 rtcpPacketTypeFlags |= kRtcpApp;
1763 _appSend = false;
1764 }
1765 if(_REMB && _sendREMB)
1766 {
1767 // Always attach REMB to SR if that is configured. Note that REMB is
1768 // only sent on one of the RTP modules in the REMB group.
1769 rtcpPacketTypeFlags |= kRtcpRemb;
1770 }
1771 if(_xrSendVoIPMetric)
1772 {
1773 rtcpPacketTypeFlags |= kRtcpXrVoipMetric;
1774 _xrSendVoIPMetric = false;
1775 }
1776 if(_sendTMMBN) // Set when having received a TMMBR.
1777 {
1778 rtcpPacketTypeFlags |= kRtcpTmmbn;
1779 _sendTMMBN = false;
1780 }
asapersson@webrtc.orgd6da2392013-10-02 13:15:34 +00001781 if (xrSendReceiverReferenceTimeEnabled_ &&
1782 (rtcpPacketTypeFlags & kRtcpReport))
1783 {
1784 if (!_sending)
1785 {
1786 rtcpPacketTypeFlags |= kRtcpXrReceiverReferenceTime;
1787 }
1788 if (feedback_state.has_last_xr_rr)
1789 {
1790 rtcpPacketTypeFlags |= kRtcpXrDlrrReportBlock;
1791 }
1792 }
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00001793 if(_method == kRtcpCompound)
1794 {
1795 if(_sending)
1796 {
1797 rtcpPacketTypeFlags |= kRtcpSr;
1798 } else
1799 {
1800 rtcpPacketTypeFlags |= kRtcpRr;
1801 }
1802 } else if(_method == kRtcpNonCompound)
1803 {
1804 if(rtcpPacketTypeFlags & kRtcpReport)
1805 {
1806 if(_sending)
1807 {
1808 rtcpPacketTypeFlags |= kRtcpSr;
1809 } else
1810 {
1811 rtcpPacketTypeFlags |= kRtcpRr;
1812 }
1813 }
1814 }
1815 if( rtcpPacketTypeFlags & kRtcpRr ||
1816 rtcpPacketTypeFlags & kRtcpSr)
1817 {
1818 // generate next time to send a RTCP report
1819 // seeded from RTP constructor
1820 int32_t random = rand() % 1000;
1821 int32_t timeToNext = RTCP_INTERVAL_AUDIO_MS;
1822
1823 if(_audio)
1824 {
1825 timeToNext = (RTCP_INTERVAL_AUDIO_MS/2) +
1826 (RTCP_INTERVAL_AUDIO_MS*random/1000);
1827 }else
1828 {
1829 uint32_t minIntervalMs = RTCP_INTERVAL_AUDIO_MS;
1830 if(_sending)
1831 {
pbos@webrtc.org4e7777b2013-09-09 16:02:19 +00001832 // Calculate bandwidth for video; 360 / send bandwidth in kbit/s.
1833 uint32_t send_bitrate_kbit = feedback_state.send_bitrate / 1000;
1834 if (send_bitrate_kbit != 0)
1835 minIntervalMs = 360000 / send_bitrate_kbit;
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00001836 }
1837 if(minIntervalMs > RTCP_INTERVAL_VIDEO_MS)
1838 {
1839 minIntervalMs = RTCP_INTERVAL_VIDEO_MS;
1840 }
1841 timeToNext = (minIntervalMs/2) + (minIntervalMs*random/1000);
1842 }
1843 _nextTimeToSendRTCP = _clock->TimeInMilliseconds() + timeToNext;
1844 }
1845
1846 // If the data does not fit in the packet we fill it as much as possible.
1847 int32_t buildVal = 0;
1848
1849 // We need to send our NTP even if we haven't received any reports.
1850 _clock->CurrentNtp(NTPsec, NTPfrac);
1851 if (ShouldSendReportBlocks(rtcpPacketTypeFlags)) {
1852 StatisticianMap statisticians =
1853 receive_statistics_->GetActiveStatisticians();
1854 if (!statisticians.empty()) {
1855 StatisticianMap::const_iterator it;
1856 int i;
1857 for (it = statisticians.begin(), i = 0; it != statisticians.end();
1858 ++it, ++i) {
1859 RTCPReportBlock report_block;
pbos@webrtc.org4e7777b2013-09-09 16:02:19 +00001860 if (PrepareReport(
1861 feedback_state, it->second, &report_block, &NTPsec, &NTPfrac))
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00001862 AddReportBlock(it->first, &internal_report_blocks_, &report_block);
1863 }
1864 if (_IJ && !statisticians.empty()) {
1865 rtcpPacketTypeFlags |= kRtcpTransmissionTimeOffset;
1866 }
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00001867 }
1868 }
1869
1870 if(rtcpPacketTypeFlags & kRtcpSr)
1871 {
pbos@webrtc.org4e7777b2013-09-09 16:02:19 +00001872 buildVal = BuildSR(feedback_state, rtcp_buffer, position, NTPsec, NTPfrac);
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00001873 if (buildVal == -1) {
1874 return -1;
1875 } else if (buildVal == -2) {
1876 return position;
1877 }
1878 buildVal = BuildSDEC(rtcp_buffer, position);
1879 if (buildVal == -1) {
1880 return -1;
1881 } else if (buildVal == -2) {
1882 return position;
1883 }
1884 }else if(rtcpPacketTypeFlags & kRtcpRr)
1885 {
1886 buildVal = BuildRR(rtcp_buffer, position, NTPsec, NTPfrac);
1887 if (buildVal == -1) {
1888 return -1;
1889 } else if (buildVal == -2) {
1890 return position;
1891 }
1892 // only of set
1893 if(_CNAME[0] != 0)
1894 {
1895 buildVal = BuildSDEC(rtcp_buffer, position);
1896 if (buildVal == -1) {
1897 return -1;
1898 }
1899 }
1900 }
1901 if(rtcpPacketTypeFlags & kRtcpTransmissionTimeOffset)
1902 {
1903 // If present, this RTCP packet must be placed after a
1904 // receiver report.
1905 buildVal = BuildExtendedJitterReport(rtcp_buffer,
1906 position,
1907 jitterTransmissionOffset);
1908 if (buildVal == -1) {
1909 return -1;
1910 } else if (buildVal == -2) {
1911 return position;
1912 }
1913 }
1914 if(rtcpPacketTypeFlags & kRtcpPli)
1915 {
1916 buildVal = BuildPLI(rtcp_buffer, position);
1917 if (buildVal == -1) {
1918 return -1;
1919 } else if (buildVal == -2) {
1920 return position;
1921 }
1922 TRACE_EVENT_INSTANT0("webrtc_rtp", "RTCPSender::PLI");
1923 _pliCount++;
1924 TRACE_COUNTER_ID1("webrtc_rtp", "RTCP_PLICount", _SSRC, _pliCount);
1925 }
1926 if(rtcpPacketTypeFlags & kRtcpFir)
1927 {
1928 buildVal = BuildFIR(rtcp_buffer, position, repeat);
1929 if (buildVal == -1) {
1930 return -1;
1931 } else if (buildVal == -2) {
1932 return position;
1933 }
1934 TRACE_EVENT_INSTANT0("webrtc_rtp", "RTCPSender::FIR");
1935 _fullIntraRequestCount++;
1936 TRACE_COUNTER_ID1("webrtc_rtp", "RTCP_FIRCount", _SSRC,
1937 _fullIntraRequestCount);
1938 }
1939 if(rtcpPacketTypeFlags & kRtcpSli)
1940 {
1941 buildVal = BuildSLI(rtcp_buffer, position, (uint8_t)pictureID);
1942 if (buildVal == -1) {
1943 return -1;
1944 } else if (buildVal == -2) {
1945 return position;
1946 }
1947 }
1948 if(rtcpPacketTypeFlags & kRtcpRpsi)
1949 {
pbos@webrtc.org4e7777b2013-09-09 16:02:19 +00001950 const int8_t payloadType = feedback_state.send_payload_type;
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00001951 if (payloadType == -1) {
1952 return -1;
1953 }
1954 buildVal = BuildRPSI(rtcp_buffer, position, pictureID,
1955 (uint8_t)payloadType);
1956 if (buildVal == -1) {
1957 return -1;
1958 } else if (buildVal == -2) {
1959 return position;
1960 }
1961 }
1962 if(rtcpPacketTypeFlags & kRtcpRemb)
1963 {
1964 buildVal = BuildREMB(rtcp_buffer, position);
1965 if (buildVal == -1) {
1966 return -1;
1967 } else if (buildVal == -2) {
1968 return position;
1969 }
1970 TRACE_EVENT_INSTANT0("webrtc_rtp", "RTCPSender::REMB");
1971 }
1972 if(rtcpPacketTypeFlags & kRtcpBye)
1973 {
1974 buildVal = BuildBYE(rtcp_buffer, position);
1975 if (buildVal == -1) {
1976 return -1;
1977 } else if (buildVal == -2) {
1978 return position;
1979 }
1980 }
1981 if(rtcpPacketTypeFlags & kRtcpApp)
1982 {
1983 buildVal = BuildAPP(rtcp_buffer, position);
1984 if (buildVal == -1) {
1985 return -1;
1986 } else if (buildVal == -2) {
1987 return position;
1988 }
1989 }
1990 if(rtcpPacketTypeFlags & kRtcpTmmbr)
1991 {
pbos@webrtc.org4e7777b2013-09-09 16:02:19 +00001992 buildVal = BuildTMMBR(feedback_state.module, rtcp_buffer, position);
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00001993 if (buildVal == -1) {
1994 return -1;
1995 } else if (buildVal == -2) {
1996 return position;
1997 }
1998 }
1999 if(rtcpPacketTypeFlags & kRtcpTmmbn)
2000 {
2001 buildVal = BuildTMMBN(rtcp_buffer, position);
2002 if (buildVal == -1) {
2003 return -1;
2004 } else if (buildVal == -2) {
2005 return position;
2006 }
2007 }
2008 if(rtcpPacketTypeFlags & kRtcpNack)
2009 {
2010 std::string nackString;
2011 buildVal = BuildNACK(rtcp_buffer, position, nackSize, nackList,
2012 &nackString);
2013 if (buildVal == -1) {
2014 return -1;
2015 } else if (buildVal == -2) {
2016 return position;
2017 }
2018 TRACE_EVENT_INSTANT1("webrtc_rtp", "RTCPSender::NACK",
2019 "nacks", TRACE_STR_COPY(nackString.c_str()));
2020 _nackCount++;
2021 TRACE_COUNTER_ID1("webrtc_rtp", "RTCP_NACKCount", _SSRC, _nackCount);
2022 }
2023 if(rtcpPacketTypeFlags & kRtcpXrVoipMetric)
2024 {
2025 buildVal = BuildVoIPMetric(rtcp_buffer, position);
2026 if (buildVal == -1) {
2027 return -1;
2028 } else if (buildVal == -2) {
2029 return position;
2030 }
2031 }
asapersson@webrtc.orgd6da2392013-10-02 13:15:34 +00002032 if (rtcpPacketTypeFlags & kRtcpXrReceiverReferenceTime)
2033 {
2034 buildVal = BuildReceiverReferenceTime(rtcp_buffer,
2035 position,
2036 NTPsec,
2037 NTPfrac);
2038 if (buildVal == -1) {
2039 return -1;
2040 } else if (buildVal == -2) {
2041 return position;
2042 }
2043 }
2044 if (rtcpPacketTypeFlags & kRtcpXrDlrrReportBlock)
2045 {
2046 buildVal = BuildDlrr(rtcp_buffer, position, feedback_state.last_xr_rr);
2047 if (buildVal == -1) {
2048 return -1;
2049 } else if (buildVal == -2) {
2050 return position;
2051 }
2052 }
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00002053 return position;
2054}
2055
2056bool RTCPSender::ShouldSendReportBlocks(uint32_t rtcp_packet_type) const {
2057 return Status() == kRtcpCompound ||
2058 (rtcp_packet_type & kRtcpReport) ||
2059 (rtcp_packet_type & kRtcpSr) ||
2060 (rtcp_packet_type & kRtcpRr);
2061}
2062
pbos@webrtc.org4e7777b2013-09-09 16:02:19 +00002063bool RTCPSender::PrepareReport(const FeedbackState& feedback_state,
2064 StreamStatistician* statistician,
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00002065 RTCPReportBlock* report_block,
2066 uint32_t* ntp_secs, uint32_t* ntp_frac) {
2067 // Do we have receive statistics to send?
sprang@webrtc.org4f1f5fa2013-12-19 13:26:02 +00002068 RtcpStatistics stats;
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00002069 if (!statistician->GetStatistics(&stats, true))
2070 return false;
2071 report_block->fractionLost = stats.fraction_lost;
2072 report_block->cumulativeLost = stats.cumulative_lost;
2073 report_block->extendedHighSeqNum =
2074 stats.extended_max_sequence_number;
2075 report_block->jitter = stats.jitter;
2076
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00002077 // get our NTP as late as possible to avoid a race
2078 _clock->CurrentNtp(*ntp_secs, *ntp_frac);
2079
2080 // Delay since last received report
2081 uint32_t delaySinceLastReceivedSR = 0;
pbos@webrtc.org4e7777b2013-09-09 16:02:19 +00002082 if ((feedback_state.last_rr_ntp_secs != 0) ||
2083 (feedback_state.last_rr_ntp_frac != 0)) {
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00002084 // get the 16 lowest bits of seconds and the 16 higest bits of fractions
2085 uint32_t now=*ntp_secs&0x0000FFFF;
2086 now <<=16;
2087 now += (*ntp_frac&0xffff0000)>>16;
2088
pbos@webrtc.org4e7777b2013-09-09 16:02:19 +00002089 uint32_t receiveTime = feedback_state.last_rr_ntp_secs&0x0000FFFF;
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00002090 receiveTime <<=16;
pbos@webrtc.org4e7777b2013-09-09 16:02:19 +00002091 receiveTime += (feedback_state.last_rr_ntp_frac&0xffff0000)>>16;
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00002092
2093 delaySinceLastReceivedSR = now-receiveTime;
2094 }
2095 report_block->delaySinceLastSR = delaySinceLastReceivedSR;
pbos@webrtc.org4e7777b2013-09-09 16:02:19 +00002096 report_block->lastSR = feedback_state.remote_sr;
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00002097 return true;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002098}
2099
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00002100int32_t
2101RTCPSender::SendToNetwork(const uint8_t* dataBuffer,
2102 const uint16_t length)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002103{
2104 CriticalSectionScoped lock(_criticalSectionTransport);
2105 if(_cbTransport)
2106 {
2107 if(_cbTransport->SendRTCPPacket(_id, dataBuffer, length) > 0)
2108 {
2109 return 0;
2110 }
2111 }
2112 return -1;
2113}
2114
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00002115int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002116RTCPSender::SetCSRCStatus(const bool include)
2117{
2118 _includeCSRCs = include;
2119 return 0;
2120}
2121
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00002122int32_t
2123RTCPSender::SetCSRCs(const uint32_t arrOfCSRC[kRtpCsrcSize],
2124 const uint8_t arrLength)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002125{
2126 if(arrLength > kRtpCsrcSize)
2127 {
2128 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", __FUNCTION__);
2129 assert(false);
2130 return -1;
2131 }
2132
2133 CriticalSectionScoped lock(_criticalSectionRTCPSender);
2134
2135 for(int i = 0; i < arrLength;i++)
2136 {
2137 _CSRC[i] = arrOfCSRC[i];
2138 }
2139 _CSRCs = arrLength;
2140 return 0;
2141}
2142
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00002143int32_t
2144RTCPSender::SetApplicationSpecificData(const uint8_t subType,
2145 const uint32_t name,
2146 const uint8_t* data,
2147 const uint16_t length)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002148{
2149 if(length %4 != 0)
2150 {
2151 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", __FUNCTION__);
2152 return -1;
2153 }
2154 CriticalSectionScoped lock(_criticalSectionRTCPSender);
2155
2156 if(_appData)
2157 {
2158 delete [] _appData;
2159 }
2160
2161 _appSend = true;
2162 _appSubType = subType;
2163 _appName = name;
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00002164 _appData = new uint8_t[length];
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002165 _appLength = length;
2166 memcpy(_appData, data, length);
2167 return 0;
2168}
2169
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00002170int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002171RTCPSender::SetRTCPVoIPMetrics(const RTCPVoIPMetric* VoIPMetric)
2172{
2173 CriticalSectionScoped lock(_criticalSectionRTCPSender);
2174 memcpy(&_xrVoIPMetric, VoIPMetric, sizeof(RTCPVoIPMetric));
2175
2176 _xrSendVoIPMetric = true;
2177 return 0;
2178}
2179
asapersson@webrtc.orgd6da2392013-10-02 13:15:34 +00002180void RTCPSender::SendRtcpXrReceiverReferenceTime(bool enable) {
2181 CriticalSectionScoped lock(_criticalSectionRTCPSender);
2182 xrSendReceiverReferenceTimeEnabled_ = enable;
2183}
2184
asapersson@webrtc.org3dc7ff32013-11-21 08:57:04 +00002185bool RTCPSender::RtcpXrReceiverReferenceTime() const {
2186 CriticalSectionScoped lock(_criticalSectionRTCPSender);
2187 return xrSendReceiverReferenceTimeEnabled_;
2188}
2189
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002190// called under critsect _criticalSectionRTCPSender
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00002191int32_t RTCPSender::WriteAllReportBlocksToBuffer(
2192 uint8_t* rtcpbuffer,
2193 int pos,
2194 uint8_t& numberOfReportBlocks,
2195 const uint32_t NTPsec,
2196 const uint32_t NTPfrac) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002197 // sanity one block
2198 if(pos + 24 >= IP_PACKET_SIZE) {
2199 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
2200 "%s invalid argument", __FUNCTION__);
2201 return -1;
2202 }
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00002203 numberOfReportBlocks = external_report_blocks_.size();
2204 numberOfReportBlocks += internal_report_blocks_.size();
2205 if ((pos + numberOfReportBlocks * 24) >= IP_PACKET_SIZE) {
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002206 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
2207 "%s invalid argument", __FUNCTION__);
2208 return -1;
2209 }
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00002210 pos = WriteReportBlocksToBuffer(rtcpbuffer, pos, internal_report_blocks_);
2211 while (!internal_report_blocks_.empty()) {
2212 delete internal_report_blocks_.begin()->second;
2213 internal_report_blocks_.erase(internal_report_blocks_.begin());
2214 }
2215 pos = WriteReportBlocksToBuffer(rtcpbuffer, pos, external_report_blocks_);
2216 return pos;
2217}
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002218
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00002219int32_t RTCPSender::WriteReportBlocksToBuffer(
2220 uint8_t* rtcpbuffer,
2221 int32_t position,
2222 const std::map<uint32_t, RTCPReportBlock*>& report_blocks) {
2223 std::map<uint32_t, RTCPReportBlock*>::const_iterator it =
2224 report_blocks.begin();
2225 for (; it != report_blocks.end(); it++) {
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00002226 uint32_t remoteSSRC = it->first;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002227 RTCPReportBlock* reportBlock = it->second;
2228 if (reportBlock) {
2229 // Remote SSRC
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00002230 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+position, remoteSSRC);
2231 position += 4;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002232
2233 // fraction lost
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00002234 rtcpbuffer[position++] = reportBlock->fractionLost;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002235
2236 // cumulative loss
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00002237 ModuleRTPUtility::AssignUWord24ToBuffer(rtcpbuffer+position,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002238 reportBlock->cumulativeLost);
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00002239 position += 3;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002240
2241 // extended highest seq_no, contain the highest sequence number received
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00002242 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+position,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002243 reportBlock->extendedHighSeqNum);
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00002244 position += 4;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002245
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00002246 // Jitter
2247 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+position,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002248 reportBlock->jitter);
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00002249 position += 4;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002250
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00002251 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+position,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002252 reportBlock->lastSR);
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00002253 position += 4;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002254
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00002255 ModuleRTPUtility::AssignUWord32ToBuffer(rtcpbuffer+position,
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002256 reportBlock->delaySinceLastSR);
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00002257 position += 4;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002258 }
2259 }
stefan@webrtc.orga20e2d42013-08-21 20:58:21 +00002260 return position;
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002261}
2262
2263// no callbacks allowed inside this function
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00002264int32_t
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002265RTCPSender::SetTMMBN(const TMMBRSet* boundingSet,
pbos@webrtc.orgb57da652013-04-08 11:08:41 +00002266 const uint32_t maxBitrateKbit)
andrew@webrtc.orgb015cbe2012-10-22 18:19:23 +00002267{
2268 CriticalSectionScoped lock(_criticalSectionRTCPSender);
2269
2270 if (0 == _tmmbrHelp.SetTMMBRBoundingSetToSend(boundingSet, maxBitrateKbit))
2271 {
2272 _sendTMMBN = true;
2273 return 0;
2274 }
2275 return -1;
2276}
pbos@webrtc.org3b89e102013-07-03 15:12:26 +00002277} // namespace webrtc