1 /*
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
11 #include "modules/rtp_rtcp/source/rtp_packet.h"
12
13 #include <cstdint>
14 #include <cstring>
15 #include <utility>
16
17 #include "modules/rtp_rtcp/source/byte_io.h"
18 #include "modules/rtp_rtcp/source/rtp_header_extensions.h"
19 #include "rtc_base/checks.h"
20 #include "rtc_base/logging.h"
21 #include "rtc_base/numerics/safe_conversions.h"
22 #include "rtc_base/strings/string_builder.h"
23
24 namespace webrtc {
25 namespace {
26 constexpr size_t kFixedHeaderSize = 12;
27 constexpr uint8_t kRtpVersion = 2;
28 constexpr uint16_t kOneByteExtensionProfileId = 0xBEDE;
29 constexpr uint16_t kTwoByteExtensionProfileId = 0x1000;
30 constexpr size_t kOneByteExtensionHeaderLength = 1;
31 constexpr size_t kTwoByteExtensionHeaderLength = 2;
32 constexpr size_t kDefaultPacketSize = 1500;
33 } // namespace
34
35 // 0 1 2 3
36 // 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
37 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38 // |V=2|P|X| CC |M| PT | sequence number |
39 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40 // | timestamp |
41 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42 // | synchronization source (SSRC) identifier |
43 // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
44 // | Contributing source (CSRC) identifiers |
45 // | .... |
46 // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
47 // | header eXtension profile id | length in 32bits |
48 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
49 // | Extensions |
50 // | .... |
51 // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
52 // | Payload |
53 // | .... : padding... |
54 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
55 // | padding | Padding size |
56 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
RtpPacket()57 RtpPacket::RtpPacket() : RtpPacket(nullptr, kDefaultPacketSize) {}
58
RtpPacket(const ExtensionManager * extensions)59 RtpPacket::RtpPacket(const ExtensionManager* extensions)
60 : RtpPacket(extensions, kDefaultPacketSize) {}
61
62 RtpPacket::RtpPacket(const RtpPacket&) = default;
63
RtpPacket(const ExtensionManager * extensions,size_t capacity)64 RtpPacket::RtpPacket(const ExtensionManager* extensions, size_t capacity)
65 : extensions_(extensions ? *extensions : ExtensionManager()),
66 buffer_(capacity) {
67 RTC_DCHECK_GE(capacity, kFixedHeaderSize);
68 Clear();
69 }
70
~RtpPacket()71 RtpPacket::~RtpPacket() {}
72
IdentifyExtensions(const ExtensionManager & extensions)73 void RtpPacket::IdentifyExtensions(const ExtensionManager& extensions) {
74 extensions_ = extensions;
75 }
76
Parse(const uint8_t * buffer,size_t buffer_size)77 bool RtpPacket::Parse(const uint8_t* buffer, size_t buffer_size) {
78 if (!ParseBuffer(buffer, buffer_size)) {
79 Clear();
80 return false;
81 }
82 buffer_.SetData(buffer, buffer_size);
83 RTC_DCHECK_EQ(size(), buffer_size);
84 return true;
85 }
86
Parse(rtc::ArrayView<const uint8_t> packet)87 bool RtpPacket::Parse(rtc::ArrayView<const uint8_t> packet) {
88 return Parse(packet.data(), packet.size());
89 }
90
Parse(rtc::CopyOnWriteBuffer buffer)91 bool RtpPacket::Parse(rtc::CopyOnWriteBuffer buffer) {
92 if (!ParseBuffer(buffer.cdata(), buffer.size())) {
93 Clear();
94 return false;
95 }
96 size_t buffer_size = buffer.size();
97 buffer_ = std::move(buffer);
98 RTC_DCHECK_EQ(size(), buffer_size);
99 return true;
100 }
101
Csrcs() const102 std::vector<uint32_t> RtpPacket::Csrcs() const {
103 size_t num_csrc = data()[0] & 0x0F;
104 RTC_DCHECK_GE(capacity(), kFixedHeaderSize + num_csrc * 4);
105 std::vector<uint32_t> csrcs(num_csrc);
106 for (size_t i = 0; i < num_csrc; ++i) {
107 csrcs[i] =
108 ByteReader<uint32_t>::ReadBigEndian(&data()[kFixedHeaderSize + i * 4]);
109 }
110 return csrcs;
111 }
112
CopyHeaderFrom(const RtpPacket & packet)113 void RtpPacket::CopyHeaderFrom(const RtpPacket& packet) {
114 RTC_DCHECK_GE(capacity(), packet.headers_size());
115
116 marker_ = packet.marker_;
117 payload_type_ = packet.payload_type_;
118 sequence_number_ = packet.sequence_number_;
119 timestamp_ = packet.timestamp_;
120 ssrc_ = packet.ssrc_;
121 payload_offset_ = packet.payload_offset_;
122 extensions_ = packet.extensions_;
123 extension_entries_ = packet.extension_entries_;
124 extensions_size_ = packet.extensions_size_;
125 buffer_ = packet.buffer_.Slice(0, packet.headers_size());
126 // Reset payload and padding.
127 payload_size_ = 0;
128 padding_size_ = 0;
129 }
130
SetMarker(bool marker_bit)131 void RtpPacket::SetMarker(bool marker_bit) {
132 marker_ = marker_bit;
133 if (marker_) {
134 WriteAt(1, data()[1] | 0x80);
135 } else {
136 WriteAt(1, data()[1] & 0x7F);
137 }
138 }
139
SetPayloadType(uint8_t payload_type)140 void RtpPacket::SetPayloadType(uint8_t payload_type) {
141 RTC_DCHECK_LE(payload_type, 0x7Fu);
142 payload_type_ = payload_type;
143 WriteAt(1, (data()[1] & 0x80) | payload_type);
144 }
145
SetSequenceNumber(uint16_t seq_no)146 void RtpPacket::SetSequenceNumber(uint16_t seq_no) {
147 sequence_number_ = seq_no;
148 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(2), seq_no);
149 }
150
SetTimestamp(uint32_t timestamp)151 void RtpPacket::SetTimestamp(uint32_t timestamp) {
152 timestamp_ = timestamp;
153 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(4), timestamp);
154 }
155
SetSsrc(uint32_t ssrc)156 void RtpPacket::SetSsrc(uint32_t ssrc) {
157 ssrc_ = ssrc;
158 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(8), ssrc);
159 }
160
ZeroMutableExtensions()161 void RtpPacket::ZeroMutableExtensions() {
162 for (const ExtensionInfo& extension : extension_entries_) {
163 switch (extensions_.GetType(extension.id)) {
164 case RTPExtensionType::kRtpExtensionNone: {
165 RTC_LOG(LS_WARNING) << "Unidentified extension in the packet.";
166 break;
167 }
168 case RTPExtensionType::kRtpExtensionVideoTiming: {
169 // Nullify last entries, starting at pacer delay.
170 // These are set by pacer and SFUs
171 if (VideoTimingExtension::kPacerExitDeltaOffset < extension.length) {
172 memset(
173 WriteAt(extension.offset +
174 VideoTimingExtension::kPacerExitDeltaOffset),
175 0,
176 extension.length - VideoTimingExtension::kPacerExitDeltaOffset);
177 }
178 break;
179 }
180 case RTPExtensionType::kRtpExtensionTransportSequenceNumber:
181 case RTPExtensionType::kRtpExtensionTransportSequenceNumber02:
182 case RTPExtensionType::kRtpExtensionTransmissionTimeOffset:
183 case RTPExtensionType::kRtpExtensionAbsoluteSendTime: {
184 // Nullify whole extension, as it's filled in the pacer.
185 memset(WriteAt(extension.offset), 0, extension.length);
186 break;
187 }
188 case RTPExtensionType::kRtpExtensionAudioLevel:
189 case RTPExtensionType::kRtpExtensionAbsoluteCaptureTime:
190 case RTPExtensionType::kRtpExtensionColorSpace:
191 case RTPExtensionType::kRtpExtensionGenericFrameDescriptor00:
192 case RTPExtensionType::kRtpExtensionGenericFrameDescriptor02:
193 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 case RTPExtensionType::kRtpExtensionInbandComfortNoise: {
201 // Non-mutable extension. Don't change it.
202 break;
203 }
204 }
205 }
206 }
207
SetCsrcs(rtc::ArrayView<const uint32_t> csrcs)208 void RtpPacket::SetCsrcs(rtc::ArrayView<const uint32_t> csrcs) {
209 RTC_DCHECK_EQ(extensions_size_, 0);
210 RTC_DCHECK_EQ(payload_size_, 0);
211 RTC_DCHECK_EQ(padding_size_, 0);
212 RTC_DCHECK_LE(csrcs.size(), 0x0fu);
213 RTC_DCHECK_LE(kFixedHeaderSize + 4 * csrcs.size(), capacity());
214 payload_offset_ = kFixedHeaderSize + 4 * csrcs.size();
215 WriteAt(0, (data()[0] & 0xF0) | rtc::dchecked_cast<uint8_t>(csrcs.size()));
216 size_t offset = kFixedHeaderSize;
217 for (uint32_t csrc : csrcs) {
218 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(offset), csrc);
219 offset += 4;
220 }
221 buffer_.SetSize(payload_offset_);
222 }
223
AllocateRawExtension(int id,size_t length)224 rtc::ArrayView<uint8_t> RtpPacket::AllocateRawExtension(int id, size_t length) {
225 RTC_DCHECK_GE(id, RtpExtension::kMinId);
226 RTC_DCHECK_LE(id, RtpExtension::kMaxId);
227 RTC_DCHECK_GE(length, 1);
228 RTC_DCHECK_LE(length, RtpExtension::kMaxValueSize);
229 const ExtensionInfo* extension_entry = FindExtensionInfo(id);
230 if (extension_entry != nullptr) {
231 // Extension already reserved. Check if same length is used.
232 if (extension_entry->length == length)
233 return rtc::MakeArrayView(WriteAt(extension_entry->offset), length);
234
235 RTC_LOG(LS_ERROR) << "Length mismatch for extension id " << id
236 << ": expected "
237 << static_cast<int>(extension_entry->length)
238 << ". received " << length;
239 return nullptr;
240 }
241 if (payload_size_ > 0) {
242 RTC_LOG(LS_ERROR) << "Can't add new extension id " << id
243 << " after payload was set.";
244 return nullptr;
245 }
246 if (padding_size_ > 0) {
247 RTC_LOG(LS_ERROR) << "Can't add new extension id " << id
248 << " after padding was set.";
249 return nullptr;
250 }
251
252 const size_t num_csrc = data()[0] & 0x0F;
253 const size_t extensions_offset = kFixedHeaderSize + (num_csrc * 4) + 4;
254 // Determine if two-byte header is required for the extension based on id and
255 // length. Please note that a length of 0 also requires two-byte header
256 // extension. See RFC8285 Section 4.2-4.3.
257 const bool two_byte_header_required =
258 id > RtpExtension::kOneByteHeaderExtensionMaxId ||
259 length > RtpExtension::kOneByteHeaderExtensionMaxValueSize || length == 0;
260 RTC_CHECK(!two_byte_header_required || extensions_.ExtmapAllowMixed());
261
262 uint16_t profile_id;
263 if (extensions_size_ > 0) {
264 profile_id =
265 ByteReader<uint16_t>::ReadBigEndian(data() + extensions_offset - 4);
266 if (profile_id == kOneByteExtensionProfileId && two_byte_header_required) {
267 // Is buffer size big enough to fit promotion and new data field?
268 // The header extension will grow with one byte per already allocated
269 // extension + the size of the extension that is about to be allocated.
270 size_t expected_new_extensions_size =
271 extensions_size_ + extension_entries_.size() +
272 kTwoByteExtensionHeaderLength + length;
273 if (extensions_offset + expected_new_extensions_size > capacity()) {
274 RTC_LOG(LS_ERROR)
275 << "Extension cannot be registered: Not enough space left in "
276 "buffer to change to two-byte header extension and add new "
277 "extension.";
278 return nullptr;
279 }
280 // Promote already written data to two-byte header format.
281 PromoteToTwoByteHeaderExtension();
282 profile_id = kTwoByteExtensionProfileId;
283 }
284 } else {
285 // Profile specific ID, set to OneByteExtensionHeader unless
286 // TwoByteExtensionHeader is required.
287 profile_id = two_byte_header_required ? kTwoByteExtensionProfileId
288 : kOneByteExtensionProfileId;
289 }
290
291 const size_t extension_header_size = profile_id == kOneByteExtensionProfileId
292 ? kOneByteExtensionHeaderLength
293 : kTwoByteExtensionHeaderLength;
294 size_t new_extensions_size =
295 extensions_size_ + extension_header_size + length;
296 if (extensions_offset + new_extensions_size > capacity()) {
297 RTC_LOG(LS_ERROR)
298 << "Extension cannot be registered: Not enough space left in buffer.";
299 return nullptr;
300 }
301
302 // All checks passed, write down the extension headers.
303 if (extensions_size_ == 0) {
304 RTC_DCHECK_EQ(payload_offset_, kFixedHeaderSize + (num_csrc * 4));
305 WriteAt(0, data()[0] | 0x10); // Set extension bit.
306 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 4),
307 profile_id);
308 }
309
310 if (profile_id == kOneByteExtensionProfileId) {
311 uint8_t one_byte_header = rtc::dchecked_cast<uint8_t>(id) << 4;
312 one_byte_header |= rtc::dchecked_cast<uint8_t>(length - 1);
313 WriteAt(extensions_offset + extensions_size_, one_byte_header);
314 } else {
315 // TwoByteHeaderExtension.
316 uint8_t extension_id = rtc::dchecked_cast<uint8_t>(id);
317 WriteAt(extensions_offset + extensions_size_, extension_id);
318 uint8_t extension_length = rtc::dchecked_cast<uint8_t>(length);
319 WriteAt(extensions_offset + extensions_size_ + 1, extension_length);
320 }
321
322 const uint16_t extension_info_offset = rtc::dchecked_cast<uint16_t>(
323 extensions_offset + extensions_size_ + extension_header_size);
324 const uint8_t extension_info_length = rtc::dchecked_cast<uint8_t>(length);
325 extension_entries_.emplace_back(id, extension_info_length,
326 extension_info_offset);
327
328 extensions_size_ = new_extensions_size;
329
330 uint16_t extensions_size_padded =
331 SetExtensionLengthMaybeAddZeroPadding(extensions_offset);
332 payload_offset_ = extensions_offset + extensions_size_padded;
333 buffer_.SetSize(payload_offset_);
334 return rtc::MakeArrayView(WriteAt(extension_info_offset),
335 extension_info_length);
336 }
337
PromoteToTwoByteHeaderExtension()338 void RtpPacket::PromoteToTwoByteHeaderExtension() {
339 size_t num_csrc = data()[0] & 0x0F;
340 size_t extensions_offset = kFixedHeaderSize + (num_csrc * 4) + 4;
341
342 RTC_CHECK_GT(extension_entries_.size(), 0);
343 RTC_CHECK_EQ(payload_size_, 0);
344 RTC_CHECK_EQ(kOneByteExtensionProfileId, ByteReader<uint16_t>::ReadBigEndian(
345 data() + extensions_offset - 4));
346 // Rewrite data.
347 // Each extension adds one to the offset. The write-read delta for the last
348 // extension is therefore the same as the number of extension entries.
349 size_t write_read_delta = extension_entries_.size();
350 for (auto extension_entry = extension_entries_.rbegin();
351 extension_entry != extension_entries_.rend(); ++extension_entry) {
352 size_t read_index = extension_entry->offset;
353 size_t write_index = read_index + write_read_delta;
354 // Update offset.
355 extension_entry->offset = rtc::dchecked_cast<uint16_t>(write_index);
356 // Copy data. Use memmove since read/write regions may overlap.
357 memmove(WriteAt(write_index), data() + read_index, extension_entry->length);
358 // Rewrite id and length.
359 WriteAt(--write_index, extension_entry->length);
360 WriteAt(--write_index, extension_entry->id);
361 --write_read_delta;
362 }
363
364 // Update profile header, extensions length, and zero padding.
365 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 4),
366 kTwoByteExtensionProfileId);
367 extensions_size_ += extension_entries_.size();
368 uint16_t extensions_size_padded =
369 SetExtensionLengthMaybeAddZeroPadding(extensions_offset);
370 payload_offset_ = extensions_offset + extensions_size_padded;
371 buffer_.SetSize(payload_offset_);
372 }
373
SetExtensionLengthMaybeAddZeroPadding(size_t extensions_offset)374 uint16_t RtpPacket::SetExtensionLengthMaybeAddZeroPadding(
375 size_t extensions_offset) {
376 // Update header length field.
377 uint16_t extensions_words = rtc::dchecked_cast<uint16_t>(
378 (extensions_size_ + 3) / 4); // Wrap up to 32bit.
379 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 2),
380 extensions_words);
381 // Fill extension padding place with zeroes.
382 size_t extension_padding_size = 4 * extensions_words - extensions_size_;
383 memset(WriteAt(extensions_offset + extensions_size_), 0,
384 extension_padding_size);
385 return 4 * extensions_words;
386 }
387
AllocatePayload(size_t size_bytes)388 uint8_t* RtpPacket::AllocatePayload(size_t size_bytes) {
389 // Reset payload size to 0. If CopyOnWrite buffer_ was shared, this will cause
390 // reallocation and memcpy. Keeping just header reduces memcpy size.
391 SetPayloadSize(0);
392 return SetPayloadSize(size_bytes);
393 }
394
SetPayloadSize(size_t size_bytes)395 uint8_t* RtpPacket::SetPayloadSize(size_t size_bytes) {
396 RTC_DCHECK_EQ(padding_size_, 0);
397 if (payload_offset_ + size_bytes > capacity()) {
398 RTC_LOG(LS_WARNING) << "Cannot set payload, not enough space in buffer.";
399 return nullptr;
400 }
401 payload_size_ = size_bytes;
402 buffer_.SetSize(payload_offset_ + payload_size_);
403 return WriteAt(payload_offset_);
404 }
405
SetPadding(size_t padding_bytes)406 bool RtpPacket::SetPadding(size_t padding_bytes) {
407 if (payload_offset_ + payload_size_ + padding_bytes > capacity()) {
408 RTC_LOG(LS_WARNING) << "Cannot set padding size " << padding_bytes
409 << ", only "
410 << (capacity() - payload_offset_ - payload_size_)
411 << " bytes left in buffer.";
412 return false;
413 }
414 padding_size_ = rtc::dchecked_cast<uint8_t>(padding_bytes);
415 buffer_.SetSize(payload_offset_ + payload_size_ + padding_size_);
416 if (padding_size_ > 0) {
417 size_t padding_offset = payload_offset_ + payload_size_;
418 size_t padding_end = padding_offset + padding_size_;
419 memset(WriteAt(padding_offset), 0, padding_size_ - 1);
420 WriteAt(padding_end - 1, padding_size_);
421 WriteAt(0, data()[0] | 0x20); // Set padding bit.
422 } else {
423 WriteAt(0, data()[0] & ~0x20); // Clear padding bit.
424 }
425 return true;
426 }
427
Clear()428 void RtpPacket::Clear() {
429 marker_ = false;
430 payload_type_ = 0;
431 sequence_number_ = 0;
432 timestamp_ = 0;
433 ssrc_ = 0;
434 payload_offset_ = kFixedHeaderSize;
435 payload_size_ = 0;
436 padding_size_ = 0;
437 extensions_size_ = 0;
438 extension_entries_.clear();
439
440 memset(WriteAt(0), 0, kFixedHeaderSize);
441 buffer_.SetSize(kFixedHeaderSize);
442 WriteAt(0, kRtpVersion << 6);
443 }
444
ParseBuffer(const uint8_t * buffer,size_t size)445 bool RtpPacket::ParseBuffer(const uint8_t* buffer, size_t size) {
446 if (size < kFixedHeaderSize) {
447 return false;
448 }
449 const uint8_t version = buffer[0] >> 6;
450 if (version != kRtpVersion) {
451 return false;
452 }
453 const bool has_padding = (buffer[0] & 0x20) != 0;
454 const bool has_extension = (buffer[0] & 0x10) != 0;
455 const uint8_t number_of_crcs = buffer[0] & 0x0f;
456 marker_ = (buffer[1] & 0x80) != 0;
457 payload_type_ = buffer[1] & 0x7f;
458
459 sequence_number_ = ByteReader<uint16_t>::ReadBigEndian(&buffer[2]);
460 timestamp_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]);
461 ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]);
462 if (size < kFixedHeaderSize + number_of_crcs * 4) {
463 return false;
464 }
465 payload_offset_ = kFixedHeaderSize + number_of_crcs * 4;
466
467 if (has_padding) {
468 padding_size_ = buffer[size - 1];
469 if (padding_size_ == 0) {
470 RTC_LOG(LS_WARNING) << "Padding was set, but padding size is zero";
471 return false;
472 }
473 } else {
474 padding_size_ = 0;
475 }
476
477 extensions_size_ = 0;
478 extension_entries_.clear();
479 if (has_extension) {
480 /* RTP header extension, RFC 3550.
481 0 1 2 3
482 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
483 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
484 | defined by profile | length |
485 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
486 | header extension |
487 | .... |
488 */
489 size_t extension_offset = payload_offset_ + 4;
490 if (extension_offset > size) {
491 return false;
492 }
493 uint16_t profile =
494 ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_]);
495 size_t extensions_capacity =
496 ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_ + 2]);
497 extensions_capacity *= 4;
498 if (extension_offset + extensions_capacity > size) {
499 return false;
500 }
501 if (profile != kOneByteExtensionProfileId &&
502 profile != kTwoByteExtensionProfileId) {
503 RTC_LOG(LS_WARNING) << "Unsupported rtp extension " << profile;
504 } else {
505 size_t extension_header_length = profile == kOneByteExtensionProfileId
506 ? kOneByteExtensionHeaderLength
507 : kTwoByteExtensionHeaderLength;
508 constexpr uint8_t kPaddingByte = 0;
509 constexpr uint8_t kPaddingId = 0;
510 constexpr uint8_t kOneByteHeaderExtensionReservedId = 15;
511 while (extensions_size_ + extension_header_length < extensions_capacity) {
512 if (buffer[extension_offset + extensions_size_] == kPaddingByte) {
513 extensions_size_++;
514 continue;
515 }
516 int id;
517 uint8_t length;
518 if (profile == kOneByteExtensionProfileId) {
519 id = buffer[extension_offset + extensions_size_] >> 4;
520 length = 1 + (buffer[extension_offset + extensions_size_] & 0xf);
521 if (id == kOneByteHeaderExtensionReservedId ||
522 (id == kPaddingId && length != 1)) {
523 break;
524 }
525 } else {
526 id = buffer[extension_offset + extensions_size_];
527 length = buffer[extension_offset + extensions_size_ + 1];
528 }
529
530 if (extensions_size_ + extension_header_length + length >
531 extensions_capacity) {
532 RTC_LOG(LS_WARNING) << "Oversized rtp header extension.";
533 break;
534 }
535
536 ExtensionInfo& extension_info = FindOrCreateExtensionInfo(id);
537 if (extension_info.length != 0) {
538 RTC_LOG(LS_VERBOSE)
539 << "Duplicate rtp header extension id " << id << ". Overwriting.";
540 }
541
542 size_t offset =
543 extension_offset + extensions_size_ + extension_header_length;
544 if (!rtc::IsValueInRangeForNumericType<uint16_t>(offset)) {
545 RTC_DLOG(LS_WARNING) << "Oversized rtp header extension.";
546 break;
547 }
548 extension_info.offset = static_cast<uint16_t>(offset);
549 extension_info.length = length;
550 extensions_size_ += extension_header_length + length;
551 }
552 }
553 payload_offset_ = extension_offset + extensions_capacity;
554 }
555
556 if (payload_offset_ + padding_size_ > size) {
557 return false;
558 }
559 payload_size_ = size - payload_offset_ - padding_size_;
560 return true;
561 }
562
FindExtensionInfo(int id) const563 const RtpPacket::ExtensionInfo* RtpPacket::FindExtensionInfo(int id) const {
564 for (const ExtensionInfo& extension : extension_entries_) {
565 if (extension.id == id) {
566 return &extension;
567 }
568 }
569 return nullptr;
570 }
571
FindOrCreateExtensionInfo(int id)572 RtpPacket::ExtensionInfo& RtpPacket::FindOrCreateExtensionInfo(int id) {
573 for (ExtensionInfo& extension : extension_entries_) {
574 if (extension.id == id) {
575 return extension;
576 }
577 }
578 extension_entries_.emplace_back(id);
579 return extension_entries_.back();
580 }
581
FindExtension(ExtensionType type) const582 rtc::ArrayView<const uint8_t> RtpPacket::FindExtension(
583 ExtensionType type) const {
584 uint8_t id = extensions_.GetId(type);
585 if (id == ExtensionManager::kInvalidId) {
586 // Extension not registered.
587 return nullptr;
588 }
589 ExtensionInfo const* extension_info = FindExtensionInfo(id);
590 if (extension_info == nullptr) {
591 return nullptr;
592 }
593 return rtc::MakeArrayView(data() + extension_info->offset,
594 extension_info->length);
595 }
596
AllocateExtension(ExtensionType type,size_t length)597 rtc::ArrayView<uint8_t> RtpPacket::AllocateExtension(ExtensionType type,
598 size_t length) {
599 // TODO(webrtc:7990): Add support for empty extensions (length==0).
600 if (length == 0 || length > RtpExtension::kMaxValueSize ||
601 (!extensions_.ExtmapAllowMixed() &&
602 length > RtpExtension::kOneByteHeaderExtensionMaxValueSize)) {
603 return nullptr;
604 }
605
606 uint8_t id = extensions_.GetId(type);
607 if (id == ExtensionManager::kInvalidId) {
608 // Extension not registered.
609 return nullptr;
610 }
611 if (!extensions_.ExtmapAllowMixed() &&
612 id > RtpExtension::kOneByteHeaderExtensionMaxId) {
613 return nullptr;
614 }
615 return AllocateRawExtension(id, length);
616 }
617
HasExtension(ExtensionType type) const618 bool RtpPacket::HasExtension(ExtensionType type) const {
619 uint8_t id = extensions_.GetId(type);
620 if (id == ExtensionManager::kInvalidId) {
621 // Extension not registered.
622 return false;
623 }
624 return FindExtensionInfo(id) != nullptr;
625 }
626
RemoveExtension(ExtensionType type)627 bool RtpPacket::RemoveExtension(ExtensionType type) {
628 uint8_t id_to_remove = extensions_.GetId(type);
629 if (id_to_remove == ExtensionManager::kInvalidId) {
630 // Extension not registered.
631 RTC_LOG(LS_ERROR) << "Extension not registered, type=" << type
632 << ", packet=" << ToString();
633 return false;
634 }
635
636 // Rebuild new packet from scratch.
637 RtpPacket new_packet;
638
639 new_packet.SetMarker(Marker());
640 new_packet.SetPayloadType(PayloadType());
641 new_packet.SetSequenceNumber(SequenceNumber());
642 new_packet.SetTimestamp(Timestamp());
643 new_packet.SetSsrc(Ssrc());
644 new_packet.IdentifyExtensions(extensions_);
645
646 // Copy all extensions, except the one we are removing.
647 bool found_extension = false;
648 for (const ExtensionInfo& ext : extension_entries_) {
649 if (ext.id == id_to_remove) {
650 found_extension = true;
651 } else {
652 auto extension_data = new_packet.AllocateRawExtension(ext.id, ext.length);
653 if (extension_data.size() != ext.length) {
654 RTC_LOG(LS_ERROR) << "Failed to allocate extension id=" << ext.id
655 << ", length=" << ext.length
656 << ", packet=" << ToString();
657 return false;
658 }
659
660 // Copy extension data to new packet.
661 memcpy(extension_data.data(), ReadAt(ext.offset), ext.length);
662 }
663 }
664
665 if (!found_extension) {
666 RTC_LOG(LS_WARNING) << "Extension not present in RTP packet, type=" << type
667 << ", packet=" << ToString();
668 return false;
669 }
670
671 // Copy payload data to new packet.
672 memcpy(new_packet.AllocatePayload(payload_size()), payload().data(),
673 payload_size());
674
675 // Allocate padding -- must be last!
676 new_packet.SetPadding(padding_size());
677
678 // Success, replace current packet with newly built packet.
679 *this = new_packet;
680 return true;
681 }
682
ToString() const683 std::string RtpPacket::ToString() const {
684 rtc::StringBuilder result;
685 result << "{payload_type=" << payload_type_ << "marker=" << marker_
686 << ", sequence_number=" << sequence_number_
687 << ", padding_size=" << padding_size_ << ", timestamp=" << timestamp_
688 << ", ssrc=" << ssrc_ << ", payload_offset=" << payload_offset_
689 << ", payload_size=" << payload_size_ << ", total_size=" << size()
690 << "}";
691
692 return result.Release();
693 }
694
695 } // namespace webrtc
696