blob: a4cdfd95deea2771edc7444cfffcf92a9db10f1c [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.org4b12d402014-06-16 14:09:28 +000016using webrtc::RTCPUtility::PT_APP;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000017using webrtc::RTCPUtility::PT_BYE;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000018using webrtc::RTCPUtility::PT_IJ;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000019using webrtc::RTCPUtility::PT_PSFB;
20using webrtc::RTCPUtility::PT_RR;
21using webrtc::RTCPUtility::PT_RTPFB;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000022using webrtc::RTCPUtility::PT_SDES;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000023using webrtc::RTCPUtility::PT_SR;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000024using webrtc::RTCPUtility::PT_XR;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000025
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000026using webrtc::RTCPUtility::RTCPPacketAPP;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000027using webrtc::RTCPUtility::RTCPPacketBYE;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000028using webrtc::RTCPUtility::RTCPPacketPSFBAPP;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000029using webrtc::RTCPUtility::RTCPPacketPSFBFIR;
30using webrtc::RTCPUtility::RTCPPacketPSFBFIRItem;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000031using webrtc::RTCPUtility::RTCPPacketPSFBPLI;
32using webrtc::RTCPUtility::RTCPPacketPSFBREMBItem;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000033using webrtc::RTCPUtility::RTCPPacketPSFBRPSI;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000034using webrtc::RTCPUtility::RTCPPacketPSFBSLI;
35using webrtc::RTCPUtility::RTCPPacketPSFBSLIItem;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000036using webrtc::RTCPUtility::RTCPPacketReportBlockItem;
37using webrtc::RTCPUtility::RTCPPacketRR;
38using webrtc::RTCPUtility::RTCPPacketRTPFBNACK;
39using webrtc::RTCPUtility::RTCPPacketRTPFBNACKItem;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000040using webrtc::RTCPUtility::RTCPPacketRTPFBTMMBN;
41using webrtc::RTCPUtility::RTCPPacketRTPFBTMMBNItem;
42using webrtc::RTCPUtility::RTCPPacketRTPFBTMMBR;
43using webrtc::RTCPUtility::RTCPPacketRTPFBTMMBRItem;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000044using webrtc::RTCPUtility::RTCPPacketSR;
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000045using webrtc::RTCPUtility::RTCPPacketXRDLRRReportBlockItem;
46using webrtc::RTCPUtility::RTCPPacketXRReceiverReferenceTimeItem;
47using webrtc::RTCPUtility::RTCPPacketXR;
48using webrtc::RTCPUtility::RTCPPacketXRVOIPMetricItem;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000049
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +000050namespace webrtc {
51namespace rtcp {
52namespace {
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000053// Unused SSRC of media source, set to 0.
54const uint32_t kUnusedMediaSourceSsrc0 = 0;
55
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000056void AssignUWord8(uint8_t* buffer, size_t* offset, uint8_t value) {
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +000057 buffer[(*offset)++] = value;
58}
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000059void AssignUWord16(uint8_t* buffer, size_t* offset, uint16_t value) {
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +000060 ModuleRTPUtility::AssignUWord16ToBuffer(buffer + *offset, value);
61 *offset += 2;
62}
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000063void AssignUWord24(uint8_t* buffer, size_t* offset, uint32_t value) {
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +000064 ModuleRTPUtility::AssignUWord24ToBuffer(buffer + *offset, value);
65 *offset += 3;
66}
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000067void AssignUWord32(uint8_t* buffer, size_t* offset, uint32_t value) {
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +000068 ModuleRTPUtility::AssignUWord32ToBuffer(buffer + *offset, value);
69 *offset += 4;
70}
71
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000072size_t BlockToHeaderLength(size_t length_in_bytes) {
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000073 // Length in 32-bit words minus 1.
74 assert(length_in_bytes > 0);
75 assert(length_in_bytes % 4 == 0);
76 return (length_in_bytes / 4) - 1;
77}
78
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +000079// From RFC 3550, RTP: A Transport Protocol for Real-Time Applications.
80//
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000081// RTP header format.
82// 0 1 2 3
83// 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
84// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
85// |V=2|P| RC/FMT | PT | length |
86// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
87
88void CreateHeader(uint8_t count_or_format, // Depends on packet type.
89 uint8_t packet_type,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000090 size_t length,
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000091 uint8_t* buffer,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +000092 size_t* pos) {
93 assert(length <= 0xffff);
asapersson@webrtc.orga8260062014-05-20 09:53:51 +000094 const uint8_t kVersion = 2;
95 AssignUWord8(buffer, pos, (kVersion << 6) + count_or_format);
96 AssignUWord8(buffer, pos, packet_type);
97 AssignUWord16(buffer, pos, length);
98}
99
100// Sender report (SR) (RFC 3550).
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000101// 0 1 2 3
102// 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
103// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
104// |V=2|P| RC | PT=SR=200 | length |
105// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
106// | SSRC of sender |
107// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
108// | NTP timestamp, most significant word |
109// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
110// | NTP timestamp, least significant word |
111// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
112// | RTP timestamp |
113// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
114// | sender's packet count |
115// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
116// | sender's octet count |
117// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
118
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000119void CreateSenderReport(const RTCPPacketSR& sr,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000120 size_t length,
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000121 uint8_t* buffer,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000122 size_t* pos) {
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000123 CreateHeader(sr.NumberOfReportBlocks, PT_SR, length, buffer, pos);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000124 AssignUWord32(buffer, pos, sr.SenderSSRC);
125 AssignUWord32(buffer, pos, sr.NTPMostSignificant);
126 AssignUWord32(buffer, pos, sr.NTPLeastSignificant);
127 AssignUWord32(buffer, pos, sr.RTPTimestamp);
128 AssignUWord32(buffer, pos, sr.SenderPacketCount);
129 AssignUWord32(buffer, pos, sr.SenderOctetCount);
130}
131
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000132// Receiver report (RR), header (RFC 3550).
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000133//
134// 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
135// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
136// |V=2|P| RC | PT=RR=201 | length |
137// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
138// | SSRC of packet sender |
139// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
140
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000141void CreateReceiverReport(const RTCPPacketRR& rr,
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(rr.NumberOfReportBlocks, PT_RR, length, buffer, pos);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000146 AssignUWord32(buffer, pos, rr.SenderSSRC);
147}
148
149// Report block (RFC 3550).
150//
151// 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
152// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
153// | SSRC_1 (SSRC of first source) |
154// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
155// | fraction lost | cumulative number of packets lost |
156// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
157// | extended highest sequence number received |
158// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
159// | interarrival jitter |
160// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
161// | last SR (LSR) |
162// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
163// | delay since last SR (DLSR) |
164// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
165
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000166void CreateReportBlocks(const std::vector<RTCPPacketReportBlockItem>& blocks,
167 uint8_t* buffer,
168 size_t* pos) {
169 for (std::vector<RTCPPacketReportBlockItem>::const_iterator
170 it = blocks.begin(); it != blocks.end(); ++it) {
171 AssignUWord32(buffer, pos, (*it).SSRC);
172 AssignUWord8(buffer, pos, (*it).FractionLost);
173 AssignUWord24(buffer, pos, (*it).CumulativeNumOfPacketsLost);
174 AssignUWord32(buffer, pos, (*it).ExtendedHighestSequenceNumber);
175 AssignUWord32(buffer, pos, (*it).Jitter);
176 AssignUWord32(buffer, pos, (*it).LastSR);
177 AssignUWord32(buffer, pos, (*it).DelayLastSR);
178 }
179}
180
181// Transmission Time Offsets in RTP Streams (RFC 5450).
182//
183// 0 1 2 3
184// 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
185// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
186// hdr |V=2|P| RC | PT=IJ=195 | length |
187// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
188// | inter-arrival jitter |
189// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
190// . .
191// . .
192// . .
193// | inter-arrival jitter |
194// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
195
196void CreateIj(const std::vector<uint32_t>& ij_items,
197 uint8_t* buffer,
198 size_t* pos) {
199 size_t length = ij_items.size();
200 CreateHeader(length, PT_IJ, length, buffer, pos);
201 for (std::vector<uint32_t>::const_iterator it = ij_items.begin();
202 it != ij_items.end(); ++it) {
203 AssignUWord32(buffer, pos, *it);
204 }
205}
206
207// Source Description (SDES) (RFC 3550).
208//
209// 0 1 2 3
210// 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
211// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
212// header |V=2|P| SC | PT=SDES=202 | length |
213// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
214// chunk | SSRC/CSRC_1 |
215// 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
216// | SDES items |
217// | ... |
218// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
219// chunk | SSRC/CSRC_2 |
220// 2 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
221// | SDES items |
222// | ... |
223// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
224//
225// Canonical End-Point Identifier SDES Item (CNAME)
226//
227// 0 1 2 3
228// 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
229// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
230// | CNAME=1 | length | user and domain name ...
231// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
232
233void CreateSdes(const std::vector<Sdes::Chunk>& chunks,
234 size_t length,
235 uint8_t* buffer,
236 size_t* pos) {
237 CreateHeader(chunks.size(), PT_SDES, length, buffer, pos);
238 const uint8_t kSdesItemType = 1;
239 for (std::vector<Sdes::Chunk>::const_iterator it = chunks.begin();
240 it != chunks.end(); ++it) {
241 AssignUWord32(buffer, pos, (*it).ssrc);
242 AssignUWord8(buffer, pos, kSdesItemType);
243 AssignUWord8(buffer, pos, (*it).name.length());
244 memcpy(buffer + *pos, (*it).name.data(), (*it).name.length());
245 *pos += (*it).name.length();
246 memset(buffer + *pos, 0, (*it).null_octets);
247 *pos += (*it).null_octets;
248 }
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000249}
250
251// Bye packet (BYE) (RFC 3550).
252//
253// 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
254// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
255// |V=2|P| SC | PT=BYE=203 | length |
256// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
257// | SSRC/CSRC |
258// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
259// : ... :
260// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
261// (opt) | length | reason for leaving ...
262// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
263
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000264void CreateBye(const RTCPPacketBYE& bye,
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000265 const std::vector<uint32_t>& csrcs,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000266 size_t length,
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000267 uint8_t* buffer,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000268 size_t* pos) {
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000269 CreateHeader(length, PT_BYE, length, buffer, pos);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000270 AssignUWord32(buffer, pos, bye.SenderSSRC);
271 for (std::vector<uint32_t>::const_iterator it = csrcs.begin();
272 it != csrcs.end(); ++it) {
273 AssignUWord32(buffer, pos, *it);
274 }
275}
276
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000277// Application-Defined packet (APP) (RFC 3550).
278//
279// 0 1 2 3
280// 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
281// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
282// |V=2|P| subtype | PT=APP=204 | length |
283// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
284// | SSRC/CSRC |
285// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
286// | name (ASCII) |
287// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
288// | application-dependent data ...
289// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
290
291void CreateApp(const RTCPPacketAPP& app,
292 uint32_t ssrc,
293 size_t length,
294 uint8_t* buffer,
295 size_t* pos) {
296 CreateHeader(app.SubType, PT_APP, length, buffer, pos);
297 AssignUWord32(buffer, pos, ssrc);
298 AssignUWord32(buffer, pos, app.Name);
299 memcpy(buffer + *pos, app.Data, app.Size);
300 *pos += app.Size;
301}
302
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000303// RFC 4585: Feedback format.
304//
305// Common packet format:
306//
307// 0 1 2 3
308// 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
309// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
310// |V=2|P| FMT | PT | length |
311// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
312// | SSRC of packet sender |
313// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
314// | SSRC of media source |
315// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
316// : Feedback Control Information (FCI) :
317// :
318//
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000319
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000320// Picture loss indication (PLI) (RFC 4585).
321//
322// FCI: no feedback control information.
323
324void CreatePli(const RTCPPacketPSFBPLI& pli,
325 size_t length,
326 uint8_t* buffer,
327 size_t* pos) {
328 const uint8_t kFmt = 1;
329 CreateHeader(kFmt, PT_PSFB, length, buffer, pos);
330 AssignUWord32(buffer, pos, pli.SenderSSRC);
331 AssignUWord32(buffer, pos, pli.MediaSSRC);
332}
333
334// Slice loss indication (SLI) (RFC 4585).
335//
336// FCI:
337//
338// 0 1 2 3
339// 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
340// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
341// | First | Number | PictureID |
342// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
343
344void CreateSli(const RTCPPacketPSFBSLI& sli,
345 const RTCPPacketPSFBSLIItem& sli_item,
346 size_t length,
347 uint8_t* buffer,
348 size_t* pos) {
349 const uint8_t kFmt = 2;
350 CreateHeader(kFmt, PT_PSFB, length, buffer, pos);
351 AssignUWord32(buffer, pos, sli.SenderSSRC);
352 AssignUWord32(buffer, pos, sli.MediaSSRC);
353
354 AssignUWord8(buffer, pos, sli_item.FirstMB >> 5);
355 AssignUWord8(buffer, pos, (sli_item.FirstMB << 3) +
356 ((sli_item.NumberOfMB >> 10) & 0x07));
357 AssignUWord8(buffer, pos, sli_item.NumberOfMB >> 2);
358 AssignUWord8(buffer, pos, (sli_item.NumberOfMB << 6) + sli_item.PictureId);
359}
360
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000361// Generic NACK (RFC 4585).
362//
363// FCI:
364//
365// 0 1 2 3
366// 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
367// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
368// | PID | BLP |
369// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
370
371void CreateNack(const RTCPPacketRTPFBNACK& nack,
372 const std::vector<RTCPPacketRTPFBNACKItem>& nack_fields,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000373 size_t length,
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000374 uint8_t* buffer,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000375 size_t* pos) {
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000376 const uint8_t kFmt = 1;
377 CreateHeader(kFmt, PT_RTPFB, length, buffer, pos);
378 AssignUWord32(buffer, pos, nack.SenderSSRC);
379 AssignUWord32(buffer, pos, nack.MediaSSRC);
380 for (std::vector<RTCPPacketRTPFBNACKItem>::const_iterator
381 it = nack_fields.begin(); it != nack_fields.end(); ++it) {
382 AssignUWord16(buffer, pos, (*it).PacketID);
383 AssignUWord16(buffer, pos, (*it).BitMask);
384 }
385}
386
387// Reference picture selection indication (RPSI) (RFC 4585).
388//
389// FCI:
390//
391// 0 1 2 3
392// 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
393// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
394// | PB |0| Payload Type| Native RPSI bit string |
395// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
396// | defined per codec ... | Padding (0) |
397// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
398
399void CreateRpsi(const RTCPPacketPSFBRPSI& rpsi,
400 uint8_t padding_bytes,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000401 size_t length,
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000402 uint8_t* buffer,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000403 size_t* pos) {
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000404 // Native bit string should be a multiple of 8 bits.
405 assert(rpsi.NumberOfValidBits % 8 == 0);
406 const uint8_t kFmt = 3;
407 CreateHeader(kFmt, PT_PSFB, length, buffer, pos);
408 AssignUWord32(buffer, pos, rpsi.SenderSSRC);
409 AssignUWord32(buffer, pos, rpsi.MediaSSRC);
410 AssignUWord8(buffer, pos, padding_bytes * 8);
411 AssignUWord8(buffer, pos, rpsi.PayloadType);
412 memcpy(buffer + *pos, rpsi.NativeBitString, rpsi.NumberOfValidBits / 8);
413 *pos += rpsi.NumberOfValidBits / 8;
414 memset(buffer + *pos, 0, padding_bytes);
415 *pos += padding_bytes;
416}
417
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000418// Full intra request (FIR) (RFC 5104).
419//
420// FCI:
421//
422// 0 1 2 3
423// 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
424// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
425// | SSRC |
426// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
427// | Seq nr. | Reserved |
428// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
429
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000430void CreateFir(const RTCPPacketPSFBFIR& fir,
431 const RTCPPacketPSFBFIRItem& fir_item,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000432 size_t length,
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000433 uint8_t* buffer,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000434 size_t* pos) {
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000435 const uint8_t kFmt = 4;
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000436 CreateHeader(kFmt, PT_PSFB, length, buffer, pos);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000437 AssignUWord32(buffer, pos, fir.SenderSSRC);
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000438 AssignUWord32(buffer, pos, kUnusedMediaSourceSsrc0);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000439 AssignUWord32(buffer, pos, fir_item.SSRC);
440 AssignUWord8(buffer, pos, fir_item.CommandSequenceNumber);
441 AssignUWord24(buffer, pos, 0);
442}
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000443} // namespace
444
445void RtcpPacket::Append(RtcpPacket* packet) {
446 assert(packet);
447 appended_packets_.push_back(packet);
448}
449
450RawPacket RtcpPacket::Build() const {
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000451 size_t length = 0;
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000452 uint8_t packet[IP_PACKET_SIZE];
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000453 CreateAndAddAppended(packet, &length, IP_PACKET_SIZE);
454 return RawPacket(packet, length);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000455}
456
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000457void RtcpPacket::Build(uint8_t* packet,
458 size_t* length,
459 size_t max_length) const {
460 *length = 0;
461 CreateAndAddAppended(packet, length, max_length);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000462}
463
464void RtcpPacket::CreateAndAddAppended(uint8_t* packet,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000465 size_t* length,
466 size_t max_length) const {
467 Create(packet, length, max_length);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000468 for (std::vector<RtcpPacket*>::const_iterator it = appended_packets_.begin();
469 it != appended_packets_.end(); ++it) {
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000470 (*it)->CreateAndAddAppended(packet, length, max_length);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000471 }
472}
473
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000474void Empty::Create(uint8_t* packet, size_t* length, size_t max_length) const {
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000475}
476
477void SenderReport::Create(uint8_t* packet,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000478 size_t* length,
479 size_t max_length) const {
480 if (*length + BlockLength() > max_length) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000481 LOG(LS_WARNING) << "Max packet size reached.";
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000482 return;
483 }
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000484 CreateSenderReport(sr_, BlockToHeaderLength(BlockLength()), packet, length);
485 CreateReportBlocks(report_blocks_, packet, length);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000486}
487
488void SenderReport::WithReportBlock(ReportBlock* block) {
489 assert(block);
490 if (report_blocks_.size() >= kMaxNumberOfReportBlocks) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000491 LOG(LS_WARNING) << "Max report blocks reached.";
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000492 return;
493 }
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000494 report_blocks_.push_back(block->report_block_);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000495 sr_.NumberOfReportBlocks = report_blocks_.size();
496}
497
498void ReceiverReport::Create(uint8_t* packet,
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000499 size_t* length,
500 size_t max_length) const {
501 if (*length + BlockLength() > max_length) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000502 LOG(LS_WARNING) << "Max packet size reached.";
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000503 return;
504 }
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000505 CreateReceiverReport(rr_, BlockToHeaderLength(BlockLength()), packet, length);
506 CreateReportBlocks(report_blocks_, packet, length);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000507}
508
509void ReceiverReport::WithReportBlock(ReportBlock* block) {
510 assert(block);
511 if (report_blocks_.size() >= kMaxNumberOfReportBlocks) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000512 LOG(LS_WARNING) << "Max report blocks reached.";
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000513 return;
514 }
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000515 report_blocks_.push_back(block->report_block_);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000516 rr_.NumberOfReportBlocks = report_blocks_.size();
517}
518
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000519void Ij::Create(uint8_t* packet, size_t* length, size_t max_length) const {
520 if (*length + BlockLength() > max_length) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000521 LOG(LS_WARNING) << "Max packet size reached.";
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000522 return;
523 }
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000524 CreateIj(ij_items_, packet, length);
525}
526
527void Ij::WithJitterItem(uint32_t jitter) {
528 if (ij_items_.size() >= kMaxNumberOfIjItems) {
529 LOG(LS_WARNING) << "Max inter-arrival jitter items reached.";
530 return;
531 }
532 ij_items_.push_back(jitter);
533}
534
535void Sdes::Create(uint8_t* packet, size_t* length, size_t max_length) const {
536 assert(!chunks_.empty());
537 if (*length + BlockLength() > max_length) {
538 LOG(LS_WARNING) << "Max packet size reached.";
539 return;
540 }
541 CreateSdes(chunks_, BlockToHeaderLength(BlockLength()), packet, length);
542}
543
544void Sdes::WithCName(uint32_t ssrc, std::string cname) {
545 assert(cname.length() <= 0xff);
546 if (chunks_.size() >= kMaxNumberOfChunks) {
547 LOG(LS_WARNING) << "Max SDES chunks reached.";
548 return;
549 }
550 // In each chunk, the list of items must be terminated by one or more null
551 // octets. The next chunk must start on a 32-bit boundary.
552 // CNAME (1 byte) | length (1 byte) | name | padding.
553 int null_octets = 4 - ((2 + cname.length()) % 4);
554 Chunk chunk;
555 chunk.ssrc = ssrc;
556 chunk.name = cname;
557 chunk.null_octets = null_octets;
558 chunks_.push_back(chunk);
559}
560
561size_t Sdes::BlockLength() const {
562 // Header (4 bytes).
563 // Chunk:
564 // SSRC/CSRC (4 bytes) | CNAME (1 byte) | length (1 byte) | name | padding.
565 size_t length = kHeaderLength;
566 for (std::vector<Chunk>::const_iterator it = chunks_.begin();
567 it != chunks_.end(); ++it) {
568 length += 6 + (*it).name.length() + (*it).null_octets;
569 }
570 assert(length % 4 == 0);
571 return length;
572}
573
574void Bye::Create(uint8_t* packet, size_t* length, size_t max_length) const {
575 if (*length + BlockLength() > max_length) {
576 LOG(LS_WARNING) << "Max packet size reached.";
577 return;
578 }
579 CreateBye(bye_, csrcs_, BlockToHeaderLength(BlockLength()), packet, length);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000580}
581
582void Bye::WithCsrc(uint32_t csrc) {
583 if (csrcs_.size() >= kMaxNumberOfCsrcs) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000584 LOG(LS_WARNING) << "Max CSRC size reached.";
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000585 return;
586 }
587 csrcs_.push_back(csrc);
588}
589
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000590void App::Create(uint8_t* packet, size_t* length, size_t max_length) const {
591 if (*length + BlockLength() > max_length) {
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000592 LOG(LS_WARNING) << "Max packet size reached.";
593 return;
594 }
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000595 CreateApp(app_, ssrc_, BlockToHeaderLength(BlockLength()), packet, length);
596}
597
598void Pli::Create(uint8_t* packet, size_t* length, size_t max_length) const {
599 if (*length + BlockLength() > max_length) {
600 LOG(LS_WARNING) << "Max packet size reached.";
601 return;
602 }
603 CreatePli(pli_, BlockToHeaderLength(BlockLength()), packet, length);
604}
605
606void Sli::Create(uint8_t* packet, size_t* length, size_t max_length) const {
607 if (*length + BlockLength() > max_length) {
608 LOG(LS_WARNING) << "Max packet size reached.";
609 return;
610 }
611 CreateSli(sli_, sli_item_, BlockToHeaderLength(BlockLength()), packet,
612 length);
613}
614
615void Nack::Create(uint8_t* packet, size_t* length, size_t max_length) const {
616 assert(!nack_fields_.empty());
617 if (*length + BlockLength() > max_length) {
618 LOG(LS_WARNING) << "Max packet size reached.";
619 return;
620 }
621 CreateNack(nack_, nack_fields_, BlockToHeaderLength(BlockLength()), packet,
622 length);
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000623}
624
625void Nack::WithList(const uint16_t* nack_list, int length) {
626 assert(nack_list);
627 assert(nack_fields_.empty());
628 int i = 0;
629 while (i < length) {
630 uint16_t pid = nack_list[i++];
631 // Bitmask specifies losses in any of the 16 packets following the pid.
632 uint16_t bitmask = 0;
633 while (i < length) {
634 int shift = static_cast<uint16_t>(nack_list[i] - pid) - 1;
635 if (shift >= 0 && shift <= 15) {
636 bitmask |= (1 << shift);
637 ++i;
638 } else {
639 break;
640 }
641 }
642 RTCPUtility::RTCPPacketRTPFBNACKItem item;
643 item.PacketID = pid;
644 item.BitMask = bitmask;
645 nack_fields_.push_back(item);
646 }
647}
648
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000649void Rpsi::Create(uint8_t* packet, size_t* length, size_t max_length) const {
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000650 assert(rpsi_.NumberOfValidBits > 0);
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000651 if (*length + BlockLength() > max_length) {
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000652 LOG(LS_WARNING) << "Max packet size reached.";
653 return;
654 }
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000655 CreateRpsi(rpsi_, padding_bytes_, BlockToHeaderLength(BlockLength()), packet,
656 length);
asapersson@webrtc.orga8260062014-05-20 09:53:51 +0000657}
658
659void Rpsi::WithPictureId(uint64_t picture_id) {
660 const uint32_t kPidBits = 7;
661 const uint64_t k7MsbZeroMask = 0x1ffffffffffffff;
662 uint8_t required_bytes = 0;
663 uint64_t shifted_pid = picture_id;
664 do {
665 ++required_bytes;
666 shifted_pid = (shifted_pid >> kPidBits) & k7MsbZeroMask;
667 } while (shifted_pid > 0);
668
669 // Convert picture id to native bit string (natively defined by the video
670 // codec).
671 int pos = 0;
672 for (int i = required_bytes - 1; i > 0; i--) {
673 rpsi_.NativeBitString[pos++] =
674 0x80 | static_cast<uint8_t>(picture_id >> (i * kPidBits));
675 }
676 rpsi_.NativeBitString[pos++] = static_cast<uint8_t>(picture_id & 0x7f);
677 rpsi_.NumberOfValidBits = pos * 8;
678
679 // Calculate padding bytes (to reach next 32-bit boundary, 1, 2 or 3 bytes).
680 padding_bytes_ = 4 - ((2 + required_bytes) % 4);
681 if (padding_bytes_ == 4) {
682 padding_bytes_ = 0;
683 }
684}
685
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000686void Fir::Create(uint8_t* packet, size_t* length, size_t max_length) const {
687 if (*length + BlockLength() > max_length) {
andresp@webrtc.orgdc80bae2014-04-08 11:06:12 +0000688 LOG(LS_WARNING) << "Max packet size reached.";
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000689 return;
690 }
asapersson@webrtc.org4b12d402014-06-16 14:09:28 +0000691 CreateFir(fir_, fir_item_, BlockToHeaderLength(BlockLength()), packet,
692 length);
asapersson@webrtc.org0f2809a2014-02-21 08:14:45 +0000693}
694} // namespace rtcp
695} // namespace webrtc