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