123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263 |
- #include "../rtp_header_extension/rtp_header_extension_packet.h"
- #include <cstdint>
- #include <cstring>
- #include <utility>
- #include "../rtp_header_extension/byte_io.h"
- static const uint16_t kOneByteExtensionProfileId = 0xBEDE;
- static const uint16_t kTwoByteExtensionProfileId = 0x1000;
- static const size_t kOneByteExtensionHeaderLength = 1;
- static const size_t kTwoByteExtensionHeaderLength = 2;
- static const size_t kDefaultPacketSize = 1500;
- // 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 |
- // | .... |
- // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
- // | header eXtension profile id | length in 32bits |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | Extensions |
- // | .... |
- // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
- // | Payload |
- // | .... : padding... |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- // | padding | Padding size |
- // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- RTPExtensionPacket::RTPExtensionPacket() {RTPExtensionPacket(nullptr);}
- RTPExtensionPacket::RTPExtensionPacket(const RtpHeaderExtensionMap* extensions)
- : extensions_(extensions ? *extensions : RtpHeaderExtensionMap()) {
- extensions_size_ = 0;
- Clear();
- }
- RTPExtensionPacket::~RTPExtensionPacket() {}
- void RTPExtensionPacket::IdentifyExtensions(const RtpHeaderExtensionMap& extensions) {
- extensions_ = extensions;
- }
- uint8_t *RTPExtensionPacket::AllocateRawExtension(int id, size_t length) {
- const ExtensionInfo* extension_entry = FindExtensionInfo(id);
- if (extension_entry != NULL) {
- // Extension already reserved. Check if same length is used.
- if (extension_entry->length == length)
- return WriteAt(extension_entry->offset);
- //RTC_LOG(LS_ERROR) << "Length mismatch for extension id " << id
- // << ": expected "
- // << static_cast<int>(extension_entry->length)
- // << ". received " << length;
- return NULL;
- }
- const size_t extensions_offset = 4;
- // Determine if two-byte header is required for the extension based on id and
- // length. Please note that a length of 0 also requires two-byte header
- // extension. See RFC8285 Section 4.2-4.3.
- const bool two_byte_header_required =
- id > RtpExtension::kOneByteHeaderExtensionMaxId ||
- length > RtpExtension::kOneByteHeaderExtensionMaxValueSize || length == 0;
- uint16_t profile_id;
- if (extensions_size_ > 0) {
- profile_id =
- ByteReader<uint16_t>::ReadBigEndian(data() + extensions_offset - 4);
- if (profile_id == kOneByteExtensionProfileId && two_byte_header_required) {
- // Is buffer size big enough to fit promotion and new data field?
- // The header extension will grow with one byte per already allocated
- // extension + the size of the extension that is about to be allocated.
- size_t expected_new_extensions_size =
- extensions_size_ + extension_entries_.size() +
- kTwoByteExtensionHeaderLength + length;
- if (extensions_offset + expected_new_extensions_size > capacity()) {
- //RTC_LOG(LS_ERROR)
- // << "Extension cannot be registered: Not enough space left in "
- // "buffer to change to two-byte header extension and add new "
- // "extension.";
- return NULL;
- }
- // Promote already written data to two-byte header format.
- PromoteToTwoByteHeaderExtension();
- profile_id = kTwoByteExtensionProfileId;
- }
- } else {
- // Profile specific ID, set to OneByteExtensionHeader unless
- // TwoByteExtensionHeader is required.
- profile_id = two_byte_header_required ? kTwoByteExtensionProfileId
- : kOneByteExtensionProfileId;
- }
- const size_t extension_header_size = profile_id == kOneByteExtensionProfileId
- ? kOneByteExtensionHeaderLength
- : kTwoByteExtensionHeaderLength;
- size_t new_extensions_size =
- extensions_size_ + extension_header_size + length;
- if (extensions_offset + new_extensions_size > capacity()) {
- //RTC_LOG(LS_ERROR)
- // << "Extension cannot be registered: Not enough space left in buffer.";
- return NULL;
- }
- // All checks passed, write down the extension headers.
- if (extensions_size_ == 0) {
- //huchen delete, we only write extension, no rtp header
- //WriteAt(0, data()[0] | 0x10); // Set extension bit.
- ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 4),
- profile_id);
- }
- if (profile_id == kOneByteExtensionProfileId) {
- uint8_t one_byte_header = (uint8_t)(id) << 4;
- one_byte_header |= (uint8_t)(length - 1);
- WriteAt(extensions_offset + extensions_size_, one_byte_header);
- } else {
- // TwoByteHeaderExtension.
- uint8_t extension_id = (uint8_t)(id);
- WriteAt(extensions_offset + extensions_size_, extension_id);
- uint8_t extension_length = (uint8_t)(length);
- WriteAt(extensions_offset + extensions_size_ + 1, extension_length);
- }
- const uint16_t extension_info_offset = (uint16_t)(
- extensions_offset + extensions_size_ + extension_header_size);
- const uint8_t extension_info_length = (uint8_t)(length);
- ExtensionInfo info(id, extension_info_length, extension_info_offset);
- extension_entries_.emplace_back(info);
- extensions_size_ = new_extensions_size;
- uint16_t extensions_size_padded =
- SetExtensionLengthMaybeAddZeroPadding(extensions_offset);
- payload_offset_ = extensions_offset + extensions_size_padded;
- return WriteAt(extension_info_offset);
- }
- void RTPExtensionPacket::PromoteToTwoByteHeaderExtension() {
- size_t extensions_offset = 4;
- // Rewrite data.
- // Each extension adds one to the offset. The write-read delta for the last
- // extension is therefore the same as the number of extension entries.
- size_t write_read_delta = extension_entries_.size();
- for (auto extension_entry = extension_entries_.rbegin();
- extension_entry != extension_entries_.rend(); ++extension_entry) {
- size_t read_index = extension_entry->offset;
- size_t write_index = read_index + write_read_delta;
- // Update offset.
- extension_entry->offset = uint16_t(write_index);
- // Copy data. Use memmove since read/write regions may overlap.
- memmove(WriteAt(write_index), data() + read_index, extension_entry->length);
- // Rewrite id and length.
- WriteAt(--write_index, extension_entry->length);
- WriteAt(--write_index, extension_entry->id);
- --write_read_delta;
- }
- // Update profile header, extensions length, and zero padding.
- ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 4),
- kTwoByteExtensionProfileId);
- extensions_size_ += extension_entries_.size();
- uint16_t extensions_size_padded =
- SetExtensionLengthMaybeAddZeroPadding(extensions_offset);
- payload_offset_ = extensions_offset + extensions_size_padded;
- }
- uint16_t RTPExtensionPacket::SetExtensionLengthMaybeAddZeroPadding(
- size_t extensions_offset) {
- // Update header length field.
- uint16_t extensions_words = (uint16_t)(
- (extensions_size_ + 3) / 4); // Wrap up to 32bit.
- ByteWriter<uint16_t>::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);
- return 4 * extensions_words;
- }
- void RTPExtensionPacket::Clear() {
- extensions_size_ = 0;
- extension_entries_.clear();
- memset(WriteAt(0), 0, kDefaultPacketSize);
- payload_offset_ = 0;
- }
- const RTPExtensionPacket::ExtensionInfo* RTPExtensionPacket::FindExtensionInfo(int id) const {
- for(int i = 0; i < extension_entries_.size(); i++){
- if (extension_entries_[i].id == id) {
- return &extension_entries_[i];
- }
- }
- return NULL;
- }
- RTPExtensionPacket::ExtensionInfo& RTPExtensionPacket::FindOrCreateExtensionInfo(int id) {
- for(int i = 0; i < extension_entries_.size(); i++){
- if (extension_entries_[i].id == id) {
- return extension_entries_[i];
- }
- }
- extension_entries_.emplace_back(id);
- return extension_entries_.back();
- }
- const uint8_t *RTPExtensionPacket::FindExtension(
- RTPExtensionType type) const {
- uint8_t id = extensions_.GetId(type);
- if (id == RtpHeaderExtensionMap::kInvalidId) {
- // Extension not registered.
- return NULL;
- }
- ExtensionInfo const* extension_info = FindExtensionInfo(id);
- if (extension_info == NULL) {
- return NULL;
- }
- return data() + extension_info->offset;
- }
- uint8_t *RTPExtensionPacket::AllocateExtension(RTPExtensionType type,
- size_t length) {
- // TODO(webrtc:7990): Add support for empty extensions (length==0).
- if (length == 0 || length > RtpExtension::kMaxValueSize ||
- (!extensions_.ExtmapAllowMixed() &&
- length > RtpExtension::kOneByteHeaderExtensionMaxValueSize)) {
- return NULL;
- }
- uint8_t id = extensions_.GetId(type);
- if (id == RtpHeaderExtensionMap::kInvalidId) {
- // Extension not registered.
- return NULL;
- }
- if (!extensions_.ExtmapAllowMixed() &&
- id > RtpExtension::kOneByteHeaderExtensionMaxId) {
- return NULL;
- }
- return AllocateRawExtension(id, length);
- }
- bool RTPExtensionPacket::HasExtension(RTPExtensionType type) const {
- // TODO(webrtc:7990): Add support for empty extensions (length==0).
- return FindExtension(type) != NULL;
- }
|