blob: c713852b2a56738a1ae7e5a497600b2ecf2a0928 [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.org1d0fa5d2015-02-19 12:47:00 +000079RTCPSender::RTCPSender(
80 int32_t id,
81 bool audio,
82 Clock* clock,
83 ReceiveStatistics* receive_statistics,
84 RtcpPacketTypeCounterObserver* packet_type_counter_observer)
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +000085 : _id(id),
86 _audio(audio),
87 _clock(clock),
88 _method(kRtcpOff),
89 _criticalSectionTransport(
90 CriticalSectionWrapper::CreateCriticalSection()),
91 _cbTransport(NULL),
niklase@google.com470e71d2011-07-07 08:21:25 +000092
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +000093 _criticalSectionRTCPSender(
94 CriticalSectionWrapper::CreateCriticalSection()),
95 _usingNack(false),
96 _sending(false),
97 _sendTMMBN(false),
98 _REMB(false),
99 _sendREMB(false),
100 _TMMBR(false),
101 _IJ(false),
102 _nextTimeToSendRTCP(0),
103 start_timestamp_(0),
104 last_rtp_timestamp_(0),
105 last_frame_capture_time_ms_(-1),
106 _SSRC(0),
107 _remoteSSRC(0),
108 _CNAME(),
109 receive_statistics_(receive_statistics),
110 internal_report_blocks_(),
111 external_report_blocks_(),
112 _csrcCNAMEs(),
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000113 _lastSendReport(),
114 _lastRTCPTime(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000115
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000116 last_xr_rr_(),
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000117
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000118 _sequenceNumberFIR(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000119
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000120 _rembBitrate(0),
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000121
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000122 _tmmbrHelp(),
123 _tmmbr_Send(0),
124 _packetOH_Send(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000125
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000126 _appSend(false),
127 _appSubType(0),
128 _appName(),
129 _appData(NULL),
130 _appLength(0),
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000131
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000132 xrSendReceiverReferenceTimeEnabled_(false),
133 _xrSendVoIPMetric(false),
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +0000134 _xrVoIPMetric(),
135 packet_type_counter_observer_(packet_type_counter_observer) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000136 memset(_CNAME, 0, sizeof(_CNAME));
137 memset(_lastSendReport, 0, sizeof(_lastSendReport));
138 memset(_lastRTCPTime, 0, sizeof(_lastRTCPTime));
niklase@google.com470e71d2011-07-07 08:21:25 +0000139}
140
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000141RTCPSender::~RTCPSender() {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000142 delete [] _appData;
niklase@google.com470e71d2011-07-07 08:21:25 +0000143
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000144 while (!internal_report_blocks_.empty()) {
145 delete internal_report_blocks_.begin()->second;
146 internal_report_blocks_.erase(internal_report_blocks_.begin());
147 }
148 while (!external_report_blocks_.empty()) {
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000149 std::map<uint32_t, RTCPReportBlock*>::iterator it =
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000150 external_report_blocks_.begin();
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000151 delete it->second;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000152 external_report_blocks_.erase(it);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000153 }
154 while (!_csrcCNAMEs.empty()) {
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000155 std::map<uint32_t, RTCPCnameInformation*>::iterator it =
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000156 _csrcCNAMEs.begin();
157 delete it->second;
158 _csrcCNAMEs.erase(it);
159 }
160 delete _criticalSectionTransport;
161 delete _criticalSectionRTCPSender;
niklase@google.com470e71d2011-07-07 08:21:25 +0000162}
163
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000164int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +0000165RTCPSender::RegisterSendTransport(Transport* outgoingTransport)
166{
167 CriticalSectionScoped lock(_criticalSectionTransport);
168 _cbTransport = outgoingTransport;
169 return 0;
170}
171
172RTCPMethod
173RTCPSender::Status() const
174{
175 CriticalSectionScoped lock(_criticalSectionRTCPSender);
176 return _method;
177}
178
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000179void RTCPSender::SetRTCPStatus(RTCPMethod method) {
180 CriticalSectionScoped lock(_criticalSectionRTCPSender);
181 _method = method;
182
183 if (method == kRtcpOff)
184 return;
185 _nextTimeToSendRTCP =
186 _clock->TimeInMilliseconds() +
187 (_audio ? RTCP_INTERVAL_AUDIO_MS / 2 : RTCP_INTERVAL_VIDEO_MS / 2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000188}
189
190bool
191RTCPSender::Sending() const
192{
193 CriticalSectionScoped lock(_criticalSectionRTCPSender);
194 return _sending;
195}
196
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000197int32_t
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +0000198RTCPSender::SetSendingStatus(const FeedbackState& feedback_state, bool sending)
niklase@google.com470e71d2011-07-07 08:21:25 +0000199{
200 bool sendRTCPBye = false;
201 {
202 CriticalSectionScoped lock(_criticalSectionRTCPSender);
203
204 if(_method != kRtcpOff)
205 {
206 if(sending == false && _sending == true)
207 {
208 // Trigger RTCP bye
209 sendRTCPBye = true;
210 }
211 }
212 _sending = sending;
213 }
214 if(sendRTCPBye)
215 {
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +0000216 return SendRTCP(feedback_state, kRtcpBye);
niklase@google.com470e71d2011-07-07 08:21:25 +0000217 }
218 return 0;
219}
220
221bool
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000222RTCPSender::REMB() const
223{
224 CriticalSectionScoped lock(_criticalSectionRTCPSender);
225 return _REMB;
226}
227
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000228void RTCPSender::SetREMBStatus(bool enable) {
229 CriticalSectionScoped lock(_criticalSectionRTCPSender);
230 _REMB = enable;
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000231}
232
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000233void RTCPSender::SetREMBData(uint32_t bitrate,
234 const std::vector<uint32_t>& ssrcs) {
235 CriticalSectionScoped lock(_criticalSectionRTCPSender);
236 _rembBitrate = bitrate;
237 remb_ssrcs_ = ssrcs;
stefan@webrtc.org4ef438e2014-07-11 09:55:30 +0000238
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000239 _sendREMB = true;
240 // Send a REMB immediately if we have a new REMB. The frequency of REMBs is
241 // throttled by the caller.
242 _nextTimeToSendRTCP = _clock->TimeInMilliseconds();
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000243}
244
245bool
niklase@google.com470e71d2011-07-07 08:21:25 +0000246RTCPSender::TMMBR() const
247{
248 CriticalSectionScoped lock(_criticalSectionRTCPSender);
249 return _TMMBR;
250}
251
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000252void RTCPSender::SetTMMBRStatus(bool enable) {
253 CriticalSectionScoped lock(_criticalSectionRTCPSender);
254 _TMMBR = enable;
niklase@google.com470e71d2011-07-07 08:21:25 +0000255}
256
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000257bool
258RTCPSender::IJ() const
259{
260 CriticalSectionScoped lock(_criticalSectionRTCPSender);
261 return _IJ;
262}
263
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000264void RTCPSender::SetIJStatus(bool enable) {
265 CriticalSectionScoped lock(_criticalSectionRTCPSender);
266 _IJ = enable;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000267}
268
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000269void RTCPSender::SetStartTimestamp(uint32_t start_timestamp) {
pbos@webrtc.org180e5162014-07-11 15:36:26 +0000270 CriticalSectionScoped lock(_criticalSectionRTCPSender);
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000271 start_timestamp_ = start_timestamp;
272}
273
274void RTCPSender::SetLastRtpTime(uint32_t rtp_timestamp,
275 int64_t capture_time_ms) {
henrika@webrtc.org19da7192013-04-05 14:34:57 +0000276 CriticalSectionScoped lock(_criticalSectionRTCPSender);
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000277 last_rtp_timestamp_ = rtp_timestamp;
278 if (capture_time_ms < 0) {
279 // We don't currently get a capture time from VoiceEngine.
stefan@webrtc.org7da34592013-04-09 14:56:29 +0000280 last_frame_capture_time_ms_ = _clock->TimeInMilliseconds();
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000281 } else {
282 last_frame_capture_time_ms_ = capture_time_ms;
283 }
284}
285
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000286void RTCPSender::SetSSRC(uint32_t ssrc) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000287 CriticalSectionScoped lock(_criticalSectionRTCPSender);
288
289 if(_SSRC != 0)
290 {
291 // not first SetSSRC, probably due to a collision
292 // schedule a new RTCP report
pwestin@webrtc.org0644b1d2011-12-01 15:42:31 +0000293 // make sure that we send a RTP packet
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +0000294 _nextTimeToSendRTCP = _clock->TimeInMilliseconds() + 100;
niklase@google.com470e71d2011-07-07 08:21:25 +0000295 }
296 _SSRC = ssrc;
297}
298
wu@webrtc.org822fbd82013-08-15 23:38:54 +0000299void RTCPSender::SetRemoteSSRC(uint32_t ssrc)
niklase@google.com470e71d2011-07-07 08:21:25 +0000300{
301 CriticalSectionScoped lock(_criticalSectionRTCPSender);
302 _remoteSSRC = ssrc;
niklase@google.com470e71d2011-07-07 08:21:25 +0000303}
304
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000305int32_t RTCPSender::SetCNAME(const char cName[RTCP_CNAME_SIZE]) {
tommi@webrtc.orga990e122012-04-26 15:28:22 +0000306 if (!cName)
307 return -1;
308
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000309 CriticalSectionScoped lock(_criticalSectionRTCPSender);
310 _CNAME[RTCP_CNAME_SIZE - 1] = 0;
311 strncpy(_CNAME, cName, RTCP_CNAME_SIZE - 1);
312 return 0;
313}
314
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000315int32_t RTCPSender::AddMixedCNAME(uint32_t SSRC,
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000316 const char cName[RTCP_CNAME_SIZE]) {
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000317 assert(cName);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000318 CriticalSectionScoped lock(_criticalSectionRTCPSender);
319 if (_csrcCNAMEs.size() >= kRtpCsrcSize) {
320 return -1;
321 }
322 RTCPCnameInformation* ptr = new RTCPCnameInformation();
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000323 ptr->name[RTCP_CNAME_SIZE - 1] = 0;
324 strncpy(ptr->name, cName, RTCP_CNAME_SIZE - 1);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000325 _csrcCNAMEs[SSRC] = ptr;
326 return 0;
327}
328
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000329int32_t RTCPSender::RemoveMixedCNAME(uint32_t SSRC) {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000330 CriticalSectionScoped lock(_criticalSectionRTCPSender);
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000331 std::map<uint32_t, RTCPCnameInformation*>::iterator it =
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000332 _csrcCNAMEs.find(SSRC);
333
334 if (it == _csrcCNAMEs.end()) {
335 return -1;
336 }
337 delete it->second;
338 _csrcCNAMEs.erase(it);
339 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000340}
341
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000342bool RTCPSender::TimeToSendRTCPReport(bool sendKeyframeBeforeRTP) const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000343/*
344 For audio we use a fix 5 sec interval
345
346 For video we use 1 sec interval fo a BW smaller than 360 kbit/s,
stefan@webrtc.org9d4762e2014-03-24 17:13:00 +0000347 technicaly we break the max 5% RTCP BW for video below 10 kbit/s but
348 that should be extremely rare
niklase@google.com470e71d2011-07-07 08:21:25 +0000349
350
351From RFC 3550
352
353 MAX RTCP BW is 5% if the session BW
354 A send report is approximately 65 bytes inc CNAME
stefan@webrtc.org9d4762e2014-03-24 17:13:00 +0000355 A receiver report is approximately 28 bytes
niklase@google.com470e71d2011-07-07 08:21:25 +0000356
357 The RECOMMENDED value for the reduced minimum in seconds is 360
358 divided by the session bandwidth in kilobits/second. This minimum
359 is smaller than 5 seconds for bandwidths greater than 72 kb/s.
360
361 If the participant has not yet sent an RTCP packet (the variable
362 initial is true), the constant Tmin is set to 2.5 seconds, else it
363 is set to 5 seconds.
364
365 The interval between RTCP packets is varied randomly over the
366 range [0.5,1.5] times the calculated interval to avoid unintended
367 synchronization of all participants
368
369 if we send
370 If the participant is a sender (we_sent true), the constant C is
371 set to the average RTCP packet size (avg_rtcp_size) divided by 25%
372 of the RTCP bandwidth (rtcp_bw), and the constant n is set to the
373 number of senders.
374
375 if we receive only
376 If we_sent is not true, the constant C is set
377 to the average RTCP packet size divided by 75% of the RTCP
378 bandwidth. The constant n is set to the number of receivers
379 (members - senders). If the number of senders is greater than
380 25%, senders and receivers are treated together.
381
382 reconsideration NOT required for peer-to-peer
383 "timer reconsideration" is
384 employed. This algorithm implements a simple back-off mechanism
385 which causes users to hold back RTCP packet transmission if the
386 group sizes are increasing.
387
388 n = number of members
389 C = avg_size/(rtcpBW/4)
390
391 3. The deterministic calculated interval Td is set to max(Tmin, n*C).
392
393 4. The calculated interval T is set to a number uniformly distributed
394 between 0.5 and 1.5 times the deterministic calculated interval.
395
396 5. The resulting value of T is divided by e-3/2=1.21828 to compensate
397 for the fact that the timer reconsideration algorithm converges to
398 a value of the RTCP bandwidth below the intended average
399*/
400
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000401 int64_t now = _clock->TimeInMilliseconds();
xians@webrtc.org8738d272011-11-25 13:43:53 +0000402
403 CriticalSectionScoped lock(_criticalSectionRTCPSender);
404
niklase@google.com470e71d2011-07-07 08:21:25 +0000405 if(_method == kRtcpOff)
406 {
407 return false;
408 }
409
niklase@google.com470e71d2011-07-07 08:21:25 +0000410 if(!_audio && sendKeyframeBeforeRTP)
411 {
412 // for video key-frames we want to send the RTCP before the large key-frame
413 // if we have a 100 ms margin
414 now += RTCP_SEND_BEFORE_KEY_FRAME_MS;
415 }
416
stefan@webrtc.org9d4762e2014-03-24 17:13:00 +0000417 if(now >= _nextTimeToSendRTCP)
niklase@google.com470e71d2011-07-07 08:21:25 +0000418 {
419 return true;
420
421 } else if(now < 0x0000ffff && _nextTimeToSendRTCP > 0xffff0000) // 65 sec margin
422 {
423 // wrap
424 return true;
425 }
426 return false;
427}
428
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000429uint32_t RTCPSender::LastSendReport(int64_t& lastRTCPTime)
niklase@google.com470e71d2011-07-07 08:21:25 +0000430{
431 CriticalSectionScoped lock(_criticalSectionRTCPSender);
432
433 lastRTCPTime = _lastRTCPTime[0];
434 return _lastSendReport[0];
435}
436
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000437int64_t RTCPSender::SendTimeOfSendReport(uint32_t sendReport) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000438 CriticalSectionScoped lock(_criticalSectionRTCPSender);
439
440 // This is only saved when we are the sender
441 if((_lastSendReport[0] == 0) || (sendReport == 0))
442 {
443 return 0; // will be ignored
444 } else
445 {
446 for(int i = 0; i < RTCP_NUMBER_OF_SR; ++i)
447 {
448 if( _lastSendReport[i] == sendReport)
449 {
450 return _lastRTCPTime[i];
451 }
452 }
453 }
454 return 0;
455}
456
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000457bool RTCPSender::SendTimeOfXrRrReport(uint32_t mid_ntp,
458 int64_t* time_ms) const {
459 CriticalSectionScoped lock(_criticalSectionRTCPSender);
460
461 if (last_xr_rr_.empty()) {
462 return false;
463 }
464 std::map<uint32_t, int64_t>::const_iterator it = last_xr_rr_.find(mid_ntp);
465 if (it == last_xr_rr_.end()) {
466 return false;
467 }
468 *time_ms = it->second;
469 return true;
470}
471
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000472int32_t RTCPSender::AddExternalReportBlock(
473 uint32_t SSRC,
474 const RTCPReportBlock* reportBlock) {
475 CriticalSectionScoped lock(_criticalSectionRTCPSender);
476 return AddReportBlock(SSRC, &external_report_blocks_, reportBlock);
477}
478
479int32_t RTCPSender::AddReportBlock(
480 uint32_t SSRC,
481 std::map<uint32_t, RTCPReportBlock*>* report_blocks,
482 const RTCPReportBlock* reportBlock) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000483 assert(reportBlock);
niklase@google.com470e71d2011-07-07 08:21:25 +0000484
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000485 if (report_blocks->size() >= RTCP_MAX_REPORT_BLOCKS) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000486 LOG(LS_WARNING) << "Too many report blocks.";
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000487 return -1;
488 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000489 std::map<uint32_t, RTCPReportBlock*>::iterator it =
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000490 report_blocks->find(SSRC);
491 if (it != report_blocks->end()) {
stefan@webrtc.org8d0cd072012-12-03 14:01:46 +0000492 delete it->second;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000493 report_blocks->erase(it);
stefan@webrtc.org8d0cd072012-12-03 14:01:46 +0000494 }
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000495 RTCPReportBlock* copyReportBlock = new RTCPReportBlock();
496 memcpy(copyReportBlock, reportBlock, sizeof(RTCPReportBlock));
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000497 (*report_blocks)[SSRC] = copyReportBlock;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000498 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000499}
500
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000501int32_t RTCPSender::RemoveExternalReportBlock(uint32_t SSRC) {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000502 CriticalSectionScoped lock(_criticalSectionRTCPSender);
niklase@google.com470e71d2011-07-07 08:21:25 +0000503
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000504 std::map<uint32_t, RTCPReportBlock*>::iterator it =
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000505 external_report_blocks_.find(SSRC);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000506
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000507 if (it == external_report_blocks_.end()) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000508 return -1;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000509 }
510 delete it->second;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000511 external_report_blocks_.erase(it);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000512 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000513}
514
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +0000515int32_t RTCPSender::BuildSR(const FeedbackState& feedback_state,
516 uint8_t* rtcpbuffer,
517 int& pos,
518 uint32_t NTPsec,
519 uint32_t NTPfrac)
niklase@google.com470e71d2011-07-07 08:21:25 +0000520{
521 // sanity
522 if(pos + 52 >= IP_PACKET_SIZE)
523 {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000524 LOG(LS_WARNING) << "Failed to build Sender Report.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000525 return -2;
526 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000527 uint32_t RTPtime;
niklase@google.com470e71d2011-07-07 08:21:25 +0000528
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000529 uint32_t posNumberOfReportBlocks = pos;
530 rtcpbuffer[pos++]=(uint8_t)0x80;
niklase@google.com470e71d2011-07-07 08:21:25 +0000531
532 // Sender report
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000533 rtcpbuffer[pos++]=(uint8_t)200;
niklase@google.com470e71d2011-07-07 08:21:25 +0000534
535 for(int i = (RTCP_NUMBER_OF_SR-2); i >= 0; i--)
536 {
537 // shift old
538 _lastSendReport[i+1] = _lastSendReport[i];
539 _lastRTCPTime[i+1] =_lastRTCPTime[i];
540 }
541
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +0000542 _lastRTCPTime[0] = Clock::NtpToMs(NTPsec, NTPfrac);
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000543 _lastSendReport[0] = (NTPsec << 16) + (NTPfrac >> 16);
niklase@google.com470e71d2011-07-07 08:21:25 +0000544
stefan@webrtc.org7da34592013-04-09 14:56:29 +0000545 // The timestamp of this RTCP packet should be estimated as the timestamp of
546 // the frame being captured at this moment. We are calculating that
547 // timestamp as the last frame's timestamp + the time since the last frame
548 // was captured.
pbos@webrtc.org180e5162014-07-11 15:36:26 +0000549 RTPtime = start_timestamp_ + last_rtp_timestamp_ +
550 (_clock->TimeInMilliseconds() - last_frame_capture_time_ms_) *
551 (feedback_state.frequency_hz / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +0000552
553 // Add sender data
554 // Save for our length field
555 pos++;
556 pos++;
557
558 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000559 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000560 pos += 4;
561 // NTP
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000562 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, NTPsec);
niklase@google.com470e71d2011-07-07 08:21:25 +0000563 pos += 4;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000564 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, NTPfrac);
niklase@google.com470e71d2011-07-07 08:21:25 +0000565 pos += 4;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000566 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, RTPtime);
niklase@google.com470e71d2011-07-07 08:21:25 +0000567 pos += 4;
568
569 //sender's packet count
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000570 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos,
pbos@webrtc.org2f4b14e2014-07-15 15:25:39 +0000571 feedback_state.packets_sent);
niklase@google.com470e71d2011-07-07 08:21:25 +0000572 pos += 4;
573
574 //sender's octet count
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000575 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos,
pbos@webrtc.org2f4b14e2014-07-15 15:25:39 +0000576 feedback_state.media_bytes_sent);
niklase@google.com470e71d2011-07-07 08:21:25 +0000577 pos += 4;
578
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000579 uint8_t numberOfReportBlocks = 0;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000580 int32_t retVal = WriteAllReportBlocksToBuffer(rtcpbuffer, pos,
581 numberOfReportBlocks,
582 NTPsec, NTPfrac);
niklase@google.com470e71d2011-07-07 08:21:25 +0000583 if(retVal < 0)
584 {
585 //
586 return retVal ;
587 }
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000588 pos = retVal;
niklase@google.com470e71d2011-07-07 08:21:25 +0000589 rtcpbuffer[posNumberOfReportBlocks] += numberOfReportBlocks;
590
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000591 uint16_t len = uint16_t((pos/4) -1);
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000592 RtpUtility::AssignUWord16ToBuffer(rtcpbuffer + 2, len);
niklase@google.com470e71d2011-07-07 08:21:25 +0000593 return 0;
594}
595
596
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000597int32_t RTCPSender::BuildSDEC(uint8_t* rtcpbuffer, int& pos) {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000598 size_t lengthCname = strlen(_CNAME);
599 assert(lengthCname < RTCP_CNAME_SIZE);
niklase@google.com470e71d2011-07-07 08:21:25 +0000600
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000601 // sanity
602 if(pos + 12 + lengthCname >= IP_PACKET_SIZE) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000603 LOG(LS_WARNING) << "Failed to build SDEC.";
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000604 return -2;
605 }
606 // SDEC Source Description
niklase@google.com470e71d2011-07-07 08:21:25 +0000607
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000608 // We always need to add SDES CNAME
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000609 rtcpbuffer[pos++] = static_cast<uint8_t>(0x80 + 1 + _csrcCNAMEs.size());
610 rtcpbuffer[pos++] = static_cast<uint8_t>(202);
niklase@google.com470e71d2011-07-07 08:21:25 +0000611
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000612 // handle SDES length later on
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000613 uint32_t SDESLengthPos = pos;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000614 pos++;
615 pos++;
niklase@google.com470e71d2011-07-07 08:21:25 +0000616
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000617 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000618 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000619 pos += 4;
620
621 // CNAME = 1
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000622 rtcpbuffer[pos++] = static_cast<uint8_t>(1);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000623
624 //
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000625 rtcpbuffer[pos++] = static_cast<uint8_t>(lengthCname);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000626
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000627 uint16_t SDESLength = 10;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000628
629 memcpy(&rtcpbuffer[pos], _CNAME, lengthCname);
630 pos += lengthCname;
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000631 SDESLength += (uint16_t)lengthCname;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000632
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000633 uint16_t padding = 0;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000634 // We must have a zero field even if we have an even multiple of 4 bytes
635 if ((pos % 4) == 0) {
636 padding++;
637 rtcpbuffer[pos++]=0;
638 }
639 while ((pos % 4) != 0) {
640 padding++;
641 rtcpbuffer[pos++]=0;
642 }
643 SDESLength += padding;
644
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000645 std::map<uint32_t, RTCPUtility::RTCPCnameInformation*>::iterator it =
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000646 _csrcCNAMEs.begin();
647
648 for(; it != _csrcCNAMEs.end(); it++) {
649 RTCPCnameInformation* cname = it->second;
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000650 uint32_t SSRC = it->first;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000651
652 // Add SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000653 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000654 pos += 4;
655
656 // CNAME = 1
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000657 rtcpbuffer[pos++] = static_cast<uint8_t>(1);
niklase@google.com470e71d2011-07-07 08:21:25 +0000658
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000659 size_t length = strlen(cname->name);
660 assert(length < RTCP_CNAME_SIZE);
niklase@google.com470e71d2011-07-07 08:21:25 +0000661
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000662 rtcpbuffer[pos++]= static_cast<uint8_t>(length);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000663 SDESLength += 6;
niklase@google.com470e71d2011-07-07 08:21:25 +0000664
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000665 memcpy(&rtcpbuffer[pos],cname->name, length);
niklase@google.com470e71d2011-07-07 08:21:25 +0000666
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000667 pos += length;
668 SDESLength += length;
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000669 uint16_t padding = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000670
671 // We must have a zero field even if we have an even multiple of 4 bytes
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000672 if((pos % 4) == 0){
673 padding++;
674 rtcpbuffer[pos++]=0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000675 }
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000676 while((pos % 4) != 0){
677 padding++;
678 rtcpbuffer[pos++] = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000679 }
680 SDESLength += padding;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000681 }
682 // in 32-bit words minus one and we don't count the header
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000683 uint16_t buffer_length = (SDESLength / 4) - 1;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000684 RtpUtility::AssignUWord16ToBuffer(rtcpbuffer + SDESLengthPos, buffer_length);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000685 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000686}
687
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000688int32_t RTCPSender::BuildRR(uint8_t* rtcpbuffer,
689 int& pos,
690 uint32_t NTPsec,
691 uint32_t NTPfrac) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000692 // sanity one block
693 if(pos + 32 >= IP_PACKET_SIZE)
694 {
695 return -2;
696 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000697 uint32_t posNumberOfReportBlocks = pos;
niklase@google.com470e71d2011-07-07 08:21:25 +0000698
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000699 rtcpbuffer[pos++]=(uint8_t)0x80;
700 rtcpbuffer[pos++]=(uint8_t)201;
niklase@google.com470e71d2011-07-07 08:21:25 +0000701
702 // Save for our length field
703 pos++;
704 pos++;
705
706 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000707 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000708 pos += 4;
709
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000710 uint8_t numberOfReportBlocks = 0;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000711 int retVal = WriteAllReportBlocksToBuffer(rtcpbuffer, pos,
712 numberOfReportBlocks,
713 NTPsec, NTPfrac);
niklase@google.com470e71d2011-07-07 08:21:25 +0000714 if(retVal < 0)
715 {
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000716 return pos;
niklase@google.com470e71d2011-07-07 08:21:25 +0000717 }
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000718 pos = retVal;
niklase@google.com470e71d2011-07-07 08:21:25 +0000719 rtcpbuffer[posNumberOfReportBlocks] += numberOfReportBlocks;
720
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000721 uint16_t len = uint16_t((pos)/4 -1);
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000722 RtpUtility::AssignUWord16ToBuffer(rtcpbuffer + 2, len);
niklase@google.com470e71d2011-07-07 08:21:25 +0000723 return 0;
724}
725
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000726// From RFC 5450: Transmission Time Offsets in RTP Streams.
727// 0 1 2 3
728// 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
729// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
730// hdr |V=2|P| RC | PT=IJ=195 | length |
731// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
732// | inter-arrival jitter |
733// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
734// . .
735// . .
736// . .
737// | inter-arrival jitter |
738// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
739//
740// If present, this RTCP packet must be placed after a receiver report
741// (inside a compound RTCP packet), and MUST have the same value for RC
742// (reception report count) as the receiver report.
743
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000744int32_t
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000745RTCPSender::BuildExtendedJitterReport(
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000746 uint8_t* rtcpbuffer,
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000747 int& pos,
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000748 const uint32_t jitterTransmissionTimeOffset)
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000749{
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000750 if (external_report_blocks_.size() > 0)
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000751 {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000752 // TODO(andresp): Remove external report blocks since they are not
753 // supported.
754 LOG(LS_ERROR) << "Handling of external report blocks not implemented.";
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000755 return 0;
756 }
757
758 // sanity
759 if(pos + 8 >= IP_PACKET_SIZE)
760 {
761 return -2;
762 }
763 // add picture loss indicator
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000764 uint8_t RC = 1;
765 rtcpbuffer[pos++]=(uint8_t)0x80 + RC;
766 rtcpbuffer[pos++]=(uint8_t)195;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000767
768 // Used fixed length of 2
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000769 rtcpbuffer[pos++]=(uint8_t)0;
770 rtcpbuffer[pos++]=(uint8_t)(1);
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000771
772 // Add inter-arrival jitter
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000773 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos,
774 jitterTransmissionTimeOffset);
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000775 pos += 4;
776 return 0;
777}
778
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000779int32_t
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000780RTCPSender::BuildPLI(uint8_t* rtcpbuffer, int& pos)
niklase@google.com470e71d2011-07-07 08:21:25 +0000781{
782 // sanity
783 if(pos + 12 >= IP_PACKET_SIZE)
784 {
785 return -2;
786 }
787 // add picture loss indicator
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000788 uint8_t FMT = 1;
789 rtcpbuffer[pos++]=(uint8_t)0x80 + FMT;
790 rtcpbuffer[pos++]=(uint8_t)206;
niklase@google.com470e71d2011-07-07 08:21:25 +0000791
792 //Used fixed length of 2
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000793 rtcpbuffer[pos++]=(uint8_t)0;
794 rtcpbuffer[pos++]=(uint8_t)(2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000795
796 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000797 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000798 pos += 4;
799
800 // Add the remote SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000801 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000802 pos += 4;
803 return 0;
804}
805
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000806int32_t RTCPSender::BuildFIR(uint8_t* rtcpbuffer,
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000807 int& pos,
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000808 bool repeat) {
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000809 // sanity
810 if(pos + 20 >= IP_PACKET_SIZE) {
811 return -2;
812 }
813 if (!repeat) {
814 _sequenceNumberFIR++; // do not increase if repetition
815 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000816
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000817 // add full intra request indicator
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000818 uint8_t FMT = 4;
819 rtcpbuffer[pos++] = (uint8_t)0x80 + FMT;
820 rtcpbuffer[pos++] = (uint8_t)206;
niklase@google.com470e71d2011-07-07 08:21:25 +0000821
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000822 //Length of 4
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000823 rtcpbuffer[pos++] = (uint8_t)0;
824 rtcpbuffer[pos++] = (uint8_t)(4);
niklase@google.com470e71d2011-07-07 08:21:25 +0000825
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000826 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000827 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000828 pos += 4;
niklase@google.com470e71d2011-07-07 08:21:25 +0000829
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000830 // RFC 5104 4.3.1.2. Semantics
831 // SSRC of media source
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000832 rtcpbuffer[pos++] = (uint8_t)0;
833 rtcpbuffer[pos++] = (uint8_t)0;
834 rtcpbuffer[pos++] = (uint8_t)0;
835 rtcpbuffer[pos++] = (uint8_t)0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000836
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000837 // Additional Feedback Control Information (FCI)
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000838 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _remoteSSRC);
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000839 pos += 4;
niklase@google.com470e71d2011-07-07 08:21:25 +0000840
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000841 rtcpbuffer[pos++] = (uint8_t)(_sequenceNumberFIR);
842 rtcpbuffer[pos++] = (uint8_t)0;
843 rtcpbuffer[pos++] = (uint8_t)0;
844 rtcpbuffer[pos++] = (uint8_t)0;
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000845 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000846}
847
848/*
849 0 1 2 3
850 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
851 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
852 | First | Number | PictureID |
853 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
854*/
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000855int32_t RTCPSender::BuildSLI(uint8_t* rtcpbuffer, int& pos, uint8_t pictureID) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000856 // sanity
857 if(pos + 16 >= IP_PACKET_SIZE)
858 {
859 return -2;
860 }
861 // add slice loss indicator
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000862 uint8_t FMT = 2;
863 rtcpbuffer[pos++]=(uint8_t)0x80 + FMT;
864 rtcpbuffer[pos++]=(uint8_t)206;
niklase@google.com470e71d2011-07-07 08:21:25 +0000865
866 //Used fixed length of 3
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000867 rtcpbuffer[pos++]=(uint8_t)0;
868 rtcpbuffer[pos++]=(uint8_t)(3);
niklase@google.com470e71d2011-07-07 08:21:25 +0000869
870 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000871 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000872 pos += 4;
873
874 // Add the remote SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000875 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000876 pos += 4;
877
878 // Add first, number & picture ID 6 bits
879 // first = 0, 13 - bits
880 // number = 0x1fff, 13 - bits only ones for now
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000881 uint32_t sliField = (0x1fff << 6)+ (0x3f & pictureID);
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000882 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, sliField);
niklase@google.com470e71d2011-07-07 08:21:25 +0000883 pos += 4;
884 return 0;
885}
886
887/*
888 0 1 2 3
889 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
890 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
891 | PB |0| Payload Type| Native RPSI bit string |
892 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
893 | defined per codec ... | Padding (0) |
894 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
895*/
896/*
897* Note: not generic made for VP8
898*/
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000899int32_t RTCPSender::BuildRPSI(uint8_t* rtcpbuffer,
900 int& pos,
901 uint64_t pictureID,
902 uint8_t payloadType) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000903 // sanity
904 if(pos + 24 >= IP_PACKET_SIZE)
905 {
906 return -2;
907 }
908 // add Reference Picture Selection Indication
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000909 uint8_t FMT = 3;
910 rtcpbuffer[pos++]=(uint8_t)0x80 + FMT;
911 rtcpbuffer[pos++]=(uint8_t)206;
niklase@google.com470e71d2011-07-07 08:21:25 +0000912
913 // calc length
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000914 uint32_t bitsRequired = 7;
915 uint8_t bytesRequired = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000916 while((pictureID>>bitsRequired) > 0)
917 {
918 bitsRequired += 7;
919 bytesRequired++;
920 }
921
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000922 uint8_t size = 3;
niklase@google.com470e71d2011-07-07 08:21:25 +0000923 if(bytesRequired > 6)
924 {
925 size = 5;
926 } else if(bytesRequired > 2)
927 {
928 size = 4;
929 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000930 rtcpbuffer[pos++]=(uint8_t)0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000931 rtcpbuffer[pos++]=size;
932
933 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000934 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000935 pos += 4;
936
937 // Add the remote SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000938 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000939 pos += 4;
940
941 // calc padding length
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000942 uint8_t paddingBytes = 4-((2+bytesRequired)%4);
niklase@google.com470e71d2011-07-07 08:21:25 +0000943 if(paddingBytes == 4)
944 {
945 paddingBytes = 0;
946 }
947 // add padding length in bits
948 rtcpbuffer[pos] = paddingBytes*8; // padding can be 0, 8, 16 or 24
949 pos++;
950
951 // add payload type
952 rtcpbuffer[pos] = payloadType;
953 pos++;
954
955 // add picture ID
956 for(int i = bytesRequired-1; i > 0; i--)
957 {
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000958 rtcpbuffer[pos] = 0x80 | uint8_t(pictureID >> (i*7));
niklase@google.com470e71d2011-07-07 08:21:25 +0000959 pos++;
960 }
961 // add last byte of picture ID
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000962 rtcpbuffer[pos] = uint8_t(pictureID & 0x7f);
niklase@google.com470e71d2011-07-07 08:21:25 +0000963 pos++;
964
965 // add padding
966 for(int j = 0; j <paddingBytes; j++)
967 {
968 rtcpbuffer[pos] = 0;
969 pos++;
970 }
971 return 0;
972}
973
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000974int32_t
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000975RTCPSender::BuildREMB(uint8_t* rtcpbuffer, int& pos)
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000976{
977 // sanity
pbos@webrtc.org49ff40e2014-11-13 14:42:37 +0000978 if(pos + 20 + 4 * remb_ssrcs_.size() >= IP_PACKET_SIZE)
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000979 {
980 return -2;
981 }
982 // add application layer feedback
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000983 uint8_t FMT = 15;
984 rtcpbuffer[pos++]=(uint8_t)0x80 + FMT;
985 rtcpbuffer[pos++]=(uint8_t)206;
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000986
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000987 rtcpbuffer[pos++]=(uint8_t)0;
pbos@webrtc.org49ff40e2014-11-13 14:42:37 +0000988 rtcpbuffer[pos++]=remb_ssrcs_.size() + 4;
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000989
990 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000991 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000992 pos += 4;
993
994 // Remote SSRC must be 0
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000995 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, 0);
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000996 pos += 4;
997
998 rtcpbuffer[pos++]='R';
999 rtcpbuffer[pos++]='E';
1000 rtcpbuffer[pos++]='M';
1001 rtcpbuffer[pos++]='B';
1002
pbos@webrtc.org49ff40e2014-11-13 14:42:37 +00001003 rtcpbuffer[pos++] = remb_ssrcs_.size();
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001004 // 6 bit Exp
1005 // 18 bit mantissa
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001006 uint8_t brExp = 0;
1007 for(uint32_t i=0; i<64; i++)
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001008 {
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001009 if(_rembBitrate <= ((uint32_t)262143 << i))
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001010 {
1011 brExp = i;
1012 break;
1013 }
1014 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001015 const uint32_t brMantissa = (_rembBitrate >> brExp);
1016 rtcpbuffer[pos++]=(uint8_t)((brExp << 2) + ((brMantissa >> 16) & 0x03));
1017 rtcpbuffer[pos++]=(uint8_t)(brMantissa >> 8);
1018 rtcpbuffer[pos++]=(uint8_t)(brMantissa);
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001019
pbos@webrtc.org49ff40e2014-11-13 14:42:37 +00001020 for (size_t i = 0; i < remb_ssrcs_.size(); i++)
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001021 {
pbos@webrtc.org49ff40e2014-11-13 14:42:37 +00001022 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, remb_ssrcs_[i]);
1023 pos += 4;
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001024 }
1025 return 0;
1026}
1027
stefan@webrtc.org9354cc92012-06-07 08:10:14 +00001028void
1029RTCPSender::SetTargetBitrate(unsigned int target_bitrate)
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001030{
mflodman@webrtc.org117c1192012-01-13 08:52:58 +00001031 CriticalSectionScoped lock(_criticalSectionRTCPSender);
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001032 _tmmbr_Send = target_bitrate / 1000;
mflodman@webrtc.org117c1192012-01-13 08:52:58 +00001033}
1034
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001035int32_t RTCPSender::BuildTMMBR(ModuleRtpRtcpImpl* rtp_rtcp_module,
1036 uint8_t* rtcpbuffer,
1037 int& pos) {
1038 if (rtp_rtcp_module == NULL)
1039 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001040 // Before sending the TMMBR check the received TMMBN, only an owner is allowed to raise the bitrate
1041 // If the sender is an owner of the TMMBN -> send TMMBR
1042 // If not an owner but the TMMBR would enter the TMMBN -> send TMMBR
1043
niklase@google.com470e71d2011-07-07 08:21:25 +00001044 // get current bounding set from RTCP receiver
1045 bool tmmbrOwner = false;
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001046 // store in candidateSet, allocates one extra slot
1047 TMMBRSet* candidateSet = _tmmbrHelp.CandidateSet();
niklase@google.com470e71d2011-07-07 08:21:25 +00001048
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001049 // holding _criticalSectionRTCPSender while calling RTCPreceiver which
1050 // will accuire _criticalSectionRTCPReceiver is a potental deadlock but
1051 // since RTCPreceiver is not doing the reverse we should be fine
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001052 int32_t lengthOfBoundingSet =
1053 rtp_rtcp_module->BoundingSet(tmmbrOwner, candidateSet);
niklase@google.com470e71d2011-07-07 08:21:25 +00001054
1055 if(lengthOfBoundingSet > 0)
1056 {
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001057 for (int32_t i = 0; i < lengthOfBoundingSet; i++)
niklase@google.com470e71d2011-07-07 08:21:25 +00001058 {
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001059 if( candidateSet->Tmmbr(i) == _tmmbr_Send &&
1060 candidateSet->PacketOH(i) == _packetOH_Send)
niklase@google.com470e71d2011-07-07 08:21:25 +00001061 {
1062 // do not send the same tuple
1063 return 0;
1064 }
1065 }
1066 if(!tmmbrOwner)
1067 {
1068 // use received bounding set as candidate set
1069 // add current tuple
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001070 candidateSet->SetEntry(lengthOfBoundingSet,
1071 _tmmbr_Send,
1072 _packetOH_Send,
1073 _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001074 int numCandidates = lengthOfBoundingSet+ 1;
1075
1076 // find bounding set
1077 TMMBRSet* boundingSet = NULL;
1078 int numBoundingSet = _tmmbrHelp.FindTMMBRBoundingSet(boundingSet);
1079 if(numBoundingSet > 0 || numBoundingSet <= numCandidates)
1080 {
1081 tmmbrOwner = _tmmbrHelp.IsOwner(_SSRC, numBoundingSet);
1082 }
1083 if(!tmmbrOwner)
1084 {
1085 // did not enter bounding set, no meaning to send this request
1086 return 0;
1087 }
1088 }
1089 }
1090
1091 if(_tmmbr_Send)
1092 {
1093 // sanity
1094 if(pos + 20 >= IP_PACKET_SIZE)
1095 {
1096 return -2;
1097 }
1098 // add TMMBR indicator
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001099 uint8_t FMT = 3;
1100 rtcpbuffer[pos++]=(uint8_t)0x80 + FMT;
1101 rtcpbuffer[pos++]=(uint8_t)205;
niklase@google.com470e71d2011-07-07 08:21:25 +00001102
1103 //Length of 4
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001104 rtcpbuffer[pos++]=(uint8_t)0;
1105 rtcpbuffer[pos++]=(uint8_t)(4);
niklase@google.com470e71d2011-07-07 08:21:25 +00001106
1107 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001108 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001109 pos += 4;
1110
1111 // RFC 5104 4.2.1.2. Semantics
1112
1113 // SSRC of media source
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001114 rtcpbuffer[pos++]=(uint8_t)0;
1115 rtcpbuffer[pos++]=(uint8_t)0;
1116 rtcpbuffer[pos++]=(uint8_t)0;
1117 rtcpbuffer[pos++]=(uint8_t)0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001118
1119 // Additional Feedback Control Information (FCI)
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001120 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001121 pos += 4;
1122
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001123 uint32_t bitRate = _tmmbr_Send*1000;
1124 uint32_t mmbrExp = 0;
1125 for(uint32_t i=0;i<64;i++)
niklase@google.com470e71d2011-07-07 08:21:25 +00001126 {
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001127 if(bitRate <= ((uint32_t)131071 << i))
niklase@google.com470e71d2011-07-07 08:21:25 +00001128 {
1129 mmbrExp = i;
1130 break;
1131 }
1132 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001133 uint32_t mmbrMantissa = (bitRate >> mmbrExp);
niklase@google.com470e71d2011-07-07 08:21:25 +00001134
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001135 rtcpbuffer[pos++]=(uint8_t)((mmbrExp << 2) + ((mmbrMantissa >> 15) & 0x03));
1136 rtcpbuffer[pos++]=(uint8_t)(mmbrMantissa >> 7);
1137 rtcpbuffer[pos++]=(uint8_t)((mmbrMantissa << 1) + ((_packetOH_Send >> 8)& 0x01));
1138 rtcpbuffer[pos++]=(uint8_t)(_packetOH_Send);
niklase@google.com470e71d2011-07-07 08:21:25 +00001139 }
1140 return 0;
1141}
1142
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001143int32_t
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001144RTCPSender::BuildTMMBN(uint8_t* rtcpbuffer, int& pos)
niklase@google.com470e71d2011-07-07 08:21:25 +00001145{
1146 TMMBRSet* boundingSet = _tmmbrHelp.BoundingSetToSend();
1147 if(boundingSet == NULL)
1148 {
1149 return -1;
1150 }
1151 // sanity
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001152 if(pos + 12 + boundingSet->lengthOfSet()*8 >= IP_PACKET_SIZE)
niklase@google.com470e71d2011-07-07 08:21:25 +00001153 {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +00001154 LOG(LS_WARNING) << "Failed to build TMMBN.";
niklase@google.com470e71d2011-07-07 08:21:25 +00001155 return -2;
1156 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001157 uint8_t FMT = 4;
niklase@google.com470e71d2011-07-07 08:21:25 +00001158 // add TMMBN indicator
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001159 rtcpbuffer[pos++]=(uint8_t)0x80 + FMT;
1160 rtcpbuffer[pos++]=(uint8_t)205;
niklase@google.com470e71d2011-07-07 08:21:25 +00001161
1162 //Add length later
1163 int posLength = pos;
1164 pos++;
1165 pos++;
1166
1167 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001168 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001169 pos += 4;
1170
1171 // RFC 5104 4.2.2.2. Semantics
1172
1173 // SSRC of media source
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001174 rtcpbuffer[pos++]=(uint8_t)0;
1175 rtcpbuffer[pos++]=(uint8_t)0;
1176 rtcpbuffer[pos++]=(uint8_t)0;
1177 rtcpbuffer[pos++]=(uint8_t)0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001178
1179 // Additional Feedback Control Information (FCI)
1180 int numBoundingSet = 0;
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001181 for(uint32_t n=0; n< boundingSet->lengthOfSet(); n++)
niklase@google.com470e71d2011-07-07 08:21:25 +00001182 {
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001183 if (boundingSet->Tmmbr(n) > 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001184 {
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001185 uint32_t tmmbrSSRC = boundingSet->Ssrc(n);
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001186 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, tmmbrSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001187 pos += 4;
1188
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001189 uint32_t bitRate = boundingSet->Tmmbr(n) * 1000;
1190 uint32_t mmbrExp = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001191 for(int i=0; i<64; i++)
1192 {
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001193 if(bitRate <= ((uint32_t)131071 << i))
niklase@google.com470e71d2011-07-07 08:21:25 +00001194 {
1195 mmbrExp = i;
1196 break;
1197 }
1198 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001199 uint32_t mmbrMantissa = (bitRate >> mmbrExp);
1200 uint32_t measuredOH = boundingSet->PacketOH(n);
niklase@google.com470e71d2011-07-07 08:21:25 +00001201
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001202 rtcpbuffer[pos++]=(uint8_t)((mmbrExp << 2) + ((mmbrMantissa >> 15) & 0x03));
1203 rtcpbuffer[pos++]=(uint8_t)(mmbrMantissa >> 7);
1204 rtcpbuffer[pos++]=(uint8_t)((mmbrMantissa << 1) + ((measuredOH >> 8)& 0x01));
1205 rtcpbuffer[pos++]=(uint8_t)(measuredOH);
niklase@google.com470e71d2011-07-07 08:21:25 +00001206 numBoundingSet++;
1207 }
1208 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001209 uint16_t length= (uint16_t)(2+2*numBoundingSet);
1210 rtcpbuffer[posLength++]=(uint8_t)(length>>8);
1211 rtcpbuffer[posLength]=(uint8_t)(length);
niklase@google.com470e71d2011-07-07 08:21:25 +00001212 return 0;
1213}
1214
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001215int32_t
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001216RTCPSender::BuildAPP(uint8_t* rtcpbuffer, int& pos)
niklase@google.com470e71d2011-07-07 08:21:25 +00001217{
1218 // sanity
1219 if(_appData == NULL)
1220 {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +00001221 LOG(LS_WARNING) << "Failed to build app specific.";
niklase@google.com470e71d2011-07-07 08:21:25 +00001222 return -1;
1223 }
1224 if(pos + 12 + _appLength >= IP_PACKET_SIZE)
1225 {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +00001226 LOG(LS_WARNING) << "Failed to build app specific.";
niklase@google.com470e71d2011-07-07 08:21:25 +00001227 return -2;
1228 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001229 rtcpbuffer[pos++]=(uint8_t)0x80 + _appSubType;
niklase@google.com470e71d2011-07-07 08:21:25 +00001230
1231 // Add APP ID
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001232 rtcpbuffer[pos++]=(uint8_t)204;
niklase@google.com470e71d2011-07-07 08:21:25 +00001233
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001234 uint16_t length = (_appLength>>2) + 2; // include SSRC and name
1235 rtcpbuffer[pos++]=(uint8_t)(length>>8);
1236 rtcpbuffer[pos++]=(uint8_t)(length);
niklase@google.com470e71d2011-07-07 08:21:25 +00001237
1238 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001239 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001240 pos += 4;
1241
1242 // Add our application name
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001243 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _appName);
niklase@google.com470e71d2011-07-07 08:21:25 +00001244 pos += 4;
1245
1246 // Add the data
1247 memcpy(rtcpbuffer +pos, _appData,_appLength);
1248 pos += _appLength;
1249 return 0;
1250}
1251
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00001252int32_t RTCPSender::BuildNACK(uint8_t* rtcpbuffer,
1253 int& pos,
1254 int32_t nackSize,
1255 const uint16_t* nackList,
1256 std::string* nackString) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001257 // sanity
1258 if(pos + 16 >= IP_PACKET_SIZE)
1259 {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +00001260 LOG(LS_WARNING) << "Failed to build NACK.";
niklase@google.com470e71d2011-07-07 08:21:25 +00001261 return -2;
1262 }
1263
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001264 // int size, uint16_t* nackList
niklase@google.com470e71d2011-07-07 08:21:25 +00001265 // add nack list
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001266 uint8_t FMT = 1;
1267 rtcpbuffer[pos++]=(uint8_t)0x80 + FMT;
1268 rtcpbuffer[pos++]=(uint8_t)205;
niklase@google.com470e71d2011-07-07 08:21:25 +00001269
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001270 rtcpbuffer[pos++]=(uint8_t) 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001271 int nackSizePos = pos;
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001272 rtcpbuffer[pos++]=(uint8_t)(3); //setting it to one kNACK signal as default
niklase@google.com470e71d2011-07-07 08:21:25 +00001273
1274 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001275 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001276 pos += 4;
1277
1278 // Add the remote SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001279 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001280 pos += 4;
1281
andresp@webrtc.org523f9372013-04-11 11:30:39 +00001282 // Build NACK bitmasks and write them to the RTCP message.
1283 // The nack list should be sorted and not contain duplicates if one
1284 // wants to build the smallest rtcp nack packet.
1285 int numOfNackFields = 0;
1286 int maxNackFields = std::min<int>(kRtcpMaxNackFields,
1287 (IP_PACKET_SIZE - pos) / 4);
1288 int i = 0;
1289 while (i < nackSize && numOfNackFields < maxNackFields) {
andresp@webrtc.org523f9372013-04-11 11:30:39 +00001290 uint16_t nack = nackList[i++];
1291 uint16_t bitmask = 0;
1292 while (i < nackSize) {
1293 int shift = static_cast<uint16_t>(nackList[i] - nack) - 1;
1294 if (shift >= 0 && shift <= 15) {
andresp@webrtc.org523f9372013-04-11 11:30:39 +00001295 bitmask |= (1 << shift);
1296 ++i;
1297 } else {
1298 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00001299 }
andresp@webrtc.org523f9372013-04-11 11:30:39 +00001300 }
1301 // Write the sequence number and the bitmask to the packet.
1302 assert(pos + 4 < IP_PACKET_SIZE);
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001303 RtpUtility::AssignUWord16ToBuffer(rtcpbuffer + pos, nack);
andresp@webrtc.org523f9372013-04-11 11:30:39 +00001304 pos += 2;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001305 RtpUtility::AssignUWord16ToBuffer(rtcpbuffer + pos, bitmask);
andresp@webrtc.org523f9372013-04-11 11:30:39 +00001306 pos += 2;
1307 numOfNackFields++;
niklase@google.com470e71d2011-07-07 08:21:25 +00001308 }
andresp@webrtc.org523f9372013-04-11 11:30:39 +00001309 rtcpbuffer[nackSizePos] = static_cast<uint8_t>(2 + numOfNackFields);
asapersson@webrtc.org2dd31342014-10-29 12:42:30 +00001310
1311 if (i != nackSize) {
1312 LOG(LS_WARNING) << "Nack list too large for one packet.";
1313 }
1314
1315 // Report stats.
1316 NACKStringBuilder stringBuilder;
1317 for (int idx = 0; idx < i; ++idx) {
1318 stringBuilder.PushNACK(nackList[idx]);
1319 nack_stats_.ReportRequest(nackList[idx]);
1320 }
edjee@google.com79b02892013-04-04 19:43:34 +00001321 *nackString = stringBuilder.GetResult();
asapersson@webrtc.org2dd31342014-10-29 12:42:30 +00001322 packet_type_counter_.nack_requests = nack_stats_.requests();
1323 packet_type_counter_.unique_nack_requests = nack_stats_.unique_requests();
niklase@google.com470e71d2011-07-07 08:21:25 +00001324 return 0;
1325}
1326
pbos@webrtc.org9334ac22014-11-24 08:25:50 +00001327int32_t RTCPSender::BuildBYE(uint8_t* rtcpbuffer, int& pos) {
1328 // sanity
1329 if (pos + 8 >= IP_PACKET_SIZE) {
1330 return -2;
1331 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001332
pbos@webrtc.org9334ac22014-11-24 08:25:50 +00001333 // Add a bye packet
1334 // Number of SSRC + CSRCs.
1335 rtcpbuffer[pos++] = (uint8_t)0x80 + 1 + csrcs_.size();
1336 rtcpbuffer[pos++] = (uint8_t)203;
niklase@google.com470e71d2011-07-07 08:21:25 +00001337
pbos@webrtc.org9334ac22014-11-24 08:25:50 +00001338 // length
1339 rtcpbuffer[pos++] = (uint8_t)0;
1340 rtcpbuffer[pos++] = (uint8_t)(1 + csrcs_.size());
niklase@google.com470e71d2011-07-07 08:21:25 +00001341
pbos@webrtc.org9334ac22014-11-24 08:25:50 +00001342 // Add our own SSRC
1343 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
1344 pos += 4;
niklase@google.com470e71d2011-07-07 08:21:25 +00001345
pbos@webrtc.org9334ac22014-11-24 08:25:50 +00001346 // add CSRCs
1347 for (size_t i = 0; i < csrcs_.size(); i++) {
1348 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, csrcs_[i]);
1349 pos += 4;
1350 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001351
pbos@webrtc.org9334ac22014-11-24 08:25:50 +00001352 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001353}
1354
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001355int32_t RTCPSender::BuildReceiverReferenceTime(uint8_t* buffer,
1356 int& pos,
1357 uint32_t ntp_sec,
1358 uint32_t ntp_frac) {
1359 const int kRrTimeBlockLength = 20;
1360 if (pos + kRrTimeBlockLength >= IP_PACKET_SIZE) {
1361 return -2;
1362 }
1363
1364 if (last_xr_rr_.size() >= RTCP_NUMBER_OF_SR) {
1365 last_xr_rr_.erase(last_xr_rr_.begin());
1366 }
1367 last_xr_rr_.insert(std::pair<uint32_t, int64_t>(
1368 RTCPUtility::MidNtp(ntp_sec, ntp_frac),
1369 Clock::NtpToMs(ntp_sec, ntp_frac)));
1370
1371 // Add XR header.
1372 buffer[pos++] = 0x80;
1373 buffer[pos++] = 207;
1374 buffer[pos++] = 0; // XR packet length.
1375 buffer[pos++] = 4; // XR packet length.
1376
1377 // Add our own SSRC.
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001378 RtpUtility::AssignUWord32ToBuffer(buffer + pos, _SSRC);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001379 pos += 4;
1380
1381 // 0 1 2 3
1382 // 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
1383 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1384 // | BT=4 | reserved | block length = 2 |
1385 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1386 // | NTP timestamp, most significant word |
1387 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1388 // | NTP timestamp, least significant word |
1389 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1390
1391 // Add Receiver Reference Time Report block.
1392 buffer[pos++] = 4; // BT.
1393 buffer[pos++] = 0; // Reserved.
1394 buffer[pos++] = 0; // Block length.
1395 buffer[pos++] = 2; // Block length.
1396
1397 // NTP timestamp.
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001398 RtpUtility::AssignUWord32ToBuffer(buffer + pos, ntp_sec);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001399 pos += 4;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001400 RtpUtility::AssignUWord32ToBuffer(buffer + pos, ntp_frac);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001401 pos += 4;
1402
1403 return 0;
1404}
1405
1406int32_t RTCPSender::BuildDlrr(uint8_t* buffer,
1407 int& pos,
1408 const RtcpReceiveTimeInfo& info) {
1409 const int kDlrrBlockLength = 24;
1410 if (pos + kDlrrBlockLength >= IP_PACKET_SIZE) {
1411 return -2;
1412 }
1413
1414 // Add XR header.
1415 buffer[pos++] = 0x80;
1416 buffer[pos++] = 207;
1417 buffer[pos++] = 0; // XR packet length.
1418 buffer[pos++] = 5; // XR packet length.
1419
1420 // Add our own SSRC.
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001421 RtpUtility::AssignUWord32ToBuffer(buffer + pos, _SSRC);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001422 pos += 4;
1423
1424 // 0 1 2 3
1425 // 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
1426 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1427 // | BT=5 | reserved | block length |
1428 // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
1429 // | SSRC_1 (SSRC of first receiver) | sub-
1430 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
1431 // | last RR (LRR) | 1
1432 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1433 // | delay since last RR (DLRR) |
1434 // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
1435 // | SSRC_2 (SSRC of second receiver) | sub-
1436 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
1437 // : ... : 2
1438
1439 // Add DLRR sub block.
1440 buffer[pos++] = 5; // BT.
1441 buffer[pos++] = 0; // Reserved.
1442 buffer[pos++] = 0; // Block length.
1443 buffer[pos++] = 3; // Block length.
1444
1445 // NTP timestamp.
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001446 RtpUtility::AssignUWord32ToBuffer(buffer + pos, info.sourceSSRC);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001447 pos += 4;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001448 RtpUtility::AssignUWord32ToBuffer(buffer + pos, info.lastRR);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001449 pos += 4;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001450 RtpUtility::AssignUWord32ToBuffer(buffer + pos, info.delaySinceLastRR);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001451 pos += 4;
1452
1453 return 0;
1454}
1455
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001456int32_t
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001457RTCPSender::BuildVoIPMetric(uint8_t* rtcpbuffer, int& pos)
niklase@google.com470e71d2011-07-07 08:21:25 +00001458{
1459 // sanity
1460 if(pos + 44 >= IP_PACKET_SIZE)
1461 {
1462 return -2;
1463 }
1464
1465 // Add XR header
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001466 rtcpbuffer[pos++]=(uint8_t)0x80;
1467 rtcpbuffer[pos++]=(uint8_t)207;
niklase@google.com470e71d2011-07-07 08:21:25 +00001468
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001469 uint32_t XRLengthPos = pos;
niklase@google.com470e71d2011-07-07 08:21:25 +00001470
1471 // handle length later on
1472 pos++;
1473 pos++;
1474
1475 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001476 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001477 pos += 4;
1478
1479 // Add a VoIP metrics block
1480 rtcpbuffer[pos++]=7;
1481 rtcpbuffer[pos++]=0;
1482 rtcpbuffer[pos++]=0;
1483 rtcpbuffer[pos++]=8;
1484
1485 // Add the remote SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001486 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001487 pos += 4;
1488
1489 rtcpbuffer[pos++] = _xrVoIPMetric.lossRate;
1490 rtcpbuffer[pos++] = _xrVoIPMetric.discardRate;
1491 rtcpbuffer[pos++] = _xrVoIPMetric.burstDensity;
1492 rtcpbuffer[pos++] = _xrVoIPMetric.gapDensity;
1493
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001494 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.burstDuration >> 8);
1495 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.burstDuration);
1496 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.gapDuration >> 8);
1497 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.gapDuration);
niklase@google.com470e71d2011-07-07 08:21:25 +00001498
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001499 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.roundTripDelay >> 8);
1500 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.roundTripDelay);
1501 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.endSystemDelay >> 8);
1502 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.endSystemDelay);
niklase@google.com470e71d2011-07-07 08:21:25 +00001503
1504 rtcpbuffer[pos++] = _xrVoIPMetric.signalLevel;
1505 rtcpbuffer[pos++] = _xrVoIPMetric.noiseLevel;
1506 rtcpbuffer[pos++] = _xrVoIPMetric.RERL;
1507 rtcpbuffer[pos++] = _xrVoIPMetric.Gmin;
1508
1509 rtcpbuffer[pos++] = _xrVoIPMetric.Rfactor;
1510 rtcpbuffer[pos++] = _xrVoIPMetric.extRfactor;
1511 rtcpbuffer[pos++] = _xrVoIPMetric.MOSLQ;
1512 rtcpbuffer[pos++] = _xrVoIPMetric.MOSCQ;
1513
1514 rtcpbuffer[pos++] = _xrVoIPMetric.RXconfig;
1515 rtcpbuffer[pos++] = 0; // reserved
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001516 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.JBnominal >> 8);
1517 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.JBnominal);
niklase@google.com470e71d2011-07-07 08:21:25 +00001518
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001519 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.JBmax >> 8);
1520 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.JBmax);
1521 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.JBabsMax >> 8);
1522 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.JBabsMax);
niklase@google.com470e71d2011-07-07 08:21:25 +00001523
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001524 rtcpbuffer[XRLengthPos]=(uint8_t)(0);
1525 rtcpbuffer[XRLengthPos+1]=(uint8_t)(10);
niklase@google.com470e71d2011-07-07 08:21:25 +00001526 return 0;
1527}
1528
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001529int32_t RTCPSender::SendRTCP(const FeedbackState& feedback_state,
1530 uint32_t packetTypeFlags,
1531 int32_t nackSize,
1532 const uint16_t* nackList,
1533 bool repeat,
1534 uint64_t pictureID) {
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001535 {
1536 CriticalSectionScoped lock(_criticalSectionRTCPSender);
1537 if(_method == kRtcpOff)
niklase@google.com470e71d2011-07-07 08:21:25 +00001538 {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +00001539 LOG(LS_WARNING) << "Can't send rtcp if it is disabled.";
pwestin@webrtc.org8edb39d2011-12-22 07:40:33 +00001540 return -1;
1541 }
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001542 }
1543 uint8_t rtcp_buffer[IP_PACKET_SIZE];
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001544 int rtcp_length = PrepareRTCP(feedback_state,
1545 packetTypeFlags,
1546 nackSize,
1547 nackList,
1548 repeat,
1549 pictureID,
1550 rtcp_buffer,
1551 IP_PACKET_SIZE);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001552 if (rtcp_length < 0) {
1553 return -1;
1554 }
1555 // Sanity don't send empty packets.
1556 if (rtcp_length == 0)
1557 {
1558 return -1;
1559 }
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001560 return SendToNetwork(rtcp_buffer, static_cast<size_t>(rtcp_length));
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001561}
1562
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001563int RTCPSender::PrepareRTCP(const FeedbackState& feedback_state,
1564 uint32_t packetTypeFlags,
1565 int32_t nackSize,
1566 const uint16_t* nackList,
1567 bool repeat,
1568 uint64_t pictureID,
1569 uint8_t* rtcp_buffer,
1570 int buffer_size) {
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001571 uint32_t rtcpPacketTypeFlags = packetTypeFlags;
1572 // Collect the received information.
1573 uint32_t NTPsec = 0;
1574 uint32_t NTPfrac = 0;
1575 uint32_t jitterTransmissionOffset = 0;
1576 int position = 0;
1577
1578 CriticalSectionScoped lock(_criticalSectionRTCPSender);
1579
asapersson@webrtc.orgd08d3892014-12-16 12:03:11 +00001580 if (packet_type_counter_.first_packet_time_ms == -1) {
1581 packet_type_counter_.first_packet_time_ms = _clock->TimeInMilliseconds();
1582 }
1583
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001584 if(_TMMBR ) // Attach TMMBR to send and receive reports.
1585 {
1586 rtcpPacketTypeFlags |= kRtcpTmmbr;
1587 }
1588 if(_appSend)
1589 {
1590 rtcpPacketTypeFlags |= kRtcpApp;
1591 _appSend = false;
1592 }
1593 if(_REMB && _sendREMB)
1594 {
1595 // Always attach REMB to SR if that is configured. Note that REMB is
1596 // only sent on one of the RTP modules in the REMB group.
1597 rtcpPacketTypeFlags |= kRtcpRemb;
1598 }
1599 if(_xrSendVoIPMetric)
1600 {
1601 rtcpPacketTypeFlags |= kRtcpXrVoipMetric;
1602 _xrSendVoIPMetric = false;
1603 }
1604 if(_sendTMMBN) // Set when having received a TMMBR.
1605 {
1606 rtcpPacketTypeFlags |= kRtcpTmmbn;
1607 _sendTMMBN = false;
1608 }
asapersson@webrtc.orgefaeda02014-01-20 08:34:49 +00001609 if (rtcpPacketTypeFlags & kRtcpReport)
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001610 {
asapersson@webrtc.orgefaeda02014-01-20 08:34:49 +00001611 if (xrSendReceiverReferenceTimeEnabled_ && !_sending)
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001612 {
1613 rtcpPacketTypeFlags |= kRtcpXrReceiverReferenceTime;
1614 }
1615 if (feedback_state.has_last_xr_rr)
1616 {
1617 rtcpPacketTypeFlags |= kRtcpXrDlrrReportBlock;
1618 }
1619 }
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001620 if(_method == kRtcpCompound)
1621 {
1622 if(_sending)
1623 {
1624 rtcpPacketTypeFlags |= kRtcpSr;
1625 } else
1626 {
1627 rtcpPacketTypeFlags |= kRtcpRr;
1628 }
1629 } else if(_method == kRtcpNonCompound)
1630 {
1631 if(rtcpPacketTypeFlags & kRtcpReport)
1632 {
1633 if(_sending)
1634 {
1635 rtcpPacketTypeFlags |= kRtcpSr;
1636 } else
1637 {
1638 rtcpPacketTypeFlags |= kRtcpRr;
1639 }
1640 }
1641 }
1642 if( rtcpPacketTypeFlags & kRtcpRr ||
1643 rtcpPacketTypeFlags & kRtcpSr)
1644 {
1645 // generate next time to send a RTCP report
1646 // seeded from RTP constructor
1647 int32_t random = rand() % 1000;
1648 int32_t timeToNext = RTCP_INTERVAL_AUDIO_MS;
1649
1650 if(_audio)
1651 {
1652 timeToNext = (RTCP_INTERVAL_AUDIO_MS/2) +
1653 (RTCP_INTERVAL_AUDIO_MS*random/1000);
1654 }else
1655 {
1656 uint32_t minIntervalMs = RTCP_INTERVAL_AUDIO_MS;
1657 if(_sending)
1658 {
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001659 // Calculate bandwidth for video; 360 / send bandwidth in kbit/s.
1660 uint32_t send_bitrate_kbit = feedback_state.send_bitrate / 1000;
1661 if (send_bitrate_kbit != 0)
1662 minIntervalMs = 360000 / send_bitrate_kbit;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001663 }
1664 if(minIntervalMs > RTCP_INTERVAL_VIDEO_MS)
1665 {
1666 minIntervalMs = RTCP_INTERVAL_VIDEO_MS;
1667 }
1668 timeToNext = (minIntervalMs/2) + (minIntervalMs*random/1000);
1669 }
1670 _nextTimeToSendRTCP = _clock->TimeInMilliseconds() + timeToNext;
1671 }
1672
1673 // If the data does not fit in the packet we fill it as much as possible.
1674 int32_t buildVal = 0;
1675
1676 // We need to send our NTP even if we haven't received any reports.
1677 _clock->CurrentNtp(NTPsec, NTPfrac);
1678 if (ShouldSendReportBlocks(rtcpPacketTypeFlags)) {
1679 StatisticianMap statisticians =
1680 receive_statistics_->GetActiveStatisticians();
1681 if (!statisticians.empty()) {
1682 StatisticianMap::const_iterator it;
1683 int i;
1684 for (it = statisticians.begin(), i = 0; it != statisticians.end();
1685 ++it, ++i) {
1686 RTCPReportBlock report_block;
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001687 if (PrepareReport(
1688 feedback_state, it->second, &report_block, &NTPsec, &NTPfrac))
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001689 AddReportBlock(it->first, &internal_report_blocks_, &report_block);
1690 }
1691 if (_IJ && !statisticians.empty()) {
1692 rtcpPacketTypeFlags |= kRtcpTransmissionTimeOffset;
1693 }
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001694 }
1695 }
1696
1697 if(rtcpPacketTypeFlags & kRtcpSr)
1698 {
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001699 buildVal = BuildSR(feedback_state, rtcp_buffer, position, NTPsec, NTPfrac);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001700 if (buildVal == -1) {
1701 return -1;
1702 } else if (buildVal == -2) {
1703 return position;
1704 }
1705 buildVal = BuildSDEC(rtcp_buffer, position);
1706 if (buildVal == -1) {
1707 return -1;
1708 } else if (buildVal == -2) {
1709 return position;
1710 }
1711 }else if(rtcpPacketTypeFlags & kRtcpRr)
1712 {
1713 buildVal = BuildRR(rtcp_buffer, position, NTPsec, NTPfrac);
1714 if (buildVal == -1) {
1715 return -1;
1716 } else if (buildVal == -2) {
1717 return position;
1718 }
1719 // only of set
1720 if(_CNAME[0] != 0)
1721 {
1722 buildVal = BuildSDEC(rtcp_buffer, position);
1723 if (buildVal == -1) {
1724 return -1;
1725 }
1726 }
1727 }
1728 if(rtcpPacketTypeFlags & kRtcpTransmissionTimeOffset)
1729 {
1730 // If present, this RTCP packet must be placed after a
1731 // receiver report.
1732 buildVal = BuildExtendedJitterReport(rtcp_buffer,
1733 position,
1734 jitterTransmissionOffset);
1735 if (buildVal == -1) {
1736 return -1;
1737 } else if (buildVal == -2) {
1738 return position;
1739 }
1740 }
1741 if(rtcpPacketTypeFlags & kRtcpPli)
1742 {
1743 buildVal = BuildPLI(rtcp_buffer, position);
1744 if (buildVal == -1) {
1745 return -1;
1746 } else if (buildVal == -2) {
1747 return position;
1748 }
sprang@webrtc.org0200f702015-02-16 12:06:00 +00001749 TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
1750 "RTCPSender::PLI");
asapersson@webrtc.org8098e072014-02-19 11:59:02 +00001751 ++packet_type_counter_.pli_packets;
sprang@webrtc.org0200f702015-02-16 12:06:00 +00001752 TRACE_COUNTER_ID1(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
1753 "RTCP_PLICount", _SSRC,
asapersson@webrtc.org8098e072014-02-19 11:59:02 +00001754 packet_type_counter_.pli_packets);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001755 }
1756 if(rtcpPacketTypeFlags & kRtcpFir)
1757 {
1758 buildVal = BuildFIR(rtcp_buffer, position, repeat);
1759 if (buildVal == -1) {
1760 return -1;
1761 } else if (buildVal == -2) {
1762 return position;
1763 }
sprang@webrtc.org0200f702015-02-16 12:06:00 +00001764 TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
1765 "RTCPSender::FIR");
asapersson@webrtc.org8098e072014-02-19 11:59:02 +00001766 ++packet_type_counter_.fir_packets;
sprang@webrtc.org0200f702015-02-16 12:06:00 +00001767 TRACE_COUNTER_ID1(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
1768 "RTCP_FIRCount", _SSRC,
asapersson@webrtc.org8098e072014-02-19 11:59:02 +00001769 packet_type_counter_.fir_packets);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001770 }
1771 if(rtcpPacketTypeFlags & kRtcpSli)
1772 {
1773 buildVal = BuildSLI(rtcp_buffer, position, (uint8_t)pictureID);
1774 if (buildVal == -1) {
1775 return -1;
1776 } else if (buildVal == -2) {
1777 return position;
1778 }
1779 }
1780 if(rtcpPacketTypeFlags & kRtcpRpsi)
1781 {
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001782 const int8_t payloadType = feedback_state.send_payload_type;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001783 if (payloadType == -1) {
1784 return -1;
1785 }
1786 buildVal = BuildRPSI(rtcp_buffer, position, pictureID,
1787 (uint8_t)payloadType);
1788 if (buildVal == -1) {
1789 return -1;
1790 } else if (buildVal == -2) {
1791 return position;
1792 }
1793 }
1794 if(rtcpPacketTypeFlags & kRtcpRemb)
1795 {
1796 buildVal = BuildREMB(rtcp_buffer, position);
1797 if (buildVal == -1) {
1798 return -1;
1799 } else if (buildVal == -2) {
1800 return position;
1801 }
sprang@webrtc.org0200f702015-02-16 12:06:00 +00001802 TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
1803 "RTCPSender::REMB");
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001804 }
1805 if(rtcpPacketTypeFlags & kRtcpBye)
1806 {
1807 buildVal = BuildBYE(rtcp_buffer, position);
1808 if (buildVal == -1) {
1809 return -1;
1810 } else if (buildVal == -2) {
1811 return position;
1812 }
1813 }
1814 if(rtcpPacketTypeFlags & kRtcpApp)
1815 {
1816 buildVal = BuildAPP(rtcp_buffer, position);
1817 if (buildVal == -1) {
1818 return -1;
1819 } else if (buildVal == -2) {
1820 return position;
1821 }
1822 }
1823 if(rtcpPacketTypeFlags & kRtcpTmmbr)
1824 {
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001825 buildVal = BuildTMMBR(feedback_state.module, rtcp_buffer, position);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001826 if (buildVal == -1) {
1827 return -1;
1828 } else if (buildVal == -2) {
1829 return position;
1830 }
1831 }
1832 if(rtcpPacketTypeFlags & kRtcpTmmbn)
1833 {
1834 buildVal = BuildTMMBN(rtcp_buffer, position);
1835 if (buildVal == -1) {
1836 return -1;
1837 } else if (buildVal == -2) {
1838 return position;
1839 }
1840 }
1841 if(rtcpPacketTypeFlags & kRtcpNack)
1842 {
1843 std::string nackString;
1844 buildVal = BuildNACK(rtcp_buffer, position, nackSize, nackList,
1845 &nackString);
1846 if (buildVal == -1) {
1847 return -1;
1848 } else if (buildVal == -2) {
1849 return position;
1850 }
sprang@webrtc.org0200f702015-02-16 12:06:00 +00001851 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
1852 "RTCPSender::NACK", "nacks",
1853 TRACE_STR_COPY(nackString.c_str()));
asapersson@webrtc.org8098e072014-02-19 11:59:02 +00001854 ++packet_type_counter_.nack_packets;
sprang@webrtc.org0200f702015-02-16 12:06:00 +00001855 TRACE_COUNTER_ID1(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
1856 "RTCP_NACKCount", _SSRC,
asapersson@webrtc.org8098e072014-02-19 11:59:02 +00001857 packet_type_counter_.nack_packets);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001858 }
1859 if(rtcpPacketTypeFlags & kRtcpXrVoipMetric)
1860 {
1861 buildVal = BuildVoIPMetric(rtcp_buffer, position);
1862 if (buildVal == -1) {
1863 return -1;
1864 } else if (buildVal == -2) {
1865 return position;
1866 }
1867 }
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001868 if (rtcpPacketTypeFlags & kRtcpXrReceiverReferenceTime)
1869 {
1870 buildVal = BuildReceiverReferenceTime(rtcp_buffer,
1871 position,
1872 NTPsec,
1873 NTPfrac);
1874 if (buildVal == -1) {
1875 return -1;
1876 } else if (buildVal == -2) {
1877 return position;
1878 }
1879 }
1880 if (rtcpPacketTypeFlags & kRtcpXrDlrrReportBlock)
1881 {
1882 buildVal = BuildDlrr(rtcp_buffer, position, feedback_state.last_xr_rr);
1883 if (buildVal == -1) {
1884 return -1;
1885 } else if (buildVal == -2) {
1886 return position;
1887 }
1888 }
pbos@webrtc.org1d0fa5d2015-02-19 12:47:00 +00001889
1890 if (packet_type_counter_observer_ != NULL) {
1891 packet_type_counter_observer_->RtcpPacketTypesCounterUpdated(
1892 _remoteSSRC, packet_type_counter_);
1893 }
1894
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001895 return position;
1896}
1897
1898bool RTCPSender::ShouldSendReportBlocks(uint32_t rtcp_packet_type) const {
1899 return Status() == kRtcpCompound ||
1900 (rtcp_packet_type & kRtcpReport) ||
1901 (rtcp_packet_type & kRtcpSr) ||
1902 (rtcp_packet_type & kRtcpRr);
1903}
1904
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001905bool RTCPSender::PrepareReport(const FeedbackState& feedback_state,
1906 StreamStatistician* statistician,
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001907 RTCPReportBlock* report_block,
1908 uint32_t* ntp_secs, uint32_t* ntp_frac) {
1909 // Do we have receive statistics to send?
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00001910 RtcpStatistics stats;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001911 if (!statistician->GetStatistics(&stats, true))
1912 return false;
1913 report_block->fractionLost = stats.fraction_lost;
1914 report_block->cumulativeLost = stats.cumulative_lost;
1915 report_block->extendedHighSeqNum =
1916 stats.extended_max_sequence_number;
1917 report_block->jitter = stats.jitter;
1918
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001919 // get our NTP as late as possible to avoid a race
1920 _clock->CurrentNtp(*ntp_secs, *ntp_frac);
1921
1922 // Delay since last received report
1923 uint32_t delaySinceLastReceivedSR = 0;
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001924 if ((feedback_state.last_rr_ntp_secs != 0) ||
1925 (feedback_state.last_rr_ntp_frac != 0)) {
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001926 // get the 16 lowest bits of seconds and the 16 higest bits of fractions
1927 uint32_t now=*ntp_secs&0x0000FFFF;
1928 now <<=16;
1929 now += (*ntp_frac&0xffff0000)>>16;
1930
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001931 uint32_t receiveTime = feedback_state.last_rr_ntp_secs&0x0000FFFF;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001932 receiveTime <<=16;
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001933 receiveTime += (feedback_state.last_rr_ntp_frac&0xffff0000)>>16;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001934
1935 delaySinceLastReceivedSR = now-receiveTime;
1936 }
1937 report_block->delaySinceLastSR = delaySinceLastReceivedSR;
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001938 report_block->lastSR = feedback_state.remote_sr;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001939 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00001940}
1941
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00001942int32_t RTCPSender::SendToNetwork(const uint8_t* dataBuffer, size_t length) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001943 CriticalSectionScoped lock(_criticalSectionTransport);
1944 if(_cbTransport)
1945 {
1946 if(_cbTransport->SendRTCPPacket(_id, dataBuffer, length) > 0)
1947 {
1948 return 0;
1949 }
1950 }
1951 return -1;
1952}
1953
pbos@webrtc.org9334ac22014-11-24 08:25:50 +00001954void RTCPSender::SetCsrcs(const std::vector<uint32_t>& csrcs) {
1955 assert(csrcs.size() <= kRtpCsrcSize);
1956 CriticalSectionScoped lock(_criticalSectionRTCPSender);
1957 csrcs_ = csrcs;
niklase@google.com470e71d2011-07-07 08:21:25 +00001958}
1959
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00001960int32_t RTCPSender::SetApplicationSpecificData(uint8_t subType,
1961 uint32_t name,
1962 const uint8_t* data,
1963 uint16_t length) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001964 if(length %4 != 0)
1965 {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +00001966 LOG(LS_ERROR) << "Failed to SetApplicationSpecificData.";
niklase@google.com470e71d2011-07-07 08:21:25 +00001967 return -1;
1968 }
1969 CriticalSectionScoped lock(_criticalSectionRTCPSender);
1970
1971 if(_appData)
1972 {
1973 delete [] _appData;
1974 }
1975
1976 _appSend = true;
1977 _appSubType = subType;
1978 _appName = name;
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001979 _appData = new uint8_t[length];
niklase@google.com470e71d2011-07-07 08:21:25 +00001980 _appLength = length;
1981 memcpy(_appData, data, length);
1982 return 0;
1983}
1984
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001985int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001986RTCPSender::SetRTCPVoIPMetrics(const RTCPVoIPMetric* VoIPMetric)
1987{
1988 CriticalSectionScoped lock(_criticalSectionRTCPSender);
1989 memcpy(&_xrVoIPMetric, VoIPMetric, sizeof(RTCPVoIPMetric));
1990
1991 _xrSendVoIPMetric = true;
1992 return 0;
1993}
1994
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001995void RTCPSender::SendRtcpXrReceiverReferenceTime(bool enable) {
1996 CriticalSectionScoped lock(_criticalSectionRTCPSender);
1997 xrSendReceiverReferenceTimeEnabled_ = enable;
1998}
1999
asapersson@webrtc.org8d02f5d2013-11-21 08:57:04 +00002000bool RTCPSender::RtcpXrReceiverReferenceTime() const {
2001 CriticalSectionScoped lock(_criticalSectionRTCPSender);
2002 return xrSendReceiverReferenceTimeEnabled_;
2003}
2004
niklase@google.com470e71d2011-07-07 08:21:25 +00002005// called under critsect _criticalSectionRTCPSender
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00002006int32_t RTCPSender::WriteAllReportBlocksToBuffer(uint8_t* rtcpbuffer,
2007 int pos,
2008 uint8_t& numberOfReportBlocks,
2009 uint32_t NTPsec,
2010 uint32_t NTPfrac) {
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002011 numberOfReportBlocks = external_report_blocks_.size();
2012 numberOfReportBlocks += internal_report_blocks_.size();
2013 if ((pos + numberOfReportBlocks * 24) >= IP_PACKET_SIZE) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +00002014 LOG(LS_WARNING) << "Can't fit all report blocks.";
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002015 return -1;
2016 }
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002017 pos = WriteReportBlocksToBuffer(rtcpbuffer, pos, internal_report_blocks_);
2018 while (!internal_report_blocks_.empty()) {
2019 delete internal_report_blocks_.begin()->second;
2020 internal_report_blocks_.erase(internal_report_blocks_.begin());
2021 }
2022 pos = WriteReportBlocksToBuffer(rtcpbuffer, pos, external_report_blocks_);
2023 return pos;
2024}
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002025
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002026int32_t RTCPSender::WriteReportBlocksToBuffer(
2027 uint8_t* rtcpbuffer,
2028 int32_t position,
2029 const std::map<uint32_t, RTCPReportBlock*>& report_blocks) {
2030 std::map<uint32_t, RTCPReportBlock*>::const_iterator it =
2031 report_blocks.begin();
2032 for (; it != report_blocks.end(); it++) {
pbos@webrtc.org2f446732013-04-08 11:08:41 +00002033 uint32_t remoteSSRC = it->first;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002034 RTCPReportBlock* reportBlock = it->second;
2035 if (reportBlock) {
2036 // Remote SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00002037 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + position, remoteSSRC);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002038 position += 4;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002039
2040 // fraction lost
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002041 rtcpbuffer[position++] = reportBlock->fractionLost;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002042
2043 // cumulative loss
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00002044 RtpUtility::AssignUWord24ToBuffer(rtcpbuffer + position,
2045 reportBlock->cumulativeLost);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002046 position += 3;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002047
2048 // extended highest seq_no, contain the highest sequence number received
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00002049 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + position,
2050 reportBlock->extendedHighSeqNum);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002051 position += 4;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002052
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002053 // Jitter
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00002054 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + position,
2055 reportBlock->jitter);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002056 position += 4;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002057
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00002058 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + position,
2059 reportBlock->lastSR);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002060 position += 4;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002061
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00002062 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + position,
2063 reportBlock->delaySinceLastSR);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002064 position += 4;
niklase@google.com470e71d2011-07-07 08:21:25 +00002065 }
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002066 }
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002067 return position;
niklase@google.com470e71d2011-07-07 08:21:25 +00002068}
2069
2070// no callbacks allowed inside this function
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00002071int32_t RTCPSender::SetTMMBN(const TMMBRSet* boundingSet,
2072 uint32_t maxBitrateKbit) {
niklase@google.com470e71d2011-07-07 08:21:25 +00002073 CriticalSectionScoped lock(_criticalSectionRTCPSender);
2074
2075 if (0 == _tmmbrHelp.SetTMMBRBoundingSetToSend(boundingSet, maxBitrateKbit))
2076 {
2077 _sendTMMBN = true;
2078 return 0;
2079 }
2080 return -1;
2081}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00002082} // namespace webrtc