blob: c896d14ec61754cb56d32feb3ccf60a87f582146 [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(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000111
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000112 _cameraDelayMS(0),
stefan@webrtc.org7da34592013-04-09 14:56:29 +0000113
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000114 _lastSendReport(),
115 _lastRTCPTime(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000116
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000117 last_xr_rr_(),
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000118
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000119 _sequenceNumberFIR(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000120
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000121 _rembBitrate(0),
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000122
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000123 _tmmbrHelp(),
124 _tmmbr_Send(0),
125 _packetOH_Send(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000126
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000127 _appSend(false),
128 _appSubType(0),
129 _appName(),
130 _appData(NULL),
131 _appLength(0),
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000132
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000133 xrSendReceiverReferenceTimeEnabled_(false),
134 _xrSendVoIPMetric(false),
135 _xrVoIPMetric() {
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.orgd16e8392014-12-19 13:49:55 +0000305int32_t RTCPSender::SetCameraDelay(int32_t delayMS) {
stefan@webrtc.org7da34592013-04-09 14:56:29 +0000306 CriticalSectionScoped lock(_criticalSectionRTCPSender);
307 if(delayMS > 1000 || delayMS < -1000)
308 {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000309 LOG(LS_WARNING) << "Delay can't be larger than 1 second: "
310 << delayMS << " ms";
stefan@webrtc.org7da34592013-04-09 14:56:29 +0000311 return -1;
312 }
313 _cameraDelayMS = delayMS;
314 return 0;
315}
316
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000317int32_t RTCPSender::SetCNAME(const char cName[RTCP_CNAME_SIZE]) {
tommi@webrtc.orga990e122012-04-26 15:28:22 +0000318 if (!cName)
319 return -1;
320
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000321 CriticalSectionScoped lock(_criticalSectionRTCPSender);
322 _CNAME[RTCP_CNAME_SIZE - 1] = 0;
323 strncpy(_CNAME, cName, RTCP_CNAME_SIZE - 1);
324 return 0;
325}
326
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000327int32_t RTCPSender::AddMixedCNAME(uint32_t SSRC,
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000328 const char cName[RTCP_CNAME_SIZE]) {
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000329 assert(cName);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000330 CriticalSectionScoped lock(_criticalSectionRTCPSender);
331 if (_csrcCNAMEs.size() >= kRtpCsrcSize) {
332 return -1;
333 }
334 RTCPCnameInformation* ptr = new RTCPCnameInformation();
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000335 ptr->name[RTCP_CNAME_SIZE - 1] = 0;
336 strncpy(ptr->name, cName, RTCP_CNAME_SIZE - 1);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000337 _csrcCNAMEs[SSRC] = ptr;
338 return 0;
339}
340
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000341int32_t RTCPSender::RemoveMixedCNAME(uint32_t SSRC) {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000342 CriticalSectionScoped lock(_criticalSectionRTCPSender);
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000343 std::map<uint32_t, RTCPCnameInformation*>::iterator it =
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000344 _csrcCNAMEs.find(SSRC);
345
346 if (it == _csrcCNAMEs.end()) {
347 return -1;
348 }
349 delete it->second;
350 _csrcCNAMEs.erase(it);
351 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000352}
353
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000354bool RTCPSender::TimeToSendRTCPReport(bool sendKeyframeBeforeRTP) const {
niklase@google.com470e71d2011-07-07 08:21:25 +0000355/*
356 For audio we use a fix 5 sec interval
357
358 For video we use 1 sec interval fo a BW smaller than 360 kbit/s,
stefan@webrtc.org9d4762e2014-03-24 17:13:00 +0000359 technicaly we break the max 5% RTCP BW for video below 10 kbit/s but
360 that should be extremely rare
niklase@google.com470e71d2011-07-07 08:21:25 +0000361
362
363From RFC 3550
364
365 MAX RTCP BW is 5% if the session BW
366 A send report is approximately 65 bytes inc CNAME
stefan@webrtc.org9d4762e2014-03-24 17:13:00 +0000367 A receiver report is approximately 28 bytes
niklase@google.com470e71d2011-07-07 08:21:25 +0000368
369 The RECOMMENDED value for the reduced minimum in seconds is 360
370 divided by the session bandwidth in kilobits/second. This minimum
371 is smaller than 5 seconds for bandwidths greater than 72 kb/s.
372
373 If the participant has not yet sent an RTCP packet (the variable
374 initial is true), the constant Tmin is set to 2.5 seconds, else it
375 is set to 5 seconds.
376
377 The interval between RTCP packets is varied randomly over the
378 range [0.5,1.5] times the calculated interval to avoid unintended
379 synchronization of all participants
380
381 if we send
382 If the participant is a sender (we_sent true), the constant C is
383 set to the average RTCP packet size (avg_rtcp_size) divided by 25%
384 of the RTCP bandwidth (rtcp_bw), and the constant n is set to the
385 number of senders.
386
387 if we receive only
388 If we_sent is not true, the constant C is set
389 to the average RTCP packet size divided by 75% of the RTCP
390 bandwidth. The constant n is set to the number of receivers
391 (members - senders). If the number of senders is greater than
392 25%, senders and receivers are treated together.
393
394 reconsideration NOT required for peer-to-peer
395 "timer reconsideration" is
396 employed. This algorithm implements a simple back-off mechanism
397 which causes users to hold back RTCP packet transmission if the
398 group sizes are increasing.
399
400 n = number of members
401 C = avg_size/(rtcpBW/4)
402
403 3. The deterministic calculated interval Td is set to max(Tmin, n*C).
404
405 4. The calculated interval T is set to a number uniformly distributed
406 between 0.5 and 1.5 times the deterministic calculated interval.
407
408 5. The resulting value of T is divided by e-3/2=1.21828 to compensate
409 for the fact that the timer reconsideration algorithm converges to
410 a value of the RTCP bandwidth below the intended average
411*/
412
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000413 int64_t now = _clock->TimeInMilliseconds();
xians@webrtc.org8738d272011-11-25 13:43:53 +0000414
415 CriticalSectionScoped lock(_criticalSectionRTCPSender);
416
niklase@google.com470e71d2011-07-07 08:21:25 +0000417 if(_method == kRtcpOff)
418 {
419 return false;
420 }
421
niklase@google.com470e71d2011-07-07 08:21:25 +0000422 if(!_audio && sendKeyframeBeforeRTP)
423 {
424 // for video key-frames we want to send the RTCP before the large key-frame
425 // if we have a 100 ms margin
426 now += RTCP_SEND_BEFORE_KEY_FRAME_MS;
427 }
428
stefan@webrtc.org9d4762e2014-03-24 17:13:00 +0000429 if(now >= _nextTimeToSendRTCP)
niklase@google.com470e71d2011-07-07 08:21:25 +0000430 {
431 return true;
432
433 } else if(now < 0x0000ffff && _nextTimeToSendRTCP > 0xffff0000) // 65 sec margin
434 {
435 // wrap
436 return true;
437 }
438 return false;
439}
440
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000441uint32_t
442RTCPSender::LastSendReport( uint32_t& lastRTCPTime)
niklase@google.com470e71d2011-07-07 08:21:25 +0000443{
444 CriticalSectionScoped lock(_criticalSectionRTCPSender);
445
446 lastRTCPTime = _lastRTCPTime[0];
447 return _lastSendReport[0];
448}
449
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000450uint32_t RTCPSender::SendTimeOfSendReport(uint32_t sendReport) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000451 CriticalSectionScoped lock(_criticalSectionRTCPSender);
452
453 // This is only saved when we are the sender
454 if((_lastSendReport[0] == 0) || (sendReport == 0))
455 {
456 return 0; // will be ignored
457 } else
458 {
459 for(int i = 0; i < RTCP_NUMBER_OF_SR; ++i)
460 {
461 if( _lastSendReport[i] == sendReport)
462 {
463 return _lastRTCPTime[i];
464 }
465 }
466 }
467 return 0;
468}
469
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +0000470bool RTCPSender::SendTimeOfXrRrReport(uint32_t mid_ntp,
471 int64_t* time_ms) const {
472 CriticalSectionScoped lock(_criticalSectionRTCPSender);
473
474 if (last_xr_rr_.empty()) {
475 return false;
476 }
477 std::map<uint32_t, int64_t>::const_iterator it = last_xr_rr_.find(mid_ntp);
478 if (it == last_xr_rr_.end()) {
479 return false;
480 }
481 *time_ms = it->second;
482 return true;
483}
484
asapersson@webrtc.org8098e072014-02-19 11:59:02 +0000485void RTCPSender::GetPacketTypeCounter(
486 RtcpPacketTypeCounter* packet_counter) const {
487 CriticalSectionScoped lock(_criticalSectionRTCPSender);
488 *packet_counter = packet_type_counter_;
489}
490
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000491int32_t RTCPSender::AddExternalReportBlock(
492 uint32_t SSRC,
493 const RTCPReportBlock* reportBlock) {
494 CriticalSectionScoped lock(_criticalSectionRTCPSender);
495 return AddReportBlock(SSRC, &external_report_blocks_, reportBlock);
496}
497
498int32_t RTCPSender::AddReportBlock(
499 uint32_t SSRC,
500 std::map<uint32_t, RTCPReportBlock*>* report_blocks,
501 const RTCPReportBlock* reportBlock) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000502 assert(reportBlock);
niklase@google.com470e71d2011-07-07 08:21:25 +0000503
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000504 if (report_blocks->size() >= RTCP_MAX_REPORT_BLOCKS) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000505 LOG(LS_WARNING) << "Too many report blocks.";
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000506 return -1;
507 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000508 std::map<uint32_t, RTCPReportBlock*>::iterator it =
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000509 report_blocks->find(SSRC);
510 if (it != report_blocks->end()) {
stefan@webrtc.org8d0cd072012-12-03 14:01:46 +0000511 delete it->second;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000512 report_blocks->erase(it);
stefan@webrtc.org8d0cd072012-12-03 14:01:46 +0000513 }
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000514 RTCPReportBlock* copyReportBlock = new RTCPReportBlock();
515 memcpy(copyReportBlock, reportBlock, sizeof(RTCPReportBlock));
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000516 (*report_blocks)[SSRC] = copyReportBlock;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000517 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000518}
519
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000520int32_t RTCPSender::RemoveExternalReportBlock(uint32_t SSRC) {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000521 CriticalSectionScoped lock(_criticalSectionRTCPSender);
niklase@google.com470e71d2011-07-07 08:21:25 +0000522
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000523 std::map<uint32_t, RTCPReportBlock*>::iterator it =
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000524 external_report_blocks_.find(SSRC);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000525
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000526 if (it == external_report_blocks_.end()) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000527 return -1;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000528 }
529 delete it->second;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000530 external_report_blocks_.erase(it);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000531 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000532}
533
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +0000534int32_t RTCPSender::BuildSR(const FeedbackState& feedback_state,
535 uint8_t* rtcpbuffer,
536 int& pos,
537 uint32_t NTPsec,
538 uint32_t NTPfrac)
niklase@google.com470e71d2011-07-07 08:21:25 +0000539{
540 // sanity
541 if(pos + 52 >= IP_PACKET_SIZE)
542 {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000543 LOG(LS_WARNING) << "Failed to build Sender Report.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000544 return -2;
545 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000546 uint32_t RTPtime;
niklase@google.com470e71d2011-07-07 08:21:25 +0000547
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000548 uint32_t posNumberOfReportBlocks = pos;
549 rtcpbuffer[pos++]=(uint8_t)0x80;
niklase@google.com470e71d2011-07-07 08:21:25 +0000550
551 // Sender report
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000552 rtcpbuffer[pos++]=(uint8_t)200;
niklase@google.com470e71d2011-07-07 08:21:25 +0000553
554 for(int i = (RTCP_NUMBER_OF_SR-2); i >= 0; i--)
555 {
556 // shift old
557 _lastSendReport[i+1] = _lastSendReport[i];
558 _lastRTCPTime[i+1] =_lastRTCPTime[i];
559 }
560
stefan@webrtc.orgb8e7f4c2013-04-12 11:56:23 +0000561 _lastRTCPTime[0] = Clock::NtpToMs(NTPsec, NTPfrac);
stefan@webrtc.org7c3523c2012-09-11 07:00:42 +0000562 _lastSendReport[0] = (NTPsec << 16) + (NTPfrac >> 16);
niklase@google.com470e71d2011-07-07 08:21:25 +0000563
stefan@webrtc.org7da34592013-04-09 14:56:29 +0000564 // The timestamp of this RTCP packet should be estimated as the timestamp of
565 // the frame being captured at this moment. We are calculating that
566 // timestamp as the last frame's timestamp + the time since the last frame
567 // was captured.
pbos@webrtc.org180e5162014-07-11 15:36:26 +0000568 RTPtime = start_timestamp_ + last_rtp_timestamp_ +
569 (_clock->TimeInMilliseconds() - last_frame_capture_time_ms_) *
570 (feedback_state.frequency_hz / 1000);
niklase@google.com470e71d2011-07-07 08:21:25 +0000571
572 // Add sender data
573 // Save for our length field
574 pos++;
575 pos++;
576
577 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000578 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000579 pos += 4;
580 // NTP
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000581 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, NTPsec);
niklase@google.com470e71d2011-07-07 08:21:25 +0000582 pos += 4;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000583 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, NTPfrac);
niklase@google.com470e71d2011-07-07 08:21:25 +0000584 pos += 4;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000585 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, RTPtime);
niklase@google.com470e71d2011-07-07 08:21:25 +0000586 pos += 4;
587
588 //sender's packet count
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000589 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos,
pbos@webrtc.org2f4b14e2014-07-15 15:25:39 +0000590 feedback_state.packets_sent);
niklase@google.com470e71d2011-07-07 08:21:25 +0000591 pos += 4;
592
593 //sender's octet count
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000594 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos,
pbos@webrtc.org2f4b14e2014-07-15 15:25:39 +0000595 feedback_state.media_bytes_sent);
niklase@google.com470e71d2011-07-07 08:21:25 +0000596 pos += 4;
597
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000598 uint8_t numberOfReportBlocks = 0;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000599 int32_t retVal = WriteAllReportBlocksToBuffer(rtcpbuffer, pos,
600 numberOfReportBlocks,
601 NTPsec, NTPfrac);
niklase@google.com470e71d2011-07-07 08:21:25 +0000602 if(retVal < 0)
603 {
604 //
605 return retVal ;
606 }
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000607 pos = retVal;
niklase@google.com470e71d2011-07-07 08:21:25 +0000608 rtcpbuffer[posNumberOfReportBlocks] += numberOfReportBlocks;
609
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000610 uint16_t len = uint16_t((pos/4) -1);
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000611 RtpUtility::AssignUWord16ToBuffer(rtcpbuffer + 2, len);
niklase@google.com470e71d2011-07-07 08:21:25 +0000612 return 0;
613}
614
615
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000616int32_t RTCPSender::BuildSDEC(uint8_t* rtcpbuffer, int& pos) {
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000617 size_t lengthCname = strlen(_CNAME);
618 assert(lengthCname < RTCP_CNAME_SIZE);
niklase@google.com470e71d2011-07-07 08:21:25 +0000619
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000620 // sanity
621 if(pos + 12 + lengthCname >= IP_PACKET_SIZE) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000622 LOG(LS_WARNING) << "Failed to build SDEC.";
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000623 return -2;
624 }
625 // SDEC Source Description
niklase@google.com470e71d2011-07-07 08:21:25 +0000626
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000627 // We always need to add SDES CNAME
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000628 rtcpbuffer[pos++] = static_cast<uint8_t>(0x80 + 1 + _csrcCNAMEs.size());
629 rtcpbuffer[pos++] = static_cast<uint8_t>(202);
niklase@google.com470e71d2011-07-07 08:21:25 +0000630
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000631 // handle SDES length later on
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000632 uint32_t SDESLengthPos = pos;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000633 pos++;
634 pos++;
niklase@google.com470e71d2011-07-07 08:21:25 +0000635
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000636 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000637 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000638 pos += 4;
639
640 // CNAME = 1
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000641 rtcpbuffer[pos++] = static_cast<uint8_t>(1);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000642
643 //
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000644 rtcpbuffer[pos++] = static_cast<uint8_t>(lengthCname);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000645
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000646 uint16_t SDESLength = 10;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000647
648 memcpy(&rtcpbuffer[pos], _CNAME, lengthCname);
649 pos += lengthCname;
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000650 SDESLength += (uint16_t)lengthCname;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000651
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000652 uint16_t padding = 0;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000653 // We must have a zero field even if we have an even multiple of 4 bytes
654 if ((pos % 4) == 0) {
655 padding++;
656 rtcpbuffer[pos++]=0;
657 }
658 while ((pos % 4) != 0) {
659 padding++;
660 rtcpbuffer[pos++]=0;
661 }
662 SDESLength += padding;
663
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000664 std::map<uint32_t, RTCPUtility::RTCPCnameInformation*>::iterator it =
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000665 _csrcCNAMEs.begin();
666
667 for(; it != _csrcCNAMEs.end(); it++) {
668 RTCPCnameInformation* cname = it->second;
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000669 uint32_t SSRC = it->first;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000670
671 // Add SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000672 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000673 pos += 4;
674
675 // CNAME = 1
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000676 rtcpbuffer[pos++] = static_cast<uint8_t>(1);
niklase@google.com470e71d2011-07-07 08:21:25 +0000677
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000678 size_t length = strlen(cname->name);
679 assert(length < RTCP_CNAME_SIZE);
niklase@google.com470e71d2011-07-07 08:21:25 +0000680
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000681 rtcpbuffer[pos++]= static_cast<uint8_t>(length);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000682 SDESLength += 6;
niklase@google.com470e71d2011-07-07 08:21:25 +0000683
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000684 memcpy(&rtcpbuffer[pos],cname->name, length);
niklase@google.com470e71d2011-07-07 08:21:25 +0000685
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +0000686 pos += length;
687 SDESLength += length;
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000688 uint16_t padding = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000689
690 // We must have a zero field even if we have an even multiple of 4 bytes
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000691 if((pos % 4) == 0){
692 padding++;
693 rtcpbuffer[pos++]=0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000694 }
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000695 while((pos % 4) != 0){
696 padding++;
697 rtcpbuffer[pos++] = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000698 }
699 SDESLength += padding;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000700 }
701 // in 32-bit words minus one and we don't count the header
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000702 uint16_t buffer_length = (SDESLength / 4) - 1;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000703 RtpUtility::AssignUWord16ToBuffer(rtcpbuffer + SDESLengthPos, buffer_length);
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +0000704 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000705}
706
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000707int32_t RTCPSender::BuildRR(uint8_t* rtcpbuffer,
708 int& pos,
709 uint32_t NTPsec,
710 uint32_t NTPfrac) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000711 // sanity one block
712 if(pos + 32 >= IP_PACKET_SIZE)
713 {
714 return -2;
715 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000716 uint32_t posNumberOfReportBlocks = pos;
niklase@google.com470e71d2011-07-07 08:21:25 +0000717
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000718 rtcpbuffer[pos++]=(uint8_t)0x80;
719 rtcpbuffer[pos++]=(uint8_t)201;
niklase@google.com470e71d2011-07-07 08:21:25 +0000720
721 // Save for our length field
722 pos++;
723 pos++;
724
725 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000726 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000727 pos += 4;
728
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000729 uint8_t numberOfReportBlocks = 0;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000730 int retVal = WriteAllReportBlocksToBuffer(rtcpbuffer, pos,
731 numberOfReportBlocks,
732 NTPsec, NTPfrac);
niklase@google.com470e71d2011-07-07 08:21:25 +0000733 if(retVal < 0)
734 {
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000735 return pos;
niklase@google.com470e71d2011-07-07 08:21:25 +0000736 }
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000737 pos = retVal;
niklase@google.com470e71d2011-07-07 08:21:25 +0000738 rtcpbuffer[posNumberOfReportBlocks] += numberOfReportBlocks;
739
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000740 uint16_t len = uint16_t((pos)/4 -1);
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000741 RtpUtility::AssignUWord16ToBuffer(rtcpbuffer + 2, len);
niklase@google.com470e71d2011-07-07 08:21:25 +0000742 return 0;
743}
744
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000745// From RFC 5450: Transmission Time Offsets in RTP Streams.
746// 0 1 2 3
747// 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
748// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
749// hdr |V=2|P| RC | PT=IJ=195 | length |
750// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
751// | inter-arrival jitter |
752// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
753// . .
754// . .
755// . .
756// | inter-arrival jitter |
757// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
758//
759// If present, this RTCP packet must be placed after a receiver report
760// (inside a compound RTCP packet), and MUST have the same value for RC
761// (reception report count) as the receiver report.
762
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000763int32_t
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000764RTCPSender::BuildExtendedJitterReport(
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000765 uint8_t* rtcpbuffer,
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000766 int& pos,
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000767 const uint32_t jitterTransmissionTimeOffset)
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000768{
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000769 if (external_report_blocks_.size() > 0)
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000770 {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000771 // TODO(andresp): Remove external report blocks since they are not
772 // supported.
773 LOG(LS_ERROR) << "Handling of external report blocks not implemented.";
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000774 return 0;
775 }
776
777 // sanity
778 if(pos + 8 >= IP_PACKET_SIZE)
779 {
780 return -2;
781 }
782 // add picture loss indicator
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000783 uint8_t RC = 1;
784 rtcpbuffer[pos++]=(uint8_t)0x80 + RC;
785 rtcpbuffer[pos++]=(uint8_t)195;
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000786
787 // Used fixed length of 2
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000788 rtcpbuffer[pos++]=(uint8_t)0;
789 rtcpbuffer[pos++]=(uint8_t)(1);
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000790
791 // Add inter-arrival jitter
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000792 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos,
793 jitterTransmissionTimeOffset);
asapersson@webrtc.org5249cc82011-12-16 14:31:37 +0000794 pos += 4;
795 return 0;
796}
797
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000798int32_t
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000799RTCPSender::BuildPLI(uint8_t* rtcpbuffer, int& pos)
niklase@google.com470e71d2011-07-07 08:21:25 +0000800{
801 // sanity
802 if(pos + 12 >= IP_PACKET_SIZE)
803 {
804 return -2;
805 }
806 // add picture loss indicator
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000807 uint8_t FMT = 1;
808 rtcpbuffer[pos++]=(uint8_t)0x80 + FMT;
809 rtcpbuffer[pos++]=(uint8_t)206;
niklase@google.com470e71d2011-07-07 08:21:25 +0000810
811 //Used fixed length of 2
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000812 rtcpbuffer[pos++]=(uint8_t)0;
813 rtcpbuffer[pos++]=(uint8_t)(2);
niklase@google.com470e71d2011-07-07 08:21:25 +0000814
815 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000816 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000817 pos += 4;
818
819 // Add the remote SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000820 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000821 pos += 4;
822 return 0;
823}
824
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000825int32_t RTCPSender::BuildFIR(uint8_t* rtcpbuffer,
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000826 int& pos,
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000827 bool repeat) {
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000828 // sanity
829 if(pos + 20 >= IP_PACKET_SIZE) {
830 return -2;
831 }
832 if (!repeat) {
833 _sequenceNumberFIR++; // do not increase if repetition
834 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000835
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000836 // add full intra request indicator
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000837 uint8_t FMT = 4;
838 rtcpbuffer[pos++] = (uint8_t)0x80 + FMT;
839 rtcpbuffer[pos++] = (uint8_t)206;
niklase@google.com470e71d2011-07-07 08:21:25 +0000840
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000841 //Length of 4
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000842 rtcpbuffer[pos++] = (uint8_t)0;
843 rtcpbuffer[pos++] = (uint8_t)(4);
niklase@google.com470e71d2011-07-07 08:21:25 +0000844
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000845 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000846 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000847 pos += 4;
niklase@google.com470e71d2011-07-07 08:21:25 +0000848
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000849 // RFC 5104 4.3.1.2. Semantics
850 // SSRC of media source
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000851 rtcpbuffer[pos++] = (uint8_t)0;
852 rtcpbuffer[pos++] = (uint8_t)0;
853 rtcpbuffer[pos++] = (uint8_t)0;
854 rtcpbuffer[pos++] = (uint8_t)0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000855
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000856 // Additional Feedback Control Information (FCI)
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000857 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _remoteSSRC);
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000858 pos += 4;
niklase@google.com470e71d2011-07-07 08:21:25 +0000859
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000860 rtcpbuffer[pos++] = (uint8_t)(_sequenceNumberFIR);
861 rtcpbuffer[pos++] = (uint8_t)0;
862 rtcpbuffer[pos++] = (uint8_t)0;
863 rtcpbuffer[pos++] = (uint8_t)0;
pwestin@webrtc.org5e954812012-02-10 12:13:12 +0000864 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000865}
866
867/*
868 0 1 2 3
869 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
870 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
871 | First | Number | PictureID |
872 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
873*/
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000874int32_t RTCPSender::BuildSLI(uint8_t* rtcpbuffer, int& pos, uint8_t pictureID) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000875 // sanity
876 if(pos + 16 >= IP_PACKET_SIZE)
877 {
878 return -2;
879 }
880 // add slice loss indicator
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000881 uint8_t FMT = 2;
882 rtcpbuffer[pos++]=(uint8_t)0x80 + FMT;
883 rtcpbuffer[pos++]=(uint8_t)206;
niklase@google.com470e71d2011-07-07 08:21:25 +0000884
885 //Used fixed length of 3
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000886 rtcpbuffer[pos++]=(uint8_t)0;
887 rtcpbuffer[pos++]=(uint8_t)(3);
niklase@google.com470e71d2011-07-07 08:21:25 +0000888
889 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000890 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000891 pos += 4;
892
893 // Add the remote SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000894 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000895 pos += 4;
896
897 // Add first, number & picture ID 6 bits
898 // first = 0, 13 - bits
899 // number = 0x1fff, 13 - bits only ones for now
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000900 uint32_t sliField = (0x1fff << 6)+ (0x3f & pictureID);
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000901 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, sliField);
niklase@google.com470e71d2011-07-07 08:21:25 +0000902 pos += 4;
903 return 0;
904}
905
906/*
907 0 1 2 3
908 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
909 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
910 | PB |0| Payload Type| Native RPSI bit string |
911 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
912 | defined per codec ... | Padding (0) |
913 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
914*/
915/*
916* Note: not generic made for VP8
917*/
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +0000918int32_t RTCPSender::BuildRPSI(uint8_t* rtcpbuffer,
919 int& pos,
920 uint64_t pictureID,
921 uint8_t payloadType) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000922 // sanity
923 if(pos + 24 >= IP_PACKET_SIZE)
924 {
925 return -2;
926 }
927 // add Reference Picture Selection Indication
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000928 uint8_t FMT = 3;
929 rtcpbuffer[pos++]=(uint8_t)0x80 + FMT;
930 rtcpbuffer[pos++]=(uint8_t)206;
niklase@google.com470e71d2011-07-07 08:21:25 +0000931
932 // calc length
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000933 uint32_t bitsRequired = 7;
934 uint8_t bytesRequired = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000935 while((pictureID>>bitsRequired) > 0)
936 {
937 bitsRequired += 7;
938 bytesRequired++;
939 }
940
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000941 uint8_t size = 3;
niklase@google.com470e71d2011-07-07 08:21:25 +0000942 if(bytesRequired > 6)
943 {
944 size = 5;
945 } else if(bytesRequired > 2)
946 {
947 size = 4;
948 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000949 rtcpbuffer[pos++]=(uint8_t)0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000950 rtcpbuffer[pos++]=size;
951
952 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000953 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000954 pos += 4;
955
956 // Add the remote SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000957 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +0000958 pos += 4;
959
960 // calc padding length
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000961 uint8_t paddingBytes = 4-((2+bytesRequired)%4);
niklase@google.com470e71d2011-07-07 08:21:25 +0000962 if(paddingBytes == 4)
963 {
964 paddingBytes = 0;
965 }
966 // add padding length in bits
967 rtcpbuffer[pos] = paddingBytes*8; // padding can be 0, 8, 16 or 24
968 pos++;
969
970 // add payload type
971 rtcpbuffer[pos] = payloadType;
972 pos++;
973
974 // add picture ID
975 for(int i = bytesRequired-1; i > 0; i--)
976 {
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000977 rtcpbuffer[pos] = 0x80 | uint8_t(pictureID >> (i*7));
niklase@google.com470e71d2011-07-07 08:21:25 +0000978 pos++;
979 }
980 // add last byte of picture ID
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000981 rtcpbuffer[pos] = uint8_t(pictureID & 0x7f);
niklase@google.com470e71d2011-07-07 08:21:25 +0000982 pos++;
983
984 // add padding
985 for(int j = 0; j <paddingBytes; j++)
986 {
987 rtcpbuffer[pos] = 0;
988 pos++;
989 }
990 return 0;
991}
992
pbos@webrtc.org2f446732013-04-08 11:08:41 +0000993int32_t
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000994RTCPSender::BuildREMB(uint8_t* rtcpbuffer, int& pos)
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000995{
996 // sanity
pbos@webrtc.org49ff40e2014-11-13 14:42:37 +0000997 if(pos + 20 + 4 * remb_ssrcs_.size() >= IP_PACKET_SIZE)
pwestin@webrtc.org741da942011-09-20 13:52:04 +0000998 {
999 return -2;
1000 }
1001 // add application layer feedback
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001002 uint8_t FMT = 15;
1003 rtcpbuffer[pos++]=(uint8_t)0x80 + FMT;
1004 rtcpbuffer[pos++]=(uint8_t)206;
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001005
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001006 rtcpbuffer[pos++]=(uint8_t)0;
pbos@webrtc.org49ff40e2014-11-13 14:42:37 +00001007 rtcpbuffer[pos++]=remb_ssrcs_.size() + 4;
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001008
1009 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001010 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001011 pos += 4;
1012
1013 // Remote SSRC must be 0
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001014 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, 0);
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001015 pos += 4;
1016
1017 rtcpbuffer[pos++]='R';
1018 rtcpbuffer[pos++]='E';
1019 rtcpbuffer[pos++]='M';
1020 rtcpbuffer[pos++]='B';
1021
pbos@webrtc.org49ff40e2014-11-13 14:42:37 +00001022 rtcpbuffer[pos++] = remb_ssrcs_.size();
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001023 // 6 bit Exp
1024 // 18 bit mantissa
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001025 uint8_t brExp = 0;
1026 for(uint32_t i=0; i<64; i++)
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001027 {
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001028 if(_rembBitrate <= ((uint32_t)262143 << i))
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001029 {
1030 brExp = i;
1031 break;
1032 }
1033 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001034 const uint32_t brMantissa = (_rembBitrate >> brExp);
1035 rtcpbuffer[pos++]=(uint8_t)((brExp << 2) + ((brMantissa >> 16) & 0x03));
1036 rtcpbuffer[pos++]=(uint8_t)(brMantissa >> 8);
1037 rtcpbuffer[pos++]=(uint8_t)(brMantissa);
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001038
pbos@webrtc.org49ff40e2014-11-13 14:42:37 +00001039 for (size_t i = 0; i < remb_ssrcs_.size(); i++)
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001040 {
pbos@webrtc.org49ff40e2014-11-13 14:42:37 +00001041 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, remb_ssrcs_[i]);
1042 pos += 4;
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001043 }
1044 return 0;
1045}
1046
stefan@webrtc.org9354cc92012-06-07 08:10:14 +00001047void
1048RTCPSender::SetTargetBitrate(unsigned int target_bitrate)
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001049{
mflodman@webrtc.org117c1192012-01-13 08:52:58 +00001050 CriticalSectionScoped lock(_criticalSectionRTCPSender);
pwestin@webrtc.org741da942011-09-20 13:52:04 +00001051 _tmmbr_Send = target_bitrate / 1000;
mflodman@webrtc.org117c1192012-01-13 08:52:58 +00001052}
1053
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001054int32_t RTCPSender::BuildTMMBR(ModuleRtpRtcpImpl* rtp_rtcp_module,
1055 uint8_t* rtcpbuffer,
1056 int& pos) {
1057 if (rtp_rtcp_module == NULL)
1058 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +00001059 // Before sending the TMMBR check the received TMMBN, only an owner is allowed to raise the bitrate
1060 // If the sender is an owner of the TMMBN -> send TMMBR
1061 // If not an owner but the TMMBR would enter the TMMBN -> send TMMBR
1062
niklase@google.com470e71d2011-07-07 08:21:25 +00001063 // get current bounding set from RTCP receiver
1064 bool tmmbrOwner = false;
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001065 // store in candidateSet, allocates one extra slot
1066 TMMBRSet* candidateSet = _tmmbrHelp.CandidateSet();
niklase@google.com470e71d2011-07-07 08:21:25 +00001067
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001068 // holding _criticalSectionRTCPSender while calling RTCPreceiver which
1069 // will accuire _criticalSectionRTCPReceiver is a potental deadlock but
1070 // since RTCPreceiver is not doing the reverse we should be fine
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001071 int32_t lengthOfBoundingSet =
1072 rtp_rtcp_module->BoundingSet(tmmbrOwner, candidateSet);
niklase@google.com470e71d2011-07-07 08:21:25 +00001073
1074 if(lengthOfBoundingSet > 0)
1075 {
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001076 for (int32_t i = 0; i < lengthOfBoundingSet; i++)
niklase@google.com470e71d2011-07-07 08:21:25 +00001077 {
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001078 if( candidateSet->Tmmbr(i) == _tmmbr_Send &&
1079 candidateSet->PacketOH(i) == _packetOH_Send)
niklase@google.com470e71d2011-07-07 08:21:25 +00001080 {
1081 // do not send the same tuple
1082 return 0;
1083 }
1084 }
1085 if(!tmmbrOwner)
1086 {
1087 // use received bounding set as candidate set
1088 // add current tuple
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001089 candidateSet->SetEntry(lengthOfBoundingSet,
1090 _tmmbr_Send,
1091 _packetOH_Send,
1092 _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001093 int numCandidates = lengthOfBoundingSet+ 1;
1094
1095 // find bounding set
1096 TMMBRSet* boundingSet = NULL;
1097 int numBoundingSet = _tmmbrHelp.FindTMMBRBoundingSet(boundingSet);
1098 if(numBoundingSet > 0 || numBoundingSet <= numCandidates)
1099 {
1100 tmmbrOwner = _tmmbrHelp.IsOwner(_SSRC, numBoundingSet);
1101 }
1102 if(!tmmbrOwner)
1103 {
1104 // did not enter bounding set, no meaning to send this request
1105 return 0;
1106 }
1107 }
1108 }
1109
1110 if(_tmmbr_Send)
1111 {
1112 // sanity
1113 if(pos + 20 >= IP_PACKET_SIZE)
1114 {
1115 return -2;
1116 }
1117 // add TMMBR indicator
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001118 uint8_t FMT = 3;
1119 rtcpbuffer[pos++]=(uint8_t)0x80 + FMT;
1120 rtcpbuffer[pos++]=(uint8_t)205;
niklase@google.com470e71d2011-07-07 08:21:25 +00001121
1122 //Length of 4
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001123 rtcpbuffer[pos++]=(uint8_t)0;
1124 rtcpbuffer[pos++]=(uint8_t)(4);
niklase@google.com470e71d2011-07-07 08:21:25 +00001125
1126 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001127 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001128 pos += 4;
1129
1130 // RFC 5104 4.2.1.2. Semantics
1131
1132 // SSRC of media source
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001133 rtcpbuffer[pos++]=(uint8_t)0;
1134 rtcpbuffer[pos++]=(uint8_t)0;
1135 rtcpbuffer[pos++]=(uint8_t)0;
1136 rtcpbuffer[pos++]=(uint8_t)0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001137
1138 // Additional Feedback Control Information (FCI)
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001139 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001140 pos += 4;
1141
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001142 uint32_t bitRate = _tmmbr_Send*1000;
1143 uint32_t mmbrExp = 0;
1144 for(uint32_t i=0;i<64;i++)
niklase@google.com470e71d2011-07-07 08:21:25 +00001145 {
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001146 if(bitRate <= ((uint32_t)131071 << i))
niklase@google.com470e71d2011-07-07 08:21:25 +00001147 {
1148 mmbrExp = i;
1149 break;
1150 }
1151 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001152 uint32_t mmbrMantissa = (bitRate >> mmbrExp);
niklase@google.com470e71d2011-07-07 08:21:25 +00001153
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001154 rtcpbuffer[pos++]=(uint8_t)((mmbrExp << 2) + ((mmbrMantissa >> 15) & 0x03));
1155 rtcpbuffer[pos++]=(uint8_t)(mmbrMantissa >> 7);
1156 rtcpbuffer[pos++]=(uint8_t)((mmbrMantissa << 1) + ((_packetOH_Send >> 8)& 0x01));
1157 rtcpbuffer[pos++]=(uint8_t)(_packetOH_Send);
niklase@google.com470e71d2011-07-07 08:21:25 +00001158 }
1159 return 0;
1160}
1161
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001162int32_t
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001163RTCPSender::BuildTMMBN(uint8_t* rtcpbuffer, int& pos)
niklase@google.com470e71d2011-07-07 08:21:25 +00001164{
1165 TMMBRSet* boundingSet = _tmmbrHelp.BoundingSetToSend();
1166 if(boundingSet == NULL)
1167 {
1168 return -1;
1169 }
1170 // sanity
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001171 if(pos + 12 + boundingSet->lengthOfSet()*8 >= IP_PACKET_SIZE)
niklase@google.com470e71d2011-07-07 08:21:25 +00001172 {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +00001173 LOG(LS_WARNING) << "Failed to build TMMBN.";
niklase@google.com470e71d2011-07-07 08:21:25 +00001174 return -2;
1175 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001176 uint8_t FMT = 4;
niklase@google.com470e71d2011-07-07 08:21:25 +00001177 // add TMMBN indicator
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001178 rtcpbuffer[pos++]=(uint8_t)0x80 + FMT;
1179 rtcpbuffer[pos++]=(uint8_t)205;
niklase@google.com470e71d2011-07-07 08:21:25 +00001180
1181 //Add length later
1182 int posLength = pos;
1183 pos++;
1184 pos++;
1185
1186 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001187 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001188 pos += 4;
1189
1190 // RFC 5104 4.2.2.2. Semantics
1191
1192 // SSRC of media source
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001193 rtcpbuffer[pos++]=(uint8_t)0;
1194 rtcpbuffer[pos++]=(uint8_t)0;
1195 rtcpbuffer[pos++]=(uint8_t)0;
1196 rtcpbuffer[pos++]=(uint8_t)0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001197
1198 // Additional Feedback Control Information (FCI)
1199 int numBoundingSet = 0;
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001200 for(uint32_t n=0; n< boundingSet->lengthOfSet(); n++)
niklase@google.com470e71d2011-07-07 08:21:25 +00001201 {
hta@webrtc.org54536bb2012-05-03 14:07:23 +00001202 if (boundingSet->Tmmbr(n) > 0)
niklase@google.com470e71d2011-07-07 08:21:25 +00001203 {
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001204 uint32_t tmmbrSSRC = boundingSet->Ssrc(n);
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001205 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, tmmbrSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001206 pos += 4;
1207
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001208 uint32_t bitRate = boundingSet->Tmmbr(n) * 1000;
1209 uint32_t mmbrExp = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001210 for(int i=0; i<64; i++)
1211 {
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001212 if(bitRate <= ((uint32_t)131071 << i))
niklase@google.com470e71d2011-07-07 08:21:25 +00001213 {
1214 mmbrExp = i;
1215 break;
1216 }
1217 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001218 uint32_t mmbrMantissa = (bitRate >> mmbrExp);
1219 uint32_t measuredOH = boundingSet->PacketOH(n);
niklase@google.com470e71d2011-07-07 08:21:25 +00001220
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001221 rtcpbuffer[pos++]=(uint8_t)((mmbrExp << 2) + ((mmbrMantissa >> 15) & 0x03));
1222 rtcpbuffer[pos++]=(uint8_t)(mmbrMantissa >> 7);
1223 rtcpbuffer[pos++]=(uint8_t)((mmbrMantissa << 1) + ((measuredOH >> 8)& 0x01));
1224 rtcpbuffer[pos++]=(uint8_t)(measuredOH);
niklase@google.com470e71d2011-07-07 08:21:25 +00001225 numBoundingSet++;
1226 }
1227 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001228 uint16_t length= (uint16_t)(2+2*numBoundingSet);
1229 rtcpbuffer[posLength++]=(uint8_t)(length>>8);
1230 rtcpbuffer[posLength]=(uint8_t)(length);
niklase@google.com470e71d2011-07-07 08:21:25 +00001231 return 0;
1232}
1233
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001234int32_t
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001235RTCPSender::BuildAPP(uint8_t* rtcpbuffer, int& pos)
niklase@google.com470e71d2011-07-07 08:21:25 +00001236{
1237 // sanity
1238 if(_appData == NULL)
1239 {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +00001240 LOG(LS_WARNING) << "Failed to build app specific.";
niklase@google.com470e71d2011-07-07 08:21:25 +00001241 return -1;
1242 }
1243 if(pos + 12 + _appLength >= IP_PACKET_SIZE)
1244 {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +00001245 LOG(LS_WARNING) << "Failed to build app specific.";
niklase@google.com470e71d2011-07-07 08:21:25 +00001246 return -2;
1247 }
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001248 rtcpbuffer[pos++]=(uint8_t)0x80 + _appSubType;
niklase@google.com470e71d2011-07-07 08:21:25 +00001249
1250 // Add APP ID
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001251 rtcpbuffer[pos++]=(uint8_t)204;
niklase@google.com470e71d2011-07-07 08:21:25 +00001252
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001253 uint16_t length = (_appLength>>2) + 2; // include SSRC and name
1254 rtcpbuffer[pos++]=(uint8_t)(length>>8);
1255 rtcpbuffer[pos++]=(uint8_t)(length);
niklase@google.com470e71d2011-07-07 08:21:25 +00001256
1257 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001258 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001259 pos += 4;
1260
1261 // Add our application name
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001262 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _appName);
niklase@google.com470e71d2011-07-07 08:21:25 +00001263 pos += 4;
1264
1265 // Add the data
1266 memcpy(rtcpbuffer +pos, _appData,_appLength);
1267 pos += _appLength;
1268 return 0;
1269}
1270
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00001271int32_t RTCPSender::BuildNACK(uint8_t* rtcpbuffer,
1272 int& pos,
1273 int32_t nackSize,
1274 const uint16_t* nackList,
1275 std::string* nackString) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001276 // sanity
1277 if(pos + 16 >= IP_PACKET_SIZE)
1278 {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +00001279 LOG(LS_WARNING) << "Failed to build NACK.";
niklase@google.com470e71d2011-07-07 08:21:25 +00001280 return -2;
1281 }
1282
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001283 // int size, uint16_t* nackList
niklase@google.com470e71d2011-07-07 08:21:25 +00001284 // add nack list
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001285 uint8_t FMT = 1;
1286 rtcpbuffer[pos++]=(uint8_t)0x80 + FMT;
1287 rtcpbuffer[pos++]=(uint8_t)205;
niklase@google.com470e71d2011-07-07 08:21:25 +00001288
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001289 rtcpbuffer[pos++]=(uint8_t) 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001290 int nackSizePos = pos;
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001291 rtcpbuffer[pos++]=(uint8_t)(3); //setting it to one kNACK signal as default
niklase@google.com470e71d2011-07-07 08:21:25 +00001292
1293 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001294 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001295 pos += 4;
1296
1297 // Add the remote SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001298 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001299 pos += 4;
1300
andresp@webrtc.org523f9372013-04-11 11:30:39 +00001301 // Build NACK bitmasks and write them to the RTCP message.
1302 // The nack list should be sorted and not contain duplicates if one
1303 // wants to build the smallest rtcp nack packet.
1304 int numOfNackFields = 0;
1305 int maxNackFields = std::min<int>(kRtcpMaxNackFields,
1306 (IP_PACKET_SIZE - pos) / 4);
1307 int i = 0;
1308 while (i < nackSize && numOfNackFields < maxNackFields) {
andresp@webrtc.org523f9372013-04-11 11:30:39 +00001309 uint16_t nack = nackList[i++];
1310 uint16_t bitmask = 0;
1311 while (i < nackSize) {
1312 int shift = static_cast<uint16_t>(nackList[i] - nack) - 1;
1313 if (shift >= 0 && shift <= 15) {
andresp@webrtc.org523f9372013-04-11 11:30:39 +00001314 bitmask |= (1 << shift);
1315 ++i;
1316 } else {
1317 break;
niklase@google.com470e71d2011-07-07 08:21:25 +00001318 }
andresp@webrtc.org523f9372013-04-11 11:30:39 +00001319 }
1320 // Write the sequence number and the bitmask to the packet.
1321 assert(pos + 4 < IP_PACKET_SIZE);
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001322 RtpUtility::AssignUWord16ToBuffer(rtcpbuffer + pos, nack);
andresp@webrtc.org523f9372013-04-11 11:30:39 +00001323 pos += 2;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001324 RtpUtility::AssignUWord16ToBuffer(rtcpbuffer + pos, bitmask);
andresp@webrtc.org523f9372013-04-11 11:30:39 +00001325 pos += 2;
1326 numOfNackFields++;
niklase@google.com470e71d2011-07-07 08:21:25 +00001327 }
andresp@webrtc.org523f9372013-04-11 11:30:39 +00001328 rtcpbuffer[nackSizePos] = static_cast<uint8_t>(2 + numOfNackFields);
asapersson@webrtc.org2dd31342014-10-29 12:42:30 +00001329
1330 if (i != nackSize) {
1331 LOG(LS_WARNING) << "Nack list too large for one packet.";
1332 }
1333
1334 // Report stats.
1335 NACKStringBuilder stringBuilder;
1336 for (int idx = 0; idx < i; ++idx) {
1337 stringBuilder.PushNACK(nackList[idx]);
1338 nack_stats_.ReportRequest(nackList[idx]);
1339 }
edjee@google.com79b02892013-04-04 19:43:34 +00001340 *nackString = stringBuilder.GetResult();
asapersson@webrtc.org2dd31342014-10-29 12:42:30 +00001341 packet_type_counter_.nack_requests = nack_stats_.requests();
1342 packet_type_counter_.unique_nack_requests = nack_stats_.unique_requests();
niklase@google.com470e71d2011-07-07 08:21:25 +00001343 return 0;
1344}
1345
pbos@webrtc.org9334ac22014-11-24 08:25:50 +00001346int32_t RTCPSender::BuildBYE(uint8_t* rtcpbuffer, int& pos) {
1347 // sanity
1348 if (pos + 8 >= IP_PACKET_SIZE) {
1349 return -2;
1350 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001351
pbos@webrtc.org9334ac22014-11-24 08:25:50 +00001352 // Add a bye packet
1353 // Number of SSRC + CSRCs.
1354 rtcpbuffer[pos++] = (uint8_t)0x80 + 1 + csrcs_.size();
1355 rtcpbuffer[pos++] = (uint8_t)203;
niklase@google.com470e71d2011-07-07 08:21:25 +00001356
pbos@webrtc.org9334ac22014-11-24 08:25:50 +00001357 // length
1358 rtcpbuffer[pos++] = (uint8_t)0;
1359 rtcpbuffer[pos++] = (uint8_t)(1 + csrcs_.size());
niklase@google.com470e71d2011-07-07 08:21:25 +00001360
pbos@webrtc.org9334ac22014-11-24 08:25:50 +00001361 // Add our own SSRC
1362 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
1363 pos += 4;
niklase@google.com470e71d2011-07-07 08:21:25 +00001364
pbos@webrtc.org9334ac22014-11-24 08:25:50 +00001365 // add CSRCs
1366 for (size_t i = 0; i < csrcs_.size(); i++) {
1367 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, csrcs_[i]);
1368 pos += 4;
1369 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001370
pbos@webrtc.org9334ac22014-11-24 08:25:50 +00001371 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +00001372}
1373
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001374int32_t RTCPSender::BuildReceiverReferenceTime(uint8_t* buffer,
1375 int& pos,
1376 uint32_t ntp_sec,
1377 uint32_t ntp_frac) {
1378 const int kRrTimeBlockLength = 20;
1379 if (pos + kRrTimeBlockLength >= IP_PACKET_SIZE) {
1380 return -2;
1381 }
1382
1383 if (last_xr_rr_.size() >= RTCP_NUMBER_OF_SR) {
1384 last_xr_rr_.erase(last_xr_rr_.begin());
1385 }
1386 last_xr_rr_.insert(std::pair<uint32_t, int64_t>(
1387 RTCPUtility::MidNtp(ntp_sec, ntp_frac),
1388 Clock::NtpToMs(ntp_sec, ntp_frac)));
1389
1390 // Add XR header.
1391 buffer[pos++] = 0x80;
1392 buffer[pos++] = 207;
1393 buffer[pos++] = 0; // XR packet length.
1394 buffer[pos++] = 4; // XR packet length.
1395
1396 // Add our own SSRC.
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001397 RtpUtility::AssignUWord32ToBuffer(buffer + pos, _SSRC);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001398 pos += 4;
1399
1400 // 0 1 2 3
1401 // 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
1402 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1403 // | BT=4 | reserved | block length = 2 |
1404 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1405 // | NTP timestamp, most significant word |
1406 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1407 // | NTP timestamp, least significant word |
1408 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1409
1410 // Add Receiver Reference Time Report block.
1411 buffer[pos++] = 4; // BT.
1412 buffer[pos++] = 0; // Reserved.
1413 buffer[pos++] = 0; // Block length.
1414 buffer[pos++] = 2; // Block length.
1415
1416 // NTP timestamp.
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001417 RtpUtility::AssignUWord32ToBuffer(buffer + pos, ntp_sec);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001418 pos += 4;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001419 RtpUtility::AssignUWord32ToBuffer(buffer + pos, ntp_frac);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001420 pos += 4;
1421
1422 return 0;
1423}
1424
1425int32_t RTCPSender::BuildDlrr(uint8_t* buffer,
1426 int& pos,
1427 const RtcpReceiveTimeInfo& info) {
1428 const int kDlrrBlockLength = 24;
1429 if (pos + kDlrrBlockLength >= IP_PACKET_SIZE) {
1430 return -2;
1431 }
1432
1433 // Add XR header.
1434 buffer[pos++] = 0x80;
1435 buffer[pos++] = 207;
1436 buffer[pos++] = 0; // XR packet length.
1437 buffer[pos++] = 5; // XR packet length.
1438
1439 // Add our own SSRC.
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001440 RtpUtility::AssignUWord32ToBuffer(buffer + pos, _SSRC);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001441 pos += 4;
1442
1443 // 0 1 2 3
1444 // 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
1445 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1446 // | BT=5 | reserved | block length |
1447 // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
1448 // | SSRC_1 (SSRC of first receiver) | sub-
1449 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
1450 // | last RR (LRR) | 1
1451 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1452 // | delay since last RR (DLRR) |
1453 // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
1454 // | SSRC_2 (SSRC of second receiver) | sub-
1455 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
1456 // : ... : 2
1457
1458 // Add DLRR sub block.
1459 buffer[pos++] = 5; // BT.
1460 buffer[pos++] = 0; // Reserved.
1461 buffer[pos++] = 0; // Block length.
1462 buffer[pos++] = 3; // Block length.
1463
1464 // NTP timestamp.
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001465 RtpUtility::AssignUWord32ToBuffer(buffer + pos, info.sourceSSRC);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001466 pos += 4;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001467 RtpUtility::AssignUWord32ToBuffer(buffer + pos, info.lastRR);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001468 pos += 4;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001469 RtpUtility::AssignUWord32ToBuffer(buffer + pos, info.delaySinceLastRR);
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001470 pos += 4;
1471
1472 return 0;
1473}
1474
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001475int32_t
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001476RTCPSender::BuildVoIPMetric(uint8_t* rtcpbuffer, int& pos)
niklase@google.com470e71d2011-07-07 08:21:25 +00001477{
1478 // sanity
1479 if(pos + 44 >= IP_PACKET_SIZE)
1480 {
1481 return -2;
1482 }
1483
1484 // Add XR header
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001485 rtcpbuffer[pos++]=(uint8_t)0x80;
1486 rtcpbuffer[pos++]=(uint8_t)207;
niklase@google.com470e71d2011-07-07 08:21:25 +00001487
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001488 uint32_t XRLengthPos = pos;
niklase@google.com470e71d2011-07-07 08:21:25 +00001489
1490 // handle length later on
1491 pos++;
1492 pos++;
1493
1494 // Add our own SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001495 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _SSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001496 pos += 4;
1497
1498 // Add a VoIP metrics block
1499 rtcpbuffer[pos++]=7;
1500 rtcpbuffer[pos++]=0;
1501 rtcpbuffer[pos++]=0;
1502 rtcpbuffer[pos++]=8;
1503
1504 // Add the remote SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001505 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + pos, _remoteSSRC);
niklase@google.com470e71d2011-07-07 08:21:25 +00001506 pos += 4;
1507
1508 rtcpbuffer[pos++] = _xrVoIPMetric.lossRate;
1509 rtcpbuffer[pos++] = _xrVoIPMetric.discardRate;
1510 rtcpbuffer[pos++] = _xrVoIPMetric.burstDensity;
1511 rtcpbuffer[pos++] = _xrVoIPMetric.gapDensity;
1512
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001513 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.burstDuration >> 8);
1514 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.burstDuration);
1515 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.gapDuration >> 8);
1516 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.gapDuration);
niklase@google.com470e71d2011-07-07 08:21:25 +00001517
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001518 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.roundTripDelay >> 8);
1519 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.roundTripDelay);
1520 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.endSystemDelay >> 8);
1521 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.endSystemDelay);
niklase@google.com470e71d2011-07-07 08:21:25 +00001522
1523 rtcpbuffer[pos++] = _xrVoIPMetric.signalLevel;
1524 rtcpbuffer[pos++] = _xrVoIPMetric.noiseLevel;
1525 rtcpbuffer[pos++] = _xrVoIPMetric.RERL;
1526 rtcpbuffer[pos++] = _xrVoIPMetric.Gmin;
1527
1528 rtcpbuffer[pos++] = _xrVoIPMetric.Rfactor;
1529 rtcpbuffer[pos++] = _xrVoIPMetric.extRfactor;
1530 rtcpbuffer[pos++] = _xrVoIPMetric.MOSLQ;
1531 rtcpbuffer[pos++] = _xrVoIPMetric.MOSCQ;
1532
1533 rtcpbuffer[pos++] = _xrVoIPMetric.RXconfig;
1534 rtcpbuffer[pos++] = 0; // reserved
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001535 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.JBnominal >> 8);
1536 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.JBnominal);
niklase@google.com470e71d2011-07-07 08:21:25 +00001537
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001538 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.JBmax >> 8);
1539 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.JBmax);
1540 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.JBabsMax >> 8);
1541 rtcpbuffer[pos++] = (uint8_t)(_xrVoIPMetric.JBabsMax);
niklase@google.com470e71d2011-07-07 08:21:25 +00001542
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001543 rtcpbuffer[XRLengthPos]=(uint8_t)(0);
1544 rtcpbuffer[XRLengthPos+1]=(uint8_t)(10);
niklase@google.com470e71d2011-07-07 08:21:25 +00001545 return 0;
1546}
1547
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001548int32_t RTCPSender::SendRTCP(const FeedbackState& feedback_state,
1549 uint32_t packetTypeFlags,
1550 int32_t nackSize,
1551 const uint16_t* nackList,
1552 bool repeat,
1553 uint64_t pictureID) {
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001554 {
1555 CriticalSectionScoped lock(_criticalSectionRTCPSender);
1556 if(_method == kRtcpOff)
niklase@google.com470e71d2011-07-07 08:21:25 +00001557 {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +00001558 LOG(LS_WARNING) << "Can't send rtcp if it is disabled.";
pwestin@webrtc.org8edb39d2011-12-22 07:40:33 +00001559 return -1;
1560 }
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001561 }
1562 uint8_t rtcp_buffer[IP_PACKET_SIZE];
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001563 int rtcp_length = PrepareRTCP(feedback_state,
1564 packetTypeFlags,
1565 nackSize,
1566 nackList,
1567 repeat,
1568 pictureID,
1569 rtcp_buffer,
1570 IP_PACKET_SIZE);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001571 if (rtcp_length < 0) {
1572 return -1;
1573 }
1574 // Sanity don't send empty packets.
1575 if (rtcp_length == 0)
1576 {
1577 return -1;
1578 }
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +00001579 return SendToNetwork(rtcp_buffer, static_cast<size_t>(rtcp_length));
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001580}
1581
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001582int RTCPSender::PrepareRTCP(const FeedbackState& feedback_state,
1583 uint32_t packetTypeFlags,
1584 int32_t nackSize,
1585 const uint16_t* nackList,
1586 bool repeat,
1587 uint64_t pictureID,
1588 uint8_t* rtcp_buffer,
1589 int buffer_size) {
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001590 uint32_t rtcpPacketTypeFlags = packetTypeFlags;
1591 // Collect the received information.
1592 uint32_t NTPsec = 0;
1593 uint32_t NTPfrac = 0;
1594 uint32_t jitterTransmissionOffset = 0;
1595 int position = 0;
1596
1597 CriticalSectionScoped lock(_criticalSectionRTCPSender);
1598
asapersson@webrtc.orgd08d3892014-12-16 12:03:11 +00001599 if (packet_type_counter_.first_packet_time_ms == -1) {
1600 packet_type_counter_.first_packet_time_ms = _clock->TimeInMilliseconds();
1601 }
1602
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001603 if(_TMMBR ) // Attach TMMBR to send and receive reports.
1604 {
1605 rtcpPacketTypeFlags |= kRtcpTmmbr;
1606 }
1607 if(_appSend)
1608 {
1609 rtcpPacketTypeFlags |= kRtcpApp;
1610 _appSend = false;
1611 }
1612 if(_REMB && _sendREMB)
1613 {
1614 // Always attach REMB to SR if that is configured. Note that REMB is
1615 // only sent on one of the RTP modules in the REMB group.
1616 rtcpPacketTypeFlags |= kRtcpRemb;
1617 }
1618 if(_xrSendVoIPMetric)
1619 {
1620 rtcpPacketTypeFlags |= kRtcpXrVoipMetric;
1621 _xrSendVoIPMetric = false;
1622 }
1623 if(_sendTMMBN) // Set when having received a TMMBR.
1624 {
1625 rtcpPacketTypeFlags |= kRtcpTmmbn;
1626 _sendTMMBN = false;
1627 }
asapersson@webrtc.orgefaeda02014-01-20 08:34:49 +00001628 if (rtcpPacketTypeFlags & kRtcpReport)
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001629 {
asapersson@webrtc.orgefaeda02014-01-20 08:34:49 +00001630 if (xrSendReceiverReferenceTimeEnabled_ && !_sending)
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001631 {
1632 rtcpPacketTypeFlags |= kRtcpXrReceiverReferenceTime;
1633 }
1634 if (feedback_state.has_last_xr_rr)
1635 {
1636 rtcpPacketTypeFlags |= kRtcpXrDlrrReportBlock;
1637 }
1638 }
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001639 if(_method == kRtcpCompound)
1640 {
1641 if(_sending)
1642 {
1643 rtcpPacketTypeFlags |= kRtcpSr;
1644 } else
1645 {
1646 rtcpPacketTypeFlags |= kRtcpRr;
1647 }
1648 } else if(_method == kRtcpNonCompound)
1649 {
1650 if(rtcpPacketTypeFlags & kRtcpReport)
1651 {
1652 if(_sending)
1653 {
1654 rtcpPacketTypeFlags |= kRtcpSr;
1655 } else
1656 {
1657 rtcpPacketTypeFlags |= kRtcpRr;
1658 }
1659 }
1660 }
1661 if( rtcpPacketTypeFlags & kRtcpRr ||
1662 rtcpPacketTypeFlags & kRtcpSr)
1663 {
1664 // generate next time to send a RTCP report
1665 // seeded from RTP constructor
1666 int32_t random = rand() % 1000;
1667 int32_t timeToNext = RTCP_INTERVAL_AUDIO_MS;
1668
1669 if(_audio)
1670 {
1671 timeToNext = (RTCP_INTERVAL_AUDIO_MS/2) +
1672 (RTCP_INTERVAL_AUDIO_MS*random/1000);
1673 }else
1674 {
1675 uint32_t minIntervalMs = RTCP_INTERVAL_AUDIO_MS;
1676 if(_sending)
1677 {
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001678 // Calculate bandwidth for video; 360 / send bandwidth in kbit/s.
1679 uint32_t send_bitrate_kbit = feedback_state.send_bitrate / 1000;
1680 if (send_bitrate_kbit != 0)
1681 minIntervalMs = 360000 / send_bitrate_kbit;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001682 }
1683 if(minIntervalMs > RTCP_INTERVAL_VIDEO_MS)
1684 {
1685 minIntervalMs = RTCP_INTERVAL_VIDEO_MS;
1686 }
1687 timeToNext = (minIntervalMs/2) + (minIntervalMs*random/1000);
1688 }
1689 _nextTimeToSendRTCP = _clock->TimeInMilliseconds() + timeToNext;
1690 }
1691
1692 // If the data does not fit in the packet we fill it as much as possible.
1693 int32_t buildVal = 0;
1694
1695 // We need to send our NTP even if we haven't received any reports.
1696 _clock->CurrentNtp(NTPsec, NTPfrac);
1697 if (ShouldSendReportBlocks(rtcpPacketTypeFlags)) {
1698 StatisticianMap statisticians =
1699 receive_statistics_->GetActiveStatisticians();
1700 if (!statisticians.empty()) {
1701 StatisticianMap::const_iterator it;
1702 int i;
1703 for (it = statisticians.begin(), i = 0; it != statisticians.end();
1704 ++it, ++i) {
1705 RTCPReportBlock report_block;
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001706 if (PrepareReport(
1707 feedback_state, it->second, &report_block, &NTPsec, &NTPfrac))
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001708 AddReportBlock(it->first, &internal_report_blocks_, &report_block);
1709 }
1710 if (_IJ && !statisticians.empty()) {
1711 rtcpPacketTypeFlags |= kRtcpTransmissionTimeOffset;
1712 }
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001713 }
1714 }
1715
1716 if(rtcpPacketTypeFlags & kRtcpSr)
1717 {
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001718 buildVal = BuildSR(feedback_state, rtcp_buffer, position, NTPsec, NTPfrac);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001719 if (buildVal == -1) {
1720 return -1;
1721 } else if (buildVal == -2) {
1722 return position;
1723 }
1724 buildVal = BuildSDEC(rtcp_buffer, position);
1725 if (buildVal == -1) {
1726 return -1;
1727 } else if (buildVal == -2) {
1728 return position;
1729 }
1730 }else if(rtcpPacketTypeFlags & kRtcpRr)
1731 {
1732 buildVal = BuildRR(rtcp_buffer, position, NTPsec, NTPfrac);
1733 if (buildVal == -1) {
1734 return -1;
1735 } else if (buildVal == -2) {
1736 return position;
1737 }
1738 // only of set
1739 if(_CNAME[0] != 0)
1740 {
1741 buildVal = BuildSDEC(rtcp_buffer, position);
1742 if (buildVal == -1) {
1743 return -1;
1744 }
1745 }
1746 }
1747 if(rtcpPacketTypeFlags & kRtcpTransmissionTimeOffset)
1748 {
1749 // If present, this RTCP packet must be placed after a
1750 // receiver report.
1751 buildVal = BuildExtendedJitterReport(rtcp_buffer,
1752 position,
1753 jitterTransmissionOffset);
1754 if (buildVal == -1) {
1755 return -1;
1756 } else if (buildVal == -2) {
1757 return position;
1758 }
1759 }
1760 if(rtcpPacketTypeFlags & kRtcpPli)
1761 {
1762 buildVal = BuildPLI(rtcp_buffer, position);
1763 if (buildVal == -1) {
1764 return -1;
1765 } else if (buildVal == -2) {
1766 return position;
1767 }
1768 TRACE_EVENT_INSTANT0("webrtc_rtp", "RTCPSender::PLI");
asapersson@webrtc.org8098e072014-02-19 11:59:02 +00001769 ++packet_type_counter_.pli_packets;
1770 TRACE_COUNTER_ID1("webrtc_rtp", "RTCP_PLICount", _SSRC,
1771 packet_type_counter_.pli_packets);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001772 }
1773 if(rtcpPacketTypeFlags & kRtcpFir)
1774 {
1775 buildVal = BuildFIR(rtcp_buffer, position, repeat);
1776 if (buildVal == -1) {
1777 return -1;
1778 } else if (buildVal == -2) {
1779 return position;
1780 }
1781 TRACE_EVENT_INSTANT0("webrtc_rtp", "RTCPSender::FIR");
asapersson@webrtc.org8098e072014-02-19 11:59:02 +00001782 ++packet_type_counter_.fir_packets;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001783 TRACE_COUNTER_ID1("webrtc_rtp", "RTCP_FIRCount", _SSRC,
asapersson@webrtc.org8098e072014-02-19 11:59:02 +00001784 packet_type_counter_.fir_packets);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001785 }
1786 if(rtcpPacketTypeFlags & kRtcpSli)
1787 {
1788 buildVal = BuildSLI(rtcp_buffer, position, (uint8_t)pictureID);
1789 if (buildVal == -1) {
1790 return -1;
1791 } else if (buildVal == -2) {
1792 return position;
1793 }
1794 }
1795 if(rtcpPacketTypeFlags & kRtcpRpsi)
1796 {
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001797 const int8_t payloadType = feedback_state.send_payload_type;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001798 if (payloadType == -1) {
1799 return -1;
1800 }
1801 buildVal = BuildRPSI(rtcp_buffer, position, pictureID,
1802 (uint8_t)payloadType);
1803 if (buildVal == -1) {
1804 return -1;
1805 } else if (buildVal == -2) {
1806 return position;
1807 }
1808 }
1809 if(rtcpPacketTypeFlags & kRtcpRemb)
1810 {
1811 buildVal = BuildREMB(rtcp_buffer, position);
1812 if (buildVal == -1) {
1813 return -1;
1814 } else if (buildVal == -2) {
1815 return position;
1816 }
1817 TRACE_EVENT_INSTANT0("webrtc_rtp", "RTCPSender::REMB");
1818 }
1819 if(rtcpPacketTypeFlags & kRtcpBye)
1820 {
1821 buildVal = BuildBYE(rtcp_buffer, position);
1822 if (buildVal == -1) {
1823 return -1;
1824 } else if (buildVal == -2) {
1825 return position;
1826 }
1827 }
1828 if(rtcpPacketTypeFlags & kRtcpApp)
1829 {
1830 buildVal = BuildAPP(rtcp_buffer, position);
1831 if (buildVal == -1) {
1832 return -1;
1833 } else if (buildVal == -2) {
1834 return position;
1835 }
1836 }
1837 if(rtcpPacketTypeFlags & kRtcpTmmbr)
1838 {
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001839 buildVal = BuildTMMBR(feedback_state.module, rtcp_buffer, position);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001840 if (buildVal == -1) {
1841 return -1;
1842 } else if (buildVal == -2) {
1843 return position;
1844 }
1845 }
1846 if(rtcpPacketTypeFlags & kRtcpTmmbn)
1847 {
1848 buildVal = BuildTMMBN(rtcp_buffer, position);
1849 if (buildVal == -1) {
1850 return -1;
1851 } else if (buildVal == -2) {
1852 return position;
1853 }
1854 }
1855 if(rtcpPacketTypeFlags & kRtcpNack)
1856 {
1857 std::string nackString;
1858 buildVal = BuildNACK(rtcp_buffer, position, nackSize, nackList,
1859 &nackString);
1860 if (buildVal == -1) {
1861 return -1;
1862 } else if (buildVal == -2) {
1863 return position;
1864 }
1865 TRACE_EVENT_INSTANT1("webrtc_rtp", "RTCPSender::NACK",
1866 "nacks", TRACE_STR_COPY(nackString.c_str()));
asapersson@webrtc.org8098e072014-02-19 11:59:02 +00001867 ++packet_type_counter_.nack_packets;
1868 TRACE_COUNTER_ID1("webrtc_rtp", "RTCP_NACKCount", _SSRC,
1869 packet_type_counter_.nack_packets);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001870 }
1871 if(rtcpPacketTypeFlags & kRtcpXrVoipMetric)
1872 {
1873 buildVal = BuildVoIPMetric(rtcp_buffer, position);
1874 if (buildVal == -1) {
1875 return -1;
1876 } else if (buildVal == -2) {
1877 return position;
1878 }
1879 }
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00001880 if (rtcpPacketTypeFlags & kRtcpXrReceiverReferenceTime)
1881 {
1882 buildVal = BuildReceiverReferenceTime(rtcp_buffer,
1883 position,
1884 NTPsec,
1885 NTPfrac);
1886 if (buildVal == -1) {
1887 return -1;
1888 } else if (buildVal == -2) {
1889 return position;
1890 }
1891 }
1892 if (rtcpPacketTypeFlags & kRtcpXrDlrrReportBlock)
1893 {
1894 buildVal = BuildDlrr(rtcp_buffer, position, feedback_state.last_xr_rr);
1895 if (buildVal == -1) {
1896 return -1;
1897 } else if (buildVal == -2) {
1898 return position;
1899 }
1900 }
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001901 return position;
1902}
1903
1904bool RTCPSender::ShouldSendReportBlocks(uint32_t rtcp_packet_type) const {
1905 return Status() == kRtcpCompound ||
1906 (rtcp_packet_type & kRtcpReport) ||
1907 (rtcp_packet_type & kRtcpSr) ||
1908 (rtcp_packet_type & kRtcpRr);
1909}
1910
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001911bool RTCPSender::PrepareReport(const FeedbackState& feedback_state,
1912 StreamStatistician* statistician,
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001913 RTCPReportBlock* report_block,
1914 uint32_t* ntp_secs, uint32_t* ntp_frac) {
1915 // Do we have receive statistics to send?
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +00001916 RtcpStatistics stats;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001917 if (!statistician->GetStatistics(&stats, true))
1918 return false;
1919 report_block->fractionLost = stats.fraction_lost;
1920 report_block->cumulativeLost = stats.cumulative_lost;
1921 report_block->extendedHighSeqNum =
1922 stats.extended_max_sequence_number;
1923 report_block->jitter = stats.jitter;
1924
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001925 // get our NTP as late as possible to avoid a race
1926 _clock->CurrentNtp(*ntp_secs, *ntp_frac);
1927
1928 // Delay since last received report
1929 uint32_t delaySinceLastReceivedSR = 0;
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001930 if ((feedback_state.last_rr_ntp_secs != 0) ||
1931 (feedback_state.last_rr_ntp_frac != 0)) {
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001932 // get the 16 lowest bits of seconds and the 16 higest bits of fractions
1933 uint32_t now=*ntp_secs&0x0000FFFF;
1934 now <<=16;
1935 now += (*ntp_frac&0xffff0000)>>16;
1936
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001937 uint32_t receiveTime = feedback_state.last_rr_ntp_secs&0x0000FFFF;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001938 receiveTime <<=16;
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001939 receiveTime += (feedback_state.last_rr_ntp_frac&0xffff0000)>>16;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001940
1941 delaySinceLastReceivedSR = now-receiveTime;
1942 }
1943 report_block->delaySinceLastSR = delaySinceLastReceivedSR;
pbos@webrtc.org59f20bb2013-09-09 16:02:19 +00001944 report_block->lastSR = feedback_state.remote_sr;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00001945 return true;
niklase@google.com470e71d2011-07-07 08:21:25 +00001946}
1947
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00001948int32_t RTCPSender::SendToNetwork(const uint8_t* dataBuffer, size_t length) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001949 CriticalSectionScoped lock(_criticalSectionTransport);
1950 if(_cbTransport)
1951 {
1952 if(_cbTransport->SendRTCPPacket(_id, dataBuffer, length) > 0)
1953 {
1954 return 0;
1955 }
1956 }
1957 return -1;
1958}
1959
pbos@webrtc.org9334ac22014-11-24 08:25:50 +00001960void RTCPSender::SetCsrcs(const std::vector<uint32_t>& csrcs) {
1961 assert(csrcs.size() <= kRtpCsrcSize);
1962 CriticalSectionScoped lock(_criticalSectionRTCPSender);
1963 csrcs_ = csrcs;
niklase@google.com470e71d2011-07-07 08:21:25 +00001964}
1965
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00001966int32_t RTCPSender::SetApplicationSpecificData(uint8_t subType,
1967 uint32_t name,
1968 const uint8_t* data,
1969 uint16_t length) {
niklase@google.com470e71d2011-07-07 08:21:25 +00001970 if(length %4 != 0)
1971 {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +00001972 LOG(LS_ERROR) << "Failed to SetApplicationSpecificData.";
niklase@google.com470e71d2011-07-07 08:21:25 +00001973 return -1;
1974 }
1975 CriticalSectionScoped lock(_criticalSectionRTCPSender);
1976
1977 if(_appData)
1978 {
1979 delete [] _appData;
1980 }
1981
1982 _appSend = true;
1983 _appSubType = subType;
1984 _appName = name;
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001985 _appData = new uint8_t[length];
niklase@google.com470e71d2011-07-07 08:21:25 +00001986 _appLength = length;
1987 memcpy(_appData, data, length);
1988 return 0;
1989}
1990
pbos@webrtc.org2f446732013-04-08 11:08:41 +00001991int32_t
niklase@google.com470e71d2011-07-07 08:21:25 +00001992RTCPSender::SetRTCPVoIPMetrics(const RTCPVoIPMetric* VoIPMetric)
1993{
1994 CriticalSectionScoped lock(_criticalSectionRTCPSender);
1995 memcpy(&_xrVoIPMetric, VoIPMetric, sizeof(RTCPVoIPMetric));
1996
1997 _xrSendVoIPMetric = true;
1998 return 0;
1999}
2000
asapersson@webrtc.org8469f7b2013-10-02 13:15:34 +00002001void RTCPSender::SendRtcpXrReceiverReferenceTime(bool enable) {
2002 CriticalSectionScoped lock(_criticalSectionRTCPSender);
2003 xrSendReceiverReferenceTimeEnabled_ = enable;
2004}
2005
asapersson@webrtc.org8d02f5d2013-11-21 08:57:04 +00002006bool RTCPSender::RtcpXrReceiverReferenceTime() const {
2007 CriticalSectionScoped lock(_criticalSectionRTCPSender);
2008 return xrSendReceiverReferenceTimeEnabled_;
2009}
2010
niklase@google.com470e71d2011-07-07 08:21:25 +00002011// called under critsect _criticalSectionRTCPSender
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00002012int32_t RTCPSender::WriteAllReportBlocksToBuffer(uint8_t* rtcpbuffer,
2013 int pos,
2014 uint8_t& numberOfReportBlocks,
2015 uint32_t NTPsec,
2016 uint32_t NTPfrac) {
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002017 numberOfReportBlocks = external_report_blocks_.size();
2018 numberOfReportBlocks += internal_report_blocks_.size();
2019 if ((pos + numberOfReportBlocks * 24) >= IP_PACKET_SIZE) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +00002020 LOG(LS_WARNING) << "Can't fit all report blocks.";
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002021 return -1;
2022 }
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002023 pos = WriteReportBlocksToBuffer(rtcpbuffer, pos, internal_report_blocks_);
2024 while (!internal_report_blocks_.empty()) {
2025 delete internal_report_blocks_.begin()->second;
2026 internal_report_blocks_.erase(internal_report_blocks_.begin());
2027 }
2028 pos = WriteReportBlocksToBuffer(rtcpbuffer, pos, external_report_blocks_);
2029 return pos;
2030}
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002031
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002032int32_t RTCPSender::WriteReportBlocksToBuffer(
2033 uint8_t* rtcpbuffer,
2034 int32_t position,
2035 const std::map<uint32_t, RTCPReportBlock*>& report_blocks) {
2036 std::map<uint32_t, RTCPReportBlock*>::const_iterator it =
2037 report_blocks.begin();
2038 for (; it != report_blocks.end(); it++) {
pbos@webrtc.org2f446732013-04-08 11:08:41 +00002039 uint32_t remoteSSRC = it->first;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002040 RTCPReportBlock* reportBlock = it->second;
2041 if (reportBlock) {
2042 // Remote SSRC
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00002043 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + position, remoteSSRC);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002044 position += 4;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002045
2046 // fraction lost
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002047 rtcpbuffer[position++] = reportBlock->fractionLost;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002048
2049 // cumulative loss
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00002050 RtpUtility::AssignUWord24ToBuffer(rtcpbuffer + position,
2051 reportBlock->cumulativeLost);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002052 position += 3;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002053
2054 // extended highest seq_no, contain the highest sequence number received
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00002055 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + position,
2056 reportBlock->extendedHighSeqNum);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002057 position += 4;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002058
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002059 // Jitter
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00002060 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + position,
2061 reportBlock->jitter);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002062 position += 4;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002063
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00002064 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + position,
2065 reportBlock->lastSR);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002066 position += 4;
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002067
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00002068 RtpUtility::AssignUWord32ToBuffer(rtcpbuffer + position,
2069 reportBlock->delaySinceLastSR);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002070 position += 4;
niklase@google.com470e71d2011-07-07 08:21:25 +00002071 }
pwestin@webrtc.org26f8d9c2012-01-19 15:53:09 +00002072 }
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +00002073 return position;
niklase@google.com470e71d2011-07-07 08:21:25 +00002074}
2075
2076// no callbacks allowed inside this function
pbos@webrtc.orgd16e8392014-12-19 13:49:55 +00002077int32_t RTCPSender::SetTMMBN(const TMMBRSet* boundingSet,
2078 uint32_t maxBitrateKbit) {
niklase@google.com470e71d2011-07-07 08:21:25 +00002079 CriticalSectionScoped lock(_criticalSectionRTCPSender);
2080
2081 if (0 == _tmmbrHelp.SetTMMBRBoundingSetToSend(boundingSet, maxBitrateKbit))
2082 {
2083 _sendTMMBN = true;
2084 return 0;
2085 }
2086 return -1;
2087}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +00002088} // namespace webrtc