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