xref: /aosp_15_r20/external/webrtc/modules/rtp_rtcp/source/rtp_packet.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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