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