blob: 6b54be7b4c8abb424d74085ba7c35d78eb1a6087 [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
16#include "webrtc/base/checks.h"
17#include "webrtc/base/logging.h"
18#include "webrtc/base/random.h"
19#include "webrtc/common_types.h"
20#include "webrtc/modules/rtp_rtcp/source/rtp_header_extension.h"
21#include "webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h"
22#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
23
24namespace webrtc {
25namespace rtp {
26namespace {
27constexpr size_t kFixedHeaderSize = 12;
28constexpr uint8_t kRtpVersion = 2;
29constexpr uint16_t kOneByteExtensionId = 0xBEDE;
30constexpr size_t kOneByteHeaderSize = 1;
31constexpr size_t kDefaultPacketSize = 1500;
32} // namespace
danilchap653063f2017-04-03 06:16:30 -070033
34constexpr size_t Packet::kMaxExtensionHeaders;
35constexpr int Packet::kMinExtensionId;
36constexpr int Packet::kMaxExtensionId;
37
danilchap1edb7ab2016-04-20 05:25:10 -070038// 0 1 2 3
39// 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
40// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41// |V=2|P|X| CC |M| PT | sequence number |
42// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43// | timestamp |
44// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
45// | synchronization source (SSRC) identifier |
46// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
47// | Contributing source (CSRC) identifiers |
48// | .... |
49// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
50// |One-byte eXtensions id = 0xbede| length in 32bits |
51// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
52// | Extensions |
53// | .... |
54// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
55// | Payload |
56// | .... : padding... |
57// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
58// | padding | Padding size |
59// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchap70f39a32016-12-16 05:48:18 -080060Packet::Packet() : Packet(nullptr, kDefaultPacketSize) {}
61
danilchap1edb7ab2016-04-20 05:25:10 -070062Packet::Packet(const ExtensionManager* extensions)
danilchap70f39a32016-12-16 05:48:18 -080063 : Packet(extensions, kDefaultPacketSize) {}
danilchap1edb7ab2016-04-20 05:25:10 -070064
65Packet::Packet(const ExtensionManager* extensions, size_t capacity)
danilchap70f39a32016-12-16 05:48:18 -080066 : buffer_(capacity) {
danilchap1edb7ab2016-04-20 05:25:10 -070067 RTC_DCHECK_GE(capacity, kFixedHeaderSize);
68 Clear();
danilchap70f39a32016-12-16 05:48:18 -080069 if (extensions) {
70 IdentifyExtensions(*extensions);
71 } else {
72 for (size_t i = 0; i < kMaxExtensionHeaders; ++i)
73 extension_entries_[i].type = ExtensionManager::kInvalidType;
74 }
danilchap1edb7ab2016-04-20 05:25:10 -070075}
76
77Packet::~Packet() {}
78
danilchap70f39a32016-12-16 05:48:18 -080079void Packet::IdentifyExtensions(const ExtensionManager& extensions) {
80 for (size_t i = 0; i < kMaxExtensionHeaders; ++i)
81 extension_entries_[i].type = extensions.GetType(i + 1);
danilchap1edb7ab2016-04-20 05:25:10 -070082}
83
84bool Packet::Parse(const uint8_t* buffer, size_t buffer_size) {
85 if (!ParseBuffer(buffer, buffer_size)) {
86 Clear();
87 return false;
88 }
danilchap1edb7ab2016-04-20 05:25:10 -070089 buffer_.SetData(buffer, buffer_size);
Danil Chapovalov31e4e802016-08-03 18:27:40 +020090 RTC_DCHECK_EQ(size(), buffer_size);
danilchap1edb7ab2016-04-20 05:25:10 -070091 return true;
92}
93
brandtrb29e6522016-12-21 06:37:18 -080094bool Packet::Parse(rtc::ArrayView<const uint8_t> packet) {
95 return Parse(packet.data(), packet.size());
96}
97
Danil Chapovalov31e4e802016-08-03 18:27:40 +020098bool Packet::Parse(rtc::CopyOnWriteBuffer buffer) {
99 if (!ParseBuffer(buffer.cdata(), buffer.size())) {
danilchap1edb7ab2016-04-20 05:25:10 -0700100 Clear();
101 return false;
102 }
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200103 size_t buffer_size = buffer.size();
danilchap1edb7ab2016-04-20 05:25:10 -0700104 buffer_ = std::move(buffer);
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200105 RTC_DCHECK_EQ(size(), buffer_size);
danilchap1edb7ab2016-04-20 05:25:10 -0700106 return true;
107}
108
109bool Packet::Marker() const {
110 RTC_DCHECK_EQ(marker_, (data()[1] & 0x80) != 0);
111 return marker_;
112}
113
114uint8_t Packet::PayloadType() const {
115 RTC_DCHECK_EQ(payload_type_, data()[1] & 0x7f);
116 return payload_type_;
117}
118
119uint16_t Packet::SequenceNumber() const {
120 RTC_DCHECK_EQ(sequence_number_,
121 ByteReader<uint16_t>::ReadBigEndian(data() + 2));
122 return sequence_number_;
123}
124
125uint32_t Packet::Timestamp() const {
126 RTC_DCHECK_EQ(timestamp_, ByteReader<uint32_t>::ReadBigEndian(data() + 4));
127 return timestamp_;
128}
129
130uint32_t Packet::Ssrc() const {
131 RTC_DCHECK_EQ(ssrc_, ByteReader<uint32_t>::ReadBigEndian(data() + 8));
132 return ssrc_;
133}
134
135std::vector<uint32_t> Packet::Csrcs() const {
136 size_t num_csrc = data()[0] & 0x0F;
137 RTC_DCHECK_GE(capacity(), kFixedHeaderSize + num_csrc * 4);
138 std::vector<uint32_t> csrcs(num_csrc);
139 for (size_t i = 0; i < num_csrc; ++i) {
140 csrcs[i] =
141 ByteReader<uint32_t>::ReadBigEndian(&data()[kFixedHeaderSize + i * 4]);
142 }
143 return csrcs;
144}
145
146void Packet::GetHeader(RTPHeader* header) const {
147 header->markerBit = Marker();
148 header->payloadType = PayloadType();
149 header->sequenceNumber = SequenceNumber();
150 header->timestamp = Timestamp();
151 header->ssrc = Ssrc();
152 std::vector<uint32_t> csrcs = Csrcs();
153 header->numCSRCs = csrcs.size();
154 for (size_t i = 0; i < csrcs.size(); ++i) {
155 header->arrOfCSRCs[i] = csrcs[i];
156 }
157 header->paddingLength = padding_size();
158 header->headerLength = headers_size();
159 header->payload_type_frequency = 0;
160 header->extension.hasTransmissionTimeOffset =
161 GetExtension<TransmissionOffset>(
162 &header->extension.transmissionTimeOffset);
163 header->extension.hasAbsoluteSendTime =
164 GetExtension<AbsoluteSendTime>(&header->extension.absoluteSendTime);
165 header->extension.hasTransportSequenceNumber =
166 GetExtension<TransportSequenceNumber>(
167 &header->extension.transportSequenceNumber);
168 header->extension.hasAudioLevel = GetExtension<AudioLevel>(
169 &header->extension.voiceActivity, &header->extension.audioLevel);
170 header->extension.hasVideoRotation =
171 GetExtension<VideoOrientation>(&header->extension.videoRotation);
ilnik00d802b2017-04-11 10:34:31 -0700172 header->extension.hasVideoContentType =
173 GetExtension<VideoContentTypeExtension>(
174 &header->extension.videoContentType);
danilchapef8d7732017-04-19 02:59:48 -0700175 GetExtension<RtpStreamId>(&header->extension.stream_id);
176 GetExtension<RepairedRtpStreamId>(&header->extension.repaired_stream_id);
sergeyub2c001a2017-05-20 14:16:52 -0700177 GetExtension<PlayoutDelayLimits>(&header->extension.playout_delay);
danilchap1edb7ab2016-04-20 05:25:10 -0700178}
179
180size_t Packet::headers_size() const {
181 return payload_offset_;
182}
183
184size_t Packet::payload_size() const {
185 return payload_size_;
186}
187
188size_t Packet::padding_size() const {
189 return padding_size_;
190}
191
danilchap96c15872016-11-21 01:35:29 -0800192rtc::ArrayView<const uint8_t> Packet::payload() const {
193 return rtc::MakeArrayView(data() + payload_offset_, payload_size_);
danilchap1edb7ab2016-04-20 05:25:10 -0700194}
195
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200196rtc::CopyOnWriteBuffer Packet::Buffer() const {
197 return buffer_;
198}
199
danilchap1edb7ab2016-04-20 05:25:10 -0700200size_t Packet::capacity() const {
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200201 return buffer_.capacity();
danilchap1edb7ab2016-04-20 05:25:10 -0700202}
203
204size_t Packet::size() const {
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200205 size_t ret = payload_offset_ + payload_size_ + padding_size_;
206 RTC_DCHECK_EQ(buffer_.size(), ret);
207 return ret;
danilchap1edb7ab2016-04-20 05:25:10 -0700208}
209
210const uint8_t* Packet::data() const {
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200211 return buffer_.cdata();
danilchap1edb7ab2016-04-20 05:25:10 -0700212}
213
214size_t Packet::FreeCapacity() const {
215 return capacity() - size();
216}
217
218size_t Packet::MaxPayloadSize() const {
219 return capacity() - payload_offset_;
220}
221
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200222void Packet::CopyHeaderFrom(const Packet& packet) {
danilchap1edb7ab2016-04-20 05:25:10 -0700223 RTC_DCHECK_GE(capacity(), packet.headers_size());
224
225 marker_ = packet.marker_;
226 payload_type_ = packet.payload_type_;
227 sequence_number_ = packet.sequence_number_;
228 timestamp_ = packet.timestamp_;
229 ssrc_ = packet.ssrc_;
230 payload_offset_ = packet.payload_offset_;
danilchap70f39a32016-12-16 05:48:18 -0800231 for (size_t i = 0; i < kMaxExtensionHeaders; ++i) {
danilchap1edb7ab2016-04-20 05:25:10 -0700232 extension_entries_[i] = packet.extension_entries_[i];
233 }
234 extensions_size_ = packet.extensions_size_;
235 buffer_.SetData(packet.data(), packet.headers_size());
236 // Reset payload and padding.
237 payload_size_ = 0;
238 padding_size_ = 0;
239}
240
241void Packet::SetMarker(bool marker_bit) {
242 marker_ = marker_bit;
243 if (marker_) {
244 WriteAt(1, data()[1] | 0x80);
245 } else {
246 WriteAt(1, data()[1] & 0x7F);
247 }
248}
249
250void Packet::SetPayloadType(uint8_t payload_type) {
251 RTC_DCHECK_LE(payload_type, 0x7Fu);
252 payload_type_ = payload_type;
253 WriteAt(1, (data()[1] & 0x80) | payload_type);
254}
255
256void Packet::SetSequenceNumber(uint16_t seq_no) {
257 sequence_number_ = seq_no;
258 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(2), seq_no);
259}
260
261void Packet::SetTimestamp(uint32_t timestamp) {
262 timestamp_ = timestamp;
263 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(4), timestamp);
264}
265
266void Packet::SetSsrc(uint32_t ssrc) {
267 ssrc_ = ssrc;
268 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(8), ssrc);
269}
270
271void Packet::SetCsrcs(const std::vector<uint32_t>& csrcs) {
danilchap70f39a32016-12-16 05:48:18 -0800272 RTC_DCHECK_EQ(extensions_size_, 0);
kwibergaf476c72016-11-28 15:21:39 -0800273 RTC_DCHECK_EQ(payload_size_, 0);
274 RTC_DCHECK_EQ(padding_size_, 0);
danilchap1edb7ab2016-04-20 05:25:10 -0700275 RTC_DCHECK_LE(csrcs.size(), 0x0fu);
276 RTC_DCHECK_LE(kFixedHeaderSize + 4 * csrcs.size(), capacity());
277 payload_offset_ = kFixedHeaderSize + 4 * csrcs.size();
278 WriteAt(0, (data()[0] & 0xF0) | csrcs.size());
279 size_t offset = kFixedHeaderSize;
280 for (uint32_t csrc : csrcs) {
281 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(offset), csrc);
282 offset += 4;
283 }
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200284 buffer_.SetSize(payload_offset_);
danilchap1edb7ab2016-04-20 05:25:10 -0700285}
286
danilchap653063f2017-04-03 06:16:30 -0700287bool Packet::HasRawExtension(int id) const {
danilchapc547e842017-04-10 01:31:49 -0700288 if (id == ExtensionManager::kInvalidId)
289 return false;
danilchap653063f2017-04-03 06:16:30 -0700290 RTC_DCHECK_GE(id, kMinExtensionId);
291 RTC_DCHECK_LE(id, kMaxExtensionId);
292 return extension_entries_[id - 1].offset != 0;
293}
294
295rtc::ArrayView<const uint8_t> Packet::GetRawExtension(int id) const {
danilchapc547e842017-04-10 01:31:49 -0700296 if (id == ExtensionManager::kInvalidId)
297 return nullptr;
danilchap653063f2017-04-03 06:16:30 -0700298 RTC_DCHECK_GE(id, kMinExtensionId);
299 RTC_DCHECK_LE(id, kMaxExtensionId);
300 const ExtensionInfo& extension = extension_entries_[id - 1];
301 if (extension.offset == 0)
302 return nullptr;
303 return rtc::MakeArrayView(data() + extension.offset, extension.length);
304}
305
306bool Packet::SetRawExtension(int id, rtc::ArrayView<const uint8_t> data) {
307 auto buffer = AllocateRawExtension(id, data.size());
308 if (buffer.empty())
309 return false;
310 RTC_DCHECK_EQ(buffer.size(), data.size());
311 memcpy(buffer.data(), data.data(), data.size());
312 return true;
313}
314
315rtc::ArrayView<uint8_t> Packet::AllocateRawExtension(int id, size_t length) {
danilchapc547e842017-04-10 01:31:49 -0700316 if (id == ExtensionManager::kInvalidId)
317 return nullptr;
danilchap653063f2017-04-03 06:16:30 -0700318 RTC_DCHECK_GE(id, kMinExtensionId);
319 RTC_DCHECK_LE(id, kMaxExtensionId);
320 RTC_DCHECK_GE(length, 1);
321 RTC_DCHECK_LE(length, 16);
322
323 ExtensionInfo* extension_entry = &extension_entries_[id - 1];
324 if (extension_entry->offset != 0) {
325 // Extension already reserved. Check if same length is used.
326 if (extension_entry->length == length)
327 return rtc::MakeArrayView(WriteAt(extension_entry->offset), length);
328
329 LOG(LS_ERROR) << "Length mismatch for extension id " << id << " type "
330 << static_cast<int>(extension_entry->type) << ": expected "
331 << static_cast<int>(extension_entry->length) << ". received "
332 << length;
333 return nullptr;
334 }
335 if (payload_size_ > 0) {
336 LOG(LS_ERROR) << "Can't add new extension id " << id
337 << " after payload was set.";
338 return nullptr;
339 }
340 if (padding_size_ > 0) {
341 LOG(LS_ERROR) << "Can't add new extension id " << id
342 << " after padding was set.";
343 return nullptr;
344 }
345
346 size_t num_csrc = data()[0] & 0x0F;
347 size_t extensions_offset = kFixedHeaderSize + (num_csrc * 4) + 4;
348 size_t new_extensions_size = extensions_size_ + kOneByteHeaderSize + length;
349 if (extensions_offset + new_extensions_size > capacity()) {
350 LOG(LS_ERROR)
351 << "Extension cannot be registered: Not enough space left in buffer.";
352 return nullptr;
353 }
354
355 // All checks passed, write down the extension headers.
356 if (extensions_size_ == 0) {
357 RTC_DCHECK_EQ(payload_offset_, kFixedHeaderSize + (num_csrc * 4));
358 WriteAt(0, data()[0] | 0x10); // Set extension bit.
359 // Profile specific ID always set to OneByteExtensionHeader.
360 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 4),
361 kOneByteExtensionId);
362 }
363
364 WriteAt(extensions_offset + extensions_size_, (id << 4) | (length - 1));
365
366 extension_entry->offset =
367 extensions_offset + extensions_size_ + kOneByteHeaderSize;
368 extension_entry->length = length;
369 extensions_size_ = new_extensions_size;
370
371 // Update header length field.
372 uint16_t extensions_words = (extensions_size_ + 3) / 4; // Wrap up to 32bit.
373 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 2),
374 extensions_words);
375 // Fill extension padding place with zeroes.
376 size_t extension_padding_size = 4 * extensions_words - extensions_size_;
377 memset(WriteAt(extensions_offset + extensions_size_), 0,
378 extension_padding_size);
379 payload_offset_ = extensions_offset + 4 * extensions_words;
380 buffer_.SetSize(payload_offset_);
381 return rtc::MakeArrayView(WriteAt(extension_entry->offset), length);
382}
383
danilchap1edb7ab2016-04-20 05:25:10 -0700384uint8_t* Packet::AllocatePayload(size_t size_bytes) {
danilchap07a01b32017-03-29 07:33:13 -0700385 // Reset payload size to 0. If CopyOnWrite buffer_ was shared, this will cause
386 // reallocation and memcpy. Keeping just header reduces memcpy size.
387 SetPayloadSize(0);
388 return SetPayloadSize(size_bytes);
389}
390
391uint8_t* Packet::SetPayloadSize(size_t size_bytes) {
kwibergaf476c72016-11-28 15:21:39 -0800392 RTC_DCHECK_EQ(padding_size_, 0);
danilchap1edb7ab2016-04-20 05:25:10 -0700393 if (payload_offset_ + size_bytes > capacity()) {
394 LOG(LS_WARNING) << "Cannot set payload, not enough space in buffer.";
395 return nullptr;
396 }
397 payload_size_ = size_bytes;
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200398 buffer_.SetSize(payload_offset_ + payload_size_);
danilchap1edb7ab2016-04-20 05:25:10 -0700399 return WriteAt(payload_offset_);
400}
401
danilchap1edb7ab2016-04-20 05:25:10 -0700402bool Packet::SetPadding(uint8_t size_bytes, Random* random) {
403 RTC_DCHECK(random);
404 if (payload_offset_ + payload_size_ + size_bytes > capacity()) {
405 LOG(LS_WARNING) << "Cannot set padding size " << size_bytes << ", only "
406 << (capacity() - payload_offset_ - payload_size_)
407 << " bytes left in buffer.";
408 return false;
409 }
410 padding_size_ = size_bytes;
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200411 buffer_.SetSize(payload_offset_ + payload_size_ + padding_size_);
danilchap1edb7ab2016-04-20 05:25:10 -0700412 if (padding_size_ > 0) {
413 size_t padding_offset = payload_offset_ + payload_size_;
414 size_t padding_end = padding_offset + padding_size_;
415 for (size_t offset = padding_offset; offset < padding_end - 1; ++offset) {
416 WriteAt(offset, random->Rand<uint8_t>());
417 }
418 WriteAt(padding_end - 1, padding_size_);
419 WriteAt(0, data()[0] | 0x20); // Set padding bit.
420 } else {
421 WriteAt(0, data()[0] & ~0x20); // Clear padding bit.
422 }
423 return true;
424}
425
426void Packet::Clear() {
427 marker_ = false;
428 payload_type_ = 0;
429 sequence_number_ = 0;
430 timestamp_ = 0;
431 ssrc_ = 0;
432 payload_offset_ = kFixedHeaderSize;
433 payload_size_ = 0;
434 padding_size_ = 0;
danilchap1edb7ab2016-04-20 05:25:10 -0700435 extensions_size_ = 0;
danilchap70f39a32016-12-16 05:48:18 -0800436 for (ExtensionInfo& location : extension_entries_) {
437 location.offset = 0;
438 location.length = 0;
439 }
danilchap1edb7ab2016-04-20 05:25:10 -0700440
441 memset(WriteAt(0), 0, kFixedHeaderSize);
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200442 buffer_.SetSize(kFixedHeaderSize);
danilchap1edb7ab2016-04-20 05:25:10 -0700443 WriteAt(0, kRtpVersion << 6);
444}
445
446bool Packet::ParseBuffer(const uint8_t* buffer, size_t size) {
447 if (size < kFixedHeaderSize) {
448 return false;
449 }
450 const uint8_t version = buffer[0] >> 6;
451 if (version != kRtpVersion) {
452 return false;
453 }
454 const bool has_padding = (buffer[0] & 0x20) != 0;
455 const bool has_extension = (buffer[0] & 0x10) != 0;
456 const uint8_t number_of_crcs = buffer[0] & 0x0f;
457 marker_ = (buffer[1] & 0x80) != 0;
458 payload_type_ = buffer[1] & 0x7f;
459
460 sequence_number_ = ByteReader<uint16_t>::ReadBigEndian(&buffer[2]);
461 timestamp_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]);
462 ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]);
463 if (size < kFixedHeaderSize + number_of_crcs * 4) {
464 return false;
465 }
466 payload_offset_ = kFixedHeaderSize + number_of_crcs * 4;
467
468 if (has_padding) {
469 padding_size_ = buffer[size - 1];
470 if (padding_size_ == 0) {
471 LOG(LS_WARNING) << "Padding was set, but padding size is zero";
472 return false;
473 }
474 } else {
475 padding_size_ = 0;
476 }
477
danilchap1edb7ab2016-04-20 05:25:10 -0700478 extensions_size_ = 0;
danilchap70f39a32016-12-16 05:48:18 -0800479 for (ExtensionInfo& location : extension_entries_) {
480 location.offset = 0;
481 location.length = 0;
482 }
danilchap1edb7ab2016-04-20 05:25:10 -0700483 if (has_extension) {
484 /* RTP header extension, RFC 3550.
485 0 1 2 3
486 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
487 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
488 | defined by profile | length |
489 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
490 | header extension |
491 | .... |
492 */
493 size_t extension_offset = payload_offset_ + 4;
494 if (extension_offset > size) {
495 return false;
496 }
497 uint16_t profile =
498 ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_]);
499 size_t extensions_capacity =
500 ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_ + 2]);
501 extensions_capacity *= 4;
502 if (extension_offset + extensions_capacity > size) {
503 return false;
504 }
505 if (profile != kOneByteExtensionId) {
506 LOG(LS_WARNING) << "Unsupported rtp extension " << profile;
507 } else {
508 constexpr uint8_t kPaddingId = 0;
509 constexpr uint8_t kReservedId = 15;
510 while (extensions_size_ + kOneByteHeaderSize < extensions_capacity) {
danilchap70f39a32016-12-16 05:48:18 -0800511 int id = buffer[extension_offset + extensions_size_] >> 4;
danilchap1edb7ab2016-04-20 05:25:10 -0700512 if (id == kReservedId) {
513 break;
514 } else if (id == kPaddingId) {
515 extensions_size_++;
516 continue;
517 }
518 uint8_t length =
519 1 + (buffer[extension_offset + extensions_size_] & 0xf);
Danil Chapovalova64a2fb2016-09-12 11:41:35 +0200520 if (extensions_size_ + kOneByteHeaderSize + length >
521 extensions_capacity) {
522 LOG(LS_WARNING) << "Oversized rtp header extension.";
523 break;
danilchap1edb7ab2016-04-20 05:25:10 -0700524 }
danilchap70f39a32016-12-16 05:48:18 -0800525
526 size_t idx = id - 1;
527 if (extension_entries_[idx].length != 0) {
528 LOG(LS_VERBOSE) << "Duplicate rtp header extension id " << id
529 << ". Overwriting.";
Danil Chapovalova64a2fb2016-09-12 11:41:35 +0200530 }
danilchap70f39a32016-12-16 05:48:18 -0800531
Danil Chapovalova64a2fb2016-09-12 11:41:35 +0200532 extensions_size_ += kOneByteHeaderSize;
danilchap70f39a32016-12-16 05:48:18 -0800533 extension_entries_[idx].offset = extension_offset + extensions_size_;
534 extension_entries_[idx].length = length;
danilchap1edb7ab2016-04-20 05:25:10 -0700535 extensions_size_ += length;
536 }
537 }
538 payload_offset_ = extension_offset + extensions_capacity;
539 }
540
541 if (payload_offset_ + padding_size_ > size) {
542 return false;
543 }
544 payload_size_ = size - payload_offset_ - padding_size_;
545 return true;
546}
547
danilchap978504e2017-04-06 01:03:53 -0700548rtc::ArrayView<const uint8_t> Packet::FindExtension(ExtensionType type) const {
danilchap70f39a32016-12-16 05:48:18 -0800549 for (const ExtensionInfo& extension : extension_entries_) {
550 if (extension.type == type) {
551 if (extension.length == 0) {
552 // Extension is registered but not set.
danilchap978504e2017-04-06 01:03:53 -0700553 return nullptr;
danilchap07ec26d2016-06-17 04:18:54 -0700554 }
danilchap978504e2017-04-06 01:03:53 -0700555 return rtc::MakeArrayView(data() + extension.offset, extension.length);
danilchap1edb7ab2016-04-20 05:25:10 -0700556 }
557 }
danilchap978504e2017-04-06 01:03:53 -0700558 return nullptr;
danilchap1edb7ab2016-04-20 05:25:10 -0700559}
560
danilchap653063f2017-04-03 06:16:30 -0700561rtc::ArrayView<uint8_t> Packet::AllocateExtension(ExtensionType type,
562 size_t length) {
danilchap70f39a32016-12-16 05:48:18 -0800563 for (size_t i = 0; i < kMaxExtensionHeaders; ++i) {
564 if (extension_entries_[i].type == type) {
danilchap653063f2017-04-03 06:16:30 -0700565 int extension_id = i + 1;
566 return AllocateRawExtension(extension_id, length);
danilchap70f39a32016-12-16 05:48:18 -0800567 }
danilchap1edb7ab2016-04-20 05:25:10 -0700568 }
danilchap653063f2017-04-03 06:16:30 -0700569 // Extension not registered.
570 return nullptr;
danilchap1edb7ab2016-04-20 05:25:10 -0700571}
572
573uint8_t* Packet::WriteAt(size_t offset) {
574 return buffer_.data() + offset;
575}
576
577void Packet::WriteAt(size_t offset, uint8_t byte) {
578 buffer_.data()[offset] = byte;
579}
580
581} // namespace rtp
582} // namespace webrtc