blob: 68da3aebe6b7493f13c8b510aa2f984500ee2f23 [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
13#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +000014#include "webrtc/system_wrappers/interface/logging.h"
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +000015
asapersson@webrtc.org3b84b3a2014-06-25 12:22:17 +000016using webrtc::RTCPUtility::kBtDlrr;
17using webrtc::RTCPUtility::kBtReceiverReferenceTime;
18using webrtc::RTCPUtility::kBtVoipMetric;
19
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000020using webrtc::RTCPUtility::PT_APP;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000021using webrtc::RTCPUtility::PT_BYE;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000022using webrtc::RTCPUtility::PT_IJ;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000023using webrtc::RTCPUtility::PT_PSFB;
24using webrtc::RTCPUtility::PT_RR;
25using webrtc::RTCPUtility::PT_RTPFB;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000026using webrtc::RTCPUtility::PT_SDES;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000027using webrtc::RTCPUtility::PT_SR;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000028using webrtc::RTCPUtility::PT_XR;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000029
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000030using webrtc::RTCPUtility::RTCPPacketAPP;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000031using webrtc::RTCPUtility::RTCPPacketBYE;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000032using webrtc::RTCPUtility::RTCPPacketPSFBAPP;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000033using webrtc::RTCPUtility::RTCPPacketPSFBFIR;
34using webrtc::RTCPUtility::RTCPPacketPSFBFIRItem;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000035using webrtc::RTCPUtility::RTCPPacketPSFBPLI;
36using webrtc::RTCPUtility::RTCPPacketPSFBREMBItem;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000037using webrtc::RTCPUtility::RTCPPacketPSFBRPSI;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000038using webrtc::RTCPUtility::RTCPPacketPSFBSLI;
39using webrtc::RTCPUtility::RTCPPacketPSFBSLIItem;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000040using webrtc::RTCPUtility::RTCPPacketReportBlockItem;
41using webrtc::RTCPUtility::RTCPPacketRR;
42using webrtc::RTCPUtility::RTCPPacketRTPFBNACK;
43using webrtc::RTCPUtility::RTCPPacketRTPFBNACKItem;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000044using webrtc::RTCPUtility::RTCPPacketRTPFBTMMBN;
45using webrtc::RTCPUtility::RTCPPacketRTPFBTMMBNItem;
46using webrtc::RTCPUtility::RTCPPacketRTPFBTMMBR;
47using webrtc::RTCPUtility::RTCPPacketRTPFBTMMBRItem;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000048using webrtc::RTCPUtility::RTCPPacketSR;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000049using webrtc::RTCPUtility::RTCPPacketXRDLRRReportBlockItem;
50using webrtc::RTCPUtility::RTCPPacketXRReceiverReferenceTimeItem;
51using webrtc::RTCPUtility::RTCPPacketXR;
52using webrtc::RTCPUtility::RTCPPacketXRVOIPMetricItem;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000053
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +000054namespace webrtc {
55namespace rtcp {
56namespace {
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000057// Unused SSRC of media source, set to 0.
58const uint32_t kUnusedMediaSourceSsrc0 = 0;
59
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000060void AssignUWord8(uint8_t* buffer, size_t* offset, uint8_t value) {
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +000061 buffer[(*offset)++] = value;
62}
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000063void AssignUWord16(uint8_t* buffer, size_t* offset, uint16_t value) {
pbos@webrtc.org62bafae2014-07-08 12:10:51 +000064 RtpUtility::AssignUWord16ToBuffer(buffer + *offset, value);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +000065 *offset += 2;
66}
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000067void AssignUWord24(uint8_t* buffer, size_t* offset, uint32_t value) {
pbos@webrtc.org62bafae2014-07-08 12:10:51 +000068 RtpUtility::AssignUWord24ToBuffer(buffer + *offset, value);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +000069 *offset += 3;
70}
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000071void AssignUWord32(uint8_t* buffer, size_t* offset, uint32_t value) {
pbos@webrtc.org62bafae2014-07-08 12:10:51 +000072 RtpUtility::AssignUWord32ToBuffer(buffer + *offset, value);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +000073 *offset += 4;
74}
75
asapersson@webrtc.org3b84b3a2014-06-25 12:22:17 +000076void ComputeMantissaAnd6bitBase2Exponent(uint32_t input_base10,
77 uint8_t bits_mantissa,
78 uint32_t* mantissa,
79 uint8_t* exp) {
80 // input_base10 = mantissa * 2^exp
81 assert(bits_mantissa <= 32);
82 uint32_t mantissa_max = (1 << bits_mantissa) - 1;
83 uint8_t exponent = 0;
84 for (uint32_t i = 0; i < 64; ++i) {
85 if (input_base10 <= (mantissa_max << i)) {
86 exponent = i;
87 break;
88 }
89 }
90 *exp = exponent;
91 *mantissa = (input_base10 >> exponent);
92}
93
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000094size_t BlockToHeaderLength(size_t length_in_bytes) {
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000095 // Length in 32-bit words minus 1.
96 assert(length_in_bytes > 0);
97 assert(length_in_bytes % 4 == 0);
98 return (length_in_bytes / 4) - 1;
99}
100
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000101// From RFC 3550, RTP: A Transport Protocol for Real-Time Applications.
102//
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000103// RTP header format.
104// 0 1 2 3
105// 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
106// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
107// |V=2|P| RC/FMT | PT | length |
108// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
109
110void CreateHeader(uint8_t count_or_format, // Depends on packet type.
111 uint8_t packet_type,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000112 size_t length,
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000113 uint8_t* buffer,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000114 size_t* pos) {
115 assert(length <= 0xffff);
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000116 const uint8_t kVersion = 2;
117 AssignUWord8(buffer, pos, (kVersion << 6) + count_or_format);
118 AssignUWord8(buffer, pos, packet_type);
119 AssignUWord16(buffer, pos, length);
120}
121
122// Sender report (SR) (RFC 3550).
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000123// 0 1 2 3
124// 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
125// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
126// |V=2|P| RC | PT=SR=200 | length |
127// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
128// | SSRC of sender |
129// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
130// | NTP timestamp, most significant word |
131// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
132// | NTP timestamp, least significant word |
133// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
134// | RTP timestamp |
135// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
136// | sender's packet count |
137// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
138// | sender's octet count |
139// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
140
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000141void CreateSenderReport(const RTCPPacketSR& sr,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000142 size_t length,
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000143 uint8_t* buffer,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000144 size_t* pos) {
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000145 CreateHeader(sr.NumberOfReportBlocks, PT_SR, length, buffer, pos);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000146 AssignUWord32(buffer, pos, sr.SenderSSRC);
147 AssignUWord32(buffer, pos, sr.NTPMostSignificant);
148 AssignUWord32(buffer, pos, sr.NTPLeastSignificant);
149 AssignUWord32(buffer, pos, sr.RTPTimestamp);
150 AssignUWord32(buffer, pos, sr.SenderPacketCount);
151 AssignUWord32(buffer, pos, sr.SenderOctetCount);
152}
153
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000154// Receiver report (RR), header (RFC 3550).
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000155//
156// 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
157// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
158// |V=2|P| RC | PT=RR=201 | length |
159// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
160// | SSRC of packet sender |
161// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
162
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000163void CreateReceiverReport(const RTCPPacketRR& rr,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000164 size_t length,
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000165 uint8_t* buffer,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000166 size_t* pos) {
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000167 CreateHeader(rr.NumberOfReportBlocks, PT_RR, length, buffer, pos);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000168 AssignUWord32(buffer, pos, rr.SenderSSRC);
169}
170
171// Report block (RFC 3550).
172//
173// 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
174// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
175// | SSRC_1 (SSRC of first source) |
176// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
177// | fraction lost | cumulative number of packets lost |
178// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
179// | extended highest sequence number received |
180// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
181// | interarrival jitter |
182// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
183// | last SR (LSR) |
184// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
185// | delay since last SR (DLSR) |
186// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
187
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000188void CreateReportBlocks(const std::vector<RTCPPacketReportBlockItem>& blocks,
189 uint8_t* buffer,
190 size_t* pos) {
191 for (std::vector<RTCPPacketReportBlockItem>::const_iterator
192 it = blocks.begin(); it != blocks.end(); ++it) {
193 AssignUWord32(buffer, pos, (*it).SSRC);
194 AssignUWord8(buffer, pos, (*it).FractionLost);
195 AssignUWord24(buffer, pos, (*it).CumulativeNumOfPacketsLost);
196 AssignUWord32(buffer, pos, (*it).ExtendedHighestSequenceNumber);
197 AssignUWord32(buffer, pos, (*it).Jitter);
198 AssignUWord32(buffer, pos, (*it).LastSR);
199 AssignUWord32(buffer, pos, (*it).DelayLastSR);
200 }
201}
202
203// Transmission Time Offsets in RTP Streams (RFC 5450).
204//
205// 0 1 2 3
206// 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
207// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
208// hdr |V=2|P| RC | PT=IJ=195 | length |
209// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
210// | inter-arrival jitter |
211// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
212// . .
213// . .
214// . .
215// | inter-arrival jitter |
216// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
217
218void CreateIj(const std::vector<uint32_t>& ij_items,
219 uint8_t* buffer,
220 size_t* pos) {
221 size_t length = ij_items.size();
222 CreateHeader(length, PT_IJ, length, buffer, pos);
223 for (std::vector<uint32_t>::const_iterator it = ij_items.begin();
224 it != ij_items.end(); ++it) {
225 AssignUWord32(buffer, pos, *it);
226 }
227}
228
229// Source Description (SDES) (RFC 3550).
230//
231// 0 1 2 3
232// 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
233// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
234// header |V=2|P| SC | PT=SDES=202 | length |
235// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
236// chunk | SSRC/CSRC_1 |
237// 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
238// | SDES items |
239// | ... |
240// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
241// chunk | SSRC/CSRC_2 |
242// 2 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
243// | SDES items |
244// | ... |
245// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
246//
247// Canonical End-Point Identifier SDES Item (CNAME)
248//
249// 0 1 2 3
250// 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
251// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
252// | CNAME=1 | length | user and domain name ...
253// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
254
255void CreateSdes(const std::vector<Sdes::Chunk>& chunks,
256 size_t length,
257 uint8_t* buffer,
258 size_t* pos) {
259 CreateHeader(chunks.size(), PT_SDES, length, buffer, pos);
260 const uint8_t kSdesItemType = 1;
261 for (std::vector<Sdes::Chunk>::const_iterator it = chunks.begin();
262 it != chunks.end(); ++it) {
263 AssignUWord32(buffer, pos, (*it).ssrc);
264 AssignUWord8(buffer, pos, kSdesItemType);
265 AssignUWord8(buffer, pos, (*it).name.length());
266 memcpy(buffer + *pos, (*it).name.data(), (*it).name.length());
267 *pos += (*it).name.length();
268 memset(buffer + *pos, 0, (*it).null_octets);
269 *pos += (*it).null_octets;
270 }
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000271}
272
273// Bye packet (BYE) (RFC 3550).
274//
275// 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
276// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
277// |V=2|P| SC | PT=BYE=203 | length |
278// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
279// | SSRC/CSRC |
280// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
281// : ... :
282// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
283// (opt) | length | reason for leaving ...
284// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
285
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000286void CreateBye(const RTCPPacketBYE& bye,
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000287 const std::vector<uint32_t>& csrcs,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000288 size_t length,
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000289 uint8_t* buffer,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000290 size_t* pos) {
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000291 CreateHeader(length, PT_BYE, length, buffer, pos);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000292 AssignUWord32(buffer, pos, bye.SenderSSRC);
293 for (std::vector<uint32_t>::const_iterator it = csrcs.begin();
294 it != csrcs.end(); ++it) {
295 AssignUWord32(buffer, pos, *it);
296 }
297}
298
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000299// Application-Defined packet (APP) (RFC 3550).
300//
301// 0 1 2 3
302// 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
303// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
304// |V=2|P| subtype | PT=APP=204 | length |
305// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
306// | SSRC/CSRC |
307// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
308// | name (ASCII) |
309// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
310// | application-dependent data ...
311// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
312
313void CreateApp(const RTCPPacketAPP& app,
314 uint32_t ssrc,
315 size_t length,
316 uint8_t* buffer,
317 size_t* pos) {
318 CreateHeader(app.SubType, PT_APP, length, buffer, pos);
319 AssignUWord32(buffer, pos, ssrc);
320 AssignUWord32(buffer, pos, app.Name);
321 memcpy(buffer + *pos, app.Data, app.Size);
322 *pos += app.Size;
323}
324
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000325// RFC 4585: Feedback format.
326//
327// Common packet format:
328//
329// 0 1 2 3
330// 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
331// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
332// |V=2|P| FMT | PT | length |
333// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
334// | SSRC of packet sender |
335// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
336// | SSRC of media source |
337// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
338// : Feedback Control Information (FCI) :
339// :
340//
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000341
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000342// Picture loss indication (PLI) (RFC 4585).
343//
344// FCI: no feedback control information.
345
346void CreatePli(const RTCPPacketPSFBPLI& pli,
347 size_t length,
348 uint8_t* buffer,
349 size_t* pos) {
350 const uint8_t kFmt = 1;
351 CreateHeader(kFmt, PT_PSFB, length, buffer, pos);
352 AssignUWord32(buffer, pos, pli.SenderSSRC);
353 AssignUWord32(buffer, pos, pli.MediaSSRC);
354}
355
356// Slice loss indication (SLI) (RFC 4585).
357//
358// FCI:
359//
360// 0 1 2 3
361// 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
362// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
363// | First | Number | PictureID |
364// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
365
366void CreateSli(const RTCPPacketPSFBSLI& sli,
367 const RTCPPacketPSFBSLIItem& sli_item,
368 size_t length,
369 uint8_t* buffer,
370 size_t* pos) {
371 const uint8_t kFmt = 2;
372 CreateHeader(kFmt, PT_PSFB, length, buffer, pos);
373 AssignUWord32(buffer, pos, sli.SenderSSRC);
374 AssignUWord32(buffer, pos, sli.MediaSSRC);
375
376 AssignUWord8(buffer, pos, sli_item.FirstMB >> 5);
377 AssignUWord8(buffer, pos, (sli_item.FirstMB << 3) +
378 ((sli_item.NumberOfMB >> 10) & 0x07));
379 AssignUWord8(buffer, pos, sli_item.NumberOfMB >> 2);
380 AssignUWord8(buffer, pos, (sli_item.NumberOfMB << 6) + sli_item.PictureId);
381}
382
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000383// Generic NACK (RFC 4585).
384//
385// FCI:
386//
387// 0 1 2 3
388// 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
389// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
390// | PID | BLP |
391// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
392
393void CreateNack(const RTCPPacketRTPFBNACK& nack,
394 const std::vector<RTCPPacketRTPFBNACKItem>& nack_fields,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000395 size_t length,
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000396 uint8_t* buffer,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000397 size_t* pos) {
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000398 const uint8_t kFmt = 1;
399 CreateHeader(kFmt, PT_RTPFB, length, buffer, pos);
400 AssignUWord32(buffer, pos, nack.SenderSSRC);
401 AssignUWord32(buffer, pos, nack.MediaSSRC);
402 for (std::vector<RTCPPacketRTPFBNACKItem>::const_iterator
403 it = nack_fields.begin(); it != nack_fields.end(); ++it) {
404 AssignUWord16(buffer, pos, (*it).PacketID);
405 AssignUWord16(buffer, pos, (*it).BitMask);
406 }
407}
408
409// Reference picture selection indication (RPSI) (RFC 4585).
410//
411// FCI:
412//
413// 0 1 2 3
414// 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
415// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
416// | PB |0| Payload Type| Native RPSI bit string |
417// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
418// | defined per codec ... | Padding (0) |
419// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
420
421void CreateRpsi(const RTCPPacketPSFBRPSI& rpsi,
422 uint8_t padding_bytes,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000423 size_t length,
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000424 uint8_t* buffer,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000425 size_t* pos) {
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000426 // Native bit string should be a multiple of 8 bits.
427 assert(rpsi.NumberOfValidBits % 8 == 0);
428 const uint8_t kFmt = 3;
429 CreateHeader(kFmt, PT_PSFB, length, buffer, pos);
430 AssignUWord32(buffer, pos, rpsi.SenderSSRC);
431 AssignUWord32(buffer, pos, rpsi.MediaSSRC);
432 AssignUWord8(buffer, pos, padding_bytes * 8);
433 AssignUWord8(buffer, pos, rpsi.PayloadType);
434 memcpy(buffer + *pos, rpsi.NativeBitString, rpsi.NumberOfValidBits / 8);
435 *pos += rpsi.NumberOfValidBits / 8;
436 memset(buffer + *pos, 0, padding_bytes);
437 *pos += padding_bytes;
438}
439
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000440// Full intra request (FIR) (RFC 5104).
441//
442// FCI:
443//
444// 0 1 2 3
445// 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
446// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
447// | SSRC |
448// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
449// | Seq nr. | Reserved |
450// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
451
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000452void CreateFir(const RTCPPacketPSFBFIR& fir,
453 const RTCPPacketPSFBFIRItem& fir_item,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000454 size_t length,
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000455 uint8_t* buffer,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000456 size_t* pos) {
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000457 const uint8_t kFmt = 4;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000458 CreateHeader(kFmt, PT_PSFB, length, buffer, pos);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000459 AssignUWord32(buffer, pos, fir.SenderSSRC);
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000460 AssignUWord32(buffer, pos, kUnusedMediaSourceSsrc0);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000461 AssignUWord32(buffer, pos, fir_item.SSRC);
462 AssignUWord8(buffer, pos, fir_item.CommandSequenceNumber);
463 AssignUWord24(buffer, pos, 0);
464}
asapersson@webrtc.org3b84b3a2014-06-25 12:22:17 +0000465
466void CreateTmmbrItem(const RTCPPacketRTPFBTMMBRItem& tmmbr_item,
467 uint8_t* buffer,
468 size_t* pos) {
469 uint32_t bitrate_bps = tmmbr_item.MaxTotalMediaBitRate * 1000;
470 uint32_t mantissa = 0;
471 uint8_t exp = 0;
472 ComputeMantissaAnd6bitBase2Exponent(bitrate_bps, 17, &mantissa, &exp);
473
474 AssignUWord32(buffer, pos, tmmbr_item.SSRC);
475 AssignUWord8(buffer, pos, (exp << 2) + ((mantissa >> 15) & 0x03));
476 AssignUWord8(buffer, pos, mantissa >> 7);
477 AssignUWord8(buffer, pos, (mantissa << 1) +
478 ((tmmbr_item.MeasuredOverhead >> 8) & 0x01));
479 AssignUWord8(buffer, pos, tmmbr_item.MeasuredOverhead);
480}
481
482// Temporary Maximum Media Stream Bit Rate Request (TMMBR) (RFC 5104).
483//
484// FCI:
485//
486// 0 1 2 3
487// 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
488// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
489// | SSRC |
490// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
491// | MxTBR Exp | MxTBR Mantissa |Measured Overhead|
492// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
493
494void CreateTmmbr(const RTCPPacketRTPFBTMMBR& tmmbr,
495 const RTCPPacketRTPFBTMMBRItem& tmmbr_item,
496 size_t length,
497 uint8_t* buffer,
498 size_t* pos) {
499 const uint8_t kFmt = 3;
500 CreateHeader(kFmt, PT_RTPFB, length, buffer, pos);
501 AssignUWord32(buffer, pos, tmmbr.SenderSSRC);
502 AssignUWord32(buffer, pos, kUnusedMediaSourceSsrc0);
503 CreateTmmbrItem(tmmbr_item, buffer, pos);
504}
505
506// Temporary Maximum Media Stream Bit Rate Notification (TMMBN) (RFC 5104).
507//
508// FCI:
509//
510// 0 1 2 3
511// 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
512// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
513// | SSRC |
514// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
515// | MxTBR Exp | MxTBR Mantissa |Measured Overhead|
516// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
517
518void CreateTmmbn(const RTCPPacketRTPFBTMMBN& tmmbn,
519 const std::vector<RTCPPacketRTPFBTMMBRItem>& tmmbn_items,
520 size_t length,
521 uint8_t* buffer,
522 size_t* pos) {
523 const uint8_t kFmt = 4;
524 CreateHeader(kFmt, PT_RTPFB, length, buffer, pos);
525 AssignUWord32(buffer, pos, tmmbn.SenderSSRC);
526 AssignUWord32(buffer, pos, kUnusedMediaSourceSsrc0);
527 for (uint8_t i = 0; i < tmmbn_items.size(); ++i) {
528 CreateTmmbrItem(tmmbn_items[i], buffer, pos);
529 }
530}
531
532// Receiver Estimated Max Bitrate (REMB) (draft-alvestrand-rmcat-remb).
533//
534// 0 1 2 3
535// 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
536// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
537// |V=2|P| FMT=15 | PT=206 | length |
538// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
539// | SSRC of packet sender |
540// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
541// | SSRC of media source |
542// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
543// | Unique identifier 'R' 'E' 'M' 'B' |
544// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
545// | Num SSRC | BR Exp | BR Mantissa |
546// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
547// | SSRC feedback |
548// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
549// | ... |
550
551void CreateRemb(const RTCPPacketPSFBAPP& remb,
552 const RTCPPacketPSFBREMBItem& remb_item,
553 size_t length,
554 uint8_t* buffer,
555 size_t* pos) {
556 uint32_t mantissa = 0;
557 uint8_t exp = 0;
558 ComputeMantissaAnd6bitBase2Exponent(remb_item.BitRate, 18, &mantissa, &exp);
559
560 const uint8_t kFmt = 15;
561 CreateHeader(kFmt, PT_PSFB, length, buffer, pos);
562 AssignUWord32(buffer, pos, remb.SenderSSRC);
563 AssignUWord32(buffer, pos, kUnusedMediaSourceSsrc0);
564 AssignUWord8(buffer, pos, 'R');
565 AssignUWord8(buffer, pos, 'E');
566 AssignUWord8(buffer, pos, 'M');
567 AssignUWord8(buffer, pos, 'B');
568 AssignUWord8(buffer, pos, remb_item.NumberOfSSRCs);
569 AssignUWord8(buffer, pos, (exp << 2) + ((mantissa >> 16) & 0x03));
570 AssignUWord8(buffer, pos, mantissa >> 8);
571 AssignUWord8(buffer, pos, mantissa);
572 for (uint8_t i = 0; i < remb_item.NumberOfSSRCs; ++i) {
573 AssignUWord32(buffer, pos, remb_item.SSRCs[i]);
574 }
575}
576
577// From RFC 3611: RTP Control Protocol Extended Reports (RTCP XR).
578//
579// Format for XR packets:
580//
581// 0 1 2 3
582// 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
583// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
584// |V=2|P|reserved | PT=XR=207 | length |
585// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
586// | SSRC |
587// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
588// : report blocks :
589// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
590
591void CreateXrHeader(const RTCPPacketXR& header,
592 size_t length,
593 uint8_t* buffer,
594 size_t* pos) {
595 CreateHeader(0U, PT_XR, length, buffer, pos);
596 AssignUWord32(buffer, pos, header.OriginatorSSRC);
597}
598
599void CreateXrBlockHeader(uint8_t block_type,
600 uint16_t block_length,
601 uint8_t* buffer,
602 size_t* pos) {
603 AssignUWord8(buffer, pos, block_type);
604 AssignUWord8(buffer, pos, 0);
605 AssignUWord16(buffer, pos, block_length);
606}
607
608// Receiver Reference Time Report Block (RFC 3611).
609//
610// 0 1 2 3
611// 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
612// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
613// | BT=4 | reserved | block length = 2 |
614// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
615// | NTP timestamp, most significant word |
616// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
617// | NTP timestamp, least significant word |
618// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
619
620void CreateRrtr(const std::vector<RTCPPacketXRReceiverReferenceTimeItem>& rrtrs,
621 uint8_t* buffer,
622 size_t* pos) {
623 const uint16_t kBlockLength = 2;
624 for (std::vector<RTCPPacketXRReceiverReferenceTimeItem>::const_iterator it =
625 rrtrs.begin(); it != rrtrs.end(); ++it) {
626 CreateXrBlockHeader(kBtReceiverReferenceTime, kBlockLength, buffer, pos);
627 AssignUWord32(buffer, pos, (*it).NTPMostSignificant);
628 AssignUWord32(buffer, pos, (*it).NTPLeastSignificant);
629 }
630}
631
632// DLRR Report Block (RFC 3611).
633//
634// 0 1 2 3
635// 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
636// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
637// | BT=5 | reserved | block length |
638// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
639// | SSRC_1 (SSRC of first receiver) | sub-
640// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
641// | last RR (LRR) | 1
642// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
643// | delay since last RR (DLRR) |
644// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
645// | SSRC_2 (SSRC of second receiver) | sub-
646// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
647// : ... : 2
648
649void CreateDlrr(const std::vector<Xr::DlrrBlock>& dlrrs,
650 uint8_t* buffer,
651 size_t* pos) {
652 for (std::vector<Xr::DlrrBlock>::const_iterator it = dlrrs.begin();
653 it != dlrrs.end(); ++it) {
654 if ((*it).empty()) {
655 continue;
656 }
657 uint16_t block_length = 3 * (*it).size();
658 CreateXrBlockHeader(kBtDlrr, block_length, buffer, pos);
659 for (Xr::DlrrBlock::const_iterator it_block = (*it).begin();
660 it_block != (*it).end(); ++it_block) {
661 AssignUWord32(buffer, pos, (*it_block).SSRC);
662 AssignUWord32(buffer, pos, (*it_block).LastRR);
663 AssignUWord32(buffer, pos, (*it_block).DelayLastRR);
664 }
665 }
666}
667
668// VoIP Metrics Report Block (RFC 3611).
669//
670// 0 1 2 3
671// 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
672// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
673// | BT=7 | reserved | block length = 8 |
674// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
675// | SSRC of source |
676// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
677// | loss rate | discard rate | burst density | gap density |
678// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
679// | burst duration | gap duration |
680// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
681// | round trip delay | end system delay |
682// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
683// | signal level | noise level | RERL | Gmin |
684// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
685// | R factor | ext. R factor | MOS-LQ | MOS-CQ |
686// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
687// | RX config | reserved | JB nominal |
688// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
689// | JB maximum | JB abs max |
690// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
691
692void CreateVoipMetric(const std::vector<RTCPPacketXRVOIPMetricItem>& metrics,
693 uint8_t* buffer,
694 size_t* pos) {
695 const uint16_t kBlockLength = 8;
696 for (std::vector<RTCPPacketXRVOIPMetricItem>::const_iterator it =
697 metrics.begin(); it != metrics.end(); ++it) {
698 CreateXrBlockHeader(kBtVoipMetric, kBlockLength, buffer, pos);
699 AssignUWord32(buffer, pos, (*it).SSRC);
700 AssignUWord8(buffer, pos, (*it).lossRate);
701 AssignUWord8(buffer, pos, (*it).discardRate);
702 AssignUWord8(buffer, pos, (*it).burstDensity);
703 AssignUWord8(buffer, pos, (*it).gapDensity);
704 AssignUWord16(buffer, pos, (*it).burstDuration);
705 AssignUWord16(buffer, pos, (*it).gapDuration);
706 AssignUWord16(buffer, pos, (*it).roundTripDelay);
707 AssignUWord16(buffer, pos, (*it).endSystemDelay);
708 AssignUWord8(buffer, pos, (*it).signalLevel);
709 AssignUWord8(buffer, pos, (*it).noiseLevel);
710 AssignUWord8(buffer, pos, (*it).RERL);
711 AssignUWord8(buffer, pos, (*it).Gmin);
712 AssignUWord8(buffer, pos, (*it).Rfactor);
713 AssignUWord8(buffer, pos, (*it).extRfactor);
714 AssignUWord8(buffer, pos, (*it).MOSLQ);
715 AssignUWord8(buffer, pos, (*it).MOSCQ);
716 AssignUWord8(buffer, pos, (*it).RXconfig);
717 AssignUWord8(buffer, pos, 0);
718 AssignUWord16(buffer, pos, (*it).JBnominal);
719 AssignUWord16(buffer, pos, (*it).JBmax);
720 AssignUWord16(buffer, pos, (*it).JBabsMax);
721 }
722}
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000723} // namespace
724
725void RtcpPacket::Append(RtcpPacket* packet) {
726 assert(packet);
727 appended_packets_.push_back(packet);
728}
729
730RawPacket RtcpPacket::Build() const {
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000731 size_t length = 0;
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000732 uint8_t packet[IP_PACKET_SIZE];
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000733 CreateAndAddAppended(packet, &length, IP_PACKET_SIZE);
734 return RawPacket(packet, length);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000735}
736
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000737void RtcpPacket::Build(uint8_t* packet,
738 size_t* length,
739 size_t max_length) const {
740 *length = 0;
741 CreateAndAddAppended(packet, length, max_length);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000742}
743
744void RtcpPacket::CreateAndAddAppended(uint8_t* packet,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000745 size_t* length,
746 size_t max_length) const {
747 Create(packet, length, max_length);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000748 for (std::vector<RtcpPacket*>::const_iterator it = appended_packets_.begin();
749 it != appended_packets_.end(); ++it) {
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000750 (*it)->CreateAndAddAppended(packet, length, max_length);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000751 }
752}
753
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000754void Empty::Create(uint8_t* packet, size_t* length, size_t max_length) const {
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000755}
756
757void SenderReport::Create(uint8_t* packet,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000758 size_t* length,
759 size_t max_length) const {
760 if (*length + BlockLength() > max_length) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000761 LOG(LS_WARNING) << "Max packet size reached.";
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000762 return;
763 }
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000764 CreateSenderReport(sr_, BlockToHeaderLength(BlockLength()), packet, length);
765 CreateReportBlocks(report_blocks_, packet, length);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000766}
767
768void SenderReport::WithReportBlock(ReportBlock* block) {
769 assert(block);
770 if (report_blocks_.size() >= kMaxNumberOfReportBlocks) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000771 LOG(LS_WARNING) << "Max report blocks reached.";
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000772 return;
773 }
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000774 report_blocks_.push_back(block->report_block_);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000775 sr_.NumberOfReportBlocks = report_blocks_.size();
776}
777
778void ReceiverReport::Create(uint8_t* packet,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000779 size_t* length,
780 size_t max_length) const {
781 if (*length + BlockLength() > max_length) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000782 LOG(LS_WARNING) << "Max packet size reached.";
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000783 return;
784 }
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000785 CreateReceiverReport(rr_, BlockToHeaderLength(BlockLength()), packet, length);
786 CreateReportBlocks(report_blocks_, packet, length);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000787}
788
789void ReceiverReport::WithReportBlock(ReportBlock* block) {
790 assert(block);
791 if (report_blocks_.size() >= kMaxNumberOfReportBlocks) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000792 LOG(LS_WARNING) << "Max report blocks reached.";
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000793 return;
794 }
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000795 report_blocks_.push_back(block->report_block_);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000796 rr_.NumberOfReportBlocks = report_blocks_.size();
797}
798
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000799void Ij::Create(uint8_t* packet, size_t* length, size_t max_length) const {
800 if (*length + BlockLength() > max_length) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000801 LOG(LS_WARNING) << "Max packet size reached.";
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000802 return;
803 }
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000804 CreateIj(ij_items_, packet, length);
805}
806
807void Ij::WithJitterItem(uint32_t jitter) {
808 if (ij_items_.size() >= kMaxNumberOfIjItems) {
809 LOG(LS_WARNING) << "Max inter-arrival jitter items reached.";
810 return;
811 }
812 ij_items_.push_back(jitter);
813}
814
815void Sdes::Create(uint8_t* packet, size_t* length, size_t max_length) const {
816 assert(!chunks_.empty());
817 if (*length + BlockLength() > max_length) {
818 LOG(LS_WARNING) << "Max packet size reached.";
819 return;
820 }
821 CreateSdes(chunks_, BlockToHeaderLength(BlockLength()), packet, length);
822}
823
824void Sdes::WithCName(uint32_t ssrc, std::string cname) {
825 assert(cname.length() <= 0xff);
826 if (chunks_.size() >= kMaxNumberOfChunks) {
827 LOG(LS_WARNING) << "Max SDES chunks reached.";
828 return;
829 }
830 // In each chunk, the list of items must be terminated by one or more null
831 // octets. The next chunk must start on a 32-bit boundary.
832 // CNAME (1 byte) | length (1 byte) | name | padding.
833 int null_octets = 4 - ((2 + cname.length()) % 4);
834 Chunk chunk;
835 chunk.ssrc = ssrc;
836 chunk.name = cname;
837 chunk.null_octets = null_octets;
838 chunks_.push_back(chunk);
839}
840
841size_t Sdes::BlockLength() const {
842 // Header (4 bytes).
843 // Chunk:
844 // SSRC/CSRC (4 bytes) | CNAME (1 byte) | length (1 byte) | name | padding.
845 size_t length = kHeaderLength;
846 for (std::vector<Chunk>::const_iterator it = chunks_.begin();
847 it != chunks_.end(); ++it) {
848 length += 6 + (*it).name.length() + (*it).null_octets;
849 }
850 assert(length % 4 == 0);
851 return length;
852}
853
854void Bye::Create(uint8_t* packet, size_t* length, size_t max_length) const {
855 if (*length + BlockLength() > max_length) {
856 LOG(LS_WARNING) << "Max packet size reached.";
857 return;
858 }
859 CreateBye(bye_, csrcs_, BlockToHeaderLength(BlockLength()), packet, length);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000860}
861
862void Bye::WithCsrc(uint32_t csrc) {
863 if (csrcs_.size() >= kMaxNumberOfCsrcs) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000864 LOG(LS_WARNING) << "Max CSRC size reached.";
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000865 return;
866 }
867 csrcs_.push_back(csrc);
868}
869
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000870void App::Create(uint8_t* packet, size_t* length, size_t max_length) const {
871 if (*length + BlockLength() > max_length) {
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000872 LOG(LS_WARNING) << "Max packet size reached.";
873 return;
874 }
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000875 CreateApp(app_, ssrc_, BlockToHeaderLength(BlockLength()), packet, length);
876}
877
878void Pli::Create(uint8_t* packet, size_t* length, size_t max_length) const {
879 if (*length + BlockLength() > max_length) {
880 LOG(LS_WARNING) << "Max packet size reached.";
881 return;
882 }
883 CreatePli(pli_, BlockToHeaderLength(BlockLength()), packet, length);
884}
885
886void Sli::Create(uint8_t* packet, size_t* length, size_t max_length) const {
887 if (*length + BlockLength() > max_length) {
888 LOG(LS_WARNING) << "Max packet size reached.";
889 return;
890 }
891 CreateSli(sli_, sli_item_, BlockToHeaderLength(BlockLength()), packet,
892 length);
893}
894
895void Nack::Create(uint8_t* packet, size_t* length, size_t max_length) const {
896 assert(!nack_fields_.empty());
897 if (*length + BlockLength() > max_length) {
898 LOG(LS_WARNING) << "Max packet size reached.";
899 return;
900 }
901 CreateNack(nack_, nack_fields_, BlockToHeaderLength(BlockLength()), packet,
902 length);
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000903}
904
905void Nack::WithList(const uint16_t* nack_list, int length) {
906 assert(nack_list);
907 assert(nack_fields_.empty());
908 int i = 0;
909 while (i < length) {
910 uint16_t pid = nack_list[i++];
911 // Bitmask specifies losses in any of the 16 packets following the pid.
912 uint16_t bitmask = 0;
913 while (i < length) {
914 int shift = static_cast<uint16_t>(nack_list[i] - pid) - 1;
915 if (shift >= 0 && shift <= 15) {
916 bitmask |= (1 << shift);
917 ++i;
918 } else {
919 break;
920 }
921 }
922 RTCPUtility::RTCPPacketRTPFBNACKItem item;
923 item.PacketID = pid;
924 item.BitMask = bitmask;
925 nack_fields_.push_back(item);
926 }
927}
928
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000929void Rpsi::Create(uint8_t* packet, size_t* length, size_t max_length) const {
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000930 assert(rpsi_.NumberOfValidBits > 0);
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000931 if (*length + BlockLength() > max_length) {
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000932 LOG(LS_WARNING) << "Max packet size reached.";
933 return;
934 }
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000935 CreateRpsi(rpsi_, padding_bytes_, BlockToHeaderLength(BlockLength()), packet,
936 length);
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000937}
938
939void Rpsi::WithPictureId(uint64_t picture_id) {
940 const uint32_t kPidBits = 7;
941 const uint64_t k7MsbZeroMask = 0x1ffffffffffffff;
942 uint8_t required_bytes = 0;
943 uint64_t shifted_pid = picture_id;
944 do {
945 ++required_bytes;
946 shifted_pid = (shifted_pid >> kPidBits) & k7MsbZeroMask;
947 } while (shifted_pid > 0);
948
949 // Convert picture id to native bit string (natively defined by the video
950 // codec).
951 int pos = 0;
952 for (int i = required_bytes - 1; i > 0; i--) {
953 rpsi_.NativeBitString[pos++] =
954 0x80 | static_cast<uint8_t>(picture_id >> (i * kPidBits));
955 }
956 rpsi_.NativeBitString[pos++] = static_cast<uint8_t>(picture_id & 0x7f);
957 rpsi_.NumberOfValidBits = pos * 8;
958
959 // Calculate padding bytes (to reach next 32-bit boundary, 1, 2 or 3 bytes).
960 padding_bytes_ = 4 - ((2 + required_bytes) % 4);
961 if (padding_bytes_ == 4) {
962 padding_bytes_ = 0;
963 }
964}
965
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000966void Fir::Create(uint8_t* packet, size_t* length, size_t max_length) const {
967 if (*length + BlockLength() > max_length) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000968 LOG(LS_WARNING) << "Max packet size reached.";
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000969 return;
970 }
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000971 CreateFir(fir_, fir_item_, BlockToHeaderLength(BlockLength()), packet,
972 length);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000973}
asapersson@webrtc.org3b84b3a2014-06-25 12:22:17 +0000974
975void Remb::Create(uint8_t* packet, size_t* length, size_t max_length) const {
976 if (*length + BlockLength() > max_length) {
977 LOG(LS_WARNING) << "Max packet size reached.";
978 return;
979 }
980 CreateRemb(remb_, remb_item_, BlockToHeaderLength(BlockLength()), packet,
981 length);
982}
983
984void Remb::AppliesTo(uint32_t ssrc) {
985 if (remb_item_.NumberOfSSRCs >= kMaxNumberOfSsrcs) {
986 LOG(LS_WARNING) << "Max number of REMB feedback SSRCs reached.";
987 return;
988 }
989 remb_item_.SSRCs[remb_item_.NumberOfSSRCs++] = ssrc;
990}
991
992void Tmmbr::Create(uint8_t* packet, size_t* length, size_t max_length) const {
993 if (*length + BlockLength() > max_length) {
994 LOG(LS_WARNING) << "Max packet size reached.";
995 return;
996 }
997 CreateTmmbr(tmmbr_, tmmbr_item_, BlockToHeaderLength(BlockLength()), packet,
998 length);
999}
1000
1001void Tmmbn::WithTmmbr(uint32_t ssrc, uint32_t bitrate_kbps, uint16_t overhead) {
1002 assert(overhead <= 0x1ff);
1003 if (tmmbn_items_.size() >= kMaxNumberOfTmmbrs) {
1004 LOG(LS_WARNING) << "Max TMMBN size reached.";
1005 return;
1006 }
1007 RTCPPacketRTPFBTMMBRItem tmmbn_item;
1008 tmmbn_item.SSRC = ssrc;
1009 tmmbn_item.MaxTotalMediaBitRate = bitrate_kbps;
1010 tmmbn_item.MeasuredOverhead = overhead;
1011 tmmbn_items_.push_back(tmmbn_item);
1012}
1013
1014void Tmmbn::Create(uint8_t* packet, size_t* length, size_t max_length) const {
1015 if (*length + BlockLength() > max_length) {
1016 LOG(LS_WARNING) << "Max packet size reached.";
1017 return;
1018 }
1019 CreateTmmbn(tmmbn_, tmmbn_items_, BlockToHeaderLength(BlockLength()), packet,
1020 length);
1021}
1022
1023void Xr::Create(uint8_t* packet, size_t* length, size_t max_length) const {
1024 if (*length + BlockLength() > max_length) {
1025 LOG(LS_WARNING) << "Max packet size reached.";
1026 return;
1027 }
1028 CreateXrHeader(xr_header_, BlockToHeaderLength(BlockLength()), packet,
1029 length);
1030 CreateRrtr(rrtr_blocks_, packet, length);
1031 CreateDlrr(dlrr_blocks_, packet, length);
1032 CreateVoipMetric(voip_metric_blocks_, packet, length);
1033}
1034
1035void Xr::WithRrtr(Rrtr* rrtr) {
1036 assert(rrtr);
1037 if (rrtr_blocks_.size() >= kMaxNumberOfRrtrBlocks) {
1038 LOG(LS_WARNING) << "Max RRTR blocks reached.";
1039 return;
1040 }
1041 rrtr_blocks_.push_back(rrtr->rrtr_block_);
1042}
1043
1044void Xr::WithDlrr(Dlrr* dlrr) {
1045 assert(dlrr);
1046 if (dlrr_blocks_.size() >= kMaxNumberOfDlrrBlocks) {
1047 LOG(LS_WARNING) << "Max DLRR blocks reached.";
1048 return;
1049 }
1050 dlrr_blocks_.push_back(dlrr->dlrr_block_);
1051}
1052
1053void Xr::WithVoipMetric(VoipMetric* voip_metric) {
1054 assert(voip_metric);
1055 if (voip_metric_blocks_.size() >= kMaxNumberOfVoipMetricBlocks) {
1056 LOG(LS_WARNING) << "Max Voip Metric blocks reached.";
1057 return;
1058 }
1059 voip_metric_blocks_.push_back(voip_metric->metric_);
1060}
1061
1062size_t Xr::DlrrLength() const {
1063 const size_t kBlockHeaderLen = 4;
1064 const size_t kSubBlockLen = 12;
1065 size_t length = 0;
1066 for (std::vector<DlrrBlock>::const_iterator it = dlrr_blocks_.begin();
1067 it != dlrr_blocks_.end(); ++it) {
1068 if (!(*it).empty()) {
1069 length += kBlockHeaderLen + kSubBlockLen * (*it).size();
1070 }
1071 }
1072 return length;
1073}
1074
1075void Dlrr::WithDlrrItem(uint32_t ssrc,
1076 uint32_t last_rr,
1077 uint32_t delay_last_rr) {
1078 if (dlrr_block_.size() >= kMaxNumberOfDlrrItems) {
1079 LOG(LS_WARNING) << "Max DLRR items reached.";
1080 return;
1081 }
1082 RTCPPacketXRDLRRReportBlockItem dlrr;
1083 dlrr.SSRC = ssrc;
1084 dlrr.LastRR = last_rr;
1085 dlrr.DelayLastRR = delay_last_rr;
1086 dlrr_block_.push_back(dlrr);
1087}
1088
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +00001089} // namespace rtcp
1090} // namespace webrtc