blob: 10d4143513244f203e88ac18fb88b4419c5a6dc8 [file] [log] [blame]
danilchap1edb7ab2016-04-20 05:25:10 -07001/*
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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/rtp_rtcp/source/rtp_packet.h"
danilchap1edb7ab2016-04-20 05:25:10 -070012
13#include <cstring>
Danil Chapovalova64a2fb2016-09-12 11:41:35 +020014#include <utility>
danilchap1edb7ab2016-04-20 05:25:10 -070015
Mirko Bonadei71207422017-09-15 13:58:09 +020016#include "common_types.h" // NOLINT(build/include)
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
18#include "modules/rtp_rtcp/source/byte_io.h"
19#include "rtc_base/checks.h"
20#include "rtc_base/logging.h"
Karl Wiberge40468b2017-11-22 10:42:26 +010021#include "rtc_base/numerics/safe_conversions.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "rtc_base/random.h"
danilchap1edb7ab2016-04-20 05:25:10 -070023
24namespace webrtc {
danilchap1edb7ab2016-04-20 05:25:10 -070025namespace {
26constexpr size_t kFixedHeaderSize = 12;
27constexpr uint8_t kRtpVersion = 2;
28constexpr uint16_t kOneByteExtensionId = 0xBEDE;
29constexpr size_t kOneByteHeaderSize = 1;
30constexpr size_t kDefaultPacketSize = 1500;
31} // namespace
danilchap653063f2017-04-03 06:16:30 -070032
Danil Chapovalov8769e172017-09-14 14:08:22 +020033constexpr int RtpPacket::kMaxExtensionHeaders;
34constexpr int RtpPacket::kMinExtensionId;
35constexpr int RtpPacket::kMaxExtensionId;
danilchap653063f2017-04-03 06:16:30 -070036
danilchap1edb7ab2016-04-20 05:25:10 -070037// 0 1 2 3
38// 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
39// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40// |V=2|P|X| CC |M| PT | sequence number |
41// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42// | timestamp |
43// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44// | synchronization source (SSRC) identifier |
45// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
46// | Contributing source (CSRC) identifiers |
47// | .... |
48// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
49// |One-byte eXtensions id = 0xbede| length in 32bits |
50// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51// | Extensions |
52// | .... |
53// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
54// | Payload |
55// | .... : padding... |
56// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
57// | padding | Padding size |
58// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Danil Chapovalov8769e172017-09-14 14:08:22 +020059RtpPacket::RtpPacket() : RtpPacket(nullptr, kDefaultPacketSize) {}
danilchap70f39a32016-12-16 05:48:18 -080060
Danil Chapovalov8769e172017-09-14 14:08:22 +020061RtpPacket::RtpPacket(const ExtensionManager* extensions)
62 : RtpPacket(extensions, kDefaultPacketSize) {}
danilchap1edb7ab2016-04-20 05:25:10 -070063
Danil Chapovalov8769e172017-09-14 14:08:22 +020064RtpPacket::RtpPacket(const RtpPacket&) = default;
nisse76e62b02017-05-31 02:24:52 -070065
Danil Chapovalov8769e172017-09-14 14:08:22 +020066RtpPacket::RtpPacket(const ExtensionManager* extensions, size_t capacity)
danilchap70f39a32016-12-16 05:48:18 -080067 : buffer_(capacity) {
danilchap1edb7ab2016-04-20 05:25:10 -070068 RTC_DCHECK_GE(capacity, kFixedHeaderSize);
69 Clear();
danilchap70f39a32016-12-16 05:48:18 -080070 if (extensions) {
Johannes Kronc5744b82018-09-24 14:50:48 +020071 extensions_ = *extensions;
danilchap70f39a32016-12-16 05:48:18 -080072 }
danilchap1edb7ab2016-04-20 05:25:10 -070073}
74
Danil Chapovalov8769e172017-09-14 14:08:22 +020075RtpPacket::~RtpPacket() {}
danilchap1edb7ab2016-04-20 05:25:10 -070076
Danil Chapovalov8769e172017-09-14 14:08:22 +020077void RtpPacket::IdentifyExtensions(const ExtensionManager& extensions) {
Johannes Kronc5744b82018-09-24 14:50:48 +020078 extensions_ = extensions;
danilchap1edb7ab2016-04-20 05:25:10 -070079}
80
Danil Chapovalov8769e172017-09-14 14:08:22 +020081bool RtpPacket::Parse(const uint8_t* buffer, size_t buffer_size) {
danilchap1edb7ab2016-04-20 05:25:10 -070082 if (!ParseBuffer(buffer, buffer_size)) {
83 Clear();
84 return false;
85 }
danilchap1edb7ab2016-04-20 05:25:10 -070086 buffer_.SetData(buffer, buffer_size);
Danil Chapovalov31e4e802016-08-03 18:27:40 +020087 RTC_DCHECK_EQ(size(), buffer_size);
danilchap1edb7ab2016-04-20 05:25:10 -070088 return true;
89}
90
Danil Chapovalov8769e172017-09-14 14:08:22 +020091bool RtpPacket::Parse(rtc::ArrayView<const uint8_t> packet) {
brandtrb29e6522016-12-21 06:37:18 -080092 return Parse(packet.data(), packet.size());
93}
94
Danil Chapovalov8769e172017-09-14 14:08:22 +020095bool RtpPacket::Parse(rtc::CopyOnWriteBuffer buffer) {
Danil Chapovalov31e4e802016-08-03 18:27:40 +020096 if (!ParseBuffer(buffer.cdata(), buffer.size())) {
danilchap1edb7ab2016-04-20 05:25:10 -070097 Clear();
98 return false;
99 }
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200100 size_t buffer_size = buffer.size();
danilchap1edb7ab2016-04-20 05:25:10 -0700101 buffer_ = std::move(buffer);
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200102 RTC_DCHECK_EQ(size(), buffer_size);
danilchap1edb7ab2016-04-20 05:25:10 -0700103 return true;
104}
105
Danil Chapovalov8769e172017-09-14 14:08:22 +0200106std::vector<uint32_t> RtpPacket::Csrcs() const {
danilchap1edb7ab2016-04-20 05:25:10 -0700107 size_t num_csrc = data()[0] & 0x0F;
108 RTC_DCHECK_GE(capacity(), kFixedHeaderSize + num_csrc * 4);
109 std::vector<uint32_t> csrcs(num_csrc);
110 for (size_t i = 0; i < num_csrc; ++i) {
111 csrcs[i] =
112 ByteReader<uint32_t>::ReadBigEndian(&data()[kFixedHeaderSize + i * 4]);
113 }
114 return csrcs;
115}
116
Danil Chapovalov8769e172017-09-14 14:08:22 +0200117void RtpPacket::CopyHeaderFrom(const RtpPacket& packet) {
danilchap1edb7ab2016-04-20 05:25:10 -0700118 RTC_DCHECK_GE(capacity(), packet.headers_size());
119
120 marker_ = packet.marker_;
121 payload_type_ = packet.payload_type_;
122 sequence_number_ = packet.sequence_number_;
123 timestamp_ = packet.timestamp_;
124 ssrc_ = packet.ssrc_;
125 payload_offset_ = packet.payload_offset_;
Johannes Kronc5744b82018-09-24 14:50:48 +0200126 extensions_ = packet.extensions_;
127 extension_entries_ = packet.extension_entries_;
danilchap1edb7ab2016-04-20 05:25:10 -0700128 extensions_size_ = packet.extensions_size_;
129 buffer_.SetData(packet.data(), packet.headers_size());
130 // Reset payload and padding.
131 payload_size_ = 0;
132 padding_size_ = 0;
133}
134
Danil Chapovalov8769e172017-09-14 14:08:22 +0200135void RtpPacket::SetMarker(bool marker_bit) {
danilchap1edb7ab2016-04-20 05:25:10 -0700136 marker_ = marker_bit;
137 if (marker_) {
138 WriteAt(1, data()[1] | 0x80);
139 } else {
140 WriteAt(1, data()[1] & 0x7F);
141 }
142}
143
Danil Chapovalov8769e172017-09-14 14:08:22 +0200144void RtpPacket::SetPayloadType(uint8_t payload_type) {
danilchap1edb7ab2016-04-20 05:25:10 -0700145 RTC_DCHECK_LE(payload_type, 0x7Fu);
146 payload_type_ = payload_type;
147 WriteAt(1, (data()[1] & 0x80) | payload_type);
148}
149
Danil Chapovalov8769e172017-09-14 14:08:22 +0200150void RtpPacket::SetSequenceNumber(uint16_t seq_no) {
danilchap1edb7ab2016-04-20 05:25:10 -0700151 sequence_number_ = seq_no;
152 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(2), seq_no);
153}
154
Danil Chapovalov8769e172017-09-14 14:08:22 +0200155void RtpPacket::SetTimestamp(uint32_t timestamp) {
danilchap1edb7ab2016-04-20 05:25:10 -0700156 timestamp_ = timestamp;
157 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(4), timestamp);
158}
159
Danil Chapovalov8769e172017-09-14 14:08:22 +0200160void RtpPacket::SetSsrc(uint32_t ssrc) {
danilchap1edb7ab2016-04-20 05:25:10 -0700161 ssrc_ = ssrc;
162 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(8), ssrc);
163}
164
Danil Chapovalov7d2df3f2018-08-14 17:18:07 +0200165void RtpPacket::SetCsrcs(rtc::ArrayView<const uint32_t> csrcs) {
danilchap70f39a32016-12-16 05:48:18 -0800166 RTC_DCHECK_EQ(extensions_size_, 0);
kwibergaf476c72016-11-28 15:21:39 -0800167 RTC_DCHECK_EQ(payload_size_, 0);
168 RTC_DCHECK_EQ(padding_size_, 0);
danilchap1edb7ab2016-04-20 05:25:10 -0700169 RTC_DCHECK_LE(csrcs.size(), 0x0fu);
170 RTC_DCHECK_LE(kFixedHeaderSize + 4 * csrcs.size(), capacity());
171 payload_offset_ = kFixedHeaderSize + 4 * csrcs.size();
danilchap772bd8b2017-09-13 03:24:28 -0700172 WriteAt(0, (data()[0] & 0xF0) | rtc::dchecked_cast<uint8_t>(csrcs.size()));
danilchap1edb7ab2016-04-20 05:25:10 -0700173 size_t offset = kFixedHeaderSize;
174 for (uint32_t csrc : csrcs) {
175 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(offset), csrc);
176 offset += 4;
177 }
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200178 buffer_.SetSize(payload_offset_);
danilchap1edb7ab2016-04-20 05:25:10 -0700179}
180
Danil Chapovalov8769e172017-09-14 14:08:22 +0200181rtc::ArrayView<uint8_t> RtpPacket::AllocateRawExtension(int id, size_t length) {
danilchap653063f2017-04-03 06:16:30 -0700182 RTC_DCHECK_GE(id, kMinExtensionId);
183 RTC_DCHECK_LE(id, kMaxExtensionId);
184 RTC_DCHECK_GE(length, 1);
185 RTC_DCHECK_LE(length, 16);
186
Johannes Kronc5744b82018-09-24 14:50:48 +0200187 const ExtensionInfo* extension_entry = FindExtensionInfo(id);
188 if (extension_entry != nullptr) {
danilchap653063f2017-04-03 06:16:30 -0700189 // Extension already reserved. Check if same length is used.
190 if (extension_entry->length == length)
191 return rtc::MakeArrayView(WriteAt(extension_entry->offset), length);
192
Johannes Kronc5744b82018-09-24 14:50:48 +0200193 RTC_LOG(LS_ERROR) << "Length mismatch for extension id " << id
Mirko Bonadei675513b2017-11-09 11:09:25 +0100194 << ": expected "
195 << static_cast<int>(extension_entry->length)
196 << ". received " << length;
danilchap653063f2017-04-03 06:16:30 -0700197 return nullptr;
198 }
199 if (payload_size_ > 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100200 RTC_LOG(LS_ERROR) << "Can't add new extension id " << id
201 << " after payload was set.";
danilchap653063f2017-04-03 06:16:30 -0700202 return nullptr;
203 }
204 if (padding_size_ > 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100205 RTC_LOG(LS_ERROR) << "Can't add new extension id " << id
206 << " after padding was set.";
danilchap653063f2017-04-03 06:16:30 -0700207 return nullptr;
208 }
209
210 size_t num_csrc = data()[0] & 0x0F;
211 size_t extensions_offset = kFixedHeaderSize + (num_csrc * 4) + 4;
212 size_t new_extensions_size = extensions_size_ + kOneByteHeaderSize + length;
213 if (extensions_offset + new_extensions_size > capacity()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100214 RTC_LOG(LS_ERROR)
danilchap653063f2017-04-03 06:16:30 -0700215 << "Extension cannot be registered: Not enough space left in buffer.";
216 return nullptr;
217 }
218
219 // All checks passed, write down the extension headers.
220 if (extensions_size_ == 0) {
221 RTC_DCHECK_EQ(payload_offset_, kFixedHeaderSize + (num_csrc * 4));
222 WriteAt(0, data()[0] | 0x10); // Set extension bit.
223 // Profile specific ID always set to OneByteExtensionHeader.
224 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 4),
225 kOneByteExtensionId);
226 }
227
danilchap772bd8b2017-09-13 03:24:28 -0700228 uint8_t one_byte_header = rtc::dchecked_cast<uint8_t>(id) << 4;
229 one_byte_header |= rtc::dchecked_cast<uint8_t>(length - 1);
230 WriteAt(extensions_offset + extensions_size_, one_byte_header);
danilchap653063f2017-04-03 06:16:30 -0700231
Johannes Kronc5744b82018-09-24 14:50:48 +0200232 const uint16_t extension_info_offset = rtc::dchecked_cast<uint16_t>(
danilchap772bd8b2017-09-13 03:24:28 -0700233 extensions_offset + extensions_size_ + kOneByteHeaderSize);
Johannes Kronc5744b82018-09-24 14:50:48 +0200234 const uint8_t extension_info_length = rtc::dchecked_cast<uint8_t>(length);
235 extension_entries_.emplace_back(id, extension_info_length,
236 extension_info_offset);
Danil Chapovalov61405bc2018-02-13 13:55:30 +0100237 extensions_size_ = new_extensions_size;
danilchap653063f2017-04-03 06:16:30 -0700238
239 // Update header length field.
Danil Chapovalov61405bc2018-02-13 13:55:30 +0100240 uint16_t extensions_words = rtc::dchecked_cast<uint16_t>(
241 (extensions_size_ + 3) / 4); // Wrap up to 32bit.
danilchap653063f2017-04-03 06:16:30 -0700242 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 2),
243 extensions_words);
244 // Fill extension padding place with zeroes.
245 size_t extension_padding_size = 4 * extensions_words - extensions_size_;
246 memset(WriteAt(extensions_offset + extensions_size_), 0,
247 extension_padding_size);
248 payload_offset_ = extensions_offset + 4 * extensions_words;
249 buffer_.SetSize(payload_offset_);
Johannes Kronc5744b82018-09-24 14:50:48 +0200250 return rtc::MakeArrayView(WriteAt(extension_info_offset),
251 extension_info_length);
danilchap653063f2017-04-03 06:16:30 -0700252}
253
Danil Chapovalov8769e172017-09-14 14:08:22 +0200254uint8_t* RtpPacket::AllocatePayload(size_t size_bytes) {
danilchap07a01b32017-03-29 07:33:13 -0700255 // Reset payload size to 0. If CopyOnWrite buffer_ was shared, this will cause
256 // reallocation and memcpy. Keeping just header reduces memcpy size.
257 SetPayloadSize(0);
258 return SetPayloadSize(size_bytes);
259}
260
Danil Chapovalov8769e172017-09-14 14:08:22 +0200261uint8_t* RtpPacket::SetPayloadSize(size_t size_bytes) {
kwibergaf476c72016-11-28 15:21:39 -0800262 RTC_DCHECK_EQ(padding_size_, 0);
danilchap1edb7ab2016-04-20 05:25:10 -0700263 if (payload_offset_ + size_bytes > capacity()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100264 RTC_LOG(LS_WARNING) << "Cannot set payload, not enough space in buffer.";
danilchap1edb7ab2016-04-20 05:25:10 -0700265 return nullptr;
266 }
267 payload_size_ = size_bytes;
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200268 buffer_.SetSize(payload_offset_ + payload_size_);
danilchap1edb7ab2016-04-20 05:25:10 -0700269 return WriteAt(payload_offset_);
270}
271
Danil Chapovalov8769e172017-09-14 14:08:22 +0200272bool RtpPacket::SetPadding(uint8_t size_bytes, Random* random) {
danilchap1edb7ab2016-04-20 05:25:10 -0700273 RTC_DCHECK(random);
274 if (payload_offset_ + payload_size_ + size_bytes > capacity()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100275 RTC_LOG(LS_WARNING) << "Cannot set padding size " << size_bytes << ", only "
276 << (capacity() - payload_offset_ - payload_size_)
277 << " bytes left in buffer.";
danilchap1edb7ab2016-04-20 05:25:10 -0700278 return false;
279 }
280 padding_size_ = size_bytes;
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200281 buffer_.SetSize(payload_offset_ + payload_size_ + padding_size_);
danilchap1edb7ab2016-04-20 05:25:10 -0700282 if (padding_size_ > 0) {
283 size_t padding_offset = payload_offset_ + payload_size_;
284 size_t padding_end = padding_offset + padding_size_;
285 for (size_t offset = padding_offset; offset < padding_end - 1; ++offset) {
286 WriteAt(offset, random->Rand<uint8_t>());
287 }
288 WriteAt(padding_end - 1, padding_size_);
289 WriteAt(0, data()[0] | 0x20); // Set padding bit.
290 } else {
291 WriteAt(0, data()[0] & ~0x20); // Clear padding bit.
292 }
293 return true;
294}
295
Danil Chapovalov8769e172017-09-14 14:08:22 +0200296void RtpPacket::Clear() {
danilchap1edb7ab2016-04-20 05:25:10 -0700297 marker_ = false;
298 payload_type_ = 0;
299 sequence_number_ = 0;
300 timestamp_ = 0;
301 ssrc_ = 0;
302 payload_offset_ = kFixedHeaderSize;
303 payload_size_ = 0;
304 padding_size_ = 0;
danilchap1edb7ab2016-04-20 05:25:10 -0700305 extensions_size_ = 0;
Johannes Kronc5744b82018-09-24 14:50:48 +0200306 extension_entries_.clear();
danilchap1edb7ab2016-04-20 05:25:10 -0700307
308 memset(WriteAt(0), 0, kFixedHeaderSize);
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200309 buffer_.SetSize(kFixedHeaderSize);
danilchap1edb7ab2016-04-20 05:25:10 -0700310 WriteAt(0, kRtpVersion << 6);
311}
312
Danil Chapovalov8769e172017-09-14 14:08:22 +0200313bool RtpPacket::ParseBuffer(const uint8_t* buffer, size_t size) {
danilchap1edb7ab2016-04-20 05:25:10 -0700314 if (size < kFixedHeaderSize) {
315 return false;
316 }
317 const uint8_t version = buffer[0] >> 6;
318 if (version != kRtpVersion) {
319 return false;
320 }
321 const bool has_padding = (buffer[0] & 0x20) != 0;
322 const bool has_extension = (buffer[0] & 0x10) != 0;
323 const uint8_t number_of_crcs = buffer[0] & 0x0f;
324 marker_ = (buffer[1] & 0x80) != 0;
325 payload_type_ = buffer[1] & 0x7f;
326
327 sequence_number_ = ByteReader<uint16_t>::ReadBigEndian(&buffer[2]);
328 timestamp_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]);
329 ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]);
330 if (size < kFixedHeaderSize + number_of_crcs * 4) {
331 return false;
332 }
333 payload_offset_ = kFixedHeaderSize + number_of_crcs * 4;
334
335 if (has_padding) {
336 padding_size_ = buffer[size - 1];
337 if (padding_size_ == 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100338 RTC_LOG(LS_WARNING) << "Padding was set, but padding size is zero";
danilchap1edb7ab2016-04-20 05:25:10 -0700339 return false;
340 }
341 } else {
342 padding_size_ = 0;
343 }
344
danilchap1edb7ab2016-04-20 05:25:10 -0700345 extensions_size_ = 0;
danilchap70f39a32016-12-16 05:48:18 -0800346 for (ExtensionInfo& location : extension_entries_) {
347 location.offset = 0;
348 location.length = 0;
349 }
danilchap1edb7ab2016-04-20 05:25:10 -0700350 if (has_extension) {
351 /* RTP header extension, RFC 3550.
352 0 1 2 3
353 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
354 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
355 | defined by profile | length |
356 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
357 | header extension |
358 | .... |
359 */
360 size_t extension_offset = payload_offset_ + 4;
361 if (extension_offset > size) {
362 return false;
363 }
364 uint16_t profile =
365 ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_]);
366 size_t extensions_capacity =
367 ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_ + 2]);
368 extensions_capacity *= 4;
369 if (extension_offset + extensions_capacity > size) {
370 return false;
371 }
372 if (profile != kOneByteExtensionId) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100373 RTC_LOG(LS_WARNING) << "Unsupported rtp extension " << profile;
danilchap1edb7ab2016-04-20 05:25:10 -0700374 } else {
375 constexpr uint8_t kPaddingId = 0;
376 constexpr uint8_t kReservedId = 15;
377 while (extensions_size_ + kOneByteHeaderSize < extensions_capacity) {
danilchap70f39a32016-12-16 05:48:18 -0800378 int id = buffer[extension_offset + extensions_size_] >> 4;
danilchap1edb7ab2016-04-20 05:25:10 -0700379 if (id == kReservedId) {
380 break;
381 } else if (id == kPaddingId) {
382 extensions_size_++;
383 continue;
384 }
385 uint8_t length =
386 1 + (buffer[extension_offset + extensions_size_] & 0xf);
Danil Chapovalova64a2fb2016-09-12 11:41:35 +0200387 if (extensions_size_ + kOneByteHeaderSize + length >
388 extensions_capacity) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100389 RTC_LOG(LS_WARNING) << "Oversized rtp header extension.";
Danil Chapovalova64a2fb2016-09-12 11:41:35 +0200390 break;
danilchap1edb7ab2016-04-20 05:25:10 -0700391 }
danilchap70f39a32016-12-16 05:48:18 -0800392
Johannes Kronc5744b82018-09-24 14:50:48 +0200393 ExtensionInfo& extension_info = FindOrCreateExtensionInfo(id);
394 if (extension_info.length != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100395 RTC_LOG(LS_VERBOSE)
396 << "Duplicate rtp header extension id " << id << ". Overwriting.";
Danil Chapovalova64a2fb2016-09-12 11:41:35 +0200397 }
danilchap70f39a32016-12-16 05:48:18 -0800398
Danil Chapovalovc2dd59c2018-02-06 11:29:35 +0100399 size_t offset =
400 extension_offset + extensions_size_ + kOneByteHeaderSize;
401 if (!rtc::IsValueInRangeForNumericType<uint16_t>(offset)) {
402 RTC_DLOG(LS_WARNING) << "Oversized rtp header extension.";
403 break;
404 }
Johannes Kronc5744b82018-09-24 14:50:48 +0200405 extension_info.offset = static_cast<uint16_t>(offset);
406 extension_info.length = length;
Danil Chapovalovc2dd59c2018-02-06 11:29:35 +0100407 extensions_size_ += kOneByteHeaderSize + length;
danilchap1edb7ab2016-04-20 05:25:10 -0700408 }
409 }
410 payload_offset_ = extension_offset + extensions_capacity;
411 }
412
413 if (payload_offset_ + padding_size_ > size) {
414 return false;
415 }
416 payload_size_ = size - payload_offset_ - padding_size_;
417 return true;
418}
419
Johannes Kronc5744b82018-09-24 14:50:48 +0200420const RtpPacket::ExtensionInfo* RtpPacket::FindExtensionInfo(int id) const {
danilchap70f39a32016-12-16 05:48:18 -0800421 for (const ExtensionInfo& extension : extension_entries_) {
Johannes Kronc5744b82018-09-24 14:50:48 +0200422 if (extension.id == id) {
423 return &extension;
danilchap1edb7ab2016-04-20 05:25:10 -0700424 }
425 }
danilchap978504e2017-04-06 01:03:53 -0700426 return nullptr;
danilchap1edb7ab2016-04-20 05:25:10 -0700427}
428
Johannes Kronc5744b82018-09-24 14:50:48 +0200429RtpPacket::ExtensionInfo& RtpPacket::FindOrCreateExtensionInfo(int id) {
430 for (ExtensionInfo& extension : extension_entries_) {
431 if (extension.id == id) {
432 return extension;
danilchap70f39a32016-12-16 05:48:18 -0800433 }
danilchap1edb7ab2016-04-20 05:25:10 -0700434 }
Johannes Kronc5744b82018-09-24 14:50:48 +0200435 extension_entries_.emplace_back(id);
436 return extension_entries_.back();
437}
438
439rtc::ArrayView<const uint8_t> RtpPacket::FindExtension(
440 ExtensionType type) const {
441 uint8_t id = extensions_.GetId(type);
442 if (id == ExtensionManager::kInvalidId) {
443 // Extension not registered.
444 return nullptr;
445 }
446 ExtensionInfo const* extension_info = FindExtensionInfo(id);
447 if (extension_info == nullptr) {
448 return nullptr;
449 }
450 return rtc::MakeArrayView(data() + extension_info->offset,
451 extension_info->length);
452}
453
454rtc::ArrayView<uint8_t> RtpPacket::AllocateExtension(ExtensionType type,
455 size_t length) {
456 uint8_t id = extensions_.GetId(type);
457 if (id == ExtensionManager::kInvalidId) {
458 // Extension not registered.
459 return nullptr;
460 }
461 return AllocateRawExtension(id, length);
danilchap1edb7ab2016-04-20 05:25:10 -0700462}
463
danilchap1edb7ab2016-04-20 05:25:10 -0700464} // namespace webrtc