blob: fbfe832991c7e2ce7fad9b4204f514529353f151 [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
pbos@webrtc.orga048d7c2013-05-29 14:27:38 +000011#include "webrtc/modules/rtp_rtcp/source/rtcp_sender.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
pbos@webrtc.org12dc1a32013-08-05 16:22:53 +000013#include <assert.h> // assert
14#include <stdlib.h> // rand
stefan@webrtc.org9354cc92012-06-07 08:10:14 +000015#include <string.h> // memcpy
niklase@google.com470e71d2011-07-07 08:21:25 +000016
pbos@webrtc.org12dc1a32013-08-05 16:22:53 +000017#include <algorithm> // min
18
pbos@webrtc.orga048d7c2013-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"
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +000022#include "webrtc/system_wrappers/interface/logging.h"
pbos@webrtc.orga048d7c2013-05-29 14:27:38 +000023#include "webrtc/system_wrappers/interface/trace_event.h"
pwestin@webrtc.org741da942011-09-20 13:52:04 +000024
niklase@google.com470e71d2011-07-07 08:21:25 +000025namespace webrtc {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +000026
27using RTCPUtility::RTCPCnameInformation;
28
edjee@google.com79b02892013-04-04 19:43:34 +000029NACKStringBuilder::NACKStringBuilder() :
30 _stream(""), _count(0), _consecutive(false)
31{
32 // Empty.
33}
34
pbos@webrtc.orgf3e4cee2013-07-31 15:17:19 +000035NACKStringBuilder::~NACKStringBuilder() {}
36
pbos@webrtc.org2f446732013-04-08 11:08:41 +000037void NACKStringBuilder::PushNACK(uint16_t nack)
edjee@google.com79b02892013-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.org59f20bb2013-09-09 16:02:19 +000068RTCPSender::FeedbackState::FeedbackState()
69 : send_payload_type(0),
70 frequency_hz(0),
pbos@webrtc.org2f4b14e2014-07-15 15:25:39 +000071 packets_sent(0),
72 media_bytes_sent(0),
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +000073 send_bitrate(0),
74 last_rr_ntp_secs(0),
75 last_rr_ntp_frac(0),
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +000076 remote_sr(0),
77 has_last_xr_rr(false) {}
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +000078
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +000079RTCPSender::RTCPSender(int32_t id,
80 bool audio,
stefan@webrtc.org20ed36d2013-01-17 14:01:20 +000081 Clock* clock,
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +000082 ReceiveStatistics* receive_statistics)
83 : _id(id),
84 _audio(audio),
85 _clock(clock),
86 _method(kRtcpOff),
87 _criticalSectionTransport(
88 CriticalSectionWrapper::CreateCriticalSection()),
89 _cbTransport(NULL),
niklase@google.com470e71d2011-07-07 08:21:25 +000090
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +000091 _criticalSectionRTCPSender(
92 CriticalSectionWrapper::CreateCriticalSection()),
93 _usingNack(false),
94 _sending(false),
95 _sendTMMBN(false),
96 _REMB(false),
97 _sendREMB(false),
98 _TMMBR(false),
99 _IJ(false),
100 _nextTimeToSendRTCP(0),
101 start_timestamp_(0),
102 last_rtp_timestamp_(0),
103 last_frame_capture_time_ms_(-1),
104 _SSRC(0),
105 _remoteSSRC(0),
106 _CNAME(),
107 receive_statistics_(receive_statistics),
108 internal_report_blocks_(),
109 external_report_blocks_(),
110 _csrcCNAMEs(),
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000111 _lastSendReport(),
112 _lastRTCPTime(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000113
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000114 last_xr_rr_(),
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000115
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000116 _sequenceNumberFIR(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000117
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000118 _rembBitrate(0),
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000119
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000120 _tmmbrHelp(),
121 _tmmbr_Send(0),
122 _packetOH_Send(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000123
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000124 _appSend(false),
125 _appSubType(0),
126 _appName(),
127 _appData(NULL),
128 _appLength(0),
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000129
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000130 xrSendReceiverReferenceTimeEnabled_(false),
131 _xrSendVoIPMetric(false),
132 _xrVoIPMetric() {
niklase@google.com470e71d2011-07-07 08:21:25 +0000133 memset(_CNAME, 0, sizeof(_CNAME));
134 memset(_lastSendReport, 0, sizeof(_lastSendReport));
135 memset(_lastRTCPTime, 0, sizeof(_lastRTCPTime));
niklase@google.com470e71d2011-07-07 08:21:25 +0000136}
137
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000138RTCPSender::~RTCPSender() {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000139 delete [] _appData;
niklase@google.com470e71d2011-07-07 08:21:25 +0000140
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000141 while (!internal_report_blocks_.empty()) {
142 delete internal_report_blocks_.begin()->second;
143 internal_report_blocks_.erase(internal_report_blocks_.begin());
144 }
145 while (!external_report_blocks_.empty()) {
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000146 std::map<uint32_t, RTCPReportBlock*>::iterator it =
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000147 external_report_blocks_.begin();
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000148 delete it->second;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000149 external_report_blocks_.erase(it);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000150 }
151 while (!_csrcCNAMEs.empty()) {
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000152 std::map<uint32_t, RTCPCnameInformation*>::iterator it =
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000153 _csrcCNAMEs.begin();
154 delete it->second;
155 _csrcCNAMEs.erase(it);
156 }
157 delete _criticalSectionTransport;
158 delete _criticalSectionRTCPSender;
niklase@google.com470e71d2011-07-07 08:21:25 +0000159}
160
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000161int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000162RTCPSender::RegisterSendTransport(Transport* outgoingTransport)
163{
164 CriticalSectionScoped lock(_criticalSectionTransport);
165 _cbTransport = outgoingTransport;
166 return 0;
167}
168
169RTCPMethod
170RTCPSender::Status() const
171{
172 CriticalSectionScoped lock(_criticalSectionRTCPSender);
173 return _method;
174}
175
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000176void RTCPSender::SetRTCPStatus(RTCPMethod method) {
177 CriticalSectionScoped lock(_criticalSectionRTCPSender);
178 _method = method;
179
180 if (method == kRtcpOff)
181 return;
182 _nextTimeToSendRTCP =
183 _clock->TimeInMilliseconds() +
184 (_audio ? RTCP_INTERVAL_AUDIO_MS / 2 : RTCP_INTERVAL_VIDEO_MS / 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000185}
186
187bool
188RTCPSender::Sending() const
189{
190 CriticalSectionScoped lock(_criticalSectionRTCPSender);
191 return _sending;
192}
193
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000194int32_t
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +0000195RTCPSender::SetSendingStatus(const FeedbackState& feedback_state, bool sending)
niklase@google.com470e71d2011-07-07 08:21:25 +0000196{
197 bool sendRTCPBye = false;
198 {
199 CriticalSectionScoped lock(_criticalSectionRTCPSender);
200
201 if(_method != kRtcpOff)
202 {
203 if(sending == false && _sending == true)
204 {
205 // Trigger RTCP bye
206 sendRTCPBye = true;
207 }
208 }
209 _sending = sending;
210 }
211 if(sendRTCPBye)
212 {
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +0000213 return SendRTCP(feedback_state, kRtcpBye);
niklase@google.com470e71d2011-07-07 08:21:25 +0000214 }
215 return 0;
216}
217
218bool
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000219RTCPSender::REMB() const
220{
221 CriticalSectionScoped lock(_criticalSectionRTCPSender);
222 return _REMB;
223}
224
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000225void RTCPSender::SetREMBStatus(bool enable) {
226 CriticalSectionScoped lock(_criticalSectionRTCPSender);
227 _REMB = enable;
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000228}
229
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000230void RTCPSender::SetREMBData(uint32_t bitrate,
231 const std::vector<uint32_t>& ssrcs) {
232 CriticalSectionScoped lock(_criticalSectionRTCPSender);
233 _rembBitrate = bitrate;
234 remb_ssrcs_ = ssrcs;
stefan@webrtc.org4ef438e2014-07-11 09:55:30 +0000235
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000236 _sendREMB = true;
237 // Send a REMB immediately if we have a new REMB. The frequency of REMBs is
238 // throttled by the caller.
239 _nextTimeToSendRTCP = _clock->TimeInMilliseconds();
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000240}
241
242bool
niklase@google.com470e71d2011-07-07 08:21:25 +0000243RTCPSender::TMMBR() const
244{
245 CriticalSectionScoped lock(_criticalSectionRTCPSender);
246 return _TMMBR;
247}
248
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000249void RTCPSender::SetTMMBRStatus(bool enable) {
250 CriticalSectionScoped lock(_criticalSectionRTCPSender);
251 _TMMBR = enable;
niklase@google.com470e71d2011-07-07 08:21:25 +0000252}
253
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000254bool
255RTCPSender::IJ() const
256{
257 CriticalSectionScoped lock(_criticalSectionRTCPSender);
258 return _IJ;
259}
260
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000261void RTCPSender::SetIJStatus(bool enable) {
262 CriticalSectionScoped lock(_criticalSectionRTCPSender);
263 _IJ = enable;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000264}
265
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000266void RTCPSender::SetStartTimestamp(uint32_t start_timestamp) {
pbos@webrtc.org180e5162014-07-11 15:36:26 +0000267 CriticalSectionScoped lock(_criticalSectionRTCPSender);
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000268 start_timestamp_ = start_timestamp;
269}
270
271void RTCPSender::SetLastRtpTime(uint32_t rtp_timestamp,
272 int64_t capture_time_ms) {
henrika@webrtc.org19da7192013-04-05 14:34:57 +0000273 CriticalSectionScoped lock(_criticalSectionRTCPSender);
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000274 last_rtp_timestamp_ = rtp_timestamp;
275 if (capture_time_ms < 0) {
276 // We don't currently get a capture time from VoiceEngine.
stefan@webrtc.org7da34592013-04-09 14:56:29 +0000277 last_frame_capture_time_ms_ = _clock->TimeInMilliseconds();
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000278 } else {
279 last_frame_capture_time_ms_ = capture_time_ms;
280 }
281}
282
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000283void RTCPSender::SetSSRC(uint32_t ssrc) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000284 CriticalSectionScoped lock(_criticalSectionRTCPSender);
285
286 if(_SSRC != 0)
287 {
288 // not first SetSSRC, probably due to a collision
289 // schedule a new RTCP report
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000290 // make sure that we send a RTP packet
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +0000291 _nextTimeToSendRTCP = _clock->TimeInMilliseconds() + 100;
niklase@google.com470e71d2011-07-07 08:21:25 +0000292 }
293 _SSRC = ssrc;
294}
295
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000296void RTCPSender::SetRemoteSSRC(uint32_t ssrc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000297{
298 CriticalSectionScoped lock(_criticalSectionRTCPSender);
299 _remoteSSRC = ssrc;
niklase@google.com470e71d2011-07-07 08:21:25 +0000300}
301
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000302int32_t RTCPSender::SetCNAME(const char cName[RTCP_CNAME_SIZE]) {
tommi@webrtc.orga990e122012-04-26 15:28:22 +0000303 if (!cName)
304 return -1;
305
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000306 CriticalSectionScoped lock(_criticalSectionRTCPSender);
307 _CNAME[RTCP_CNAME_SIZE - 1] = 0;
308 strncpy(_CNAME, cName, RTCP_CNAME_SIZE - 1);
309 return 0;
310}
311
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000312int32_t RTCPSender::AddMixedCNAME(uint32_t SSRC,
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000313 const char cName[RTCP_CNAME_SIZE]) {
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000314 assert(cName);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000315 CriticalSectionScoped lock(_criticalSectionRTCPSender);
316 if (_csrcCNAMEs.size() >= kRtpCsrcSize) {
317 return -1;
318 }
319 RTCPCnameInformation* ptr = new RTCPCnameInformation();
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000320 ptr->name[RTCP_CNAME_SIZE - 1] = 0;
321 strncpy(ptr->name, cName, RTCP_CNAME_SIZE - 1);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000322 _csrcCNAMEs[SSRC] = ptr;
323 return 0;
324}
325
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000326int32_t RTCPSender::RemoveMixedCNAME(uint32_t SSRC) {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000327 CriticalSectionScoped lock(_criticalSectionRTCPSender);
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000328 std::map<uint32_t, RTCPCnameInformation*>::iterator it =
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000329 _csrcCNAMEs.find(SSRC);
330
331 if (it == _csrcCNAMEs.end()) {
332 return -1;
333 }
334 delete it->second;
335 _csrcCNAMEs.erase(it);
336 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000337}
338
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000339bool RTCPSender::TimeToSendRTCPReport(bool sendKeyframeBeforeRTP) const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000340/*
341 For audio we use a fix 5 sec interval
342
343 For video we use 1 sec interval fo a BW smaller than 360 kbit/s,
stefan@webrtc.org9d4762e2014-03-24 17:13:00 +0000344 technicaly we break the max 5% RTCP BW for video below 10 kbit/s but
345 that should be extremely rare
niklase@google.com470e71d2011-07-07 08:21:25 +0000346
347
348From RFC 3550
349
350 MAX RTCP BW is 5% if the session BW
351 A send report is approximately 65 bytes inc CNAME
stefan@webrtc.org9d4762e2014-03-24 17:13:00 +0000352 A receiver report is approximately 28 bytes
niklase@google.com470e71d2011-07-07 08:21:25 +0000353
354 The RECOMMENDED value for the reduced minimum in seconds is 360
355 divided by the session bandwidth in kilobits/second. This minimum
356 is smaller than 5 seconds for bandwidths greater than 72 kb/s.
357
358 If the participant has not yet sent an RTCP packet (the variable
359 initial is true), the constant Tmin is set to 2.5 seconds, else it
360 is set to 5 seconds.
361
362 The interval between RTCP packets is varied randomly over the
363 range [0.5,1.5] times the calculated interval to avoid unintended
364 synchronization of all participants
365
366 if we send
367 If the participant is a sender (we_sent true), the constant C is
368 set to the average RTCP packet size (avg_rtcp_size) divided by 25%
369 of the RTCP bandwidth (rtcp_bw), and the constant n is set to the
370 number of senders.
371
372 if we receive only
373 If we_sent is not true, the constant C is set
374 to the average RTCP packet size divided by 75% of the RTCP
375 bandwidth. The constant n is set to the number of receivers
376 (members - senders). If the number of senders is greater than
377 25%, senders and receivers are treated together.
378
379 reconsideration NOT required for peer-to-peer
380 "timer reconsideration" is
381 employed. This algorithm implements a simple back-off mechanism
382 which causes users to hold back RTCP packet transmission if the
383 group sizes are increasing.
384
385 n = number of members
386 C = avg_size/(rtcpBW/4)
387
388 3. The deterministic calculated interval Td is set to max(Tmin, n*C).
389
390 4. The calculated interval T is set to a number uniformly distributed
391 between 0.5 and 1.5 times the deterministic calculated interval.
392
393 5. The resulting value of T is divided by e-3/2=1.21828 to compensate
394 for the fact that the timer reconsideration algorithm converges to
395 a value of the RTCP bandwidth below the intended average
396*/
397
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000398 int64_t now = _clock->TimeInMilliseconds();
xians@webrtc.org8738d272011-11-25 13:43:53 +0000399
400 CriticalSectionScoped lock(_criticalSectionRTCPSender);
401
niklase@google.com470e71d2011-07-07 08:21:25 +0000402 if(_method == kRtcpOff)
403 {
404 return false;
405 }
406
niklase@google.com470e71d2011-07-07 08:21:25 +0000407 if(!_audio && sendKeyframeBeforeRTP)
408 {
409 // for video key-frames we want to send the RTCP before the large key-frame
410 // if we have a 100 ms margin
411 now += RTCP_SEND_BEFORE_KEY_FRAME_MS;
412 }
413
stefan@webrtc.org9d4762e2014-03-24 17:13:00 +0000414 if(now >= _nextTimeToSendRTCP)
niklase@google.com470e71d2011-07-07 08:21:25 +0000415 {
416 return true;
417
418 } else if(now < 0x0000ffff && _nextTimeToSendRTCP > 0xffff0000) // 65 sec margin
419 {
420 // wrap
421 return true;
422 }
423 return false;
424}
425
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000426uint32_t RTCPSender::LastSendReport(int64_t& lastRTCPTime)
niklase@google.com470e71d2011-07-07 08:21:25 +0000427{
428 CriticalSectionScoped lock(_criticalSectionRTCPSender);
429
430 lastRTCPTime = _lastRTCPTime[0];
431 return _lastSendReport[0];
432}
433
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000434int64_t RTCPSender::SendTimeOfSendReport(uint32_t sendReport) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000435 CriticalSectionScoped lock(_criticalSectionRTCPSender);
436
437 // This is only saved when we are the sender
438 if((_lastSendReport[0] == 0) || (sendReport == 0))
439 {
440 return 0; // will be ignored
441 } else
442 {
443 for(int i = 0; i < RTCP_NUMBER_OF_SR; ++i)
444 {
445 if( _lastSendReport[i] == sendReport)
446 {
447 return _lastRTCPTime[i];
448 }
449 }
450 }
451 return 0;
452}
453
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000454bool RTCPSender::SendTimeOfXrRrReport(uint32_t mid_ntp,
455 int64_t* time_ms) const {
456 CriticalSectionScoped lock(_criticalSectionRTCPSender);
457
458 if (last_xr_rr_.empty()) {
459 return false;
460 }
461 std::map<uint32_t, int64_t>::const_iterator it = last_xr_rr_.find(mid_ntp);
462 if (it == last_xr_rr_.end()) {
463 return false;
464 }
465 *time_ms = it->second;
466 return true;
467}
468
asapersson@webrtc.org8098e072014-02-19 11:59:02 +0000469void RTCPSender::GetPacketTypeCounter(
470 RtcpPacketTypeCounter* packet_counter) const {
471 CriticalSectionScoped lock(_criticalSectionRTCPSender);
472 *packet_counter = packet_type_counter_;
473}
474
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000475int32_t RTCPSender::AddExternalReportBlock(
476 uint32_t SSRC,
477 const RTCPReportBlock* reportBlock) {
478 CriticalSectionScoped lock(_criticalSectionRTCPSender);
479 return AddReportBlock(SSRC, &external_report_blocks_, reportBlock);
480}
481
482int32_t RTCPSender::AddReportBlock(
483 uint32_t SSRC,
484 std::map<uint32_t, RTCPReportBlock*>* report_blocks,
485 const RTCPReportBlock* reportBlock) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000486 assert(reportBlock);
niklase@google.com470e71d2011-07-07 08:21:25 +0000487
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000488 if (report_blocks->size() >= RTCP_MAX_REPORT_BLOCKS) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000489 LOG(LS_WARNING) << "Too many report blocks.";
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000490 return -1;
491 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000492 std::map<uint32_t, RTCPReportBlock*>::iterator it =
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000493 report_blocks->find(SSRC);
494 if (it != report_blocks->end()) {
stefan@webrtc.org8d0cd072012-12-03 14:01:46 +0000495 delete it->second;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000496 report_blocks->erase(it);
stefan@webrtc.org8d0cd072012-12-03 14:01:46 +0000497 }
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000498 RTCPReportBlock* copyReportBlock = new RTCPReportBlock();
499 memcpy(copyReportBlock, reportBlock, sizeof(RTCPReportBlock));
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000500 (*report_blocks)[SSRC] = copyReportBlock;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000501 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000502}
503
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000504int32_t RTCPSender::RemoveExternalReportBlock(uint32_t SSRC) {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000505 CriticalSectionScoped lock(_criticalSectionRTCPSender);
niklase@google.com470e71d2011-07-07 08:21:25 +0000506
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000507 std::map<uint32_t, RTCPReportBlock*>::iterator it =
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000508 external_report_blocks_.find(SSRC);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000509
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000510 if (it == external_report_blocks_.end()) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000511 return -1;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000512 }
513 delete it->second;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000514 external_report_blocks_.erase(it);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000515 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000516}
517
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +0000518int32_t RTCPSender::BuildSR(const FeedbackState& feedback_state,
519 uint8_t* rtcpbuffer,
520 int& pos,
521 uint32_t NTPsec,
522 uint32_t NTPfrac)
niklase@google.com470e71d2011-07-07 08:21:25 +0000523{
524 // sanity
525 if(pos + 52 >= IP_PACKET_SIZE)
526 {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000527 LOG(LS_WARNING) << "Failed to build Sender Report.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000528 return -2;
529 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000530 uint32_t RTPtime;
niklase@google.com470e71d2011-07-07 08:21:25 +0000531
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000532 uint32_t posNumberOfReportBlocks = pos;
533 rtcpbuffer[pos++]=(uint8_t)0x80;
niklase@google.com470e71d2011-07-07 08:21:25 +0000534
535 // Sender report
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000536 rtcpbuffer[pos++]=(uint8_t)200;
niklase@google.com470e71d2011-07-07 08:21:25 +0000537
538 for(int i = (RTCP_NUMBER_OF_SR-2); i >= 0; i--)
539 {
540 // shift old
541 _lastSendReport[i+1] = _lastSendReport[i];
542 _lastRTCPTime[i+1] =_lastRTCPTime[i];
543 }
544
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +0000545 _lastRTCPTime[0] = Clock::NtpToMs(NTPsec, NTPfrac);
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000546 _lastSendReport[0] = (NTPsec << 16) + (NTPfrac >> 16);
niklase@google.com470e71d2011-07-07 08:21:25 +0000547
stefan@webrtc.org7da34592013-04-09 14:56:29 +0000548 // The timestamp of this RTCP packet should be estimated as the timestamp of
549 // the frame being captured at this moment. We are calculating that
550 // timestamp as the last frame's timestamp + the time since the last frame
551 // was captured.
pbos@webrtc.org180e5162014-07-11 15:36:26 +0000552 RTPtime = start_timestamp_ + last_rtp_timestamp_ +
553 (_clock->TimeInMilliseconds() - last_frame_capture_time_ms_) *
554 (feedback_state.frequency_hz / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +0000555
556 // Add sender data
557 // Save for our length field
558 pos++;
559 pos++;
560
561 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000562 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000563 pos += 4;
564 // NTP
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000565 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, NTPsec);
niklase@google.com470e71d2011-07-07 08:21:25 +0000566 pos += 4;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000567 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, NTPfrac);
niklase@google.com470e71d2011-07-07 08:21:25 +0000568 pos += 4;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000569 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, RTPtime);
niklase@google.com470e71d2011-07-07 08:21:25 +0000570 pos += 4;
571
572 //sender's packet count
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000573 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos,
pbos@webrtc.org2f4b14e2014-07-15 15:25:39 +0000574 feedback_state.packets_sent);
niklase@google.com470e71d2011-07-07 08:21:25 +0000575 pos += 4;
576
577 //sender's octet count
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000578 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos,
pbos@webrtc.org2f4b14e2014-07-15 15:25:39 +0000579 feedback_state.media_bytes_sent);
niklase@google.com470e71d2011-07-07 08:21:25 +0000580 pos += 4;
581
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000582 uint8_t numberOfReportBlocks = 0;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000583 int32_t retVal = WriteAllReportBlocksToBuffer(rtcpbuffer, pos,
584 numberOfReportBlocks,
585 NTPsec, NTPfrac);
niklase@google.com470e71d2011-07-07 08:21:25 +0000586 if(retVal < 0)
587 {
588 //
589 return retVal ;
590 }
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000591 pos = retVal;
niklase@google.com470e71d2011-07-07 08:21:25 +0000592 rtcpbuffer[posNumberOfReportBlocks] += numberOfReportBlocks;
593
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000594 uint16_t len = uint16_t((pos/4) -1);
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000595 RtpUtility::AssignUWord16ToBuffer(rtcpbuffer + 2, len);
niklase@google.com470e71d2011-07-07 08:21:25 +0000596 return 0;
597}
598
599
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000600int32_t RTCPSender::BuildSDEC(uint8_t* rtcpbuffer, int& pos) {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000601 size_t lengthCname = strlen(_CNAME);
602 assert(lengthCname < RTCP_CNAME_SIZE);
niklase@google.com470e71d2011-07-07 08:21:25 +0000603
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000604 // sanity
605 if(pos + 12 + lengthCname >= IP_PACKET_SIZE) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000606 LOG(LS_WARNING) << "Failed to build SDEC.";
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000607 return -2;
608 }
609 // SDEC Source Description
niklase@google.com470e71d2011-07-07 08:21:25 +0000610
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000611 // We always need to add SDES CNAME
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000612 rtcpbuffer[pos++] = static_cast<uint8_t>(0x80 + 1 + _csrcCNAMEs.size());
613 rtcpbuffer[pos++] = static_cast<uint8_t>(202);
niklase@google.com470e71d2011-07-07 08:21:25 +0000614
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000615 // handle SDES length later on
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000616 uint32_t SDESLengthPos = pos;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000617 pos++;
618 pos++;
niklase@google.com470e71d2011-07-07 08:21:25 +0000619
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000620 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000621 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000622 pos += 4;
623
624 // CNAME = 1
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000625 rtcpbuffer[pos++] = static_cast<uint8_t>(1);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000626
627 //
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000628 rtcpbuffer[pos++] = static_cast<uint8_t>(lengthCname);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000629
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000630 uint16_t SDESLength = 10;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000631
632 memcpy(&rtcpbuffer[pos], _CNAME, lengthCname);
633 pos += lengthCname;
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000634 SDESLength += (uint16_t)lengthCname;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000635
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000636 uint16_t padding = 0;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000637 // We must have a zero field even if we have an even multiple of 4 bytes
638 if ((pos % 4) == 0) {
639 padding++;
640 rtcpbuffer[pos++]=0;
641 }
642 while ((pos % 4) != 0) {
643 padding++;
644 rtcpbuffer[pos++]=0;
645 }
646 SDESLength += padding;
647
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000648 std::map<uint32_t, RTCPUtility::RTCPCnameInformation*>::iterator it =
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000649 _csrcCNAMEs.begin();
650
651 for(; it != _csrcCNAMEs.end(); it++) {
652 RTCPCnameInformation* cname = it->second;
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000653 uint32_t SSRC = it->first;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000654
655 // Add SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000656 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000657 pos += 4;
658
659 // CNAME = 1
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000660 rtcpbuffer[pos++] = static_cast<uint8_t>(1);
niklase@google.com470e71d2011-07-07 08:21:25 +0000661
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000662 size_t length = strlen(cname->name);
663 assert(length < RTCP_CNAME_SIZE);
niklase@google.com470e71d2011-07-07 08:21:25 +0000664
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000665 rtcpbuffer[pos++]= static_cast<uint8_t>(length);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000666 SDESLength += 6;
niklase@google.com470e71d2011-07-07 08:21:25 +0000667
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000668 memcpy(&rtcpbuffer[pos],cname->name, length);
niklase@google.com470e71d2011-07-07 08:21:25 +0000669
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000670 pos += length;
671 SDESLength += length;
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000672 uint16_t padding = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000673
674 // We must have a zero field even if we have an even multiple of 4 bytes
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000675 if((pos % 4) == 0){
676 padding++;
677 rtcpbuffer[pos++]=0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000678 }
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000679 while((pos % 4) != 0){
680 padding++;
681 rtcpbuffer[pos++] = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000682 }
683 SDESLength += padding;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000684 }
685 // in 32-bit words minus one and we don't count the header
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000686 uint16_t buffer_length = (SDESLength / 4) - 1;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000687 RtpUtility::AssignUWord16ToBuffer(rtcpbuffer + SDESLengthPos, buffer_length);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000688 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000689}
690
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000691int32_t RTCPSender::BuildRR(uint8_t* rtcpbuffer,
692 int& pos,
693 uint32_t NTPsec,
694 uint32_t NTPfrac) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000695 // sanity one block
696 if(pos + 32 >= IP_PACKET_SIZE)
697 {
698 return -2;
699 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000700 uint32_t posNumberOfReportBlocks = pos;
niklase@google.com470e71d2011-07-07 08:21:25 +0000701
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000702 rtcpbuffer[pos++]=(uint8_t)0x80;
703 rtcpbuffer[pos++]=(uint8_t)201;
niklase@google.com470e71d2011-07-07 08:21:25 +0000704
705 // Save for our length field
706 pos++;
707 pos++;
708
709 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000710 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000711 pos += 4;
712
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000713 uint8_t numberOfReportBlocks = 0;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000714 int retVal = WriteAllReportBlocksToBuffer(rtcpbuffer, pos,
715 numberOfReportBlocks,
716 NTPsec, NTPfrac);
niklase@google.com470e71d2011-07-07 08:21:25 +0000717 if(retVal < 0)
718 {
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000719 return pos;
niklase@google.com470e71d2011-07-07 08:21:25 +0000720 }
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000721 pos = retVal;
niklase@google.com470e71d2011-07-07 08:21:25 +0000722 rtcpbuffer[posNumberOfReportBlocks] += numberOfReportBlocks;
723
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000724 uint16_t len = uint16_t((pos)/4 -1);
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000725 RtpUtility::AssignUWord16ToBuffer(rtcpbuffer + 2, len);
niklase@google.com470e71d2011-07-07 08:21:25 +0000726 return 0;
727}
728
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000729// From RFC 5450: Transmission Time Offsets in RTP Streams.
730// 0 1 2 3
731// 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
732// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
733// hdr |V=2|P| RC | PT=IJ=195 | length |
734// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
735// | inter-arrival jitter |
736// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
737// . .
738// . .
739// . .
740// | inter-arrival jitter |
741// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
742//
743// If present, this RTCP packet must be placed after a receiver report
744// (inside a compound RTCP packet), and MUST have the same value for RC
745// (reception report count) as the receiver report.
746
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000747int32_t
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000748RTCPSender::BuildExtendedJitterReport(
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000749 uint8_t* rtcpbuffer,
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000750 int& pos,
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000751 const uint32_t jitterTransmissionTimeOffset)
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000752{
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000753 if (external_report_blocks_.size() > 0)
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000754 {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000755 // TODO(andresp): Remove external report blocks since they are not
756 // supported.
757 LOG(LS_ERROR) << "Handling of external report blocks not implemented.";
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000758 return 0;
759 }
760
761 // sanity
762 if(pos + 8 >= IP_PACKET_SIZE)
763 {
764 return -2;
765 }
766 // add picture loss indicator
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000767 uint8_t RC = 1;
768 rtcpbuffer[pos++]=(uint8_t)0x80 + RC;
769 rtcpbuffer[pos++]=(uint8_t)195;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000770
771 // Used fixed length of 2
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000772 rtcpbuffer[pos++]=(uint8_t)0;
773 rtcpbuffer[pos++]=(uint8_t)(1);
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000774
775 // Add inter-arrival jitter
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000776 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos,
777 jitterTransmissionTimeOffset);
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000778 pos += 4;
779 return 0;
780}
781
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000782int32_t
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000783RTCPSender::BuildPLI(uint8_t* rtcpbuffer, int& pos)
niklase@google.com470e71d2011-07-07 08:21:25 +0000784{
785 // sanity
786 if(pos + 12 >= IP_PACKET_SIZE)
787 {
788 return -2;
789 }
790 // add picture loss indicator
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000791 uint8_t FMT = 1;
792 rtcpbuffer[pos++]=(uint8_t)0x80 + FMT;
793 rtcpbuffer[pos++]=(uint8_t)206;
niklase@google.com470e71d2011-07-07 08:21:25 +0000794
795 //Used fixed length of 2
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000796 rtcpbuffer[pos++]=(uint8_t)0;
797 rtcpbuffer[pos++]=(uint8_t)(2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000798
799 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000800 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000801 pos += 4;
802
803 // Add the remote SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000804 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000805 pos += 4;
806 return 0;
807}
808
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000809int32_t RTCPSender::BuildFIR(uint8_t* rtcpbuffer,
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000810 int& pos,
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000811 bool repeat) {
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000812 // sanity
813 if(pos + 20 >= IP_PACKET_SIZE) {
814 return -2;
815 }
816 if (!repeat) {
817 _sequenceNumberFIR++; // do not increase if repetition
818 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000819
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000820 // add full intra request indicator
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000821 uint8_t FMT = 4;
822 rtcpbuffer[pos++] = (uint8_t)0x80 + FMT;
823 rtcpbuffer[pos++] = (uint8_t)206;
niklase@google.com470e71d2011-07-07 08:21:25 +0000824
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000825 //Length of 4
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000826 rtcpbuffer[pos++] = (uint8_t)0;
827 rtcpbuffer[pos++] = (uint8_t)(4);
niklase@google.com470e71d2011-07-07 08:21:25 +0000828
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000829 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000830 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000831 pos += 4;
niklase@google.com470e71d2011-07-07 08:21:25 +0000832
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000833 // RFC 5104 4.3.1.2. Semantics
834 // SSRC of media source
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000835 rtcpbuffer[pos++] = (uint8_t)0;
836 rtcpbuffer[pos++] = (uint8_t)0;
837 rtcpbuffer[pos++] = (uint8_t)0;
838 rtcpbuffer[pos++] = (uint8_t)0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000839
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000840 // Additional Feedback Control Information (FCI)
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000841 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _remoteSSRC);
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000842 pos += 4;
niklase@google.com470e71d2011-07-07 08:21:25 +0000843
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000844 rtcpbuffer[pos++] = (uint8_t)(_sequenceNumberFIR);
845 rtcpbuffer[pos++] = (uint8_t)0;
846 rtcpbuffer[pos++] = (uint8_t)0;
847 rtcpbuffer[pos++] = (uint8_t)0;
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000848 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000849}
850
851/*
852 0 1 2 3
853 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
854 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
855 | First | Number | PictureID |
856 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
857*/
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000858int32_t RTCPSender::BuildSLI(uint8_t* rtcpbuffer, int& pos, uint8_t pictureID) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000859 // sanity
860 if(pos + 16 >= IP_PACKET_SIZE)
861 {
862 return -2;
863 }
864 // add slice loss indicator
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000865 uint8_t FMT = 2;
866 rtcpbuffer[pos++]=(uint8_t)0x80 + FMT;
867 rtcpbuffer[pos++]=(uint8_t)206;
niklase@google.com470e71d2011-07-07 08:21:25 +0000868
869 //Used fixed length of 3
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000870 rtcpbuffer[pos++]=(uint8_t)0;
871 rtcpbuffer[pos++]=(uint8_t)(3);
niklase@google.com470e71d2011-07-07 08:21:25 +0000872
873 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000874 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000875 pos += 4;
876
877 // Add the remote SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000878 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000879 pos += 4;
880
881 // Add first, number & picture ID 6 bits
882 // first = 0, 13 - bits
883 // number = 0x1fff, 13 - bits only ones for now
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000884 uint32_t sliField = (0x1fff << 6)+ (0x3f & pictureID);
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000885 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, sliField);
niklase@google.com470e71d2011-07-07 08:21:25 +0000886 pos += 4;
887 return 0;
888}
889
890/*
891 0 1 2 3
892 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
893 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
894 | PB |0| Payload Type| Native RPSI bit string |
895 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
896 | defined per codec ... | Padding (0) |
897 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
898*/
899/*
900* Note: not generic made for VP8
901*/
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000902int32_t RTCPSender::BuildRPSI(uint8_t* rtcpbuffer,
903 int& pos,
904 uint64_t pictureID,
905 uint8_t payloadType) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000906 // sanity
907 if(pos + 24 >= IP_PACKET_SIZE)
908 {
909 return -2;
910 }
911 // add Reference Picture Selection Indication
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000912 uint8_t FMT = 3;
913 rtcpbuffer[pos++]=(uint8_t)0x80 + FMT;
914 rtcpbuffer[pos++]=(uint8_t)206;
niklase@google.com470e71d2011-07-07 08:21:25 +0000915
916 // calc length
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000917 uint32_t bitsRequired = 7;
918 uint8_t bytesRequired = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000919 while((pictureID>>bitsRequired) > 0)
920 {
921 bitsRequired += 7;
922 bytesRequired++;
923 }
924
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000925 uint8_t size = 3;
niklase@google.com470e71d2011-07-07 08:21:25 +0000926 if(bytesRequired > 6)
927 {
928 size = 5;
929 } else if(bytesRequired > 2)
930 {
931 size = 4;
932 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000933 rtcpbuffer[pos++]=(uint8_t)0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000934 rtcpbuffer[pos++]=size;
935
936 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000937 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000938 pos += 4;
939
940 // Add the remote SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000941 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000942 pos += 4;
943
944 // calc padding length
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000945 uint8_t paddingBytes = 4-((2+bytesRequired)%4);
niklase@google.com470e71d2011-07-07 08:21:25 +0000946 if(paddingBytes == 4)
947 {
948 paddingBytes = 0;
949 }
950 // add padding length in bits
951 rtcpbuffer[pos] = paddingBytes*8; // padding can be 0, 8, 16 or 24
952 pos++;
953
954 // add payload type
955 rtcpbuffer[pos] = payloadType;
956 pos++;
957
958 // add picture ID
959 for(int i = bytesRequired-1; i > 0; i--)
960 {
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000961 rtcpbuffer[pos] = 0x80 | uint8_t(pictureID >> (i*7));
niklase@google.com470e71d2011-07-07 08:21:25 +0000962 pos++;
963 }
964 // add last byte of picture ID
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000965 rtcpbuffer[pos] = uint8_t(pictureID & 0x7f);
niklase@google.com470e71d2011-07-07 08:21:25 +0000966 pos++;
967
968 // add padding
969 for(int j = 0; j <paddingBytes; j++)
970 {
971 rtcpbuffer[pos] = 0;
972 pos++;
973 }
974 return 0;
975}
976
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000977int32_t
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000978RTCPSender::BuildREMB(uint8_t* rtcpbuffer, int& pos)
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000979{
980 // sanity
pbos@webrtc.org49ff40e2014-11-13 14:42:37 +0000981 if(pos + 20 + 4 * remb_ssrcs_.size() >= IP_PACKET_SIZE)
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000982 {
983 return -2;
984 }
985 // add application layer feedback
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000986 uint8_t FMT = 15;
987 rtcpbuffer[pos++]=(uint8_t)0x80 + FMT;
988 rtcpbuffer[pos++]=(uint8_t)206;
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000989
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000990 rtcpbuffer[pos++]=(uint8_t)0;
pbos@webrtc.org49ff40e2014-11-13 14:42:37 +0000991 rtcpbuffer[pos++]=remb_ssrcs_.size() + 4;
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000992
993 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000994 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000995 pos += 4;
996
997 // Remote SSRC must be 0
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000998 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, 0);
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000999 pos += 4;
1000
1001 rtcpbuffer[pos++]='R';
1002 rtcpbuffer[pos++]='E';
1003 rtcpbuffer[pos++]='M';
1004 rtcpbuffer[pos++]='B';
1005
pbos@webrtc.org49ff40e2014-11-13 14:42:37 +00001006 rtcpbuffer[pos++] = remb_ssrcs_.size();
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001007 // 6 bit Exp
1008 // 18 bit mantissa
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001009 uint8_t brExp = 0;
1010 for(uint32_t i=0; i<64; i++)
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001011 {
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001012 if(_rembBitrate <= ((uint32_t)262143 << i))
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001013 {
1014 brExp = i;
1015 break;
1016 }
1017 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001018 const uint32_t brMantissa = (_rembBitrate >> brExp);
1019 rtcpbuffer[pos++]=(uint8_t)((brExp << 2) + ((brMantissa >> 16) & 0x03));
1020 rtcpbuffer[pos++]=(uint8_t)(brMantissa >> 8);
1021 rtcpbuffer[pos++]=(uint8_t)(brMantissa);
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001022
pbos@webrtc.org49ff40e2014-11-13 14:42:37 +00001023 for (size_t i = 0; i < remb_ssrcs_.size(); i++)
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001024 {
pbos@webrtc.org49ff40e2014-11-13 14:42:37 +00001025 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, remb_ssrcs_[i]);
1026 pos += 4;
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001027 }
1028 return 0;
1029}
1030
stefan@webrtc.org9354cc92012-06-07 08:10:14 +00001031void
1032RTCPSender::SetTargetBitrate(unsigned int target_bitrate)
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001033{
mflodman@webrtc.org117c1192012-01-13 08:52:58 +00001034 CriticalSectionScoped lock(_criticalSectionRTCPSender);
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001035 _tmmbr_Send = target_bitrate / 1000;
mflodman@webrtc.org117c1192012-01-13 08:52:58 +00001036}
1037
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001038int32_t RTCPSender::BuildTMMBR(ModuleRtpRtcpImpl* rtp_rtcp_module,
1039 uint8_t* rtcpbuffer,
1040 int& pos) {
1041 if (rtp_rtcp_module == NULL)
1042 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001043 // Before sending the TMMBR check the received TMMBN, only an owner is allowed to raise the bitrate
1044 // If the sender is an owner of the TMMBN -> send TMMBR
1045 // If not an owner but the TMMBR would enter the TMMBN -> send TMMBR
1046
niklase@google.com470e71d2011-07-07 08:21:25 +00001047 // get current bounding set from RTCP receiver
1048 bool tmmbrOwner = false;
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001049 // store in candidateSet, allocates one extra slot
1050 TMMBRSet* candidateSet = _tmmbrHelp.CandidateSet();
niklase@google.com470e71d2011-07-07 08:21:25 +00001051
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001052 // holding _criticalSectionRTCPSender while calling RTCPreceiver which
1053 // will accuire _criticalSectionRTCPReceiver is a potental deadlock but
1054 // since RTCPreceiver is not doing the reverse we should be fine
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001055 int32_t lengthOfBoundingSet =
1056 rtp_rtcp_module->BoundingSet(tmmbrOwner, candidateSet);
niklase@google.com470e71d2011-07-07 08:21:25 +00001057
1058 if(lengthOfBoundingSet > 0)
1059 {
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001060 for (int32_t i = 0; i < lengthOfBoundingSet; i++)
niklase@google.com470e71d2011-07-07 08:21:25 +00001061 {
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001062 if( candidateSet->Tmmbr(i) == _tmmbr_Send &&
1063 candidateSet->PacketOH(i) == _packetOH_Send)
niklase@google.com470e71d2011-07-07 08:21:25 +00001064 {
1065 // do not send the same tuple
1066 return 0;
1067 }
1068 }
1069 if(!tmmbrOwner)
1070 {
1071 // use received bounding set as candidate set
1072 // add current tuple
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001073 candidateSet->SetEntry(lengthOfBoundingSet,
1074 _tmmbr_Send,
1075 _packetOH_Send,
1076 _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001077 int numCandidates = lengthOfBoundingSet+ 1;
1078
1079 // find bounding set
1080 TMMBRSet* boundingSet = NULL;
1081 int numBoundingSet = _tmmbrHelp.FindTMMBRBoundingSet(boundingSet);
1082 if(numBoundingSet > 0 || numBoundingSet <= numCandidates)
1083 {
1084 tmmbrOwner = _tmmbrHelp.IsOwner(_SSRC, numBoundingSet);
1085 }
1086 if(!tmmbrOwner)
1087 {
1088 // did not enter bounding set, no meaning to send this request
1089 return 0;
1090 }
1091 }
1092 }
1093
1094 if(_tmmbr_Send)
1095 {
1096 // sanity
1097 if(pos + 20 >= IP_PACKET_SIZE)
1098 {
1099 return -2;
1100 }
1101 // add TMMBR indicator
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001102 uint8_t FMT = 3;
1103 rtcpbuffer[pos++]=(uint8_t)0x80 + FMT;
1104 rtcpbuffer[pos++]=(uint8_t)205;
niklase@google.com470e71d2011-07-07 08:21:25 +00001105
1106 //Length of 4
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001107 rtcpbuffer[pos++]=(uint8_t)0;
1108 rtcpbuffer[pos++]=(uint8_t)(4);
niklase@google.com470e71d2011-07-07 08:21:25 +00001109
1110 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001111 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001112 pos += 4;
1113
1114 // RFC 5104 4.2.1.2. Semantics
1115
1116 // SSRC of media source
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001117 rtcpbuffer[pos++]=(uint8_t)0;
1118 rtcpbuffer[pos++]=(uint8_t)0;
1119 rtcpbuffer[pos++]=(uint8_t)0;
1120 rtcpbuffer[pos++]=(uint8_t)0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001121
1122 // Additional Feedback Control Information (FCI)
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001123 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001124 pos += 4;
1125
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001126 uint32_t bitRate = _tmmbr_Send*1000;
1127 uint32_t mmbrExp = 0;
1128 for(uint32_t i=0;i<64;i++)
niklase@google.com470e71d2011-07-07 08:21:25 +00001129 {
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001130 if(bitRate <= ((uint32_t)131071 << i))
niklase@google.com470e71d2011-07-07 08:21:25 +00001131 {
1132 mmbrExp = i;
1133 break;
1134 }
1135 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001136 uint32_t mmbrMantissa = (bitRate >> mmbrExp);
niklase@google.com470e71d2011-07-07 08:21:25 +00001137
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001138 rtcpbuffer[pos++]=(uint8_t)((mmbrExp << 2) + ((mmbrMantissa >> 15) & 0x03));
1139 rtcpbuffer[pos++]=(uint8_t)(mmbrMantissa >> 7);
1140 rtcpbuffer[pos++]=(uint8_t)((mmbrMantissa << 1) + ((_packetOH_Send >> 8)& 0x01));
1141 rtcpbuffer[pos++]=(uint8_t)(_packetOH_Send);
niklase@google.com470e71d2011-07-07 08:21:25 +00001142 }
1143 return 0;
1144}
1145
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001146int32_t
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001147RTCPSender::BuildTMMBN(uint8_t* rtcpbuffer, int& pos)
niklase@google.com470e71d2011-07-07 08:21:25 +00001148{
1149 TMMBRSet* boundingSet = _tmmbrHelp.BoundingSetToSend();
1150 if(boundingSet == NULL)
1151 {
1152 return -1;
1153 }
1154 // sanity
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001155 if(pos + 12 + boundingSet->lengthOfSet()*8 >= IP_PACKET_SIZE)
niklase@google.com470e71d2011-07-07 08:21:25 +00001156 {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +00001157 LOG(LS_WARNING) << "Failed to build TMMBN.";
niklase@google.com470e71d2011-07-07 08:21:25 +00001158 return -2;
1159 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001160 uint8_t FMT = 4;
niklase@google.com470e71d2011-07-07 08:21:25 +00001161 // add TMMBN indicator
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001162 rtcpbuffer[pos++]=(uint8_t)0x80 + FMT;
1163 rtcpbuffer[pos++]=(uint8_t)205;
niklase@google.com470e71d2011-07-07 08:21:25 +00001164
1165 //Add length later
1166 int posLength = pos;
1167 pos++;
1168 pos++;
1169
1170 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001171 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001172 pos += 4;
1173
1174 // RFC 5104 4.2.2.2. Semantics
1175
1176 // SSRC of media source
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001177 rtcpbuffer[pos++]=(uint8_t)0;
1178 rtcpbuffer[pos++]=(uint8_t)0;
1179 rtcpbuffer[pos++]=(uint8_t)0;
1180 rtcpbuffer[pos++]=(uint8_t)0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001181
1182 // Additional Feedback Control Information (FCI)
1183 int numBoundingSet = 0;
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001184 for(uint32_t n=0; n< boundingSet->lengthOfSet(); n++)
niklase@google.com470e71d2011-07-07 08:21:25 +00001185 {
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001186 if (boundingSet->Tmmbr(n) > 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001187 {
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001188 uint32_t tmmbrSSRC = boundingSet->Ssrc(n);
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001189 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, tmmbrSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001190 pos += 4;
1191
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001192 uint32_t bitRate = boundingSet->Tmmbr(n) * 1000;
1193 uint32_t mmbrExp = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001194 for(int i=0; i<64; i++)
1195 {
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001196 if(bitRate <= ((uint32_t)131071 << i))
niklase@google.com470e71d2011-07-07 08:21:25 +00001197 {
1198 mmbrExp = i;
1199 break;
1200 }
1201 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001202 uint32_t mmbrMantissa = (bitRate >> mmbrExp);
1203 uint32_t measuredOH = boundingSet->PacketOH(n);
niklase@google.com470e71d2011-07-07 08:21:25 +00001204
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001205 rtcpbuffer[pos++]=(uint8_t)((mmbrExp << 2) + ((mmbrMantissa >> 15) & 0x03));
1206 rtcpbuffer[pos++]=(uint8_t)(mmbrMantissa >> 7);
1207 rtcpbuffer[pos++]=(uint8_t)((mmbrMantissa << 1) + ((measuredOH >> 8)& 0x01));
1208 rtcpbuffer[pos++]=(uint8_t)(measuredOH);
niklase@google.com470e71d2011-07-07 08:21:25 +00001209 numBoundingSet++;
1210 }
1211 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001212 uint16_t length= (uint16_t)(2+2*numBoundingSet);
1213 rtcpbuffer[posLength++]=(uint8_t)(length>>8);
1214 rtcpbuffer[posLength]=(uint8_t)(length);
niklase@google.com470e71d2011-07-07 08:21:25 +00001215 return 0;
1216}
1217
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001218int32_t
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001219RTCPSender::BuildAPP(uint8_t* rtcpbuffer, int& pos)
niklase@google.com470e71d2011-07-07 08:21:25 +00001220{
1221 // sanity
1222 if(_appData == NULL)
1223 {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +00001224 LOG(LS_WARNING) << "Failed to build app specific.";
niklase@google.com470e71d2011-07-07 08:21:25 +00001225 return -1;
1226 }
1227 if(pos + 12 + _appLength >= IP_PACKET_SIZE)
1228 {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +00001229 LOG(LS_WARNING) << "Failed to build app specific.";
niklase@google.com470e71d2011-07-07 08:21:25 +00001230 return -2;
1231 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001232 rtcpbuffer[pos++]=(uint8_t)0x80 + _appSubType;
niklase@google.com470e71d2011-07-07 08:21:25 +00001233
1234 // Add APP ID
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001235 rtcpbuffer[pos++]=(uint8_t)204;
niklase@google.com470e71d2011-07-07 08:21:25 +00001236
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001237 uint16_t length = (_appLength>>2) + 2; // include SSRC and name
1238 rtcpbuffer[pos++]=(uint8_t)(length>>8);
1239 rtcpbuffer[pos++]=(uint8_t)(length);
niklase@google.com470e71d2011-07-07 08:21:25 +00001240
1241 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001242 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001243 pos += 4;
1244
1245 // Add our application name
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001246 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _appName);
niklase@google.com470e71d2011-07-07 08:21:25 +00001247 pos += 4;
1248
1249 // Add the data
1250 memcpy(rtcpbuffer +pos, _appData,_appLength);
1251 pos += _appLength;
1252 return 0;
1253}
1254
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00001255int32_t RTCPSender::BuildNACK(uint8_t* rtcpbuffer,
1256 int& pos,
1257 int32_t nackSize,
1258 const uint16_t* nackList,
1259 std::string* nackString) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001260 // sanity
1261 if(pos + 16 >= IP_PACKET_SIZE)
1262 {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +00001263 LOG(LS_WARNING) << "Failed to build NACK.";
niklase@google.com470e71d2011-07-07 08:21:25 +00001264 return -2;
1265 }
1266
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001267 // int size, uint16_t* nackList
niklase@google.com470e71d2011-07-07 08:21:25 +00001268 // add nack list
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001269 uint8_t FMT = 1;
1270 rtcpbuffer[pos++]=(uint8_t)0x80 + FMT;
1271 rtcpbuffer[pos++]=(uint8_t)205;
niklase@google.com470e71d2011-07-07 08:21:25 +00001272
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001273 rtcpbuffer[pos++]=(uint8_t) 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001274 int nackSizePos = pos;
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001275 rtcpbuffer[pos++]=(uint8_t)(3); //setting it to one kNACK signal as default
niklase@google.com470e71d2011-07-07 08:21:25 +00001276
1277 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001278 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001279 pos += 4;
1280
1281 // Add the remote SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001282 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001283 pos += 4;
1284
andresp@webrtc.org523f9372013-04-11 11:30:39 +00001285 // Build NACK bitmasks and write them to the RTCP message.
1286 // The nack list should be sorted and not contain duplicates if one
1287 // wants to build the smallest rtcp nack packet.
1288 int numOfNackFields = 0;
1289 int maxNackFields = std::min<int>(kRtcpMaxNackFields,
1290 (IP_PACKET_SIZE - pos) / 4);
1291 int i = 0;
1292 while (i < nackSize && numOfNackFields < maxNackFields) {
andresp@webrtc.org523f9372013-04-11 11:30:39 +00001293 uint16_t nack = nackList[i++];
1294 uint16_t bitmask = 0;
1295 while (i < nackSize) {
1296 int shift = static_cast<uint16_t>(nackList[i] - nack) - 1;
1297 if (shift >= 0 && shift <= 15) {
andresp@webrtc.org523f9372013-04-11 11:30:39 +00001298 bitmask |= (1 << shift);
1299 ++i;
1300 } else {
1301 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00001302 }
andresp@webrtc.org523f9372013-04-11 11:30:39 +00001303 }
1304 // Write the sequence number and the bitmask to the packet.
1305 assert(pos + 4 < IP_PACKET_SIZE);
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001306 RtpUtility::AssignUWord16ToBuffer(rtcpbuffer + pos, nack);
andresp@webrtc.org523f9372013-04-11 11:30:39 +00001307 pos += 2;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001308 RtpUtility::AssignUWord16ToBuffer(rtcpbuffer + pos, bitmask);
andresp@webrtc.org523f9372013-04-11 11:30:39 +00001309 pos += 2;
1310 numOfNackFields++;
niklase@google.com470e71d2011-07-07 08:21:25 +00001311 }
andresp@webrtc.org523f9372013-04-11 11:30:39 +00001312 rtcpbuffer[nackSizePos] = static_cast<uint8_t>(2 + numOfNackFields);
asapersson@webrtc.org2dd31342014-10-29 12:42:30 +00001313
1314 if (i != nackSize) {
1315 LOG(LS_WARNING) << "Nack list too large for one packet.";
1316 }
1317
1318 // Report stats.
1319 NACKStringBuilder stringBuilder;
1320 for (int idx = 0; idx < i; ++idx) {
1321 stringBuilder.PushNACK(nackList[idx]);
1322 nack_stats_.ReportRequest(nackList[idx]);
1323 }
edjee@google.com79b02892013-04-04 19:43:34 +00001324 *nackString = stringBuilder.GetResult();
asapersson@webrtc.org2dd31342014-10-29 12:42:30 +00001325 packet_type_counter_.nack_requests = nack_stats_.requests();
1326 packet_type_counter_.unique_nack_requests = nack_stats_.unique_requests();
niklase@google.com470e71d2011-07-07 08:21:25 +00001327 return 0;
1328}
1329
pbos@webrtc.org9334ac22014-11-24 08:25:50 +00001330int32_t RTCPSender::BuildBYE(uint8_t* rtcpbuffer, int& pos) {
1331 // sanity
1332 if (pos + 8 >= IP_PACKET_SIZE) {
1333 return -2;
1334 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001335
pbos@webrtc.org9334ac22014-11-24 08:25:50 +00001336 // Add a bye packet
1337 // Number of SSRC + CSRCs.
1338 rtcpbuffer[pos++] = (uint8_t)0x80 + 1 + csrcs_.size();
1339 rtcpbuffer[pos++] = (uint8_t)203;
niklase@google.com470e71d2011-07-07 08:21:25 +00001340
pbos@webrtc.org9334ac22014-11-24 08:25:50 +00001341 // length
1342 rtcpbuffer[pos++] = (uint8_t)0;
1343 rtcpbuffer[pos++] = (uint8_t)(1 + csrcs_.size());
niklase@google.com470e71d2011-07-07 08:21:25 +00001344
pbos@webrtc.org9334ac22014-11-24 08:25:50 +00001345 // Add our own SSRC
1346 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
1347 pos += 4;
niklase@google.com470e71d2011-07-07 08:21:25 +00001348
pbos@webrtc.org9334ac22014-11-24 08:25:50 +00001349 // add CSRCs
1350 for (size_t i = 0; i < csrcs_.size(); i++) {
1351 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, csrcs_[i]);
1352 pos += 4;
1353 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001354
pbos@webrtc.org9334ac22014-11-24 08:25:50 +00001355 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001356}
1357
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001358int32_t RTCPSender::BuildReceiverReferenceTime(uint8_t* buffer,
1359 int& pos,
1360 uint32_t ntp_sec,
1361 uint32_t ntp_frac) {
1362 const int kRrTimeBlockLength = 20;
1363 if (pos + kRrTimeBlockLength >= IP_PACKET_SIZE) {
1364 return -2;
1365 }
1366
1367 if (last_xr_rr_.size() >= RTCP_NUMBER_OF_SR) {
1368 last_xr_rr_.erase(last_xr_rr_.begin());
1369 }
1370 last_xr_rr_.insert(std::pair<uint32_t, int64_t>(
1371 RTCPUtility::MidNtp(ntp_sec, ntp_frac),
1372 Clock::NtpToMs(ntp_sec, ntp_frac)));
1373
1374 // Add XR header.
1375 buffer[pos++] = 0x80;
1376 buffer[pos++] = 207;
1377 buffer[pos++] = 0; // XR packet length.
1378 buffer[pos++] = 4; // XR packet length.
1379
1380 // Add our own SSRC.
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001381 RtpUtility::AssignUWord32ToBuffer(buffer + pos, _SSRC);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001382 pos += 4;
1383
1384 // 0 1 2 3
1385 // 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
1386 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1387 // | BT=4 | reserved | block length = 2 |
1388 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1389 // | NTP timestamp, most significant word |
1390 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1391 // | NTP timestamp, least significant word |
1392 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1393
1394 // Add Receiver Reference Time Report block.
1395 buffer[pos++] = 4; // BT.
1396 buffer[pos++] = 0; // Reserved.
1397 buffer[pos++] = 0; // Block length.
1398 buffer[pos++] = 2; // Block length.
1399
1400 // NTP timestamp.
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001401 RtpUtility::AssignUWord32ToBuffer(buffer + pos, ntp_sec);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001402 pos += 4;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001403 RtpUtility::AssignUWord32ToBuffer(buffer + pos, ntp_frac);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001404 pos += 4;
1405
1406 return 0;
1407}
1408
1409int32_t RTCPSender::BuildDlrr(uint8_t* buffer,
1410 int& pos,
1411 const RtcpReceiveTimeInfo& info) {
1412 const int kDlrrBlockLength = 24;
1413 if (pos + kDlrrBlockLength >= IP_PACKET_SIZE) {
1414 return -2;
1415 }
1416
1417 // Add XR header.
1418 buffer[pos++] = 0x80;
1419 buffer[pos++] = 207;
1420 buffer[pos++] = 0; // XR packet length.
1421 buffer[pos++] = 5; // XR packet length.
1422
1423 // Add our own SSRC.
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001424 RtpUtility::AssignUWord32ToBuffer(buffer + pos, _SSRC);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001425 pos += 4;
1426
1427 // 0 1 2 3
1428 // 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
1429 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1430 // | BT=5 | reserved | block length |
1431 // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
1432 // | SSRC_1 (SSRC of first receiver) | sub-
1433 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
1434 // | last RR (LRR) | 1
1435 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1436 // | delay since last RR (DLRR) |
1437 // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
1438 // | SSRC_2 (SSRC of second receiver) | sub-
1439 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
1440 // : ... : 2
1441
1442 // Add DLRR sub block.
1443 buffer[pos++] = 5; // BT.
1444 buffer[pos++] = 0; // Reserved.
1445 buffer[pos++] = 0; // Block length.
1446 buffer[pos++] = 3; // Block length.
1447
1448 // NTP timestamp.
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001449 RtpUtility::AssignUWord32ToBuffer(buffer + pos, info.sourceSSRC);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001450 pos += 4;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001451 RtpUtility::AssignUWord32ToBuffer(buffer + pos, info.lastRR);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001452 pos += 4;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001453 RtpUtility::AssignUWord32ToBuffer(buffer + pos, info.delaySinceLastRR);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001454 pos += 4;
1455
1456 return 0;
1457}
1458
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001459int32_t
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001460RTCPSender::BuildVoIPMetric(uint8_t* rtcpbuffer, int& pos)
niklase@google.com470e71d2011-07-07 08:21:25 +00001461{
1462 // sanity
1463 if(pos + 44 >= IP_PACKET_SIZE)
1464 {
1465 return -2;
1466 }
1467
1468 // Add XR header
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001469 rtcpbuffer[pos++]=(uint8_t)0x80;
1470 rtcpbuffer[pos++]=(uint8_t)207;
niklase@google.com470e71d2011-07-07 08:21:25 +00001471
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001472 uint32_t XRLengthPos = pos;
niklase@google.com470e71d2011-07-07 08:21:25 +00001473
1474 // handle length later on
1475 pos++;
1476 pos++;
1477
1478 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001479 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001480 pos += 4;
1481
1482 // Add a VoIP metrics block
1483 rtcpbuffer[pos++]=7;
1484 rtcpbuffer[pos++]=0;
1485 rtcpbuffer[pos++]=0;
1486 rtcpbuffer[pos++]=8;
1487
1488 // Add the remote SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001489 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001490 pos += 4;
1491
1492 rtcpbuffer[pos++] = _xrVoIPMetric.lossRate;
1493 rtcpbuffer[pos++] = _xrVoIPMetric.discardRate;
1494 rtcpbuffer[pos++] = _xrVoIPMetric.burstDensity;
1495 rtcpbuffer[pos++] = _xrVoIPMetric.gapDensity;
1496
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001497 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.burstDuration >> 8);
1498 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.burstDuration);
1499 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.gapDuration >> 8);
1500 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.gapDuration);
niklase@google.com470e71d2011-07-07 08:21:25 +00001501
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001502 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.roundTripDelay >> 8);
1503 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.roundTripDelay);
1504 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.endSystemDelay >> 8);
1505 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.endSystemDelay);
niklase@google.com470e71d2011-07-07 08:21:25 +00001506
1507 rtcpbuffer[pos++] = _xrVoIPMetric.signalLevel;
1508 rtcpbuffer[pos++] = _xrVoIPMetric.noiseLevel;
1509 rtcpbuffer[pos++] = _xrVoIPMetric.RERL;
1510 rtcpbuffer[pos++] = _xrVoIPMetric.Gmin;
1511
1512 rtcpbuffer[pos++] = _xrVoIPMetric.Rfactor;
1513 rtcpbuffer[pos++] = _xrVoIPMetric.extRfactor;
1514 rtcpbuffer[pos++] = _xrVoIPMetric.MOSLQ;
1515 rtcpbuffer[pos++] = _xrVoIPMetric.MOSCQ;
1516
1517 rtcpbuffer[pos++] = _xrVoIPMetric.RXconfig;
1518 rtcpbuffer[pos++] = 0; // reserved
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001519 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.JBnominal >> 8);
1520 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.JBnominal);
niklase@google.com470e71d2011-07-07 08:21:25 +00001521
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001522 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.JBmax >> 8);
1523 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.JBmax);
1524 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.JBabsMax >> 8);
1525 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.JBabsMax);
niklase@google.com470e71d2011-07-07 08:21:25 +00001526
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001527 rtcpbuffer[XRLengthPos]=(uint8_t)(0);
1528 rtcpbuffer[XRLengthPos+1]=(uint8_t)(10);
niklase@google.com470e71d2011-07-07 08:21:25 +00001529 return 0;
1530}
1531
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001532int32_t RTCPSender::SendRTCP(const FeedbackState& feedback_state,
1533 uint32_t packetTypeFlags,
1534 int32_t nackSize,
1535 const uint16_t* nackList,
1536 bool repeat,
1537 uint64_t pictureID) {
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001538 {
1539 CriticalSectionScoped lock(_criticalSectionRTCPSender);
1540 if(_method == kRtcpOff)
niklase@google.com470e71d2011-07-07 08:21:25 +00001541 {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +00001542 LOG(LS_WARNING) << "Can't send rtcp if it is disabled.";
pwestin@webrtc.org8edb39d2011-12-22 07:40:33 +00001543 return -1;
1544 }
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001545 }
1546 uint8_t rtcp_buffer[IP_PACKET_SIZE];
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001547 int rtcp_length = PrepareRTCP(feedback_state,
1548 packetTypeFlags,
1549 nackSize,
1550 nackList,
1551 repeat,
1552 pictureID,
1553 rtcp_buffer,
1554 IP_PACKET_SIZE);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001555 if (rtcp_length < 0) {
1556 return -1;
1557 }
1558 // Sanity don't send empty packets.
1559 if (rtcp_length == 0)
1560 {
1561 return -1;
1562 }
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001563 return SendToNetwork(rtcp_buffer, static_cast<size_t>(rtcp_length));
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001564}
1565
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001566int RTCPSender::PrepareRTCP(const FeedbackState& feedback_state,
1567 uint32_t packetTypeFlags,
1568 int32_t nackSize,
1569 const uint16_t* nackList,
1570 bool repeat,
1571 uint64_t pictureID,
1572 uint8_t* rtcp_buffer,
1573 int buffer_size) {
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001574 uint32_t rtcpPacketTypeFlags = packetTypeFlags;
1575 // Collect the received information.
1576 uint32_t NTPsec = 0;
1577 uint32_t NTPfrac = 0;
1578 uint32_t jitterTransmissionOffset = 0;
1579 int position = 0;
1580
1581 CriticalSectionScoped lock(_criticalSectionRTCPSender);
1582
asapersson@webrtc.orgd08d3892014-12-16 12:03:11 +00001583 if (packet_type_counter_.first_packet_time_ms == -1) {
1584 packet_type_counter_.first_packet_time_ms = _clock->TimeInMilliseconds();
1585 }
1586
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001587 if(_TMMBR ) // Attach TMMBR to send and receive reports.
1588 {
1589 rtcpPacketTypeFlags |= kRtcpTmmbr;
1590 }
1591 if(_appSend)
1592 {
1593 rtcpPacketTypeFlags |= kRtcpApp;
1594 _appSend = false;
1595 }
1596 if(_REMB && _sendREMB)
1597 {
1598 // Always attach REMB to SR if that is configured. Note that REMB is
1599 // only sent on one of the RTP modules in the REMB group.
1600 rtcpPacketTypeFlags |= kRtcpRemb;
1601 }
1602 if(_xrSendVoIPMetric)
1603 {
1604 rtcpPacketTypeFlags |= kRtcpXrVoipMetric;
1605 _xrSendVoIPMetric = false;
1606 }
1607 if(_sendTMMBN) // Set when having received a TMMBR.
1608 {
1609 rtcpPacketTypeFlags |= kRtcpTmmbn;
1610 _sendTMMBN = false;
1611 }
asapersson@webrtc.orgefaeda02014-01-20 08:34:49 +00001612 if (rtcpPacketTypeFlags & kRtcpReport)
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001613 {
asapersson@webrtc.orgefaeda02014-01-20 08:34:49 +00001614 if (xrSendReceiverReferenceTimeEnabled_ && !_sending)
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001615 {
1616 rtcpPacketTypeFlags |= kRtcpXrReceiverReferenceTime;
1617 }
1618 if (feedback_state.has_last_xr_rr)
1619 {
1620 rtcpPacketTypeFlags |= kRtcpXrDlrrReportBlock;
1621 }
1622 }
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001623 if(_method == kRtcpCompound)
1624 {
1625 if(_sending)
1626 {
1627 rtcpPacketTypeFlags |= kRtcpSr;
1628 } else
1629 {
1630 rtcpPacketTypeFlags |= kRtcpRr;
1631 }
1632 } else if(_method == kRtcpNonCompound)
1633 {
1634 if(rtcpPacketTypeFlags & kRtcpReport)
1635 {
1636 if(_sending)
1637 {
1638 rtcpPacketTypeFlags |= kRtcpSr;
1639 } else
1640 {
1641 rtcpPacketTypeFlags |= kRtcpRr;
1642 }
1643 }
1644 }
1645 if( rtcpPacketTypeFlags & kRtcpRr ||
1646 rtcpPacketTypeFlags & kRtcpSr)
1647 {
1648 // generate next time to send a RTCP report
1649 // seeded from RTP constructor
1650 int32_t random = rand() % 1000;
1651 int32_t timeToNext = RTCP_INTERVAL_AUDIO_MS;
1652
1653 if(_audio)
1654 {
1655 timeToNext = (RTCP_INTERVAL_AUDIO_MS/2) +
1656 (RTCP_INTERVAL_AUDIO_MS*random/1000);
1657 }else
1658 {
1659 uint32_t minIntervalMs = RTCP_INTERVAL_AUDIO_MS;
1660 if(_sending)
1661 {
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001662 // Calculate bandwidth for video; 360 / send bandwidth in kbit/s.
1663 uint32_t send_bitrate_kbit = feedback_state.send_bitrate / 1000;
1664 if (send_bitrate_kbit != 0)
1665 minIntervalMs = 360000 / send_bitrate_kbit;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001666 }
1667 if(minIntervalMs > RTCP_INTERVAL_VIDEO_MS)
1668 {
1669 minIntervalMs = RTCP_INTERVAL_VIDEO_MS;
1670 }
1671 timeToNext = (minIntervalMs/2) + (minIntervalMs*random/1000);
1672 }
1673 _nextTimeToSendRTCP = _clock->TimeInMilliseconds() + timeToNext;
1674 }
1675
1676 // If the data does not fit in the packet we fill it as much as possible.
1677 int32_t buildVal = 0;
1678
1679 // We need to send our NTP even if we haven't received any reports.
1680 _clock->CurrentNtp(NTPsec, NTPfrac);
1681 if (ShouldSendReportBlocks(rtcpPacketTypeFlags)) {
1682 StatisticianMap statisticians =
1683 receive_statistics_->GetActiveStatisticians();
1684 if (!statisticians.empty()) {
1685 StatisticianMap::const_iterator it;
1686 int i;
1687 for (it = statisticians.begin(), i = 0; it != statisticians.end();
1688 ++it, ++i) {
1689 RTCPReportBlock report_block;
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001690 if (PrepareReport(
1691 feedback_state, it->second, &report_block, &NTPsec, &NTPfrac))
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001692 AddReportBlock(it->first, &internal_report_blocks_, &report_block);
1693 }
1694 if (_IJ && !statisticians.empty()) {
1695 rtcpPacketTypeFlags |= kRtcpTransmissionTimeOffset;
1696 }
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001697 }
1698 }
1699
1700 if(rtcpPacketTypeFlags & kRtcpSr)
1701 {
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001702 buildVal = BuildSR(feedback_state, rtcp_buffer, position, NTPsec, NTPfrac);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001703 if (buildVal == -1) {
1704 return -1;
1705 } else if (buildVal == -2) {
1706 return position;
1707 }
1708 buildVal = BuildSDEC(rtcp_buffer, position);
1709 if (buildVal == -1) {
1710 return -1;
1711 } else if (buildVal == -2) {
1712 return position;
1713 }
1714 }else if(rtcpPacketTypeFlags & kRtcpRr)
1715 {
1716 buildVal = BuildRR(rtcp_buffer, position, NTPsec, NTPfrac);
1717 if (buildVal == -1) {
1718 return -1;
1719 } else if (buildVal == -2) {
1720 return position;
1721 }
1722 // only of set
1723 if(_CNAME[0] != 0)
1724 {
1725 buildVal = BuildSDEC(rtcp_buffer, position);
1726 if (buildVal == -1) {
1727 return -1;
1728 }
1729 }
1730 }
1731 if(rtcpPacketTypeFlags & kRtcpTransmissionTimeOffset)
1732 {
1733 // If present, this RTCP packet must be placed after a
1734 // receiver report.
1735 buildVal = BuildExtendedJitterReport(rtcp_buffer,
1736 position,
1737 jitterTransmissionOffset);
1738 if (buildVal == -1) {
1739 return -1;
1740 } else if (buildVal == -2) {
1741 return position;
1742 }
1743 }
1744 if(rtcpPacketTypeFlags & kRtcpPli)
1745 {
1746 buildVal = BuildPLI(rtcp_buffer, position);
1747 if (buildVal == -1) {
1748 return -1;
1749 } else if (buildVal == -2) {
1750 return position;
1751 }
sprang@webrtc.org0200f702015-02-16 12:06:00 +00001752 TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
1753 "RTCPSender::PLI");
asapersson@webrtc.org8098e072014-02-19 11:59:02 +00001754 ++packet_type_counter_.pli_packets;
sprang@webrtc.org0200f702015-02-16 12:06:00 +00001755 TRACE_COUNTER_ID1(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
1756 "RTCP_PLICount", _SSRC,
asapersson@webrtc.org8098e072014-02-19 11:59:02 +00001757 packet_type_counter_.pli_packets);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001758 }
1759 if(rtcpPacketTypeFlags & kRtcpFir)
1760 {
1761 buildVal = BuildFIR(rtcp_buffer, position, repeat);
1762 if (buildVal == -1) {
1763 return -1;
1764 } else if (buildVal == -2) {
1765 return position;
1766 }
sprang@webrtc.org0200f702015-02-16 12:06:00 +00001767 TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
1768 "RTCPSender::FIR");
asapersson@webrtc.org8098e072014-02-19 11:59:02 +00001769 ++packet_type_counter_.fir_packets;
sprang@webrtc.org0200f702015-02-16 12:06:00 +00001770 TRACE_COUNTER_ID1(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
1771 "RTCP_FIRCount", _SSRC,
asapersson@webrtc.org8098e072014-02-19 11:59:02 +00001772 packet_type_counter_.fir_packets);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001773 }
1774 if(rtcpPacketTypeFlags & kRtcpSli)
1775 {
1776 buildVal = BuildSLI(rtcp_buffer, position, (uint8_t)pictureID);
1777 if (buildVal == -1) {
1778 return -1;
1779 } else if (buildVal == -2) {
1780 return position;
1781 }
1782 }
1783 if(rtcpPacketTypeFlags & kRtcpRpsi)
1784 {
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001785 const int8_t payloadType = feedback_state.send_payload_type;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001786 if (payloadType == -1) {
1787 return -1;
1788 }
1789 buildVal = BuildRPSI(rtcp_buffer, position, pictureID,
1790 (uint8_t)payloadType);
1791 if (buildVal == -1) {
1792 return -1;
1793 } else if (buildVal == -2) {
1794 return position;
1795 }
1796 }
1797 if(rtcpPacketTypeFlags & kRtcpRemb)
1798 {
1799 buildVal = BuildREMB(rtcp_buffer, position);
1800 if (buildVal == -1) {
1801 return -1;
1802 } else if (buildVal == -2) {
1803 return position;
1804 }
sprang@webrtc.org0200f702015-02-16 12:06:00 +00001805 TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
1806 "RTCPSender::REMB");
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001807 }
1808 if(rtcpPacketTypeFlags & kRtcpBye)
1809 {
1810 buildVal = BuildBYE(rtcp_buffer, position);
1811 if (buildVal == -1) {
1812 return -1;
1813 } else if (buildVal == -2) {
1814 return position;
1815 }
1816 }
1817 if(rtcpPacketTypeFlags & kRtcpApp)
1818 {
1819 buildVal = BuildAPP(rtcp_buffer, position);
1820 if (buildVal == -1) {
1821 return -1;
1822 } else if (buildVal == -2) {
1823 return position;
1824 }
1825 }
1826 if(rtcpPacketTypeFlags & kRtcpTmmbr)
1827 {
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001828 buildVal = BuildTMMBR(feedback_state.module, rtcp_buffer, position);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001829 if (buildVal == -1) {
1830 return -1;
1831 } else if (buildVal == -2) {
1832 return position;
1833 }
1834 }
1835 if(rtcpPacketTypeFlags & kRtcpTmmbn)
1836 {
1837 buildVal = BuildTMMBN(rtcp_buffer, position);
1838 if (buildVal == -1) {
1839 return -1;
1840 } else if (buildVal == -2) {
1841 return position;
1842 }
1843 }
1844 if(rtcpPacketTypeFlags & kRtcpNack)
1845 {
1846 std::string nackString;
1847 buildVal = BuildNACK(rtcp_buffer, position, nackSize, nackList,
1848 &nackString);
1849 if (buildVal == -1) {
1850 return -1;
1851 } else if (buildVal == -2) {
1852 return position;
1853 }
sprang@webrtc.org0200f702015-02-16 12:06:00 +00001854 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
1855 "RTCPSender::NACK", "nacks",
1856 TRACE_STR_COPY(nackString.c_str()));
asapersson@webrtc.org8098e072014-02-19 11:59:02 +00001857 ++packet_type_counter_.nack_packets;
sprang@webrtc.org0200f702015-02-16 12:06:00 +00001858 TRACE_COUNTER_ID1(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
1859 "RTCP_NACKCount", _SSRC,
asapersson@webrtc.org8098e072014-02-19 11:59:02 +00001860 packet_type_counter_.nack_packets);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001861 }
1862 if(rtcpPacketTypeFlags & kRtcpXrVoipMetric)
1863 {
1864 buildVal = BuildVoIPMetric(rtcp_buffer, position);
1865 if (buildVal == -1) {
1866 return -1;
1867 } else if (buildVal == -2) {
1868 return position;
1869 }
1870 }
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001871 if (rtcpPacketTypeFlags & kRtcpXrReceiverReferenceTime)
1872 {
1873 buildVal = BuildReceiverReferenceTime(rtcp_buffer,
1874 position,
1875 NTPsec,
1876 NTPfrac);
1877 if (buildVal == -1) {
1878 return -1;
1879 } else if (buildVal == -2) {
1880 return position;
1881 }
1882 }
1883 if (rtcpPacketTypeFlags & kRtcpXrDlrrReportBlock)
1884 {
1885 buildVal = BuildDlrr(rtcp_buffer, position, feedback_state.last_xr_rr);
1886 if (buildVal == -1) {
1887 return -1;
1888 } else if (buildVal == -2) {
1889 return position;
1890 }
1891 }
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001892 return position;
1893}
1894
1895bool RTCPSender::ShouldSendReportBlocks(uint32_t rtcp_packet_type) const {
1896 return Status() == kRtcpCompound ||
1897 (rtcp_packet_type & kRtcpReport) ||
1898 (rtcp_packet_type & kRtcpSr) ||
1899 (rtcp_packet_type & kRtcpRr);
1900}
1901
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001902bool RTCPSender::PrepareReport(const FeedbackState& feedback_state,
1903 StreamStatistician* statistician,
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001904 RTCPReportBlock* report_block,
1905 uint32_t* ntp_secs, uint32_t* ntp_frac) {
1906 // Do we have receive statistics to send?
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00001907 RtcpStatistics stats;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001908 if (!statistician->GetStatistics(&stats, true))
1909 return false;
1910 report_block->fractionLost = stats.fraction_lost;
1911 report_block->cumulativeLost = stats.cumulative_lost;
1912 report_block->extendedHighSeqNum =
1913 stats.extended_max_sequence_number;
1914 report_block->jitter = stats.jitter;
1915
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001916 // get our NTP as late as possible to avoid a race
1917 _clock->CurrentNtp(*ntp_secs, *ntp_frac);
1918
1919 // Delay since last received report
1920 uint32_t delaySinceLastReceivedSR = 0;
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001921 if ((feedback_state.last_rr_ntp_secs != 0) ||
1922 (feedback_state.last_rr_ntp_frac != 0)) {
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001923 // get the 16 lowest bits of seconds and the 16 higest bits of fractions
1924 uint32_t now=*ntp_secs&0x0000FFFF;
1925 now <<=16;
1926 now += (*ntp_frac&0xffff0000)>>16;
1927
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001928 uint32_t receiveTime = feedback_state.last_rr_ntp_secs&0x0000FFFF;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001929 receiveTime <<=16;
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001930 receiveTime += (feedback_state.last_rr_ntp_frac&0xffff0000)>>16;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001931
1932 delaySinceLastReceivedSR = now-receiveTime;
1933 }
1934 report_block->delaySinceLastSR = delaySinceLastReceivedSR;
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001935 report_block->lastSR = feedback_state.remote_sr;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001936 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00001937}
1938
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00001939int32_t RTCPSender::SendToNetwork(const uint8_t* dataBuffer, size_t length) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001940 CriticalSectionScoped lock(_criticalSectionTransport);
1941 if(_cbTransport)
1942 {
1943 if(_cbTransport->SendRTCPPacket(_id, dataBuffer, length) > 0)
1944 {
1945 return 0;
1946 }
1947 }
1948 return -1;
1949}
1950
pbos@webrtc.org9334ac22014-11-24 08:25:50 +00001951void RTCPSender::SetCsrcs(const std::vector<uint32_t>& csrcs) {
1952 assert(csrcs.size() <= kRtpCsrcSize);
1953 CriticalSectionScoped lock(_criticalSectionRTCPSender);
1954 csrcs_ = csrcs;
niklase@google.com470e71d2011-07-07 08:21:25 +00001955}
1956
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00001957int32_t RTCPSender::SetApplicationSpecificData(uint8_t subType,
1958 uint32_t name,
1959 const uint8_t* data,
1960 uint16_t length) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001961 if(length %4 != 0)
1962 {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +00001963 LOG(LS_ERROR) << "Failed to SetApplicationSpecificData.";
niklase@google.com470e71d2011-07-07 08:21:25 +00001964 return -1;
1965 }
1966 CriticalSectionScoped lock(_criticalSectionRTCPSender);
1967
1968 if(_appData)
1969 {
1970 delete [] _appData;
1971 }
1972
1973 _appSend = true;
1974 _appSubType = subType;
1975 _appName = name;
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001976 _appData = new uint8_t[length];
niklase@google.com470e71d2011-07-07 08:21:25 +00001977 _appLength = length;
1978 memcpy(_appData, data, length);
1979 return 0;
1980}
1981
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001982int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001983RTCPSender::SetRTCPVoIPMetrics(const RTCPVoIPMetric* VoIPMetric)
1984{
1985 CriticalSectionScoped lock(_criticalSectionRTCPSender);
1986 memcpy(&_xrVoIPMetric, VoIPMetric, sizeof(RTCPVoIPMetric));
1987
1988 _xrSendVoIPMetric = true;
1989 return 0;
1990}
1991
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001992void RTCPSender::SendRtcpXrReceiverReferenceTime(bool enable) {
1993 CriticalSectionScoped lock(_criticalSectionRTCPSender);
1994 xrSendReceiverReferenceTimeEnabled_ = enable;
1995}
1996
asapersson@webrtc.org8d02f5d2013-11-21 08:57:04 +00001997bool RTCPSender::RtcpXrReceiverReferenceTime() const {
1998 CriticalSectionScoped lock(_criticalSectionRTCPSender);
1999 return xrSendReceiverReferenceTimeEnabled_;
2000}
2001
niklase@google.com470e71d2011-07-07 08:21:25 +00002002// called under critsect _criticalSectionRTCPSender
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00002003int32_t RTCPSender::WriteAllReportBlocksToBuffer(uint8_t* rtcpbuffer,
2004 int pos,
2005 uint8_t& numberOfReportBlocks,
2006 uint32_t NTPsec,
2007 uint32_t NTPfrac) {
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002008 numberOfReportBlocks = external_report_blocks_.size();
2009 numberOfReportBlocks += internal_report_blocks_.size();
2010 if ((pos + numberOfReportBlocks * 24) >= IP_PACKET_SIZE) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +00002011 LOG(LS_WARNING) << "Can't fit all report blocks.";
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002012 return -1;
2013 }
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002014 pos = WriteReportBlocksToBuffer(rtcpbuffer, pos, internal_report_blocks_);
2015 while (!internal_report_blocks_.empty()) {
2016 delete internal_report_blocks_.begin()->second;
2017 internal_report_blocks_.erase(internal_report_blocks_.begin());
2018 }
2019 pos = WriteReportBlocksToBuffer(rtcpbuffer, pos, external_report_blocks_);
2020 return pos;
2021}
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002022
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002023int32_t RTCPSender::WriteReportBlocksToBuffer(
2024 uint8_t* rtcpbuffer,
2025 int32_t position,
2026 const std::map<uint32_t, RTCPReportBlock*>& report_blocks) {
2027 std::map<uint32_t, RTCPReportBlock*>::const_iterator it =
2028 report_blocks.begin();
2029 for (; it != report_blocks.end(); it++) {
pbos@webrtc.org2f446732013-04-08 11:08:41 +00002030 uint32_t remoteSSRC = it->first;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002031 RTCPReportBlock* reportBlock = it->second;
2032 if (reportBlock) {
2033 // Remote SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00002034 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + position, remoteSSRC);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002035 position += 4;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002036
2037 // fraction lost
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002038 rtcpbuffer[position++] = reportBlock->fractionLost;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002039
2040 // cumulative loss
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00002041 RtpUtility::AssignUWord24ToBuffer(rtcpbuffer + position,
2042 reportBlock->cumulativeLost);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002043 position += 3;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002044
2045 // extended highest seq_no, contain the highest sequence number received
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00002046 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + position,
2047 reportBlock->extendedHighSeqNum);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002048 position += 4;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002049
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002050 // Jitter
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00002051 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + position,
2052 reportBlock->jitter);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002053 position += 4;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002054
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00002055 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + position,
2056 reportBlock->lastSR);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002057 position += 4;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002058
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00002059 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + position,
2060 reportBlock->delaySinceLastSR);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002061 position += 4;
niklase@google.com470e71d2011-07-07 08:21:25 +00002062 }
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002063 }
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002064 return position;
niklase@google.com470e71d2011-07-07 08:21:25 +00002065}
2066
2067// no callbacks allowed inside this function
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00002068int32_t RTCPSender::SetTMMBN(const TMMBRSet* boundingSet,
2069 uint32_t maxBitrateKbit) {
niklase@google.com470e71d2011-07-07 08:21:25 +00002070 CriticalSectionScoped lock(_criticalSectionRTCPSender);
2071
2072 if (0 == _tmmbrHelp.SetTMMBRBoundingSetToSend(boundingSet, maxBitrateKbit))
2073 {
2074 _sendTMMBN = true;
2075 return 0;
2076 }
2077 return -1;
2078}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00002079} // namespace webrtc