/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "webrtc/modules/rtp_rtcp/source/rtp_packet.h" #include #include "webrtc/base/checks.h" #include "webrtc/base/logging.h" #include "webrtc/base/random.h" #include "webrtc/common_types.h" #include "webrtc/modules/rtp_rtcp/source/rtp_header_extension.h" #include "webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h" #include "webrtc/modules/rtp_rtcp/source/byte_io.h" namespace webrtc { namespace rtp { namespace { constexpr size_t kFixedHeaderSize = 12; constexpr uint8_t kRtpVersion = 2; constexpr uint16_t kOneByteExtensionId = 0xBEDE; constexpr size_t kOneByteHeaderSize = 1; constexpr size_t kDefaultPacketSize = 1500; } // namespace // 0 1 2 3 // 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 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // |V=2|P|X| CC |M| PT | sequence number | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | timestamp | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | synchronization source (SSRC) identifier | // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ // | Contributing source (CSRC) identifiers | // | .... | // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ // |One-byte eXtensions id = 0xbede| length in 32bits | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | Extensions | // | .... | // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ // | Payload | // | .... : padding... | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | padding | Padding size | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Packet::Packet(const ExtensionManager* extensions) : extensions_(extensions), buffer_(kDefaultPacketSize) { Clear(); } Packet::Packet(const ExtensionManager* extensions, size_t capacity) : extensions_(extensions), buffer_(capacity) { RTC_DCHECK_GE(capacity, kFixedHeaderSize); Clear(); } Packet::~Packet() {} void Packet::IdentifyExtensions(const ExtensionManager* extensions) { RTC_DCHECK(extensions); extensions_ = extensions; for (size_t i = 0; i < num_extensions_; ++i) { uint8_t id = data()[extension_entries_[i].offset - 1] >> 4; extension_entries_[i].type = extensions_->GetType(id); } } bool Packet::Parse(const uint8_t* buffer, size_t buffer_size) { if (!ParseBuffer(buffer, buffer_size)) { Clear(); return false; } buffer_.SetData(buffer, buffer_size); RTC_DCHECK_EQ(size(), buffer_size); return true; } bool Packet::Parse(rtc::CopyOnWriteBuffer buffer) { if (!ParseBuffer(buffer.cdata(), buffer.size())) { Clear(); return false; } size_t buffer_size = buffer.size(); buffer_ = std::move(buffer); RTC_DCHECK_EQ(size(), buffer_size); return true; } bool Packet::Marker() const { RTC_DCHECK_EQ(marker_, (data()[1] & 0x80) != 0); return marker_; } uint8_t Packet::PayloadType() const { RTC_DCHECK_EQ(payload_type_, data()[1] & 0x7f); return payload_type_; } uint16_t Packet::SequenceNumber() const { RTC_DCHECK_EQ(sequence_number_, ByteReader::ReadBigEndian(data() + 2)); return sequence_number_; } uint32_t Packet::Timestamp() const { RTC_DCHECK_EQ(timestamp_, ByteReader::ReadBigEndian(data() + 4)); return timestamp_; } uint32_t Packet::Ssrc() const { RTC_DCHECK_EQ(ssrc_, ByteReader::ReadBigEndian(data() + 8)); return ssrc_; } std::vector Packet::Csrcs() const { size_t num_csrc = data()[0] & 0x0F; RTC_DCHECK_GE(capacity(), kFixedHeaderSize + num_csrc * 4); std::vector csrcs(num_csrc); for (size_t i = 0; i < num_csrc; ++i) { csrcs[i] = ByteReader::ReadBigEndian(&data()[kFixedHeaderSize + i * 4]); } return csrcs; } void Packet::GetHeader(RTPHeader* header) const { header->markerBit = Marker(); header->payloadType = PayloadType(); header->sequenceNumber = SequenceNumber(); header->timestamp = Timestamp(); header->ssrc = Ssrc(); std::vector csrcs = Csrcs(); header->numCSRCs = csrcs.size(); for (size_t i = 0; i < csrcs.size(); ++i) { header->arrOfCSRCs[i] = csrcs[i]; } header->paddingLength = padding_size(); header->headerLength = headers_size(); header->payload_type_frequency = 0; header->extension.hasTransmissionTimeOffset = GetExtension( &header->extension.transmissionTimeOffset); header->extension.hasAbsoluteSendTime = GetExtension(&header->extension.absoluteSendTime); header->extension.hasTransportSequenceNumber = GetExtension( &header->extension.transportSequenceNumber); header->extension.hasAudioLevel = GetExtension( &header->extension.voiceActivity, &header->extension.audioLevel); header->extension.hasVideoRotation = GetExtension(&header->extension.videoRotation); } size_t Packet::headers_size() const { return payload_offset_; } size_t Packet::payload_size() const { return payload_size_; } size_t Packet::padding_size() const { return padding_size_; } const uint8_t* Packet::payload() const { return data() + payload_offset_; } rtc::CopyOnWriteBuffer Packet::Buffer() const { return buffer_; } size_t Packet::capacity() const { return buffer_.capacity(); } size_t Packet::size() const { size_t ret = payload_offset_ + payload_size_ + padding_size_; RTC_DCHECK_EQ(buffer_.size(), ret); return ret; } const uint8_t* Packet::data() const { return buffer_.cdata(); } size_t Packet::FreeCapacity() const { return capacity() - size(); } size_t Packet::MaxPayloadSize() const { return capacity() - payload_offset_; } void Packet::CopyHeaderFrom(const Packet& packet) { RTC_DCHECK_GE(capacity(), packet.headers_size()); marker_ = packet.marker_; payload_type_ = packet.payload_type_; sequence_number_ = packet.sequence_number_; timestamp_ = packet.timestamp_; ssrc_ = packet.ssrc_; payload_offset_ = packet.payload_offset_; num_extensions_ = packet.num_extensions_; for (size_t i = 0; i < num_extensions_; ++i) { extension_entries_[i] = packet.extension_entries_[i]; } extensions_size_ = packet.extensions_size_; buffer_.SetData(packet.data(), packet.headers_size()); // Reset payload and padding. payload_size_ = 0; padding_size_ = 0; } void Packet::SetMarker(bool marker_bit) { marker_ = marker_bit; if (marker_) { WriteAt(1, data()[1] | 0x80); } else { WriteAt(1, data()[1] & 0x7F); } } void Packet::SetPayloadType(uint8_t payload_type) { RTC_DCHECK_LE(payload_type, 0x7Fu); payload_type_ = payload_type; WriteAt(1, (data()[1] & 0x80) | payload_type); } void Packet::SetSequenceNumber(uint16_t seq_no) { sequence_number_ = seq_no; ByteWriter::WriteBigEndian(WriteAt(2), seq_no); } void Packet::SetTimestamp(uint32_t timestamp) { timestamp_ = timestamp; ByteWriter::WriteBigEndian(WriteAt(4), timestamp); } void Packet::SetSsrc(uint32_t ssrc) { ssrc_ = ssrc; ByteWriter::WriteBigEndian(WriteAt(8), ssrc); } void Packet::SetCsrcs(const std::vector& csrcs) { RTC_DCHECK_EQ(num_extensions_, 0u); RTC_DCHECK_EQ(payload_size_, 0u); RTC_DCHECK_EQ(padding_size_, 0u); RTC_DCHECK_LE(csrcs.size(), 0x0fu); RTC_DCHECK_LE(kFixedHeaderSize + 4 * csrcs.size(), capacity()); payload_offset_ = kFixedHeaderSize + 4 * csrcs.size(); WriteAt(0, (data()[0] & 0xF0) | csrcs.size()); size_t offset = kFixedHeaderSize; for (uint32_t csrc : csrcs) { ByteWriter::WriteBigEndian(WriteAt(offset), csrc); offset += 4; } buffer_.SetSize(payload_offset_); } uint8_t* Packet::AllocatePayload(size_t size_bytes) { RTC_DCHECK_EQ(padding_size_, 0u); if (payload_offset_ + size_bytes > capacity()) { LOG(LS_WARNING) << "Cannot set payload, not enough space in buffer."; return nullptr; } payload_size_ = size_bytes; buffer_.SetSize(payload_offset_ + payload_size_); return WriteAt(payload_offset_); } void Packet::SetPayloadSize(size_t size_bytes) { RTC_DCHECK_EQ(padding_size_, 0u); RTC_DCHECK_LE(size_bytes, payload_size_); payload_size_ = size_bytes; buffer_.SetSize(payload_offset_ + payload_size_); } bool Packet::SetPadding(uint8_t size_bytes, Random* random) { RTC_DCHECK(random); if (payload_offset_ + payload_size_ + size_bytes > capacity()) { LOG(LS_WARNING) << "Cannot set padding size " << size_bytes << ", only " << (capacity() - payload_offset_ - payload_size_) << " bytes left in buffer."; return false; } padding_size_ = size_bytes; buffer_.SetSize(payload_offset_ + payload_size_ + padding_size_); if (padding_size_ > 0) { size_t padding_offset = payload_offset_ + payload_size_; size_t padding_end = padding_offset + padding_size_; for (size_t offset = padding_offset; offset < padding_end - 1; ++offset) { WriteAt(offset, random->Rand()); } WriteAt(padding_end - 1, padding_size_); WriteAt(0, data()[0] | 0x20); // Set padding bit. } else { WriteAt(0, data()[0] & ~0x20); // Clear padding bit. } return true; } void Packet::Clear() { marker_ = false; payload_type_ = 0; sequence_number_ = 0; timestamp_ = 0; ssrc_ = 0; payload_offset_ = kFixedHeaderSize; payload_size_ = 0; padding_size_ = 0; num_extensions_ = 0; extensions_size_ = 0; memset(WriteAt(0), 0, kFixedHeaderSize); buffer_.SetSize(kFixedHeaderSize); WriteAt(0, kRtpVersion << 6); } bool Packet::ParseBuffer(const uint8_t* buffer, size_t size) { if (size < kFixedHeaderSize) { return false; } const uint8_t version = buffer[0] >> 6; if (version != kRtpVersion) { return false; } const bool has_padding = (buffer[0] & 0x20) != 0; const bool has_extension = (buffer[0] & 0x10) != 0; const uint8_t number_of_crcs = buffer[0] & 0x0f; marker_ = (buffer[1] & 0x80) != 0; payload_type_ = buffer[1] & 0x7f; sequence_number_ = ByteReader::ReadBigEndian(&buffer[2]); timestamp_ = ByteReader::ReadBigEndian(&buffer[4]); ssrc_ = ByteReader::ReadBigEndian(&buffer[8]); if (size < kFixedHeaderSize + number_of_crcs * 4) { return false; } payload_offset_ = kFixedHeaderSize + number_of_crcs * 4; if (has_padding) { padding_size_ = buffer[size - 1]; if (padding_size_ == 0) { LOG(LS_WARNING) << "Padding was set, but padding size is zero"; return false; } } else { padding_size_ = 0; } num_extensions_ = 0; extensions_size_ = 0; if (has_extension) { /* RTP header extension, RFC 3550. 0 1 2 3 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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | defined by profile | length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | header extension | | .... | */ size_t extension_offset = payload_offset_ + 4; if (extension_offset > size) { return false; } uint16_t profile = ByteReader::ReadBigEndian(&buffer[payload_offset_]); size_t extensions_capacity = ByteReader::ReadBigEndian(&buffer[payload_offset_ + 2]); extensions_capacity *= 4; if (extension_offset + extensions_capacity > size) { return false; } if (profile != kOneByteExtensionId) { LOG(LS_WARNING) << "Unsupported rtp extension " << profile; } else { constexpr uint8_t kPaddingId = 0; constexpr uint8_t kReservedId = 15; while (extensions_size_ + kOneByteHeaderSize < extensions_capacity) { uint8_t id = buffer[extension_offset + extensions_size_] >> 4; if (id == kReservedId) { break; } else if (id == kPaddingId) { extensions_size_++; continue; } uint8_t length = 1 + (buffer[extension_offset + extensions_size_] & 0xf); extensions_size_ += kOneByteHeaderSize; if (num_extensions_ >= kMaxExtensionHeaders) { LOG(LS_WARNING) << "Too many extensions."; return false; } extension_entries_[num_extensions_].type = extensions_ ? extensions_->GetType(id) : ExtensionManager::kInvalidType; extension_entries_[num_extensions_].length = length; extension_entries_[num_extensions_].offset = extension_offset + extensions_size_; num_extensions_++; extensions_size_ += length; } } payload_offset_ = extension_offset + extensions_capacity; } if (payload_offset_ + padding_size_ > size) { return false; } payload_size_ = size - payload_offset_ - padding_size_; return true; } bool Packet::FindExtension(ExtensionType type, uint8_t length, uint16_t* offset) const { RTC_DCHECK(offset); for (size_t i = 0; i < num_extensions_; ++i) { if (extension_entries_[i].type == type) { if (length != extension_entries_[i].length) { LOG(LS_WARNING) << "Length mismatch for extension '" << type << "': expected " << static_cast(length) << ", received " << static_cast(extension_entries_[i].length); return false; } *offset = extension_entries_[i].offset; return true; } } return false; } bool Packet::AllocateExtension(ExtensionType type, uint8_t length, uint16_t* offset) { if (!extensions_) { return false; } if (FindExtension(type, length, offset)) { return true; } // Can't add new extension after payload/padding was set. if (payload_size_ > 0) { return false; } if (padding_size_ > 0) { return false; } uint8_t extension_id = extensions_->GetId(type); if (extension_id == ExtensionManager::kInvalidId) { return false; } RTC_DCHECK_GT(length, 0u); RTC_DCHECK_LE(length, 16u); size_t num_csrc = data()[0] & 0x0F; size_t extensions_offset = kFixedHeaderSize + (num_csrc * 4) + 4; if (extensions_offset + extensions_size_ + kOneByteHeaderSize + length > capacity()) { LOG(LS_WARNING) << "Extension cannot be registered: " "Not enough space left in buffer."; return false; } uint16_t new_extensions_size = extensions_size_ + kOneByteHeaderSize + length; uint16_t extensions_words = (new_extensions_size + 3) / 4; // Wrap up to 32bit. // All checks passed, write down the extension. if (num_extensions_ == 0) { RTC_DCHECK_EQ(payload_offset_, kFixedHeaderSize + (num_csrc * 4)); RTC_DCHECK_EQ(extensions_size_, 0); WriteAt(0, data()[0] | 0x10); // Set extension bit. // Profile specific ID always set to OneByteExtensionHeader. ByteWriter::WriteBigEndian(WriteAt(extensions_offset - 4), kOneByteExtensionId); } WriteAt(extensions_offset + extensions_size_, (extension_id << 4) | (length - 1)); RTC_DCHECK(num_extensions_ < kMaxExtensionHeaders); extension_entries_[num_extensions_].type = type; extension_entries_[num_extensions_].length = length; *offset = extensions_offset + kOneByteHeaderSize + extensions_size_; extension_entries_[num_extensions_].offset = *offset; ++num_extensions_; extensions_size_ = new_extensions_size; // Update header length field. ByteWriter::WriteBigEndian(WriteAt(extensions_offset - 2), extensions_words); // Fill extension padding place with zeroes. size_t extension_padding_size = 4 * extensions_words - extensions_size_; memset(WriteAt(extensions_offset + extensions_size_), 0, extension_padding_size); payload_offset_ = extensions_offset + 4 * extensions_words; buffer_.SetSize(payload_offset_); return true; } uint8_t* Packet::WriteAt(size_t offset) { return buffer_.data() + offset; } void Packet::WriteAt(size_t offset, uint8_t byte) { buffer_.data()[offset] = byte; } } // namespace rtp } // namespace webrtc