blob: 5f919ff24e1f9435cd7e37503c462b54e01c1aa8 [file] [log] [blame]
danilchap1edb7ab2016-04-20 05:25:10 -07001/*
2 * Copyright (c) 2016 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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/rtp_rtcp/source/rtp_packet.h"
danilchap1edb7ab2016-04-20 05:25:10 -070012
Yves Gerey988cc082018-10-23 12:03:01 +020013#include <cstdint>
danilchap1edb7ab2016-04-20 05:25:10 -070014#include <cstring>
Danil Chapovalova64a2fb2016-09-12 11:41:35 +020015#include <utility>
danilchap1edb7ab2016-04-20 05:25:10 -070016
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "modules/rtp_rtcp/source/byte_io.h"
18#include "rtc_base/checks.h"
19#include "rtc_base/logging.h"
Karl Wiberge40468b2017-11-22 10:42:26 +010020#include "rtc_base/numerics/safe_conversions.h"
Anton Sukhanovff25b872019-07-09 13:04:07 -070021#include "rtc_base/strings/string_builder.h"
danilchap1edb7ab2016-04-20 05:25:10 -070022
23namespace webrtc {
danilchap1edb7ab2016-04-20 05:25:10 -070024namespace {
25constexpr size_t kFixedHeaderSize = 12;
26constexpr uint8_t kRtpVersion = 2;
Johannes Kron07ba2b92018-09-26 13:33:35 +020027constexpr uint16_t kOneByteExtensionProfileId = 0xBEDE;
28constexpr uint16_t kTwoByteExtensionProfileId = 0x1000;
29constexpr size_t kOneByteExtensionHeaderLength = 1;
30constexpr size_t kTwoByteExtensionHeaderLength = 2;
danilchap1edb7ab2016-04-20 05:25:10 -070031constexpr size_t kDefaultPacketSize = 1500;
32} // namespace
danilchap653063f2017-04-03 06:16:30 -070033
danilchap1edb7ab2016-04-20 05:25:10 -070034// 0 1 2 3
35// 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
36// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
37// |V=2|P|X| CC |M| PT | sequence number |
38// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39// | timestamp |
40// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41// | synchronization source (SSRC) identifier |
42// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
43// | Contributing source (CSRC) identifiers |
44// | .... |
45// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
Johannes Kron07ba2b92018-09-26 13:33:35 +020046// | header eXtension profile id | length in 32bits |
danilchap1edb7ab2016-04-20 05:25:10 -070047// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48// | Extensions |
49// | .... |
50// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
51// | Payload |
52// | .... : padding... |
53// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
54// | padding | Padding size |
55// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Danil Chapovalov8769e172017-09-14 14:08:22 +020056RtpPacket::RtpPacket() : RtpPacket(nullptr, kDefaultPacketSize) {}
danilchap70f39a32016-12-16 05:48:18 -080057
Danil Chapovalov8769e172017-09-14 14:08:22 +020058RtpPacket::RtpPacket(const ExtensionManager* extensions)
59 : RtpPacket(extensions, kDefaultPacketSize) {}
danilchap1edb7ab2016-04-20 05:25:10 -070060
Danil Chapovalov8769e172017-09-14 14:08:22 +020061RtpPacket::RtpPacket(const RtpPacket&) = default;
nisse76e62b02017-05-31 02:24:52 -070062
Danil Chapovalov8769e172017-09-14 14:08:22 +020063RtpPacket::RtpPacket(const ExtensionManager* extensions, size_t capacity)
Johannes Kron3dd473b2018-10-29 14:42:36 +010064 : extensions_(extensions ? *extensions : ExtensionManager()),
65 buffer_(capacity) {
danilchap1edb7ab2016-04-20 05:25:10 -070066 RTC_DCHECK_GE(capacity, kFixedHeaderSize);
67 Clear();
68}
69
Danil Chapovalov8769e172017-09-14 14:08:22 +020070RtpPacket::~RtpPacket() {}
danilchap1edb7ab2016-04-20 05:25:10 -070071
Danil Chapovalov8769e172017-09-14 14:08:22 +020072void RtpPacket::IdentifyExtensions(const ExtensionManager& extensions) {
Johannes Kronc5744b82018-09-24 14:50:48 +020073 extensions_ = extensions;
danilchap1edb7ab2016-04-20 05:25:10 -070074}
75
Danil Chapovalov8769e172017-09-14 14:08:22 +020076bool RtpPacket::Parse(const uint8_t* buffer, size_t buffer_size) {
danilchap1edb7ab2016-04-20 05:25:10 -070077 if (!ParseBuffer(buffer, buffer_size)) {
78 Clear();
79 return false;
80 }
danilchap1edb7ab2016-04-20 05:25:10 -070081 buffer_.SetData(buffer, buffer_size);
Danil Chapovalov31e4e802016-08-03 18:27:40 +020082 RTC_DCHECK_EQ(size(), buffer_size);
danilchap1edb7ab2016-04-20 05:25:10 -070083 return true;
84}
85
Danil Chapovalov8769e172017-09-14 14:08:22 +020086bool RtpPacket::Parse(rtc::ArrayView<const uint8_t> packet) {
brandtrb29e6522016-12-21 06:37:18 -080087 return Parse(packet.data(), packet.size());
88}
89
Danil Chapovalov8769e172017-09-14 14:08:22 +020090bool RtpPacket::Parse(rtc::CopyOnWriteBuffer buffer) {
Danil Chapovalov31e4e802016-08-03 18:27:40 +020091 if (!ParseBuffer(buffer.cdata(), buffer.size())) {
danilchap1edb7ab2016-04-20 05:25:10 -070092 Clear();
93 return false;
94 }
Danil Chapovalov31e4e802016-08-03 18:27:40 +020095 size_t buffer_size = buffer.size();
danilchap1edb7ab2016-04-20 05:25:10 -070096 buffer_ = std::move(buffer);
Danil Chapovalov31e4e802016-08-03 18:27:40 +020097 RTC_DCHECK_EQ(size(), buffer_size);
danilchap1edb7ab2016-04-20 05:25:10 -070098 return true;
99}
100
Danil Chapovalov8769e172017-09-14 14:08:22 +0200101std::vector<uint32_t> RtpPacket::Csrcs() const {
danilchap1edb7ab2016-04-20 05:25:10 -0700102 size_t num_csrc = data()[0] & 0x0F;
103 RTC_DCHECK_GE(capacity(), kFixedHeaderSize + num_csrc * 4);
104 std::vector<uint32_t> csrcs(num_csrc);
105 for (size_t i = 0; i < num_csrc; ++i) {
106 csrcs[i] =
107 ByteReader<uint32_t>::ReadBigEndian(&data()[kFixedHeaderSize + i * 4]);
108 }
109 return csrcs;
110}
111
Danil Chapovalov8769e172017-09-14 14:08:22 +0200112void RtpPacket::CopyHeaderFrom(const RtpPacket& packet) {
danilchap1edb7ab2016-04-20 05:25:10 -0700113 RTC_DCHECK_GE(capacity(), packet.headers_size());
114
115 marker_ = packet.marker_;
116 payload_type_ = packet.payload_type_;
117 sequence_number_ = packet.sequence_number_;
118 timestamp_ = packet.timestamp_;
119 ssrc_ = packet.ssrc_;
120 payload_offset_ = packet.payload_offset_;
Johannes Kronc5744b82018-09-24 14:50:48 +0200121 extensions_ = packet.extensions_;
122 extension_entries_ = packet.extension_entries_;
danilchap1edb7ab2016-04-20 05:25:10 -0700123 extensions_size_ = packet.extensions_size_;
124 buffer_.SetData(packet.data(), packet.headers_size());
125 // Reset payload and padding.
126 payload_size_ = 0;
127 padding_size_ = 0;
128}
129
Danil Chapovalov8769e172017-09-14 14:08:22 +0200130void RtpPacket::SetMarker(bool marker_bit) {
danilchap1edb7ab2016-04-20 05:25:10 -0700131 marker_ = marker_bit;
132 if (marker_) {
133 WriteAt(1, data()[1] | 0x80);
134 } else {
135 WriteAt(1, data()[1] & 0x7F);
136 }
137}
138
Danil Chapovalov8769e172017-09-14 14:08:22 +0200139void RtpPacket::SetPayloadType(uint8_t payload_type) {
danilchap1edb7ab2016-04-20 05:25:10 -0700140 RTC_DCHECK_LE(payload_type, 0x7Fu);
141 payload_type_ = payload_type;
142 WriteAt(1, (data()[1] & 0x80) | payload_type);
143}
144
Danil Chapovalov8769e172017-09-14 14:08:22 +0200145void RtpPacket::SetSequenceNumber(uint16_t seq_no) {
danilchap1edb7ab2016-04-20 05:25:10 -0700146 sequence_number_ = seq_no;
147 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(2), seq_no);
148}
149
Danil Chapovalov8769e172017-09-14 14:08:22 +0200150void RtpPacket::SetTimestamp(uint32_t timestamp) {
danilchap1edb7ab2016-04-20 05:25:10 -0700151 timestamp_ = timestamp;
152 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(4), timestamp);
153}
154
Danil Chapovalov8769e172017-09-14 14:08:22 +0200155void RtpPacket::SetSsrc(uint32_t ssrc) {
danilchap1edb7ab2016-04-20 05:25:10 -0700156 ssrc_ = ssrc;
157 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(8), ssrc);
158}
159
Ilya Nikolaevskiy082696e2019-09-03 07:52:52 +0000160void RtpPacket::CopyAndZeroMutableExtensions(
161 rtc::ArrayView<uint8_t> buffer) const {
162 RTC_CHECK_GE(buffer.size(), buffer_.size());
163 memcpy(buffer.data(), buffer_.cdata(), buffer_.size());
Ilya Nikolaevskiy2d821c32019-06-26 14:39:36 +0200164 for (const ExtensionInfo& extension : extension_entries_) {
165 switch (extensions_.GetType(extension.id)) {
166 case RTPExtensionType::kRtpExtensionNone: {
167 RTC_LOG(LS_WARNING) << "Unidentified extension in the packet.";
168 break;
169 }
170 case RTPExtensionType::kRtpExtensionVideoTiming: {
171 // Nullify 3 last entries: packetization delay and 2 network timestamps.
172 // Each of them is 2 bytes.
Ilya Nikolaevskiy082696e2019-09-03 07:52:52 +0000173 memset(buffer.data() + extension.offset +
174 VideoSendTiming::kPacerExitDeltaOffset,
175 0, 6);
Ilya Nikolaevskiy2d821c32019-06-26 14:39:36 +0200176 break;
177 }
178 case RTPExtensionType::kRtpExtensionTransportSequenceNumber:
179 case RTPExtensionType::kRtpExtensionTransportSequenceNumber02:
180 case RTPExtensionType::kRtpExtensionTransmissionTimeOffset:
181 case RTPExtensionType::kRtpExtensionAbsoluteSendTime: {
182 // Nullify whole extension, as it's filled in the pacer.
Ilya Nikolaevskiy082696e2019-09-03 07:52:52 +0000183 memset(buffer.data() + extension.offset, 0, extension.length);
Ilya Nikolaevskiy2d821c32019-06-26 14:39:36 +0200184 break;
185 }
186 case RTPExtensionType::kRtpExtensionAudioLevel:
Chen Xingcd8a6e22019-07-01 10:56:51 +0200187 case RTPExtensionType::kRtpExtensionAbsoluteCaptureTime:
Ilya Nikolaevskiy2d821c32019-06-26 14:39:36 +0200188 case RTPExtensionType::kRtpExtensionColorSpace:
189 case RTPExtensionType::kRtpExtensionFrameMarking:
190 case RTPExtensionType::kRtpExtensionGenericFrameDescriptor00:
191 case RTPExtensionType::kRtpExtensionGenericFrameDescriptor01:
Danil Chapovalov52e52422019-06-27 16:45:40 +0200192 case RTPExtensionType::kRtpExtensionGenericFrameDescriptor02:
Ilya Nikolaevskiy2d821c32019-06-26 14:39:36 +0200193 case RTPExtensionType::kRtpExtensionMid:
194 case RTPExtensionType::kRtpExtensionNumberOfExtensions:
195 case RTPExtensionType::kRtpExtensionPlayoutDelay:
196 case RTPExtensionType::kRtpExtensionRepairedRtpStreamId:
197 case RTPExtensionType::kRtpExtensionRtpStreamId:
198 case RTPExtensionType::kRtpExtensionVideoContentType:
199 case RTPExtensionType::kRtpExtensionVideoRotation: {
200 // Non-mutable extension. Don't change it.
201 break;
202 }
203 }
204 }
205}
206
Danil Chapovalov7d2df3f2018-08-14 17:18:07 +0200207void RtpPacket::SetCsrcs(rtc::ArrayView<const uint32_t> csrcs) {
danilchap70f39a32016-12-16 05:48:18 -0800208 RTC_DCHECK_EQ(extensions_size_, 0);
kwibergaf476c72016-11-28 15:21:39 -0800209 RTC_DCHECK_EQ(payload_size_, 0);
210 RTC_DCHECK_EQ(padding_size_, 0);
danilchap1edb7ab2016-04-20 05:25:10 -0700211 RTC_DCHECK_LE(csrcs.size(), 0x0fu);
212 RTC_DCHECK_LE(kFixedHeaderSize + 4 * csrcs.size(), capacity());
213 payload_offset_ = kFixedHeaderSize + 4 * csrcs.size();
danilchap772bd8b2017-09-13 03:24:28 -0700214 WriteAt(0, (data()[0] & 0xF0) | rtc::dchecked_cast<uint8_t>(csrcs.size()));
danilchap1edb7ab2016-04-20 05:25:10 -0700215 size_t offset = kFixedHeaderSize;
216 for (uint32_t csrc : csrcs) {
217 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(offset), csrc);
218 offset += 4;
219 }
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200220 buffer_.SetSize(payload_offset_);
danilchap1edb7ab2016-04-20 05:25:10 -0700221}
222
Danil Chapovalov8769e172017-09-14 14:08:22 +0200223rtc::ArrayView<uint8_t> RtpPacket::AllocateRawExtension(int id, size_t length) {
Johannes Kron07ba2b92018-09-26 13:33:35 +0200224 RTC_DCHECK_GE(id, RtpExtension::kMinId);
Johannes Kron78cdde32018-10-05 10:00:46 +0200225 RTC_DCHECK_LE(id, RtpExtension::kMaxId);
danilchap653063f2017-04-03 06:16:30 -0700226 RTC_DCHECK_GE(length, 1);
Johannes Kron78cdde32018-10-05 10:00:46 +0200227 RTC_DCHECK_LE(length, RtpExtension::kMaxValueSize);
Johannes Kronc5744b82018-09-24 14:50:48 +0200228 const ExtensionInfo* extension_entry = FindExtensionInfo(id);
229 if (extension_entry != nullptr) {
danilchap653063f2017-04-03 06:16:30 -0700230 // Extension already reserved. Check if same length is used.
231 if (extension_entry->length == length)
232 return rtc::MakeArrayView(WriteAt(extension_entry->offset), length);
233
Johannes Kronc5744b82018-09-24 14:50:48 +0200234 RTC_LOG(LS_ERROR) << "Length mismatch for extension id " << id
Mirko Bonadei675513b2017-11-09 11:09:25 +0100235 << ": expected "
236 << static_cast<int>(extension_entry->length)
237 << ". received " << length;
danilchap653063f2017-04-03 06:16:30 -0700238 return nullptr;
239 }
240 if (payload_size_ > 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100241 RTC_LOG(LS_ERROR) << "Can't add new extension id " << id
242 << " after payload was set.";
danilchap653063f2017-04-03 06:16:30 -0700243 return nullptr;
244 }
245 if (padding_size_ > 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100246 RTC_LOG(LS_ERROR) << "Can't add new extension id " << id
247 << " after padding was set.";
danilchap653063f2017-04-03 06:16:30 -0700248 return nullptr;
249 }
250
Johannes Kron78cdde32018-10-05 10:00:46 +0200251 const size_t num_csrc = data()[0] & 0x0F;
252 const size_t extensions_offset = kFixedHeaderSize + (num_csrc * 4) + 4;
253 // Determine if two-byte header is required for the extension based on id and
254 // length. Please note that a length of 0 also requires two-byte header
255 // extension. See RFC8285 Section 4.2-4.3.
256 const bool two_byte_header_required =
257 id > RtpExtension::kOneByteHeaderExtensionMaxId ||
258 length > RtpExtension::kOneByteHeaderExtensionMaxValueSize || length == 0;
Johannes Kron9581bc42018-10-23 10:17:39 +0200259 RTC_CHECK(!two_byte_header_required || extensions_.ExtmapAllowMixed());
Johannes Kron78cdde32018-10-05 10:00:46 +0200260
261 uint16_t profile_id;
262 if (extensions_size_ > 0) {
263 profile_id =
264 ByteReader<uint16_t>::ReadBigEndian(data() + extensions_offset - 4);
265 if (profile_id == kOneByteExtensionProfileId && two_byte_header_required) {
266 // Is buffer size big enough to fit promotion and new data field?
267 // The header extension will grow with one byte per already allocated
268 // extension + the size of the extension that is about to be allocated.
269 size_t expected_new_extensions_size =
270 extensions_size_ + extension_entries_.size() +
271 kTwoByteExtensionHeaderLength + length;
272 if (extensions_offset + expected_new_extensions_size > capacity()) {
273 RTC_LOG(LS_ERROR)
274 << "Extension cannot be registered: Not enough space left in "
275 "buffer to change to two-byte header extension and add new "
276 "extension.";
277 return nullptr;
278 }
279 // Promote already written data to two-byte header format.
280 PromoteToTwoByteHeaderExtension();
281 profile_id = kTwoByteExtensionProfileId;
282 }
283 } else {
284 // Profile specific ID, set to OneByteExtensionHeader unless
285 // TwoByteExtensionHeader is required.
286 profile_id = two_byte_header_required ? kTwoByteExtensionProfileId
287 : kOneByteExtensionProfileId;
288 }
289
290 const size_t extension_header_size = profile_id == kOneByteExtensionProfileId
291 ? kOneByteExtensionHeaderLength
292 : kTwoByteExtensionHeaderLength;
Johannes Kron07ba2b92018-09-26 13:33:35 +0200293 size_t new_extensions_size =
Johannes Kron78cdde32018-10-05 10:00:46 +0200294 extensions_size_ + extension_header_size + length;
danilchap653063f2017-04-03 06:16:30 -0700295 if (extensions_offset + new_extensions_size > capacity()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100296 RTC_LOG(LS_ERROR)
danilchap653063f2017-04-03 06:16:30 -0700297 << "Extension cannot be registered: Not enough space left in buffer.";
298 return nullptr;
299 }
300
301 // All checks passed, write down the extension headers.
302 if (extensions_size_ == 0) {
303 RTC_DCHECK_EQ(payload_offset_, kFixedHeaderSize + (num_csrc * 4));
304 WriteAt(0, data()[0] | 0x10); // Set extension bit.
danilchap653063f2017-04-03 06:16:30 -0700305 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 4),
Johannes Kron78cdde32018-10-05 10:00:46 +0200306 profile_id);
danilchap653063f2017-04-03 06:16:30 -0700307 }
308
Johannes Kron78cdde32018-10-05 10:00:46 +0200309 if (profile_id == kOneByteExtensionProfileId) {
310 uint8_t one_byte_header = rtc::dchecked_cast<uint8_t>(id) << 4;
311 one_byte_header |= rtc::dchecked_cast<uint8_t>(length - 1);
312 WriteAt(extensions_offset + extensions_size_, one_byte_header);
313 } else {
314 // TwoByteHeaderExtension.
315 uint8_t extension_id = rtc::dchecked_cast<uint8_t>(id);
316 WriteAt(extensions_offset + extensions_size_, extension_id);
317 uint8_t extension_length = rtc::dchecked_cast<uint8_t>(length);
318 WriteAt(extensions_offset + extensions_size_ + 1, extension_length);
319 }
danilchap653063f2017-04-03 06:16:30 -0700320
Johannes Kronc5744b82018-09-24 14:50:48 +0200321 const uint16_t extension_info_offset = rtc::dchecked_cast<uint16_t>(
Johannes Kron78cdde32018-10-05 10:00:46 +0200322 extensions_offset + extensions_size_ + extension_header_size);
Johannes Kronc5744b82018-09-24 14:50:48 +0200323 const uint8_t extension_info_length = rtc::dchecked_cast<uint8_t>(length);
324 extension_entries_.emplace_back(id, extension_info_length,
325 extension_info_offset);
Johannes Kron78cdde32018-10-05 10:00:46 +0200326
Danil Chapovalov61405bc2018-02-13 13:55:30 +0100327 extensions_size_ = new_extensions_size;
danilchap653063f2017-04-03 06:16:30 -0700328
Johannes Kron78cdde32018-10-05 10:00:46 +0200329 uint16_t extensions_size_padded =
330 SetExtensionLengthMaybeAddZeroPadding(extensions_offset);
331 payload_offset_ = extensions_offset + extensions_size_padded;
332 buffer_.SetSize(payload_offset_);
333 return rtc::MakeArrayView(WriteAt(extension_info_offset),
334 extension_info_length);
335}
336
337void RtpPacket::PromoteToTwoByteHeaderExtension() {
338 size_t num_csrc = data()[0] & 0x0F;
339 size_t extensions_offset = kFixedHeaderSize + (num_csrc * 4) + 4;
340
341 RTC_CHECK_GT(extension_entries_.size(), 0);
342 RTC_CHECK_EQ(payload_size_, 0);
343 RTC_CHECK_EQ(kOneByteExtensionProfileId, ByteReader<uint16_t>::ReadBigEndian(
344 data() + extensions_offset - 4));
345 // Rewrite data.
346 // Each extension adds one to the offset. The write-read delta for the last
347 // extension is therefore the same as the number of extension entries.
348 size_t write_read_delta = extension_entries_.size();
349 for (auto extension_entry = extension_entries_.rbegin();
350 extension_entry != extension_entries_.rend(); ++extension_entry) {
351 size_t read_index = extension_entry->offset;
352 size_t write_index = read_index + write_read_delta;
353 // Update offset.
354 extension_entry->offset = rtc::dchecked_cast<uint16_t>(write_index);
355 // Copy data. Use memmove since read/write regions may overlap.
356 memmove(WriteAt(write_index), data() + read_index, extension_entry->length);
357 // Rewrite id and length.
358 WriteAt(--write_index, extension_entry->length);
359 WriteAt(--write_index, extension_entry->id);
360 --write_read_delta;
361 }
362
363 // Update profile header, extensions length, and zero padding.
364 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 4),
365 kTwoByteExtensionProfileId);
366 extensions_size_ += extension_entries_.size();
367 uint16_t extensions_size_padded =
368 SetExtensionLengthMaybeAddZeroPadding(extensions_offset);
369 payload_offset_ = extensions_offset + extensions_size_padded;
370 buffer_.SetSize(payload_offset_);
371}
372
373uint16_t RtpPacket::SetExtensionLengthMaybeAddZeroPadding(
374 size_t extensions_offset) {
danilchap653063f2017-04-03 06:16:30 -0700375 // Update header length field.
Danil Chapovalov61405bc2018-02-13 13:55:30 +0100376 uint16_t extensions_words = rtc::dchecked_cast<uint16_t>(
377 (extensions_size_ + 3) / 4); // Wrap up to 32bit.
danilchap653063f2017-04-03 06:16:30 -0700378 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 2),
379 extensions_words);
380 // Fill extension padding place with zeroes.
381 size_t extension_padding_size = 4 * extensions_words - extensions_size_;
382 memset(WriteAt(extensions_offset + extensions_size_), 0,
383 extension_padding_size);
Johannes Kron78cdde32018-10-05 10:00:46 +0200384 return 4 * extensions_words;
danilchap653063f2017-04-03 06:16:30 -0700385}
386
Danil Chapovalov8769e172017-09-14 14:08:22 +0200387uint8_t* RtpPacket::AllocatePayload(size_t size_bytes) {
danilchap07a01b32017-03-29 07:33:13 -0700388 // Reset payload size to 0. If CopyOnWrite buffer_ was shared, this will cause
389 // reallocation and memcpy. Keeping just header reduces memcpy size.
390 SetPayloadSize(0);
391 return SetPayloadSize(size_bytes);
392}
393
Danil Chapovalov8769e172017-09-14 14:08:22 +0200394uint8_t* RtpPacket::SetPayloadSize(size_t size_bytes) {
kwibergaf476c72016-11-28 15:21:39 -0800395 RTC_DCHECK_EQ(padding_size_, 0);
danilchap1edb7ab2016-04-20 05:25:10 -0700396 if (payload_offset_ + size_bytes > capacity()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100397 RTC_LOG(LS_WARNING) << "Cannot set payload, not enough space in buffer.";
danilchap1edb7ab2016-04-20 05:25:10 -0700398 return nullptr;
399 }
400 payload_size_ = size_bytes;
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200401 buffer_.SetSize(payload_offset_ + payload_size_);
danilchap1edb7ab2016-04-20 05:25:10 -0700402 return WriteAt(payload_offset_);
403}
404
Danil Chapovalovf7fcaf02018-10-10 14:56:01 +0200405bool RtpPacket::SetPadding(size_t padding_bytes) {
406 if (payload_offset_ + payload_size_ + padding_bytes > capacity()) {
407 RTC_LOG(LS_WARNING) << "Cannot set padding size " << padding_bytes
408 << ", only "
Mirko Bonadei675513b2017-11-09 11:09:25 +0100409 << (capacity() - payload_offset_ - payload_size_)
410 << " bytes left in buffer.";
danilchap1edb7ab2016-04-20 05:25:10 -0700411 return false;
412 }
Danil Chapovalovf7fcaf02018-10-10 14:56:01 +0200413 padding_size_ = rtc::dchecked_cast<uint8_t>(padding_bytes);
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200414 buffer_.SetSize(payload_offset_ + payload_size_ + padding_size_);
danilchap1edb7ab2016-04-20 05:25:10 -0700415 if (padding_size_ > 0) {
416 size_t padding_offset = payload_offset_ + payload_size_;
417 size_t padding_end = padding_offset + padding_size_;
Danil Chapovalovf7fcaf02018-10-10 14:56:01 +0200418 memset(WriteAt(padding_offset), 0, padding_size_ - 1);
danilchap1edb7ab2016-04-20 05:25:10 -0700419 WriteAt(padding_end - 1, padding_size_);
420 WriteAt(0, data()[0] | 0x20); // Set padding bit.
421 } else {
422 WriteAt(0, data()[0] & ~0x20); // Clear padding bit.
423 }
424 return true;
425}
426
Danil Chapovalov8769e172017-09-14 14:08:22 +0200427void RtpPacket::Clear() {
danilchap1edb7ab2016-04-20 05:25:10 -0700428 marker_ = false;
429 payload_type_ = 0;
430 sequence_number_ = 0;
431 timestamp_ = 0;
432 ssrc_ = 0;
433 payload_offset_ = kFixedHeaderSize;
434 payload_size_ = 0;
435 padding_size_ = 0;
danilchap1edb7ab2016-04-20 05:25:10 -0700436 extensions_size_ = 0;
Johannes Kronc5744b82018-09-24 14:50:48 +0200437 extension_entries_.clear();
danilchap1edb7ab2016-04-20 05:25:10 -0700438
439 memset(WriteAt(0), 0, kFixedHeaderSize);
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200440 buffer_.SetSize(kFixedHeaderSize);
danilchap1edb7ab2016-04-20 05:25:10 -0700441 WriteAt(0, kRtpVersion << 6);
442}
443
Danil Chapovalov8769e172017-09-14 14:08:22 +0200444bool RtpPacket::ParseBuffer(const uint8_t* buffer, size_t size) {
danilchap1edb7ab2016-04-20 05:25:10 -0700445 if (size < kFixedHeaderSize) {
446 return false;
447 }
448 const uint8_t version = buffer[0] >> 6;
449 if (version != kRtpVersion) {
450 return false;
451 }
452 const bool has_padding = (buffer[0] & 0x20) != 0;
453 const bool has_extension = (buffer[0] & 0x10) != 0;
454 const uint8_t number_of_crcs = buffer[0] & 0x0f;
455 marker_ = (buffer[1] & 0x80) != 0;
456 payload_type_ = buffer[1] & 0x7f;
457
458 sequence_number_ = ByteReader<uint16_t>::ReadBigEndian(&buffer[2]);
459 timestamp_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]);
460 ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]);
461 if (size < kFixedHeaderSize + number_of_crcs * 4) {
462 return false;
463 }
464 payload_offset_ = kFixedHeaderSize + number_of_crcs * 4;
465
466 if (has_padding) {
467 padding_size_ = buffer[size - 1];
468 if (padding_size_ == 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100469 RTC_LOG(LS_WARNING) << "Padding was set, but padding size is zero";
danilchap1edb7ab2016-04-20 05:25:10 -0700470 return false;
471 }
472 } else {
473 padding_size_ = 0;
474 }
475
danilchap1edb7ab2016-04-20 05:25:10 -0700476 extensions_size_ = 0;
Johannes Kron6ea77192018-09-24 17:19:52 +0200477 extension_entries_.clear();
danilchap1edb7ab2016-04-20 05:25:10 -0700478 if (has_extension) {
479 /* RTP header extension, RFC 3550.
480 0 1 2 3
481 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
482 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
483 | defined by profile | length |
484 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
485 | header extension |
486 | .... |
487 */
488 size_t extension_offset = payload_offset_ + 4;
489 if (extension_offset > size) {
490 return false;
491 }
492 uint16_t profile =
493 ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_]);
494 size_t extensions_capacity =
495 ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_ + 2]);
496 extensions_capacity *= 4;
497 if (extension_offset + extensions_capacity > size) {
498 return false;
499 }
Johannes Kron07ba2b92018-09-26 13:33:35 +0200500 if (profile != kOneByteExtensionProfileId &&
501 profile != kTwoByteExtensionProfileId) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100502 RTC_LOG(LS_WARNING) << "Unsupported rtp extension " << profile;
danilchap1edb7ab2016-04-20 05:25:10 -0700503 } else {
Johannes Kron07ba2b92018-09-26 13:33:35 +0200504 size_t extension_header_length = profile == kOneByteExtensionProfileId
505 ? kOneByteExtensionHeaderLength
506 : kTwoByteExtensionHeaderLength;
507 constexpr uint8_t kPaddingByte = 0;
danilchap1edb7ab2016-04-20 05:25:10 -0700508 constexpr uint8_t kPaddingId = 0;
Johannes Kron07ba2b92018-09-26 13:33:35 +0200509 constexpr uint8_t kOneByteHeaderExtensionReservedId = 15;
510 while (extensions_size_ + extension_header_length < extensions_capacity) {
511 if (buffer[extension_offset + extensions_size_] == kPaddingByte) {
danilchap1edb7ab2016-04-20 05:25:10 -0700512 extensions_size_++;
513 continue;
514 }
Johannes Kron07ba2b92018-09-26 13:33:35 +0200515 int id;
516 uint8_t length;
517 if (profile == kOneByteExtensionProfileId) {
518 id = buffer[extension_offset + extensions_size_] >> 4;
519 length = 1 + (buffer[extension_offset + extensions_size_] & 0xf);
520 if (id == kOneByteHeaderExtensionReservedId ||
521 (id == kPaddingId && length != 1)) {
522 break;
523 }
524 } else {
525 id = buffer[extension_offset + extensions_size_];
526 length = buffer[extension_offset + extensions_size_ + 1];
527 }
528
529 if (extensions_size_ + extension_header_length + length >
Danil Chapovalova64a2fb2016-09-12 11:41:35 +0200530 extensions_capacity) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100531 RTC_LOG(LS_WARNING) << "Oversized rtp header extension.";
Danil Chapovalova64a2fb2016-09-12 11:41:35 +0200532 break;
danilchap1edb7ab2016-04-20 05:25:10 -0700533 }
danilchap70f39a32016-12-16 05:48:18 -0800534
Johannes Kronc5744b82018-09-24 14:50:48 +0200535 ExtensionInfo& extension_info = FindOrCreateExtensionInfo(id);
536 if (extension_info.length != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100537 RTC_LOG(LS_VERBOSE)
538 << "Duplicate rtp header extension id " << id << ". Overwriting.";
Danil Chapovalova64a2fb2016-09-12 11:41:35 +0200539 }
danilchap70f39a32016-12-16 05:48:18 -0800540
Danil Chapovalovc2dd59c2018-02-06 11:29:35 +0100541 size_t offset =
Johannes Kron07ba2b92018-09-26 13:33:35 +0200542 extension_offset + extensions_size_ + extension_header_length;
Danil Chapovalovc2dd59c2018-02-06 11:29:35 +0100543 if (!rtc::IsValueInRangeForNumericType<uint16_t>(offset)) {
544 RTC_DLOG(LS_WARNING) << "Oversized rtp header extension.";
545 break;
546 }
Johannes Kronc5744b82018-09-24 14:50:48 +0200547 extension_info.offset = static_cast<uint16_t>(offset);
548 extension_info.length = length;
Johannes Kron07ba2b92018-09-26 13:33:35 +0200549 extensions_size_ += extension_header_length + length;
danilchap1edb7ab2016-04-20 05:25:10 -0700550 }
551 }
552 payload_offset_ = extension_offset + extensions_capacity;
553 }
554
555 if (payload_offset_ + padding_size_ > size) {
556 return false;
557 }
558 payload_size_ = size - payload_offset_ - padding_size_;
559 return true;
560}
561
Johannes Kronc5744b82018-09-24 14:50:48 +0200562const RtpPacket::ExtensionInfo* RtpPacket::FindExtensionInfo(int id) const {
danilchap70f39a32016-12-16 05:48:18 -0800563 for (const ExtensionInfo& extension : extension_entries_) {
Johannes Kronc5744b82018-09-24 14:50:48 +0200564 if (extension.id == id) {
565 return &extension;
danilchap1edb7ab2016-04-20 05:25:10 -0700566 }
567 }
danilchap978504e2017-04-06 01:03:53 -0700568 return nullptr;
danilchap1edb7ab2016-04-20 05:25:10 -0700569}
570
Johannes Kronc5744b82018-09-24 14:50:48 +0200571RtpPacket::ExtensionInfo& RtpPacket::FindOrCreateExtensionInfo(int id) {
572 for (ExtensionInfo& extension : extension_entries_) {
573 if (extension.id == id) {
574 return extension;
danilchap70f39a32016-12-16 05:48:18 -0800575 }
danilchap1edb7ab2016-04-20 05:25:10 -0700576 }
Johannes Kronc5744b82018-09-24 14:50:48 +0200577 extension_entries_.emplace_back(id);
578 return extension_entries_.back();
579}
580
581rtc::ArrayView<const uint8_t> RtpPacket::FindExtension(
582 ExtensionType type) const {
583 uint8_t id = extensions_.GetId(type);
584 if (id == ExtensionManager::kInvalidId) {
585 // Extension not registered.
586 return nullptr;
587 }
588 ExtensionInfo const* extension_info = FindExtensionInfo(id);
589 if (extension_info == nullptr) {
590 return nullptr;
591 }
592 return rtc::MakeArrayView(data() + extension_info->offset,
593 extension_info->length);
594}
595
596rtc::ArrayView<uint8_t> RtpPacket::AllocateExtension(ExtensionType type,
597 size_t length) {
Johannes Kron78cdde32018-10-05 10:00:46 +0200598 // TODO(webrtc:7990): Add support for empty extensions (length==0).
599 if (length == 0 || length > RtpExtension::kMaxValueSize ||
Johannes Kron9581bc42018-10-23 10:17:39 +0200600 (!extensions_.ExtmapAllowMixed() &&
Johannes Kron78cdde32018-10-05 10:00:46 +0200601 length > RtpExtension::kOneByteHeaderExtensionMaxValueSize)) {
602 return nullptr;
603 }
604
Johannes Kronc5744b82018-09-24 14:50:48 +0200605 uint8_t id = extensions_.GetId(type);
606 if (id == ExtensionManager::kInvalidId) {
607 // Extension not registered.
608 return nullptr;
609 }
Johannes Kron9581bc42018-10-23 10:17:39 +0200610 if (!extensions_.ExtmapAllowMixed() &&
Johannes Kron78cdde32018-10-05 10:00:46 +0200611 id > RtpExtension::kOneByteHeaderExtensionMaxId) {
612 return nullptr;
613 }
Johannes Kronc5744b82018-09-24 14:50:48 +0200614 return AllocateRawExtension(id, length);
danilchap1edb7ab2016-04-20 05:25:10 -0700615}
616
Amit Hilbuch77938e62018-12-21 09:23:38 -0800617bool RtpPacket::HasExtension(ExtensionType type) const {
618 // TODO(webrtc:7990): Add support for empty extensions (length==0).
619 return !FindExtension(type).empty();
620}
621
Erik Språng1d46f9c2019-07-02 21:24:47 +0200622bool RtpPacket::IsExtensionReserved(ExtensionType type) const {
623 uint8_t id = extensions_.GetId(type);
624 if (id == ExtensionManager::kInvalidId) {
625 // Extension not registered.
626 return false;
627 }
628 return FindExtensionInfo(id) != nullptr;
629}
630
Anton Sukhanovff25b872019-07-09 13:04:07 -0700631bool RtpPacket::RemoveExtension(ExtensionType type) {
632 uint8_t id_to_remove = extensions_.GetId(type);
633 if (id_to_remove == ExtensionManager::kInvalidId) {
634 // Extension not registered.
635 RTC_LOG(LS_ERROR) << "Extension not registered, type=" << type
636 << ", packet=" << ToString();
637 return false;
638 }
639
640 // Rebuild new packet from scratch.
641 RtpPacket new_packet;
642
643 new_packet.SetMarker(Marker());
644 new_packet.SetPayloadType(PayloadType());
645 new_packet.SetSequenceNumber(SequenceNumber());
646 new_packet.SetTimestamp(Timestamp());
647 new_packet.SetSsrc(Ssrc());
648 new_packet.IdentifyExtensions(extensions_);
649
650 // Copy all extensions, except the one we are removing.
651 bool found_extension = false;
652 for (const ExtensionInfo& ext : extension_entries_) {
653 if (ext.id == id_to_remove) {
654 found_extension = true;
655 } else {
656 auto extension_data = new_packet.AllocateRawExtension(ext.id, ext.length);
657 if (extension_data.size() != ext.length) {
658 RTC_LOG(LS_ERROR) << "Failed to allocate extension id=" << ext.id
659 << ", length=" << ext.length
660 << ", packet=" << ToString();
661 return false;
662 }
663
664 // Copy extension data to new packet.
665 memcpy(extension_data.data(), ReadAt(ext.offset), ext.length);
666 }
667 }
668
669 if (!found_extension) {
670 RTC_LOG(LS_WARNING) << "Extension not present in RTP packet, type=" << type
671 << ", packet=" << ToString();
672 return false;
673 }
674
675 // Copy payload data to new packet.
676 memcpy(new_packet.AllocatePayload(payload_size()), payload().data(),
677 payload_size());
678
679 // Allocate padding -- must be last!
680 new_packet.SetPadding(padding_size());
681
682 // Success, replace current packet with newly built packet.
683 *this = new_packet;
684 return true;
685}
686
687std::string RtpPacket::ToString() const {
688 rtc::StringBuilder result;
689 result << "{payload_type=" << payload_type_ << "marker=" << marker_
690 << ", sequence_number=" << sequence_number_
691 << ", padding_size=" << padding_size_ << ", timestamp=" << timestamp_
692 << ", ssrc=" << ssrc_ << ", payload_offset=" << payload_offset_
693 << ", payload_size=" << payload_size_ << ", total_size=" << size()
694 << "}";
695
696 return result.Release();
697}
698
danilchap1edb7ab2016-04-20 05:25:10 -0700699} // namespace webrtc