blob: 7df60053fb8e206e6d9ed0a6af12b1ecffacc66d [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
11#include "webrtc/modules/rtp_rtcp/source/rtp_packet.h"
12
13#include <cstring>
Danil Chapovalova64a2fb2016-09-12 11:41:35 +020014#include <utility>
danilchap1edb7ab2016-04-20 05:25:10 -070015
danilchap1edb7ab2016-04-20 05:25:10 -070016#include "webrtc/common_types.h"
Danil Chapovalov07633bd2017-06-01 17:10:51 +020017#include "webrtc/modules/rtp_rtcp/include/rtp_header_extension_map.h"
danilchap1edb7ab2016-04-20 05:25:10 -070018#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020019#include "webrtc/rtc_base/checks.h"
20#include "webrtc/rtc_base/logging.h"
21#include "webrtc/rtc_base/random.h"
danilchap1edb7ab2016-04-20 05:25:10 -070022
23namespace webrtc {
24namespace rtp {
25namespace {
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
33constexpr size_t Packet::kMaxExtensionHeaders;
34constexpr int Packet::kMinExtensionId;
35constexpr int Packet::kMaxExtensionId;
36
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// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchap70f39a32016-12-16 05:48:18 -080059Packet::Packet() : Packet(nullptr, kDefaultPacketSize) {}
60
danilchap1edb7ab2016-04-20 05:25:10 -070061Packet::Packet(const ExtensionManager* extensions)
danilchap70f39a32016-12-16 05:48:18 -080062 : Packet(extensions, kDefaultPacketSize) {}
danilchap1edb7ab2016-04-20 05:25:10 -070063
nisse76e62b02017-05-31 02:24:52 -070064Packet::Packet(const Packet&) = default;
65
danilchap1edb7ab2016-04-20 05:25:10 -070066Packet::Packet(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) {
71 IdentifyExtensions(*extensions);
72 } else {
73 for (size_t i = 0; i < kMaxExtensionHeaders; ++i)
74 extension_entries_[i].type = ExtensionManager::kInvalidType;
75 }
danilchap1edb7ab2016-04-20 05:25:10 -070076}
77
78Packet::~Packet() {}
79
danilchap70f39a32016-12-16 05:48:18 -080080void Packet::IdentifyExtensions(const ExtensionManager& extensions) {
81 for (size_t i = 0; i < kMaxExtensionHeaders; ++i)
82 extension_entries_[i].type = extensions.GetType(i + 1);
danilchap1edb7ab2016-04-20 05:25:10 -070083}
84
85bool Packet::Parse(const uint8_t* buffer, size_t buffer_size) {
86 if (!ParseBuffer(buffer, buffer_size)) {
87 Clear();
88 return false;
89 }
danilchap1edb7ab2016-04-20 05:25:10 -070090 buffer_.SetData(buffer, buffer_size);
Danil Chapovalov31e4e802016-08-03 18:27:40 +020091 RTC_DCHECK_EQ(size(), buffer_size);
danilchap1edb7ab2016-04-20 05:25:10 -070092 return true;
93}
94
brandtrb29e6522016-12-21 06:37:18 -080095bool Packet::Parse(rtc::ArrayView<const uint8_t> packet) {
96 return Parse(packet.data(), packet.size());
97}
98
Danil Chapovalov31e4e802016-08-03 18:27:40 +020099bool Packet::Parse(rtc::CopyOnWriteBuffer buffer) {
100 if (!ParseBuffer(buffer.cdata(), buffer.size())) {
danilchap1edb7ab2016-04-20 05:25:10 -0700101 Clear();
102 return false;
103 }
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200104 size_t buffer_size = buffer.size();
danilchap1edb7ab2016-04-20 05:25:10 -0700105 buffer_ = std::move(buffer);
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200106 RTC_DCHECK_EQ(size(), buffer_size);
danilchap1edb7ab2016-04-20 05:25:10 -0700107 return true;
108}
109
110bool Packet::Marker() const {
111 RTC_DCHECK_EQ(marker_, (data()[1] & 0x80) != 0);
112 return marker_;
113}
114
115uint8_t Packet::PayloadType() const {
116 RTC_DCHECK_EQ(payload_type_, data()[1] & 0x7f);
117 return payload_type_;
118}
119
120uint16_t Packet::SequenceNumber() const {
121 RTC_DCHECK_EQ(sequence_number_,
122 ByteReader<uint16_t>::ReadBigEndian(data() + 2));
123 return sequence_number_;
124}
125
126uint32_t Packet::Timestamp() const {
127 RTC_DCHECK_EQ(timestamp_, ByteReader<uint32_t>::ReadBigEndian(data() + 4));
128 return timestamp_;
129}
130
131uint32_t Packet::Ssrc() const {
132 RTC_DCHECK_EQ(ssrc_, ByteReader<uint32_t>::ReadBigEndian(data() + 8));
133 return ssrc_;
134}
135
136std::vector<uint32_t> Packet::Csrcs() const {
137 size_t num_csrc = data()[0] & 0x0F;
138 RTC_DCHECK_GE(capacity(), kFixedHeaderSize + num_csrc * 4);
139 std::vector<uint32_t> csrcs(num_csrc);
140 for (size_t i = 0; i < num_csrc; ++i) {
141 csrcs[i] =
142 ByteReader<uint32_t>::ReadBigEndian(&data()[kFixedHeaderSize + i * 4]);
143 }
144 return csrcs;
145}
146
danilchap1edb7ab2016-04-20 05:25:10 -0700147size_t Packet::headers_size() const {
148 return payload_offset_;
149}
150
151size_t Packet::payload_size() const {
152 return payload_size_;
153}
154
155size_t Packet::padding_size() const {
156 return padding_size_;
157}
158
danilchap96c15872016-11-21 01:35:29 -0800159rtc::ArrayView<const uint8_t> Packet::payload() const {
160 return rtc::MakeArrayView(data() + payload_offset_, payload_size_);
danilchap1edb7ab2016-04-20 05:25:10 -0700161}
162
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200163rtc::CopyOnWriteBuffer Packet::Buffer() const {
164 return buffer_;
165}
166
danilchap1edb7ab2016-04-20 05:25:10 -0700167size_t Packet::capacity() const {
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200168 return buffer_.capacity();
danilchap1edb7ab2016-04-20 05:25:10 -0700169}
170
171size_t Packet::size() const {
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200172 size_t ret = payload_offset_ + payload_size_ + padding_size_;
173 RTC_DCHECK_EQ(buffer_.size(), ret);
174 return ret;
danilchap1edb7ab2016-04-20 05:25:10 -0700175}
176
177const uint8_t* Packet::data() const {
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200178 return buffer_.cdata();
danilchap1edb7ab2016-04-20 05:25:10 -0700179}
180
181size_t Packet::FreeCapacity() const {
182 return capacity() - size();
183}
184
185size_t Packet::MaxPayloadSize() const {
186 return capacity() - payload_offset_;
187}
188
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200189void Packet::CopyHeaderFrom(const Packet& packet) {
danilchap1edb7ab2016-04-20 05:25:10 -0700190 RTC_DCHECK_GE(capacity(), packet.headers_size());
191
192 marker_ = packet.marker_;
193 payload_type_ = packet.payload_type_;
194 sequence_number_ = packet.sequence_number_;
195 timestamp_ = packet.timestamp_;
196 ssrc_ = packet.ssrc_;
197 payload_offset_ = packet.payload_offset_;
danilchap70f39a32016-12-16 05:48:18 -0800198 for (size_t i = 0; i < kMaxExtensionHeaders; ++i) {
danilchap1edb7ab2016-04-20 05:25:10 -0700199 extension_entries_[i] = packet.extension_entries_[i];
200 }
201 extensions_size_ = packet.extensions_size_;
202 buffer_.SetData(packet.data(), packet.headers_size());
203 // Reset payload and padding.
204 payload_size_ = 0;
205 padding_size_ = 0;
206}
207
208void Packet::SetMarker(bool marker_bit) {
209 marker_ = marker_bit;
210 if (marker_) {
211 WriteAt(1, data()[1] | 0x80);
212 } else {
213 WriteAt(1, data()[1] & 0x7F);
214 }
215}
216
217void Packet::SetPayloadType(uint8_t payload_type) {
218 RTC_DCHECK_LE(payload_type, 0x7Fu);
219 payload_type_ = payload_type;
220 WriteAt(1, (data()[1] & 0x80) | payload_type);
221}
222
223void Packet::SetSequenceNumber(uint16_t seq_no) {
224 sequence_number_ = seq_no;
225 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(2), seq_no);
226}
227
228void Packet::SetTimestamp(uint32_t timestamp) {
229 timestamp_ = timestamp;
230 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(4), timestamp);
231}
232
233void Packet::SetSsrc(uint32_t ssrc) {
234 ssrc_ = ssrc;
235 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(8), ssrc);
236}
237
238void Packet::SetCsrcs(const std::vector<uint32_t>& csrcs) {
danilchap70f39a32016-12-16 05:48:18 -0800239 RTC_DCHECK_EQ(extensions_size_, 0);
kwibergaf476c72016-11-28 15:21:39 -0800240 RTC_DCHECK_EQ(payload_size_, 0);
241 RTC_DCHECK_EQ(padding_size_, 0);
danilchap1edb7ab2016-04-20 05:25:10 -0700242 RTC_DCHECK_LE(csrcs.size(), 0x0fu);
243 RTC_DCHECK_LE(kFixedHeaderSize + 4 * csrcs.size(), capacity());
244 payload_offset_ = kFixedHeaderSize + 4 * csrcs.size();
245 WriteAt(0, (data()[0] & 0xF0) | csrcs.size());
246 size_t offset = kFixedHeaderSize;
247 for (uint32_t csrc : csrcs) {
248 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(offset), csrc);
249 offset += 4;
250 }
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200251 buffer_.SetSize(payload_offset_);
danilchap1edb7ab2016-04-20 05:25:10 -0700252}
253
danilchap653063f2017-04-03 06:16:30 -0700254bool Packet::HasRawExtension(int id) const {
danilchapc547e842017-04-10 01:31:49 -0700255 if (id == ExtensionManager::kInvalidId)
256 return false;
danilchap653063f2017-04-03 06:16:30 -0700257 RTC_DCHECK_GE(id, kMinExtensionId);
258 RTC_DCHECK_LE(id, kMaxExtensionId);
259 return extension_entries_[id - 1].offset != 0;
260}
261
262rtc::ArrayView<const uint8_t> Packet::GetRawExtension(int id) const {
danilchapc547e842017-04-10 01:31:49 -0700263 if (id == ExtensionManager::kInvalidId)
264 return nullptr;
danilchap653063f2017-04-03 06:16:30 -0700265 RTC_DCHECK_GE(id, kMinExtensionId);
266 RTC_DCHECK_LE(id, kMaxExtensionId);
267 const ExtensionInfo& extension = extension_entries_[id - 1];
268 if (extension.offset == 0)
269 return nullptr;
270 return rtc::MakeArrayView(data() + extension.offset, extension.length);
271}
272
273bool Packet::SetRawExtension(int id, rtc::ArrayView<const uint8_t> data) {
274 auto buffer = AllocateRawExtension(id, data.size());
275 if (buffer.empty())
276 return false;
277 RTC_DCHECK_EQ(buffer.size(), data.size());
278 memcpy(buffer.data(), data.data(), data.size());
279 return true;
280}
281
282rtc::ArrayView<uint8_t> Packet::AllocateRawExtension(int id, size_t length) {
danilchapc547e842017-04-10 01:31:49 -0700283 if (id == ExtensionManager::kInvalidId)
284 return nullptr;
danilchap653063f2017-04-03 06:16:30 -0700285 RTC_DCHECK_GE(id, kMinExtensionId);
286 RTC_DCHECK_LE(id, kMaxExtensionId);
287 RTC_DCHECK_GE(length, 1);
288 RTC_DCHECK_LE(length, 16);
289
290 ExtensionInfo* extension_entry = &extension_entries_[id - 1];
291 if (extension_entry->offset != 0) {
292 // Extension already reserved. Check if same length is used.
293 if (extension_entry->length == length)
294 return rtc::MakeArrayView(WriteAt(extension_entry->offset), length);
295
296 LOG(LS_ERROR) << "Length mismatch for extension id " << id << " type "
297 << static_cast<int>(extension_entry->type) << ": expected "
298 << static_cast<int>(extension_entry->length) << ". received "
299 << length;
300 return nullptr;
301 }
302 if (payload_size_ > 0) {
303 LOG(LS_ERROR) << "Can't add new extension id " << id
304 << " after payload was set.";
305 return nullptr;
306 }
307 if (padding_size_ > 0) {
308 LOG(LS_ERROR) << "Can't add new extension id " << id
309 << " after padding was set.";
310 return nullptr;
311 }
312
313 size_t num_csrc = data()[0] & 0x0F;
314 size_t extensions_offset = kFixedHeaderSize + (num_csrc * 4) + 4;
315 size_t new_extensions_size = extensions_size_ + kOneByteHeaderSize + length;
316 if (extensions_offset + new_extensions_size > capacity()) {
317 LOG(LS_ERROR)
318 << "Extension cannot be registered: Not enough space left in buffer.";
319 return nullptr;
320 }
321
322 // All checks passed, write down the extension headers.
323 if (extensions_size_ == 0) {
324 RTC_DCHECK_EQ(payload_offset_, kFixedHeaderSize + (num_csrc * 4));
325 WriteAt(0, data()[0] | 0x10); // Set extension bit.
326 // Profile specific ID always set to OneByteExtensionHeader.
327 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 4),
328 kOneByteExtensionId);
329 }
330
331 WriteAt(extensions_offset + extensions_size_, (id << 4) | (length - 1));
332
333 extension_entry->offset =
334 extensions_offset + extensions_size_ + kOneByteHeaderSize;
335 extension_entry->length = length;
336 extensions_size_ = new_extensions_size;
337
338 // Update header length field.
339 uint16_t extensions_words = (extensions_size_ + 3) / 4; // Wrap up to 32bit.
340 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 2),
341 extensions_words);
342 // Fill extension padding place with zeroes.
343 size_t extension_padding_size = 4 * extensions_words - extensions_size_;
344 memset(WriteAt(extensions_offset + extensions_size_), 0,
345 extension_padding_size);
346 payload_offset_ = extensions_offset + 4 * extensions_words;
347 buffer_.SetSize(payload_offset_);
348 return rtc::MakeArrayView(WriteAt(extension_entry->offset), length);
349}
350
danilchap1edb7ab2016-04-20 05:25:10 -0700351uint8_t* Packet::AllocatePayload(size_t size_bytes) {
danilchap07a01b32017-03-29 07:33:13 -0700352 // Reset payload size to 0. If CopyOnWrite buffer_ was shared, this will cause
353 // reallocation and memcpy. Keeping just header reduces memcpy size.
354 SetPayloadSize(0);
355 return SetPayloadSize(size_bytes);
356}
357
358uint8_t* Packet::SetPayloadSize(size_t size_bytes) {
kwibergaf476c72016-11-28 15:21:39 -0800359 RTC_DCHECK_EQ(padding_size_, 0);
danilchap1edb7ab2016-04-20 05:25:10 -0700360 if (payload_offset_ + size_bytes > capacity()) {
361 LOG(LS_WARNING) << "Cannot set payload, not enough space in buffer.";
362 return nullptr;
363 }
364 payload_size_ = size_bytes;
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200365 buffer_.SetSize(payload_offset_ + payload_size_);
danilchap1edb7ab2016-04-20 05:25:10 -0700366 return WriteAt(payload_offset_);
367}
368
danilchap1edb7ab2016-04-20 05:25:10 -0700369bool Packet::SetPadding(uint8_t size_bytes, Random* random) {
370 RTC_DCHECK(random);
371 if (payload_offset_ + payload_size_ + size_bytes > capacity()) {
372 LOG(LS_WARNING) << "Cannot set padding size " << size_bytes << ", only "
373 << (capacity() - payload_offset_ - payload_size_)
374 << " bytes left in buffer.";
375 return false;
376 }
377 padding_size_ = size_bytes;
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200378 buffer_.SetSize(payload_offset_ + payload_size_ + padding_size_);
danilchap1edb7ab2016-04-20 05:25:10 -0700379 if (padding_size_ > 0) {
380 size_t padding_offset = payload_offset_ + payload_size_;
381 size_t padding_end = padding_offset + padding_size_;
382 for (size_t offset = padding_offset; offset < padding_end - 1; ++offset) {
383 WriteAt(offset, random->Rand<uint8_t>());
384 }
385 WriteAt(padding_end - 1, padding_size_);
386 WriteAt(0, data()[0] | 0x20); // Set padding bit.
387 } else {
388 WriteAt(0, data()[0] & ~0x20); // Clear padding bit.
389 }
390 return true;
391}
392
393void Packet::Clear() {
394 marker_ = false;
395 payload_type_ = 0;
396 sequence_number_ = 0;
397 timestamp_ = 0;
398 ssrc_ = 0;
399 payload_offset_ = kFixedHeaderSize;
400 payload_size_ = 0;
401 padding_size_ = 0;
danilchap1edb7ab2016-04-20 05:25:10 -0700402 extensions_size_ = 0;
danilchap70f39a32016-12-16 05:48:18 -0800403 for (ExtensionInfo& location : extension_entries_) {
404 location.offset = 0;
405 location.length = 0;
406 }
danilchap1edb7ab2016-04-20 05:25:10 -0700407
408 memset(WriteAt(0), 0, kFixedHeaderSize);
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200409 buffer_.SetSize(kFixedHeaderSize);
danilchap1edb7ab2016-04-20 05:25:10 -0700410 WriteAt(0, kRtpVersion << 6);
411}
412
413bool Packet::ParseBuffer(const uint8_t* buffer, size_t size) {
414 if (size < kFixedHeaderSize) {
415 return false;
416 }
417 const uint8_t version = buffer[0] >> 6;
418 if (version != kRtpVersion) {
419 return false;
420 }
421 const bool has_padding = (buffer[0] & 0x20) != 0;
422 const bool has_extension = (buffer[0] & 0x10) != 0;
423 const uint8_t number_of_crcs = buffer[0] & 0x0f;
424 marker_ = (buffer[1] & 0x80) != 0;
425 payload_type_ = buffer[1] & 0x7f;
426
427 sequence_number_ = ByteReader<uint16_t>::ReadBigEndian(&buffer[2]);
428 timestamp_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]);
429 ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]);
430 if (size < kFixedHeaderSize + number_of_crcs * 4) {
431 return false;
432 }
433 payload_offset_ = kFixedHeaderSize + number_of_crcs * 4;
434
435 if (has_padding) {
436 padding_size_ = buffer[size - 1];
437 if (padding_size_ == 0) {
438 LOG(LS_WARNING) << "Padding was set, but padding size is zero";
439 return false;
440 }
441 } else {
442 padding_size_ = 0;
443 }
444
danilchap1edb7ab2016-04-20 05:25:10 -0700445 extensions_size_ = 0;
danilchap70f39a32016-12-16 05:48:18 -0800446 for (ExtensionInfo& location : extension_entries_) {
447 location.offset = 0;
448 location.length = 0;
449 }
danilchap1edb7ab2016-04-20 05:25:10 -0700450 if (has_extension) {
451 /* RTP header extension, RFC 3550.
452 0 1 2 3
453 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
454 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
455 | defined by profile | length |
456 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
457 | header extension |
458 | .... |
459 */
460 size_t extension_offset = payload_offset_ + 4;
461 if (extension_offset > size) {
462 return false;
463 }
464 uint16_t profile =
465 ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_]);
466 size_t extensions_capacity =
467 ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_ + 2]);
468 extensions_capacity *= 4;
469 if (extension_offset + extensions_capacity > size) {
470 return false;
471 }
472 if (profile != kOneByteExtensionId) {
473 LOG(LS_WARNING) << "Unsupported rtp extension " << profile;
474 } else {
475 constexpr uint8_t kPaddingId = 0;
476 constexpr uint8_t kReservedId = 15;
477 while (extensions_size_ + kOneByteHeaderSize < extensions_capacity) {
danilchap70f39a32016-12-16 05:48:18 -0800478 int id = buffer[extension_offset + extensions_size_] >> 4;
danilchap1edb7ab2016-04-20 05:25:10 -0700479 if (id == kReservedId) {
480 break;
481 } else if (id == kPaddingId) {
482 extensions_size_++;
483 continue;
484 }
485 uint8_t length =
486 1 + (buffer[extension_offset + extensions_size_] & 0xf);
Danil Chapovalova64a2fb2016-09-12 11:41:35 +0200487 if (extensions_size_ + kOneByteHeaderSize + length >
488 extensions_capacity) {
489 LOG(LS_WARNING) << "Oversized rtp header extension.";
490 break;
danilchap1edb7ab2016-04-20 05:25:10 -0700491 }
danilchap70f39a32016-12-16 05:48:18 -0800492
493 size_t idx = id - 1;
494 if (extension_entries_[idx].length != 0) {
495 LOG(LS_VERBOSE) << "Duplicate rtp header extension id " << id
496 << ". Overwriting.";
Danil Chapovalova64a2fb2016-09-12 11:41:35 +0200497 }
danilchap70f39a32016-12-16 05:48:18 -0800498
Danil Chapovalova64a2fb2016-09-12 11:41:35 +0200499 extensions_size_ += kOneByteHeaderSize;
danilchap70f39a32016-12-16 05:48:18 -0800500 extension_entries_[idx].offset = extension_offset + extensions_size_;
501 extension_entries_[idx].length = length;
danilchap1edb7ab2016-04-20 05:25:10 -0700502 extensions_size_ += length;
503 }
504 }
505 payload_offset_ = extension_offset + extensions_capacity;
506 }
507
508 if (payload_offset_ + padding_size_ > size) {
509 return false;
510 }
511 payload_size_ = size - payload_offset_ - padding_size_;
512 return true;
513}
514
danilchap978504e2017-04-06 01:03:53 -0700515rtc::ArrayView<const uint8_t> Packet::FindExtension(ExtensionType type) const {
danilchap70f39a32016-12-16 05:48:18 -0800516 for (const ExtensionInfo& extension : extension_entries_) {
517 if (extension.type == type) {
518 if (extension.length == 0) {
519 // Extension is registered but not set.
danilchap978504e2017-04-06 01:03:53 -0700520 return nullptr;
danilchap07ec26d2016-06-17 04:18:54 -0700521 }
danilchap978504e2017-04-06 01:03:53 -0700522 return rtc::MakeArrayView(data() + extension.offset, extension.length);
danilchap1edb7ab2016-04-20 05:25:10 -0700523 }
524 }
danilchap978504e2017-04-06 01:03:53 -0700525 return nullptr;
danilchap1edb7ab2016-04-20 05:25:10 -0700526}
527
danilchap653063f2017-04-03 06:16:30 -0700528rtc::ArrayView<uint8_t> Packet::AllocateExtension(ExtensionType type,
529 size_t length) {
danilchap70f39a32016-12-16 05:48:18 -0800530 for (size_t i = 0; i < kMaxExtensionHeaders; ++i) {
531 if (extension_entries_[i].type == type) {
danilchap653063f2017-04-03 06:16:30 -0700532 int extension_id = i + 1;
533 return AllocateRawExtension(extension_id, length);
danilchap70f39a32016-12-16 05:48:18 -0800534 }
danilchap1edb7ab2016-04-20 05:25:10 -0700535 }
danilchap653063f2017-04-03 06:16:30 -0700536 // Extension not registered.
537 return nullptr;
danilchap1edb7ab2016-04-20 05:25:10 -0700538}
539
540uint8_t* Packet::WriteAt(size_t offset) {
541 return buffer_.data() + offset;
542}
543
544void Packet::WriteAt(size_t offset, uint8_t byte) {
545 buffer_.data()[offset] = byte;
546}
547
548} // namespace rtp
549} // namespace webrtc