blob: 07ce33620ba6e451af9e65c62618ed32b13b0f91 [file] [log] [blame]
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +00001/*
2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/modules/rtp_rtcp/source/rtcp_packet.h"
12
Erik Språngc1b9d4e2015-06-08 09:54:14 +020013#include "webrtc/base/checks.h"
sprang@webrtc.org779c3d12015-03-17 16:42:49 +000014#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +000015#include "webrtc/system_wrappers/interface/logging.h"
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +000016
asapersson@webrtc.org3b84b3a2014-06-25 12:22:17 +000017using webrtc::RTCPUtility::kBtDlrr;
18using webrtc::RTCPUtility::kBtReceiverReferenceTime;
19using webrtc::RTCPUtility::kBtVoipMetric;
20
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000021using webrtc::RTCPUtility::PT_APP;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000022using webrtc::RTCPUtility::PT_BYE;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000023using webrtc::RTCPUtility::PT_IJ;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000024using webrtc::RTCPUtility::PT_PSFB;
25using webrtc::RTCPUtility::PT_RR;
26using webrtc::RTCPUtility::PT_RTPFB;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000027using webrtc::RTCPUtility::PT_SDES;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000028using webrtc::RTCPUtility::PT_SR;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000029using webrtc::RTCPUtility::PT_XR;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000030
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000031using webrtc::RTCPUtility::RTCPPacketAPP;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000032using webrtc::RTCPUtility::RTCPPacketBYE;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000033using webrtc::RTCPUtility::RTCPPacketPSFBAPP;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000034using webrtc::RTCPUtility::RTCPPacketPSFBFIR;
35using webrtc::RTCPUtility::RTCPPacketPSFBFIRItem;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000036using webrtc::RTCPUtility::RTCPPacketPSFBPLI;
37using webrtc::RTCPUtility::RTCPPacketPSFBREMBItem;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000038using webrtc::RTCPUtility::RTCPPacketPSFBRPSI;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000039using webrtc::RTCPUtility::RTCPPacketPSFBSLI;
40using webrtc::RTCPUtility::RTCPPacketPSFBSLIItem;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000041using webrtc::RTCPUtility::RTCPPacketReportBlockItem;
42using webrtc::RTCPUtility::RTCPPacketRR;
43using webrtc::RTCPUtility::RTCPPacketRTPFBNACK;
44using webrtc::RTCPUtility::RTCPPacketRTPFBNACKItem;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000045using webrtc::RTCPUtility::RTCPPacketRTPFBTMMBN;
46using webrtc::RTCPUtility::RTCPPacketRTPFBTMMBNItem;
47using webrtc::RTCPUtility::RTCPPacketRTPFBTMMBR;
48using webrtc::RTCPUtility::RTCPPacketRTPFBTMMBRItem;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000049using webrtc::RTCPUtility::RTCPPacketSR;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000050using webrtc::RTCPUtility::RTCPPacketXRDLRRReportBlockItem;
51using webrtc::RTCPUtility::RTCPPacketXRReceiverReferenceTimeItem;
52using webrtc::RTCPUtility::RTCPPacketXR;
53using webrtc::RTCPUtility::RTCPPacketXRVOIPMetricItem;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000054
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +000055namespace webrtc {
56namespace rtcp {
57namespace {
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000058// Unused SSRC of media source, set to 0.
59const uint32_t kUnusedMediaSourceSsrc0 = 0;
60
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000061void AssignUWord8(uint8_t* buffer, size_t* offset, uint8_t value) {
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +000062 buffer[(*offset)++] = value;
63}
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000064void AssignUWord16(uint8_t* buffer, size_t* offset, uint16_t value) {
sprang@webrtc.org779c3d12015-03-17 16:42:49 +000065 ByteWriter<uint16_t>::WriteBigEndian(buffer + *offset, value);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +000066 *offset += 2;
67}
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000068void AssignUWord24(uint8_t* buffer, size_t* offset, uint32_t value) {
sprang@webrtc.org779c3d12015-03-17 16:42:49 +000069 ByteWriter<uint32_t, 3>::WriteBigEndian(buffer + *offset, value);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +000070 *offset += 3;
71}
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000072void AssignUWord32(uint8_t* buffer, size_t* offset, uint32_t value) {
sprang@webrtc.org779c3d12015-03-17 16:42:49 +000073 ByteWriter<uint32_t>::WriteBigEndian(buffer + *offset, value);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +000074 *offset += 4;
75}
76
asapersson@webrtc.org3b84b3a2014-06-25 12:22:17 +000077void ComputeMantissaAnd6bitBase2Exponent(uint32_t input_base10,
78 uint8_t bits_mantissa,
79 uint32_t* mantissa,
80 uint8_t* exp) {
81 // input_base10 = mantissa * 2^exp
82 assert(bits_mantissa <= 32);
83 uint32_t mantissa_max = (1 << bits_mantissa) - 1;
84 uint8_t exponent = 0;
85 for (uint32_t i = 0; i < 64; ++i) {
86 if (input_base10 <= (mantissa_max << i)) {
87 exponent = i;
88 break;
89 }
90 }
91 *exp = exponent;
92 *mantissa = (input_base10 >> exponent);
93}
94
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000095size_t BlockToHeaderLength(size_t length_in_bytes) {
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000096 // Length in 32-bit words minus 1.
97 assert(length_in_bytes > 0);
98 assert(length_in_bytes % 4 == 0);
99 return (length_in_bytes / 4) - 1;
100}
101
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000102// From RFC 3550, RTP: A Transport Protocol for Real-Time Applications.
103//
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000104// RTP header format.
105// 0 1 2 3
106// 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
107// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
108// |V=2|P| RC/FMT | PT | length |
109// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
110
111void CreateHeader(uint8_t count_or_format, // Depends on packet type.
112 uint8_t packet_type,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000113 size_t length,
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000114 uint8_t* buffer,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000115 size_t* pos) {
116 assert(length <= 0xffff);
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000117 const uint8_t kVersion = 2;
118 AssignUWord8(buffer, pos, (kVersion << 6) + count_or_format);
119 AssignUWord8(buffer, pos, packet_type);
120 AssignUWord16(buffer, pos, length);
121}
122
123// Sender report (SR) (RFC 3550).
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000124// 0 1 2 3
125// 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
126// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
127// |V=2|P| RC | PT=SR=200 | length |
128// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
129// | SSRC of sender |
130// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
131// | NTP timestamp, most significant word |
132// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
133// | NTP timestamp, least significant word |
134// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
135// | RTP timestamp |
136// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
137// | sender's packet count |
138// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
139// | sender's octet count |
140// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
141
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000142void CreateSenderReport(const RTCPPacketSR& sr,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000143 size_t length,
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000144 uint8_t* buffer,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000145 size_t* pos) {
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000146 CreateHeader(sr.NumberOfReportBlocks, PT_SR, length, buffer, pos);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000147 AssignUWord32(buffer, pos, sr.SenderSSRC);
148 AssignUWord32(buffer, pos, sr.NTPMostSignificant);
149 AssignUWord32(buffer, pos, sr.NTPLeastSignificant);
150 AssignUWord32(buffer, pos, sr.RTPTimestamp);
151 AssignUWord32(buffer, pos, sr.SenderPacketCount);
152 AssignUWord32(buffer, pos, sr.SenderOctetCount);
153}
154
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000155// Receiver report (RR), header (RFC 3550).
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000156//
157// 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
158// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
159// |V=2|P| RC | PT=RR=201 | length |
160// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
161// | SSRC of packet sender |
162// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
163
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000164void CreateReceiverReport(const RTCPPacketRR& rr,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000165 size_t length,
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000166 uint8_t* buffer,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000167 size_t* pos) {
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000168 CreateHeader(rr.NumberOfReportBlocks, PT_RR, length, buffer, pos);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000169 AssignUWord32(buffer, pos, rr.SenderSSRC);
170}
171
172// Report block (RFC 3550).
173//
174// 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
175// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
176// | SSRC_1 (SSRC of first source) |
177// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
178// | fraction lost | cumulative number of packets lost |
179// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
180// | extended highest sequence number received |
181// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
182// | interarrival jitter |
183// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
184// | last SR (LSR) |
185// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
186// | delay since last SR (DLSR) |
187// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
188
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000189void CreateReportBlocks(const std::vector<RTCPPacketReportBlockItem>& blocks,
190 uint8_t* buffer,
191 size_t* pos) {
192 for (std::vector<RTCPPacketReportBlockItem>::const_iterator
193 it = blocks.begin(); it != blocks.end(); ++it) {
194 AssignUWord32(buffer, pos, (*it).SSRC);
195 AssignUWord8(buffer, pos, (*it).FractionLost);
196 AssignUWord24(buffer, pos, (*it).CumulativeNumOfPacketsLost);
197 AssignUWord32(buffer, pos, (*it).ExtendedHighestSequenceNumber);
198 AssignUWord32(buffer, pos, (*it).Jitter);
199 AssignUWord32(buffer, pos, (*it).LastSR);
200 AssignUWord32(buffer, pos, (*it).DelayLastSR);
201 }
202}
203
204// Transmission Time Offsets in RTP Streams (RFC 5450).
205//
206// 0 1 2 3
207// 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
208// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
209// hdr |V=2|P| RC | PT=IJ=195 | length |
210// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
211// | inter-arrival jitter |
212// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
213// . .
214// . .
215// . .
216// | inter-arrival jitter |
217// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
218
219void CreateIj(const std::vector<uint32_t>& ij_items,
220 uint8_t* buffer,
221 size_t* pos) {
222 size_t length = ij_items.size();
223 CreateHeader(length, PT_IJ, length, buffer, pos);
224 for (std::vector<uint32_t>::const_iterator it = ij_items.begin();
225 it != ij_items.end(); ++it) {
226 AssignUWord32(buffer, pos, *it);
227 }
228}
229
230// Source Description (SDES) (RFC 3550).
231//
232// 0 1 2 3
233// 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
234// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
235// header |V=2|P| SC | PT=SDES=202 | length |
236// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
237// chunk | SSRC/CSRC_1 |
238// 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
239// | SDES items |
240// | ... |
241// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
242// chunk | SSRC/CSRC_2 |
243// 2 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
244// | SDES items |
245// | ... |
246// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
247//
248// Canonical End-Point Identifier SDES Item (CNAME)
249//
250// 0 1 2 3
251// 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
252// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
253// | CNAME=1 | length | user and domain name ...
254// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
255
256void CreateSdes(const std::vector<Sdes::Chunk>& chunks,
257 size_t length,
258 uint8_t* buffer,
259 size_t* pos) {
260 CreateHeader(chunks.size(), PT_SDES, length, buffer, pos);
261 const uint8_t kSdesItemType = 1;
262 for (std::vector<Sdes::Chunk>::const_iterator it = chunks.begin();
263 it != chunks.end(); ++it) {
264 AssignUWord32(buffer, pos, (*it).ssrc);
265 AssignUWord8(buffer, pos, kSdesItemType);
266 AssignUWord8(buffer, pos, (*it).name.length());
267 memcpy(buffer + *pos, (*it).name.data(), (*it).name.length());
268 *pos += (*it).name.length();
269 memset(buffer + *pos, 0, (*it).null_octets);
270 *pos += (*it).null_octets;
271 }
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000272}
273
274// Bye packet (BYE) (RFC 3550).
275//
276// 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
277// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
278// |V=2|P| SC | PT=BYE=203 | length |
279// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
280// | SSRC/CSRC |
281// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
282// : ... :
283// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
284// (opt) | length | reason for leaving ...
285// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
286
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000287void CreateBye(const RTCPPacketBYE& bye,
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000288 const std::vector<uint32_t>& csrcs,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000289 size_t length,
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000290 uint8_t* buffer,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000291 size_t* pos) {
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000292 CreateHeader(length, PT_BYE, length, buffer, pos);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000293 AssignUWord32(buffer, pos, bye.SenderSSRC);
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200294 for (uint32_t csrc : csrcs)
295 AssignUWord32(buffer, pos, csrc);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000296}
297
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000298// Application-Defined packet (APP) (RFC 3550).
299//
300// 0 1 2 3
301// 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
302// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
303// |V=2|P| subtype | PT=APP=204 | length |
304// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
305// | SSRC/CSRC |
306// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
307// | name (ASCII) |
308// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
309// | application-dependent data ...
310// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
311
312void CreateApp(const RTCPPacketAPP& app,
313 uint32_t ssrc,
314 size_t length,
315 uint8_t* buffer,
316 size_t* pos) {
317 CreateHeader(app.SubType, PT_APP, length, buffer, pos);
318 AssignUWord32(buffer, pos, ssrc);
319 AssignUWord32(buffer, pos, app.Name);
320 memcpy(buffer + *pos, app.Data, app.Size);
321 *pos += app.Size;
322}
323
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000324// RFC 4585: Feedback format.
325//
326// Common packet format:
327//
328// 0 1 2 3
329// 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
330// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
331// |V=2|P| FMT | PT | length |
332// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
333// | SSRC of packet sender |
334// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
335// | SSRC of media source |
336// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
337// : Feedback Control Information (FCI) :
338// :
339//
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000340
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000341// Picture loss indication (PLI) (RFC 4585).
342//
343// FCI: no feedback control information.
344
345void CreatePli(const RTCPPacketPSFBPLI& pli,
346 size_t length,
347 uint8_t* buffer,
348 size_t* pos) {
349 const uint8_t kFmt = 1;
350 CreateHeader(kFmt, PT_PSFB, length, buffer, pos);
351 AssignUWord32(buffer, pos, pli.SenderSSRC);
352 AssignUWord32(buffer, pos, pli.MediaSSRC);
353}
354
355// Slice loss indication (SLI) (RFC 4585).
356//
357// FCI:
358//
359// 0 1 2 3
360// 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
361// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
362// | First | Number | PictureID |
363// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
364
365void CreateSli(const RTCPPacketPSFBSLI& sli,
366 const RTCPPacketPSFBSLIItem& sli_item,
367 size_t length,
368 uint8_t* buffer,
369 size_t* pos) {
370 const uint8_t kFmt = 2;
371 CreateHeader(kFmt, PT_PSFB, length, buffer, pos);
372 AssignUWord32(buffer, pos, sli.SenderSSRC);
373 AssignUWord32(buffer, pos, sli.MediaSSRC);
374
375 AssignUWord8(buffer, pos, sli_item.FirstMB >> 5);
376 AssignUWord8(buffer, pos, (sli_item.FirstMB << 3) +
377 ((sli_item.NumberOfMB >> 10) & 0x07));
378 AssignUWord8(buffer, pos, sli_item.NumberOfMB >> 2);
379 AssignUWord8(buffer, pos, (sli_item.NumberOfMB << 6) + sli_item.PictureId);
380}
381
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000382// Generic NACK (RFC 4585).
383//
384// FCI:
385//
386// 0 1 2 3
387// 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
388// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
389// | PID | BLP |
390// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
391
392void CreateNack(const RTCPPacketRTPFBNACK& nack,
393 const std::vector<RTCPPacketRTPFBNACKItem>& nack_fields,
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200394 size_t start_index,
395 size_t end_index,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000396 size_t length,
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000397 uint8_t* buffer,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000398 size_t* pos) {
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000399 const uint8_t kFmt = 1;
400 CreateHeader(kFmt, PT_RTPFB, length, buffer, pos);
401 AssignUWord32(buffer, pos, nack.SenderSSRC);
402 AssignUWord32(buffer, pos, nack.MediaSSRC);
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200403 for (size_t i = start_index; i < end_index; ++i) {
404 const RTCPPacketRTPFBNACKItem& nack_item = nack_fields[i];
405 AssignUWord16(buffer, pos, nack_item.PacketID);
406 AssignUWord16(buffer, pos, nack_item.BitMask);
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000407 }
408}
409
410// Reference picture selection indication (RPSI) (RFC 4585).
411//
412// FCI:
413//
414// 0 1 2 3
415// 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
416// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
417// | PB |0| Payload Type| Native RPSI bit string |
418// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
419// | defined per codec ... | Padding (0) |
420// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
421
422void CreateRpsi(const RTCPPacketPSFBRPSI& rpsi,
423 uint8_t padding_bytes,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000424 size_t length,
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000425 uint8_t* buffer,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000426 size_t* pos) {
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000427 // Native bit string should be a multiple of 8 bits.
428 assert(rpsi.NumberOfValidBits % 8 == 0);
429 const uint8_t kFmt = 3;
430 CreateHeader(kFmt, PT_PSFB, length, buffer, pos);
431 AssignUWord32(buffer, pos, rpsi.SenderSSRC);
432 AssignUWord32(buffer, pos, rpsi.MediaSSRC);
433 AssignUWord8(buffer, pos, padding_bytes * 8);
434 AssignUWord8(buffer, pos, rpsi.PayloadType);
435 memcpy(buffer + *pos, rpsi.NativeBitString, rpsi.NumberOfValidBits / 8);
436 *pos += rpsi.NumberOfValidBits / 8;
437 memset(buffer + *pos, 0, padding_bytes);
438 *pos += padding_bytes;
439}
440
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000441// Full intra request (FIR) (RFC 5104).
442//
443// FCI:
444//
445// 0 1 2 3
446// 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
447// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
448// | SSRC |
449// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
450// | Seq nr. | Reserved |
451// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
452
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000453void CreateFir(const RTCPPacketPSFBFIR& fir,
454 const RTCPPacketPSFBFIRItem& fir_item,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000455 size_t length,
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000456 uint8_t* buffer,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000457 size_t* pos) {
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000458 const uint8_t kFmt = 4;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000459 CreateHeader(kFmt, PT_PSFB, length, buffer, pos);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000460 AssignUWord32(buffer, pos, fir.SenderSSRC);
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000461 AssignUWord32(buffer, pos, kUnusedMediaSourceSsrc0);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000462 AssignUWord32(buffer, pos, fir_item.SSRC);
463 AssignUWord8(buffer, pos, fir_item.CommandSequenceNumber);
464 AssignUWord24(buffer, pos, 0);
465}
asapersson@webrtc.org3b84b3a2014-06-25 12:22:17 +0000466
467void CreateTmmbrItem(const RTCPPacketRTPFBTMMBRItem& tmmbr_item,
468 uint8_t* buffer,
469 size_t* pos) {
470 uint32_t bitrate_bps = tmmbr_item.MaxTotalMediaBitRate * 1000;
471 uint32_t mantissa = 0;
472 uint8_t exp = 0;
473 ComputeMantissaAnd6bitBase2Exponent(bitrate_bps, 17, &mantissa, &exp);
474
475 AssignUWord32(buffer, pos, tmmbr_item.SSRC);
476 AssignUWord8(buffer, pos, (exp << 2) + ((mantissa >> 15) & 0x03));
477 AssignUWord8(buffer, pos, mantissa >> 7);
478 AssignUWord8(buffer, pos, (mantissa << 1) +
479 ((tmmbr_item.MeasuredOverhead >> 8) & 0x01));
480 AssignUWord8(buffer, pos, tmmbr_item.MeasuredOverhead);
481}
482
483// Temporary Maximum Media Stream Bit Rate Request (TMMBR) (RFC 5104).
484//
485// FCI:
486//
487// 0 1 2 3
488// 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
489// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
490// | SSRC |
491// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
492// | MxTBR Exp | MxTBR Mantissa |Measured Overhead|
493// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
494
495void CreateTmmbr(const RTCPPacketRTPFBTMMBR& tmmbr,
496 const RTCPPacketRTPFBTMMBRItem& tmmbr_item,
497 size_t length,
498 uint8_t* buffer,
499 size_t* pos) {
500 const uint8_t kFmt = 3;
501 CreateHeader(kFmt, PT_RTPFB, length, buffer, pos);
502 AssignUWord32(buffer, pos, tmmbr.SenderSSRC);
503 AssignUWord32(buffer, pos, kUnusedMediaSourceSsrc0);
504 CreateTmmbrItem(tmmbr_item, buffer, pos);
505}
506
507// Temporary Maximum Media Stream Bit Rate Notification (TMMBN) (RFC 5104).
508//
509// FCI:
510//
511// 0 1 2 3
512// 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
513// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
514// | SSRC |
515// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
516// | MxTBR Exp | MxTBR Mantissa |Measured Overhead|
517// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
518
519void CreateTmmbn(const RTCPPacketRTPFBTMMBN& tmmbn,
520 const std::vector<RTCPPacketRTPFBTMMBRItem>& tmmbn_items,
521 size_t length,
522 uint8_t* buffer,
523 size_t* pos) {
524 const uint8_t kFmt = 4;
525 CreateHeader(kFmt, PT_RTPFB, length, buffer, pos);
526 AssignUWord32(buffer, pos, tmmbn.SenderSSRC);
527 AssignUWord32(buffer, pos, kUnusedMediaSourceSsrc0);
528 for (uint8_t i = 0; i < tmmbn_items.size(); ++i) {
529 CreateTmmbrItem(tmmbn_items[i], buffer, pos);
530 }
531}
532
533// Receiver Estimated Max Bitrate (REMB) (draft-alvestrand-rmcat-remb).
534//
535// 0 1 2 3
536// 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
537// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
538// |V=2|P| FMT=15 | PT=206 | length |
539// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
540// | SSRC of packet sender |
541// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
542// | SSRC of media source |
543// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
544// | Unique identifier 'R' 'E' 'M' 'B' |
545// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
546// | Num SSRC | BR Exp | BR Mantissa |
547// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
548// | SSRC feedback |
549// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
550// | ... |
551
552void CreateRemb(const RTCPPacketPSFBAPP& remb,
553 const RTCPPacketPSFBREMBItem& remb_item,
554 size_t length,
555 uint8_t* buffer,
556 size_t* pos) {
557 uint32_t mantissa = 0;
558 uint8_t exp = 0;
559 ComputeMantissaAnd6bitBase2Exponent(remb_item.BitRate, 18, &mantissa, &exp);
560
561 const uint8_t kFmt = 15;
562 CreateHeader(kFmt, PT_PSFB, length, buffer, pos);
563 AssignUWord32(buffer, pos, remb.SenderSSRC);
564 AssignUWord32(buffer, pos, kUnusedMediaSourceSsrc0);
565 AssignUWord8(buffer, pos, 'R');
566 AssignUWord8(buffer, pos, 'E');
567 AssignUWord8(buffer, pos, 'M');
568 AssignUWord8(buffer, pos, 'B');
569 AssignUWord8(buffer, pos, remb_item.NumberOfSSRCs);
570 AssignUWord8(buffer, pos, (exp << 2) + ((mantissa >> 16) & 0x03));
571 AssignUWord8(buffer, pos, mantissa >> 8);
572 AssignUWord8(buffer, pos, mantissa);
573 for (uint8_t i = 0; i < remb_item.NumberOfSSRCs; ++i) {
574 AssignUWord32(buffer, pos, remb_item.SSRCs[i]);
575 }
576}
577
578// From RFC 3611: RTP Control Protocol Extended Reports (RTCP XR).
579//
580// Format for XR packets:
581//
582// 0 1 2 3
583// 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
584// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
585// |V=2|P|reserved | PT=XR=207 | length |
586// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
587// | SSRC |
588// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
589// : report blocks :
590// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
591
592void CreateXrHeader(const RTCPPacketXR& header,
593 size_t length,
594 uint8_t* buffer,
595 size_t* pos) {
596 CreateHeader(0U, PT_XR, length, buffer, pos);
597 AssignUWord32(buffer, pos, header.OriginatorSSRC);
598}
599
600void CreateXrBlockHeader(uint8_t block_type,
601 uint16_t block_length,
602 uint8_t* buffer,
603 size_t* pos) {
604 AssignUWord8(buffer, pos, block_type);
605 AssignUWord8(buffer, pos, 0);
606 AssignUWord16(buffer, pos, block_length);
607}
608
609// Receiver Reference Time Report Block (RFC 3611).
610//
611// 0 1 2 3
612// 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
613// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
614// | BT=4 | reserved | block length = 2 |
615// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
616// | NTP timestamp, most significant word |
617// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
618// | NTP timestamp, least significant word |
619// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
620
621void CreateRrtr(const std::vector<RTCPPacketXRReceiverReferenceTimeItem>& rrtrs,
622 uint8_t* buffer,
623 size_t* pos) {
624 const uint16_t kBlockLength = 2;
625 for (std::vector<RTCPPacketXRReceiverReferenceTimeItem>::const_iterator it =
626 rrtrs.begin(); it != rrtrs.end(); ++it) {
627 CreateXrBlockHeader(kBtReceiverReferenceTime, kBlockLength, buffer, pos);
628 AssignUWord32(buffer, pos, (*it).NTPMostSignificant);
629 AssignUWord32(buffer, pos, (*it).NTPLeastSignificant);
630 }
631}
632
633// DLRR Report Block (RFC 3611).
634//
635// 0 1 2 3
636// 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
637// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
638// | BT=5 | reserved | block length |
639// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
640// | SSRC_1 (SSRC of first receiver) | sub-
641// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
642// | last RR (LRR) | 1
643// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
644// | delay since last RR (DLRR) |
645// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
646// | SSRC_2 (SSRC of second receiver) | sub-
647// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
648// : ... : 2
649
650void CreateDlrr(const std::vector<Xr::DlrrBlock>& dlrrs,
651 uint8_t* buffer,
652 size_t* pos) {
653 for (std::vector<Xr::DlrrBlock>::const_iterator it = dlrrs.begin();
654 it != dlrrs.end(); ++it) {
655 if ((*it).empty()) {
656 continue;
657 }
658 uint16_t block_length = 3 * (*it).size();
659 CreateXrBlockHeader(kBtDlrr, block_length, buffer, pos);
660 for (Xr::DlrrBlock::const_iterator it_block = (*it).begin();
661 it_block != (*it).end(); ++it_block) {
662 AssignUWord32(buffer, pos, (*it_block).SSRC);
663 AssignUWord32(buffer, pos, (*it_block).LastRR);
664 AssignUWord32(buffer, pos, (*it_block).DelayLastRR);
665 }
666 }
667}
668
669// VoIP Metrics Report Block (RFC 3611).
670//
671// 0 1 2 3
672// 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
673// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
674// | BT=7 | reserved | block length = 8 |
675// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
676// | SSRC of source |
677// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
678// | loss rate | discard rate | burst density | gap density |
679// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
680// | burst duration | gap duration |
681// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
682// | round trip delay | end system delay |
683// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
684// | signal level | noise level | RERL | Gmin |
685// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
686// | R factor | ext. R factor | MOS-LQ | MOS-CQ |
687// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
688// | RX config | reserved | JB nominal |
689// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
690// | JB maximum | JB abs max |
691// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
692
693void CreateVoipMetric(const std::vector<RTCPPacketXRVOIPMetricItem>& metrics,
694 uint8_t* buffer,
695 size_t* pos) {
696 const uint16_t kBlockLength = 8;
697 for (std::vector<RTCPPacketXRVOIPMetricItem>::const_iterator it =
698 metrics.begin(); it != metrics.end(); ++it) {
699 CreateXrBlockHeader(kBtVoipMetric, kBlockLength, buffer, pos);
700 AssignUWord32(buffer, pos, (*it).SSRC);
701 AssignUWord8(buffer, pos, (*it).lossRate);
702 AssignUWord8(buffer, pos, (*it).discardRate);
703 AssignUWord8(buffer, pos, (*it).burstDensity);
704 AssignUWord8(buffer, pos, (*it).gapDensity);
705 AssignUWord16(buffer, pos, (*it).burstDuration);
706 AssignUWord16(buffer, pos, (*it).gapDuration);
707 AssignUWord16(buffer, pos, (*it).roundTripDelay);
708 AssignUWord16(buffer, pos, (*it).endSystemDelay);
709 AssignUWord8(buffer, pos, (*it).signalLevel);
710 AssignUWord8(buffer, pos, (*it).noiseLevel);
711 AssignUWord8(buffer, pos, (*it).RERL);
712 AssignUWord8(buffer, pos, (*it).Gmin);
713 AssignUWord8(buffer, pos, (*it).Rfactor);
714 AssignUWord8(buffer, pos, (*it).extRfactor);
715 AssignUWord8(buffer, pos, (*it).MOSLQ);
716 AssignUWord8(buffer, pos, (*it).MOSCQ);
717 AssignUWord8(buffer, pos, (*it).RXconfig);
718 AssignUWord8(buffer, pos, 0);
719 AssignUWord16(buffer, pos, (*it).JBnominal);
720 AssignUWord16(buffer, pos, (*it).JBmax);
721 AssignUWord16(buffer, pos, (*it).JBabsMax);
722 }
723}
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000724} // namespace
725
726void RtcpPacket::Append(RtcpPacket* packet) {
727 assert(packet);
728 appended_packets_.push_back(packet);
729}
730
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200731rtc::scoped_ptr<RawPacket> RtcpPacket::Build() const {
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000732 size_t length = 0;
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200733 rtc::scoped_ptr<RawPacket> packet(new RawPacket(IP_PACKET_SIZE));
734
735 class PacketVerifier : public PacketReadyCallback {
736 public:
737 explicit PacketVerifier(RawPacket* packet)
738 : called_(false), packet_(packet) {}
739 virtual ~PacketVerifier() {}
740 void OnPacketReady(uint8_t* data, size_t length) override {
741 CHECK(!called_) << "Fragmentation not supported.";
742 called_ = true;
743 packet_->SetLength(length);
744 }
745
746 private:
747 bool called_;
748 RawPacket* const packet_;
749 } verifier(packet.get());
750 CreateAndAddAppended(packet->MutableBuffer(), &length, packet->BufferLength(),
751 &verifier);
752 OnBufferFull(packet->MutableBuffer(), &length, &verifier);
753 return packet;
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000754}
755
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200756bool RtcpPacket::Build(PacketReadyCallback* callback) const {
757 uint8_t buffer[IP_PACKET_SIZE];
758 return BuildExternalBuffer(buffer, IP_PACKET_SIZE, callback);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000759}
760
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200761bool RtcpPacket::BuildExternalBuffer(uint8_t* buffer,
762 size_t max_length,
763 PacketReadyCallback* callback) const {
764 size_t index = 0;
765 if (!CreateAndAddAppended(buffer, &index, max_length, callback))
766 return false;
767 return OnBufferFull(buffer, &index, callback);
768}
769
770bool RtcpPacket::CreateAndAddAppended(uint8_t* packet,
771 size_t* index,
772 size_t max_length,
773 PacketReadyCallback* callback) const {
774 if (!Create(packet, index, max_length, callback))
775 return false;
776 for (RtcpPacket* appended : appended_packets_) {
777 if (!appended->CreateAndAddAppended(packet, index, max_length, callback))
778 return false;
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000779 }
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200780 return true;
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000781}
782
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200783bool RtcpPacket::OnBufferFull(uint8_t* packet,
784 size_t* index,
785 RtcpPacket::PacketReadyCallback* callback) const {
786 if (*index == 0)
787 return false;
788 callback->OnPacketReady(packet, *index);
789 *index = 0;
790 return true;
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000791}
792
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200793bool Empty::Create(uint8_t* packet,
794 size_t* index,
795 size_t max_length,
796 RtcpPacket::PacketReadyCallback* callback) const {
797 return true;
798}
799
800bool SenderReport::Create(uint8_t* packet,
801 size_t* index,
802 size_t max_length,
803 RtcpPacket::PacketReadyCallback* callback) const {
804 while (*index + BlockLength() > max_length) {
805 if (!OnBufferFull(packet, index, callback))
806 return false;
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000807 }
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200808 CreateSenderReport(sr_, BlockToHeaderLength(BlockLength()), packet, index);
809 CreateReportBlocks(report_blocks_, packet, index);
810 return true;
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000811}
812
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200813bool SenderReport::WithReportBlock(ReportBlock* block) {
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000814 assert(block);
815 if (report_blocks_.size() >= kMaxNumberOfReportBlocks) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000816 LOG(LS_WARNING) << "Max report blocks reached.";
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200817 return false;
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000818 }
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000819 report_blocks_.push_back(block->report_block_);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000820 sr_.NumberOfReportBlocks = report_blocks_.size();
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200821 return true;
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000822}
823
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200824bool ReceiverReport::Create(uint8_t* packet,
825 size_t* index,
826 size_t max_length,
827 RtcpPacket::PacketReadyCallback* callback) const {
828 while (*index + BlockLength() > max_length) {
829 if (!OnBufferFull(packet, index, callback))
830 return false;
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000831 }
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200832 CreateReceiverReport(rr_, BlockToHeaderLength(BlockLength()), packet, index);
833 CreateReportBlocks(report_blocks_, packet, index);
834 return true;
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000835}
836
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200837bool ReceiverReport::WithReportBlock(ReportBlock* block) {
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000838 assert(block);
839 if (report_blocks_.size() >= kMaxNumberOfReportBlocks) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000840 LOG(LS_WARNING) << "Max report blocks reached.";
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200841 return false;
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000842 }
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000843 report_blocks_.push_back(block->report_block_);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000844 rr_.NumberOfReportBlocks = report_blocks_.size();
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200845 return true;
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000846}
847
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200848bool Ij::Create(uint8_t* packet,
849 size_t* index,
850 size_t max_length,
851 RtcpPacket::PacketReadyCallback* callback) const {
852 while (*index + BlockLength() > max_length) {
853 if (!OnBufferFull(packet, index, callback))
854 return false;
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000855 }
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200856 CreateIj(ij_items_, packet, index);
857 return true;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000858}
859
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200860bool Ij::WithJitterItem(uint32_t jitter) {
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000861 if (ij_items_.size() >= kMaxNumberOfIjItems) {
862 LOG(LS_WARNING) << "Max inter-arrival jitter items reached.";
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200863 return false;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000864 }
865 ij_items_.push_back(jitter);
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200866 return true;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000867}
868
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200869bool Sdes::Create(uint8_t* packet,
870 size_t* index,
871 size_t max_length,
872 RtcpPacket::PacketReadyCallback* callback) const {
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000873 assert(!chunks_.empty());
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200874 while (*index + BlockLength() > max_length) {
875 if (!OnBufferFull(packet, index, callback))
876 return false;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000877 }
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200878 CreateSdes(chunks_, BlockToHeaderLength(BlockLength()), packet, index);
879 return true;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000880}
881
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200882bool Sdes::WithCName(uint32_t ssrc, const std::string& cname) {
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000883 assert(cname.length() <= 0xff);
884 if (chunks_.size() >= kMaxNumberOfChunks) {
885 LOG(LS_WARNING) << "Max SDES chunks reached.";
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200886 return false;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000887 }
888 // In each chunk, the list of items must be terminated by one or more null
889 // octets. The next chunk must start on a 32-bit boundary.
890 // CNAME (1 byte) | length (1 byte) | name | padding.
891 int null_octets = 4 - ((2 + cname.length()) % 4);
892 Chunk chunk;
893 chunk.ssrc = ssrc;
894 chunk.name = cname;
895 chunk.null_octets = null_octets;
896 chunks_.push_back(chunk);
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200897 return true;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000898}
899
900size_t Sdes::BlockLength() const {
901 // Header (4 bytes).
902 // Chunk:
903 // SSRC/CSRC (4 bytes) | CNAME (1 byte) | length (1 byte) | name | padding.
904 size_t length = kHeaderLength;
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200905 for (const Chunk& chunk : chunks_)
906 length += 6 + chunk.name.length() + chunk.null_octets;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000907 assert(length % 4 == 0);
908 return length;
909}
910
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200911bool Bye::Create(uint8_t* packet,
912 size_t* index,
913 size_t max_length,
914 RtcpPacket::PacketReadyCallback* callback) const {
915 while (*index + BlockLength() > max_length) {
916 if (!OnBufferFull(packet, index, callback))
917 return false;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000918 }
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200919 CreateBye(bye_, csrcs_, BlockToHeaderLength(BlockLength()), packet, index);
920 return true;
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000921}
922
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200923bool Bye::WithCsrc(uint32_t csrc) {
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000924 if (csrcs_.size() >= kMaxNumberOfCsrcs) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000925 LOG(LS_WARNING) << "Max CSRC size reached.";
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200926 return false;
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000927 }
928 csrcs_.push_back(csrc);
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200929 return true;
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000930}
931
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200932bool App::Create(uint8_t* packet,
933 size_t* index,
934 size_t max_length,
935 RtcpPacket::PacketReadyCallback* callback) const {
936 while (*index + BlockLength() > max_length) {
937 if (!OnBufferFull(packet, index, callback))
938 return false;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000939 }
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200940 CreateApp(app_, ssrc_, BlockToHeaderLength(BlockLength()), packet, index);
941 return true;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000942}
943
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200944bool Pli::Create(uint8_t* packet,
945 size_t* index,
946 size_t max_length,
947 RtcpPacket::PacketReadyCallback* callback) const {
948 while (*index + BlockLength() > max_length) {
949 if (!OnBufferFull(packet, index, callback))
950 return false;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000951 }
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200952 CreatePli(pli_, BlockToHeaderLength(BlockLength()), packet, index);
953 return true;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000954}
955
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200956bool Sli::Create(uint8_t* packet,
957 size_t* index,
958 size_t max_length,
959 RtcpPacket::PacketReadyCallback* callback) const {
960 while (*index + BlockLength() > max_length) {
961 if (!OnBufferFull(packet, index, callback))
962 return false;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000963 }
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200964 CreateSli(sli_, sli_item_, BlockToHeaderLength(BlockLength()), packet, index);
965 return true;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000966}
967
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200968bool Nack::Create(uint8_t* packet,
969 size_t* index,
970 size_t max_length,
971 RtcpPacket::PacketReadyCallback* callback) const {
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000972 assert(!nack_fields_.empty());
Erik Språngc1b9d4e2015-06-08 09:54:14 +0200973 // If nack list can't fit in packet, try to fragment.
974 size_t nack_index = 0;
975 do {
976 size_t bytes_left_in_buffer = max_length - *index;
977 if (bytes_left_in_buffer < kCommonFbFmtLength + 4) {
978 if (!OnBufferFull(packet, index, callback))
979 return false;
980 continue;
981 }
982 int64_t num_nack_fields =
983 std::min((bytes_left_in_buffer - kCommonFbFmtLength) / 4,
984 nack_fields_.size() - nack_index);
985
986 CreateNack(nack_, nack_fields_, nack_index, nack_index + num_nack_fields,
987 BlockToHeaderLength((num_nack_fields * 4) + kCommonFbFmtLength),
988 packet, index);
989
990 nack_index += num_nack_fields;
991 } while (nack_index < nack_fields_.size());
992
993 return true;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000994}
995
996void Nack::WithList(const uint16_t* nack_list, int length) {
997 assert(nack_list);
998 assert(nack_fields_.empty());
999 int i = 0;
1000 while (i < length) {
1001 uint16_t pid = nack_list[i++];
1002 // Bitmask specifies losses in any of the 16 packets following the pid.
1003 uint16_t bitmask = 0;
1004 while (i < length) {
1005 int shift = static_cast<uint16_t>(nack_list[i] - pid) - 1;
1006 if (shift >= 0 && shift <= 15) {
1007 bitmask |= (1 << shift);
1008 ++i;
1009 } else {
1010 break;
1011 }
1012 }
1013 RTCPUtility::RTCPPacketRTPFBNACKItem item;
1014 item.PacketID = pid;
1015 item.BitMask = bitmask;
1016 nack_fields_.push_back(item);
1017 }
1018}
1019
Erik Språngc1b9d4e2015-06-08 09:54:14 +02001020bool Rpsi::Create(uint8_t* packet,
1021 size_t* index,
1022 size_t max_length,
1023 RtcpPacket::PacketReadyCallback* callback) const {
asapersson@webrtc.orga8260062014-05-20 09:53:51 +00001024 assert(rpsi_.NumberOfValidBits > 0);
Erik Språngc1b9d4e2015-06-08 09:54:14 +02001025 while (*index + BlockLength() > max_length) {
1026 if (!OnBufferFull(packet, index, callback))
1027 return false;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +00001028 }
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +00001029 CreateRpsi(rpsi_, padding_bytes_, BlockToHeaderLength(BlockLength()), packet,
Erik Språngc1b9d4e2015-06-08 09:54:14 +02001030 index);
1031 return true;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +00001032}
1033
1034void Rpsi::WithPictureId(uint64_t picture_id) {
1035 const uint32_t kPidBits = 7;
fbarchard@google.comc891fee2014-08-12 22:39:06 +00001036 const uint64_t k7MsbZeroMask = 0x1ffffffffffffffULL;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +00001037 uint8_t required_bytes = 0;
1038 uint64_t shifted_pid = picture_id;
1039 do {
1040 ++required_bytes;
1041 shifted_pid = (shifted_pid >> kPidBits) & k7MsbZeroMask;
1042 } while (shifted_pid > 0);
1043
1044 // Convert picture id to native bit string (natively defined by the video
1045 // codec).
1046 int pos = 0;
1047 for (int i = required_bytes - 1; i > 0; i--) {
1048 rpsi_.NativeBitString[pos++] =
1049 0x80 | static_cast<uint8_t>(picture_id >> (i * kPidBits));
1050 }
1051 rpsi_.NativeBitString[pos++] = static_cast<uint8_t>(picture_id & 0x7f);
1052 rpsi_.NumberOfValidBits = pos * 8;
1053
1054 // Calculate padding bytes (to reach next 32-bit boundary, 1, 2 or 3 bytes).
1055 padding_bytes_ = 4 - ((2 + required_bytes) % 4);
1056 if (padding_bytes_ == 4) {
1057 padding_bytes_ = 0;
1058 }
1059}
1060
Erik Språngc1b9d4e2015-06-08 09:54:14 +02001061bool Fir::Create(uint8_t* packet,
1062 size_t* index,
1063 size_t max_length,
1064 RtcpPacket::PacketReadyCallback* callback) const {
1065 while (*index + BlockLength() > max_length) {
1066 if (!OnBufferFull(packet, index, callback))
1067 return false;
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +00001068 }
Erik Språngc1b9d4e2015-06-08 09:54:14 +02001069 CreateFir(fir_, fir_item_, BlockToHeaderLength(BlockLength()), packet, index);
1070 return true;
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +00001071}
asapersson@webrtc.org3b84b3a2014-06-25 12:22:17 +00001072
Erik Språngc1b9d4e2015-06-08 09:54:14 +02001073bool Remb::Create(uint8_t* packet,
1074 size_t* index,
1075 size_t max_length,
1076 RtcpPacket::PacketReadyCallback* callback) const {
1077 while (*index + BlockLength() > max_length) {
1078 if (!OnBufferFull(packet, index, callback))
1079 return false;
asapersson@webrtc.org3b84b3a2014-06-25 12:22:17 +00001080 }
1081 CreateRemb(remb_, remb_item_, BlockToHeaderLength(BlockLength()), packet,
Erik Språngc1b9d4e2015-06-08 09:54:14 +02001082 index);
1083 return true;
asapersson@webrtc.org3b84b3a2014-06-25 12:22:17 +00001084}
1085
1086void Remb::AppliesTo(uint32_t ssrc) {
1087 if (remb_item_.NumberOfSSRCs >= kMaxNumberOfSsrcs) {
1088 LOG(LS_WARNING) << "Max number of REMB feedback SSRCs reached.";
1089 return;
1090 }
1091 remb_item_.SSRCs[remb_item_.NumberOfSSRCs++] = ssrc;
1092}
1093
Erik Språngc1b9d4e2015-06-08 09:54:14 +02001094bool Tmmbr::Create(uint8_t* packet,
1095 size_t* index,
1096 size_t max_length,
1097 RtcpPacket::PacketReadyCallback* callback) const {
1098 while (*index + BlockLength() > max_length) {
1099 if (!OnBufferFull(packet, index, callback))
1100 return false;
asapersson@webrtc.org3b84b3a2014-06-25 12:22:17 +00001101 }
1102 CreateTmmbr(tmmbr_, tmmbr_item_, BlockToHeaderLength(BlockLength()), packet,
Erik Språngc1b9d4e2015-06-08 09:54:14 +02001103 index);
1104 return true;
asapersson@webrtc.org3b84b3a2014-06-25 12:22:17 +00001105}
1106
Erik Språngc1b9d4e2015-06-08 09:54:14 +02001107bool Tmmbn::WithTmmbr(uint32_t ssrc, uint32_t bitrate_kbps, uint16_t overhead) {
asapersson@webrtc.org3b84b3a2014-06-25 12:22:17 +00001108 assert(overhead <= 0x1ff);
1109 if (tmmbn_items_.size() >= kMaxNumberOfTmmbrs) {
1110 LOG(LS_WARNING) << "Max TMMBN size reached.";
Erik Språngc1b9d4e2015-06-08 09:54:14 +02001111 return false;
asapersson@webrtc.org3b84b3a2014-06-25 12:22:17 +00001112 }
1113 RTCPPacketRTPFBTMMBRItem tmmbn_item;
1114 tmmbn_item.SSRC = ssrc;
1115 tmmbn_item.MaxTotalMediaBitRate = bitrate_kbps;
1116 tmmbn_item.MeasuredOverhead = overhead;
1117 tmmbn_items_.push_back(tmmbn_item);
Erik Språngc1b9d4e2015-06-08 09:54:14 +02001118 return true;
asapersson@webrtc.org3b84b3a2014-06-25 12:22:17 +00001119}
1120
Erik Språngc1b9d4e2015-06-08 09:54:14 +02001121bool Tmmbn::Create(uint8_t* packet,
1122 size_t* index,
1123 size_t max_length,
1124 RtcpPacket::PacketReadyCallback* callback) const {
1125 while (*index + BlockLength() > max_length) {
1126 if (!OnBufferFull(packet, index, callback))
1127 return false;
asapersson@webrtc.org3b84b3a2014-06-25 12:22:17 +00001128 }
1129 CreateTmmbn(tmmbn_, tmmbn_items_, BlockToHeaderLength(BlockLength()), packet,
Erik Språngc1b9d4e2015-06-08 09:54:14 +02001130 index);
1131 return true;
asapersson@webrtc.org3b84b3a2014-06-25 12:22:17 +00001132}
1133
Erik Språngc1b9d4e2015-06-08 09:54:14 +02001134bool Xr::Create(uint8_t* packet,
1135 size_t* index,
1136 size_t max_length,
1137 RtcpPacket::PacketReadyCallback* callback) const {
1138 while (*index + BlockLength() > max_length) {
1139 if (!OnBufferFull(packet, index, callback))
1140 return false;
asapersson@webrtc.org3b84b3a2014-06-25 12:22:17 +00001141 }
Erik Språngc1b9d4e2015-06-08 09:54:14 +02001142 CreateXrHeader(xr_header_, BlockToHeaderLength(BlockLength()), packet, index);
1143 CreateRrtr(rrtr_blocks_, packet, index);
1144 CreateDlrr(dlrr_blocks_, packet, index);
1145 CreateVoipMetric(voip_metric_blocks_, packet, index);
1146 return true;
asapersson@webrtc.org3b84b3a2014-06-25 12:22:17 +00001147}
1148
Erik Språngc1b9d4e2015-06-08 09:54:14 +02001149bool Xr::WithRrtr(Rrtr* rrtr) {
asapersson@webrtc.org3b84b3a2014-06-25 12:22:17 +00001150 assert(rrtr);
1151 if (rrtr_blocks_.size() >= kMaxNumberOfRrtrBlocks) {
1152 LOG(LS_WARNING) << "Max RRTR blocks reached.";
Erik Språngc1b9d4e2015-06-08 09:54:14 +02001153 return false;
asapersson@webrtc.org3b84b3a2014-06-25 12:22:17 +00001154 }
1155 rrtr_blocks_.push_back(rrtr->rrtr_block_);
Erik Språngc1b9d4e2015-06-08 09:54:14 +02001156 return true;
asapersson@webrtc.org3b84b3a2014-06-25 12:22:17 +00001157}
1158
Erik Språngc1b9d4e2015-06-08 09:54:14 +02001159bool Xr::WithDlrr(Dlrr* dlrr) {
asapersson@webrtc.org3b84b3a2014-06-25 12:22:17 +00001160 assert(dlrr);
1161 if (dlrr_blocks_.size() >= kMaxNumberOfDlrrBlocks) {
1162 LOG(LS_WARNING) << "Max DLRR blocks reached.";
Erik Språngc1b9d4e2015-06-08 09:54:14 +02001163 return false;
asapersson@webrtc.org3b84b3a2014-06-25 12:22:17 +00001164 }
1165 dlrr_blocks_.push_back(dlrr->dlrr_block_);
Erik Språngc1b9d4e2015-06-08 09:54:14 +02001166 return true;
asapersson@webrtc.org3b84b3a2014-06-25 12:22:17 +00001167}
1168
Erik Språngc1b9d4e2015-06-08 09:54:14 +02001169bool Xr::WithVoipMetric(VoipMetric* voip_metric) {
asapersson@webrtc.org3b84b3a2014-06-25 12:22:17 +00001170 assert(voip_metric);
1171 if (voip_metric_blocks_.size() >= kMaxNumberOfVoipMetricBlocks) {
1172 LOG(LS_WARNING) << "Max Voip Metric blocks reached.";
Erik Språngc1b9d4e2015-06-08 09:54:14 +02001173 return false;
asapersson@webrtc.org3b84b3a2014-06-25 12:22:17 +00001174 }
1175 voip_metric_blocks_.push_back(voip_metric->metric_);
Erik Språngc1b9d4e2015-06-08 09:54:14 +02001176 return true;
asapersson@webrtc.org3b84b3a2014-06-25 12:22:17 +00001177}
1178
1179size_t Xr::DlrrLength() const {
1180 const size_t kBlockHeaderLen = 4;
1181 const size_t kSubBlockLen = 12;
1182 size_t length = 0;
1183 for (std::vector<DlrrBlock>::const_iterator it = dlrr_blocks_.begin();
1184 it != dlrr_blocks_.end(); ++it) {
1185 if (!(*it).empty()) {
1186 length += kBlockHeaderLen + kSubBlockLen * (*it).size();
1187 }
1188 }
1189 return length;
1190}
1191
Erik Språngc1b9d4e2015-06-08 09:54:14 +02001192bool Dlrr::WithDlrrItem(uint32_t ssrc,
asapersson@webrtc.org3b84b3a2014-06-25 12:22:17 +00001193 uint32_t last_rr,
1194 uint32_t delay_last_rr) {
1195 if (dlrr_block_.size() >= kMaxNumberOfDlrrItems) {
1196 LOG(LS_WARNING) << "Max DLRR items reached.";
Erik Språngc1b9d4e2015-06-08 09:54:14 +02001197 return false;
asapersson@webrtc.org3b84b3a2014-06-25 12:22:17 +00001198 }
1199 RTCPPacketXRDLRRReportBlockItem dlrr;
1200 dlrr.SSRC = ssrc;
1201 dlrr.LastRR = last_rr;
1202 dlrr.DelayLastRR = delay_last_rr;
1203 dlrr_block_.push_back(dlrr);
Erik Språngc1b9d4e2015-06-08 09:54:14 +02001204 return true;
1205}
1206
1207RawPacket::RawPacket(size_t buffer_length)
1208 : buffer_length_(buffer_length), length_(0) {
1209 buffer_.reset(new uint8_t[buffer_length]);
1210}
1211
1212RawPacket::RawPacket(const uint8_t* packet, size_t packet_length)
1213 : buffer_length_(packet_length), length_(packet_length) {
1214 buffer_.reset(new uint8_t[packet_length]);
1215 memcpy(buffer_.get(), packet, packet_length);
1216}
1217
1218const uint8_t* RawPacket::Buffer() const {
1219 return buffer_.get();
1220}
1221
1222uint8_t* RawPacket::MutableBuffer() {
1223 return buffer_.get();
1224}
1225
1226size_t RawPacket::BufferLength() const {
1227 return buffer_length_;
1228}
1229
1230size_t RawPacket::Length() const {
1231 return length_;
1232}
1233
1234void RawPacket::SetLength(size_t length) {
1235 assert(length <= buffer_length_);
1236 length_ = length;
asapersson@webrtc.org3b84b3a2014-06-25 12:22:17 +00001237}
1238
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +00001239} // namespace rtcp
1240} // namespace webrtc