blob: 78fa0d2ed633abd1971f7a43eae4db223fb8d57e [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"
Danil Chapovalov07633bd2017-06-01 17:10:51 +020019#include "webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020020#include "webrtc/rtc_base/checks.h"
21#include "webrtc/rtc_base/logging.h"
22#include "webrtc/rtc_base/random.h"
danilchap1edb7ab2016-04-20 05:25:10 -070023
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
nisse76e62b02017-05-31 02:24:52 -070065Packet::Packet(const Packet&) = default;
66
danilchap1edb7ab2016-04-20 05:25:10 -070067Packet::Packet(const ExtensionManager* extensions, size_t capacity)
danilchap70f39a32016-12-16 05:48:18 -080068 : buffer_(capacity) {
danilchap1edb7ab2016-04-20 05:25:10 -070069 RTC_DCHECK_GE(capacity, kFixedHeaderSize);
70 Clear();
danilchap70f39a32016-12-16 05:48:18 -080071 if (extensions) {
72 IdentifyExtensions(*extensions);
73 } else {
74 for (size_t i = 0; i < kMaxExtensionHeaders; ++i)
75 extension_entries_[i].type = ExtensionManager::kInvalidType;
76 }
danilchap1edb7ab2016-04-20 05:25:10 -070077}
78
79Packet::~Packet() {}
80
danilchap70f39a32016-12-16 05:48:18 -080081void Packet::IdentifyExtensions(const ExtensionManager& extensions) {
82 for (size_t i = 0; i < kMaxExtensionHeaders; ++i)
83 extension_entries_[i].type = extensions.GetType(i + 1);
danilchap1edb7ab2016-04-20 05:25:10 -070084}
85
86bool Packet::Parse(const uint8_t* buffer, size_t buffer_size) {
87 if (!ParseBuffer(buffer, buffer_size)) {
88 Clear();
89 return false;
90 }
danilchap1edb7ab2016-04-20 05:25:10 -070091 buffer_.SetData(buffer, buffer_size);
Danil Chapovalov31e4e802016-08-03 18:27:40 +020092 RTC_DCHECK_EQ(size(), buffer_size);
danilchap1edb7ab2016-04-20 05:25:10 -070093 return true;
94}
95
brandtrb29e6522016-12-21 06:37:18 -080096bool Packet::Parse(rtc::ArrayView<const uint8_t> packet) {
97 return Parse(packet.data(), packet.size());
98}
99
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200100bool Packet::Parse(rtc::CopyOnWriteBuffer buffer) {
101 if (!ParseBuffer(buffer.cdata(), buffer.size())) {
danilchap1edb7ab2016-04-20 05:25:10 -0700102 Clear();
103 return false;
104 }
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200105 size_t buffer_size = buffer.size();
danilchap1edb7ab2016-04-20 05:25:10 -0700106 buffer_ = std::move(buffer);
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200107 RTC_DCHECK_EQ(size(), buffer_size);
danilchap1edb7ab2016-04-20 05:25:10 -0700108 return true;
109}
110
111bool Packet::Marker() const {
112 RTC_DCHECK_EQ(marker_, (data()[1] & 0x80) != 0);
113 return marker_;
114}
115
116uint8_t Packet::PayloadType() const {
117 RTC_DCHECK_EQ(payload_type_, data()[1] & 0x7f);
118 return payload_type_;
119}
120
121uint16_t Packet::SequenceNumber() const {
122 RTC_DCHECK_EQ(sequence_number_,
123 ByteReader<uint16_t>::ReadBigEndian(data() + 2));
124 return sequence_number_;
125}
126
127uint32_t Packet::Timestamp() const {
128 RTC_DCHECK_EQ(timestamp_, ByteReader<uint32_t>::ReadBigEndian(data() + 4));
129 return timestamp_;
130}
131
132uint32_t Packet::Ssrc() const {
133 RTC_DCHECK_EQ(ssrc_, ByteReader<uint32_t>::ReadBigEndian(data() + 8));
134 return ssrc_;
135}
136
137std::vector<uint32_t> Packet::Csrcs() const {
138 size_t num_csrc = data()[0] & 0x0F;
139 RTC_DCHECK_GE(capacity(), kFixedHeaderSize + num_csrc * 4);
140 std::vector<uint32_t> csrcs(num_csrc);
141 for (size_t i = 0; i < num_csrc; ++i) {
142 csrcs[i] =
143 ByteReader<uint32_t>::ReadBigEndian(&data()[kFixedHeaderSize + i * 4]);
144 }
145 return csrcs;
146}
147
148void Packet::GetHeader(RTPHeader* header) const {
149 header->markerBit = Marker();
150 header->payloadType = PayloadType();
151 header->sequenceNumber = SequenceNumber();
152 header->timestamp = Timestamp();
153 header->ssrc = Ssrc();
154 std::vector<uint32_t> csrcs = Csrcs();
155 header->numCSRCs = csrcs.size();
156 for (size_t i = 0; i < csrcs.size(); ++i) {
157 header->arrOfCSRCs[i] = csrcs[i];
158 }
159 header->paddingLength = padding_size();
160 header->headerLength = headers_size();
161 header->payload_type_frequency = 0;
162 header->extension.hasTransmissionTimeOffset =
163 GetExtension<TransmissionOffset>(
164 &header->extension.transmissionTimeOffset);
165 header->extension.hasAbsoluteSendTime =
166 GetExtension<AbsoluteSendTime>(&header->extension.absoluteSendTime);
167 header->extension.hasTransportSequenceNumber =
168 GetExtension<TransportSequenceNumber>(
169 &header->extension.transportSequenceNumber);
170 header->extension.hasAudioLevel = GetExtension<AudioLevel>(
171 &header->extension.voiceActivity, &header->extension.audioLevel);
172 header->extension.hasVideoRotation =
173 GetExtension<VideoOrientation>(&header->extension.videoRotation);
ilnik00d802b2017-04-11 10:34:31 -0700174 header->extension.hasVideoContentType =
175 GetExtension<VideoContentTypeExtension>(
176 &header->extension.videoContentType);
ilnik04f4d122017-06-19 07:18:55 -0700177 header->extension.has_video_timing =
178 GetExtension<VideoTimingExtension>(&header->extension.video_timing);
danilchapef8d7732017-04-19 02:59:48 -0700179 GetExtension<RtpStreamId>(&header->extension.stream_id);
180 GetExtension<RepairedRtpStreamId>(&header->extension.repaired_stream_id);
sergeyub2c001a2017-05-20 14:16:52 -0700181 GetExtension<PlayoutDelayLimits>(&header->extension.playout_delay);
danilchap1edb7ab2016-04-20 05:25:10 -0700182}
183
184size_t Packet::headers_size() const {
185 return payload_offset_;
186}
187
188size_t Packet::payload_size() const {
189 return payload_size_;
190}
191
192size_t Packet::padding_size() const {
193 return padding_size_;
194}
195
danilchap96c15872016-11-21 01:35:29 -0800196rtc::ArrayView<const uint8_t> Packet::payload() const {
197 return rtc::MakeArrayView(data() + payload_offset_, payload_size_);
danilchap1edb7ab2016-04-20 05:25:10 -0700198}
199
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200200rtc::CopyOnWriteBuffer Packet::Buffer() const {
201 return buffer_;
202}
203
danilchap1edb7ab2016-04-20 05:25:10 -0700204size_t Packet::capacity() const {
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200205 return buffer_.capacity();
danilchap1edb7ab2016-04-20 05:25:10 -0700206}
207
208size_t Packet::size() const {
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200209 size_t ret = payload_offset_ + payload_size_ + padding_size_;
210 RTC_DCHECK_EQ(buffer_.size(), ret);
211 return ret;
danilchap1edb7ab2016-04-20 05:25:10 -0700212}
213
214const uint8_t* Packet::data() const {
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200215 return buffer_.cdata();
danilchap1edb7ab2016-04-20 05:25:10 -0700216}
217
218size_t Packet::FreeCapacity() const {
219 return capacity() - size();
220}
221
222size_t Packet::MaxPayloadSize() const {
223 return capacity() - payload_offset_;
224}
225
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200226void Packet::CopyHeaderFrom(const Packet& packet) {
danilchap1edb7ab2016-04-20 05:25:10 -0700227 RTC_DCHECK_GE(capacity(), packet.headers_size());
228
229 marker_ = packet.marker_;
230 payload_type_ = packet.payload_type_;
231 sequence_number_ = packet.sequence_number_;
232 timestamp_ = packet.timestamp_;
233 ssrc_ = packet.ssrc_;
234 payload_offset_ = packet.payload_offset_;
danilchap70f39a32016-12-16 05:48:18 -0800235 for (size_t i = 0; i < kMaxExtensionHeaders; ++i) {
danilchap1edb7ab2016-04-20 05:25:10 -0700236 extension_entries_[i] = packet.extension_entries_[i];
237 }
238 extensions_size_ = packet.extensions_size_;
239 buffer_.SetData(packet.data(), packet.headers_size());
240 // Reset payload and padding.
241 payload_size_ = 0;
242 padding_size_ = 0;
243}
244
245void Packet::SetMarker(bool marker_bit) {
246 marker_ = marker_bit;
247 if (marker_) {
248 WriteAt(1, data()[1] | 0x80);
249 } else {
250 WriteAt(1, data()[1] & 0x7F);
251 }
252}
253
254void Packet::SetPayloadType(uint8_t payload_type) {
255 RTC_DCHECK_LE(payload_type, 0x7Fu);
256 payload_type_ = payload_type;
257 WriteAt(1, (data()[1] & 0x80) | payload_type);
258}
259
260void Packet::SetSequenceNumber(uint16_t seq_no) {
261 sequence_number_ = seq_no;
262 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(2), seq_no);
263}
264
265void Packet::SetTimestamp(uint32_t timestamp) {
266 timestamp_ = timestamp;
267 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(4), timestamp);
268}
269
270void Packet::SetSsrc(uint32_t ssrc) {
271 ssrc_ = ssrc;
272 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(8), ssrc);
273}
274
275void Packet::SetCsrcs(const std::vector<uint32_t>& csrcs) {
danilchap70f39a32016-12-16 05:48:18 -0800276 RTC_DCHECK_EQ(extensions_size_, 0);
kwibergaf476c72016-11-28 15:21:39 -0800277 RTC_DCHECK_EQ(payload_size_, 0);
278 RTC_DCHECK_EQ(padding_size_, 0);
danilchap1edb7ab2016-04-20 05:25:10 -0700279 RTC_DCHECK_LE(csrcs.size(), 0x0fu);
280 RTC_DCHECK_LE(kFixedHeaderSize + 4 * csrcs.size(), capacity());
281 payload_offset_ = kFixedHeaderSize + 4 * csrcs.size();
282 WriteAt(0, (data()[0] & 0xF0) | csrcs.size());
283 size_t offset = kFixedHeaderSize;
284 for (uint32_t csrc : csrcs) {
285 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(offset), csrc);
286 offset += 4;
287 }
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200288 buffer_.SetSize(payload_offset_);
danilchap1edb7ab2016-04-20 05:25:10 -0700289}
290
danilchap653063f2017-04-03 06:16:30 -0700291bool Packet::HasRawExtension(int id) const {
danilchapc547e842017-04-10 01:31:49 -0700292 if (id == ExtensionManager::kInvalidId)
293 return false;
danilchap653063f2017-04-03 06:16:30 -0700294 RTC_DCHECK_GE(id, kMinExtensionId);
295 RTC_DCHECK_LE(id, kMaxExtensionId);
296 return extension_entries_[id - 1].offset != 0;
297}
298
299rtc::ArrayView<const uint8_t> Packet::GetRawExtension(int id) const {
danilchapc547e842017-04-10 01:31:49 -0700300 if (id == ExtensionManager::kInvalidId)
301 return nullptr;
danilchap653063f2017-04-03 06:16:30 -0700302 RTC_DCHECK_GE(id, kMinExtensionId);
303 RTC_DCHECK_LE(id, kMaxExtensionId);
304 const ExtensionInfo& extension = extension_entries_[id - 1];
305 if (extension.offset == 0)
306 return nullptr;
307 return rtc::MakeArrayView(data() + extension.offset, extension.length);
308}
309
310bool Packet::SetRawExtension(int id, rtc::ArrayView<const uint8_t> data) {
311 auto buffer = AllocateRawExtension(id, data.size());
312 if (buffer.empty())
313 return false;
314 RTC_DCHECK_EQ(buffer.size(), data.size());
315 memcpy(buffer.data(), data.data(), data.size());
316 return true;
317}
318
319rtc::ArrayView<uint8_t> Packet::AllocateRawExtension(int id, size_t length) {
danilchapc547e842017-04-10 01:31:49 -0700320 if (id == ExtensionManager::kInvalidId)
321 return nullptr;
danilchap653063f2017-04-03 06:16:30 -0700322 RTC_DCHECK_GE(id, kMinExtensionId);
323 RTC_DCHECK_LE(id, kMaxExtensionId);
324 RTC_DCHECK_GE(length, 1);
325 RTC_DCHECK_LE(length, 16);
326
327 ExtensionInfo* extension_entry = &extension_entries_[id - 1];
328 if (extension_entry->offset != 0) {
329 // Extension already reserved. Check if same length is used.
330 if (extension_entry->length == length)
331 return rtc::MakeArrayView(WriteAt(extension_entry->offset), length);
332
333 LOG(LS_ERROR) << "Length mismatch for extension id " << id << " type "
334 << static_cast<int>(extension_entry->type) << ": expected "
335 << static_cast<int>(extension_entry->length) << ". received "
336 << length;
337 return nullptr;
338 }
339 if (payload_size_ > 0) {
340 LOG(LS_ERROR) << "Can't add new extension id " << id
341 << " after payload was set.";
342 return nullptr;
343 }
344 if (padding_size_ > 0) {
345 LOG(LS_ERROR) << "Can't add new extension id " << id
346 << " after padding was set.";
347 return nullptr;
348 }
349
350 size_t num_csrc = data()[0] & 0x0F;
351 size_t extensions_offset = kFixedHeaderSize + (num_csrc * 4) + 4;
352 size_t new_extensions_size = extensions_size_ + kOneByteHeaderSize + length;
353 if (extensions_offset + new_extensions_size > capacity()) {
354 LOG(LS_ERROR)
355 << "Extension cannot be registered: Not enough space left in buffer.";
356 return nullptr;
357 }
358
359 // All checks passed, write down the extension headers.
360 if (extensions_size_ == 0) {
361 RTC_DCHECK_EQ(payload_offset_, kFixedHeaderSize + (num_csrc * 4));
362 WriteAt(0, data()[0] | 0x10); // Set extension bit.
363 // Profile specific ID always set to OneByteExtensionHeader.
364 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 4),
365 kOneByteExtensionId);
366 }
367
368 WriteAt(extensions_offset + extensions_size_, (id << 4) | (length - 1));
369
370 extension_entry->offset =
371 extensions_offset + extensions_size_ + kOneByteHeaderSize;
372 extension_entry->length = length;
373 extensions_size_ = new_extensions_size;
374
375 // Update header length field.
376 uint16_t extensions_words = (extensions_size_ + 3) / 4; // Wrap up to 32bit.
377 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 2),
378 extensions_words);
379 // Fill extension padding place with zeroes.
380 size_t extension_padding_size = 4 * extensions_words - extensions_size_;
381 memset(WriteAt(extensions_offset + extensions_size_), 0,
382 extension_padding_size);
383 payload_offset_ = extensions_offset + 4 * extensions_words;
384 buffer_.SetSize(payload_offset_);
385 return rtc::MakeArrayView(WriteAt(extension_entry->offset), length);
386}
387
danilchap1edb7ab2016-04-20 05:25:10 -0700388uint8_t* Packet::AllocatePayload(size_t size_bytes) {
danilchap07a01b32017-03-29 07:33:13 -0700389 // 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
395uint8_t* Packet::SetPayloadSize(size_t size_bytes) {
kwibergaf476c72016-11-28 15:21:39 -0800396 RTC_DCHECK_EQ(padding_size_, 0);
danilchap1edb7ab2016-04-20 05:25:10 -0700397 if (payload_offset_ + size_bytes > capacity()) {
398 LOG(LS_WARNING) << "Cannot set payload, not enough space in buffer.";
399 return nullptr;
400 }
401 payload_size_ = size_bytes;
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200402 buffer_.SetSize(payload_offset_ + payload_size_);
danilchap1edb7ab2016-04-20 05:25:10 -0700403 return WriteAt(payload_offset_);
404}
405
danilchap1edb7ab2016-04-20 05:25:10 -0700406bool Packet::SetPadding(uint8_t size_bytes, Random* random) {
407 RTC_DCHECK(random);
408 if (payload_offset_ + payload_size_ + size_bytes > capacity()) {
409 LOG(LS_WARNING) << "Cannot set padding size " << size_bytes << ", only "
410 << (capacity() - payload_offset_ - payload_size_)
411 << " bytes left in buffer.";
412 return false;
413 }
414 padding_size_ = size_bytes;
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200415 buffer_.SetSize(payload_offset_ + payload_size_ + padding_size_);
danilchap1edb7ab2016-04-20 05:25:10 -0700416 if (padding_size_ > 0) {
417 size_t padding_offset = payload_offset_ + payload_size_;
418 size_t padding_end = padding_offset + padding_size_;
419 for (size_t offset = padding_offset; offset < padding_end - 1; ++offset) {
420 WriteAt(offset, random->Rand<uint8_t>());
421 }
422 WriteAt(padding_end - 1, padding_size_);
423 WriteAt(0, data()[0] | 0x20); // Set padding bit.
424 } else {
425 WriteAt(0, data()[0] & ~0x20); // Clear padding bit.
426 }
427 return true;
428}
429
430void Packet::Clear() {
431 marker_ = false;
432 payload_type_ = 0;
433 sequence_number_ = 0;
434 timestamp_ = 0;
435 ssrc_ = 0;
436 payload_offset_ = kFixedHeaderSize;
437 payload_size_ = 0;
438 padding_size_ = 0;
danilchap1edb7ab2016-04-20 05:25:10 -0700439 extensions_size_ = 0;
danilchap70f39a32016-12-16 05:48:18 -0800440 for (ExtensionInfo& location : extension_entries_) {
441 location.offset = 0;
442 location.length = 0;
443 }
danilchap1edb7ab2016-04-20 05:25:10 -0700444
445 memset(WriteAt(0), 0, kFixedHeaderSize);
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200446 buffer_.SetSize(kFixedHeaderSize);
danilchap1edb7ab2016-04-20 05:25:10 -0700447 WriteAt(0, kRtpVersion << 6);
448}
449
450bool Packet::ParseBuffer(const uint8_t* buffer, size_t size) {
451 if (size < kFixedHeaderSize) {
452 return false;
453 }
454 const uint8_t version = buffer[0] >> 6;
455 if (version != kRtpVersion) {
456 return false;
457 }
458 const bool has_padding = (buffer[0] & 0x20) != 0;
459 const bool has_extension = (buffer[0] & 0x10) != 0;
460 const uint8_t number_of_crcs = buffer[0] & 0x0f;
461 marker_ = (buffer[1] & 0x80) != 0;
462 payload_type_ = buffer[1] & 0x7f;
463
464 sequence_number_ = ByteReader<uint16_t>::ReadBigEndian(&buffer[2]);
465 timestamp_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]);
466 ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]);
467 if (size < kFixedHeaderSize + number_of_crcs * 4) {
468 return false;
469 }
470 payload_offset_ = kFixedHeaderSize + number_of_crcs * 4;
471
472 if (has_padding) {
473 padding_size_ = buffer[size - 1];
474 if (padding_size_ == 0) {
475 LOG(LS_WARNING) << "Padding was set, but padding size is zero";
476 return false;
477 }
478 } else {
479 padding_size_ = 0;
480 }
481
danilchap1edb7ab2016-04-20 05:25:10 -0700482 extensions_size_ = 0;
danilchap70f39a32016-12-16 05:48:18 -0800483 for (ExtensionInfo& location : extension_entries_) {
484 location.offset = 0;
485 location.length = 0;
486 }
danilchap1edb7ab2016-04-20 05:25:10 -0700487 if (has_extension) {
488 /* RTP header extension, RFC 3550.
489 0 1 2 3
490 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
491 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
492 | defined by profile | length |
493 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
494 | header extension |
495 | .... |
496 */
497 size_t extension_offset = payload_offset_ + 4;
498 if (extension_offset > size) {
499 return false;
500 }
501 uint16_t profile =
502 ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_]);
503 size_t extensions_capacity =
504 ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_ + 2]);
505 extensions_capacity *= 4;
506 if (extension_offset + extensions_capacity > size) {
507 return false;
508 }
509 if (profile != kOneByteExtensionId) {
510 LOG(LS_WARNING) << "Unsupported rtp extension " << profile;
511 } else {
512 constexpr uint8_t kPaddingId = 0;
513 constexpr uint8_t kReservedId = 15;
514 while (extensions_size_ + kOneByteHeaderSize < extensions_capacity) {
danilchap70f39a32016-12-16 05:48:18 -0800515 int id = buffer[extension_offset + extensions_size_] >> 4;
danilchap1edb7ab2016-04-20 05:25:10 -0700516 if (id == kReservedId) {
517 break;
518 } else if (id == kPaddingId) {
519 extensions_size_++;
520 continue;
521 }
522 uint8_t length =
523 1 + (buffer[extension_offset + extensions_size_] & 0xf);
Danil Chapovalova64a2fb2016-09-12 11:41:35 +0200524 if (extensions_size_ + kOneByteHeaderSize + length >
525 extensions_capacity) {
526 LOG(LS_WARNING) << "Oversized rtp header extension.";
527 break;
danilchap1edb7ab2016-04-20 05:25:10 -0700528 }
danilchap70f39a32016-12-16 05:48:18 -0800529
530 size_t idx = id - 1;
531 if (extension_entries_[idx].length != 0) {
532 LOG(LS_VERBOSE) << "Duplicate rtp header extension id " << id
533 << ". Overwriting.";
Danil Chapovalova64a2fb2016-09-12 11:41:35 +0200534 }
danilchap70f39a32016-12-16 05:48:18 -0800535
Danil Chapovalova64a2fb2016-09-12 11:41:35 +0200536 extensions_size_ += kOneByteHeaderSize;
danilchap70f39a32016-12-16 05:48:18 -0800537 extension_entries_[idx].offset = extension_offset + extensions_size_;
538 extension_entries_[idx].length = length;
danilchap1edb7ab2016-04-20 05:25:10 -0700539 extensions_size_ += length;
540 }
541 }
542 payload_offset_ = extension_offset + extensions_capacity;
543 }
544
545 if (payload_offset_ + padding_size_ > size) {
546 return false;
547 }
548 payload_size_ = size - payload_offset_ - padding_size_;
549 return true;
550}
551
danilchap978504e2017-04-06 01:03:53 -0700552rtc::ArrayView<const uint8_t> Packet::FindExtension(ExtensionType type) const {
danilchap70f39a32016-12-16 05:48:18 -0800553 for (const ExtensionInfo& extension : extension_entries_) {
554 if (extension.type == type) {
555 if (extension.length == 0) {
556 // Extension is registered but not set.
danilchap978504e2017-04-06 01:03:53 -0700557 return nullptr;
danilchap07ec26d2016-06-17 04:18:54 -0700558 }
danilchap978504e2017-04-06 01:03:53 -0700559 return rtc::MakeArrayView(data() + extension.offset, extension.length);
danilchap1edb7ab2016-04-20 05:25:10 -0700560 }
561 }
danilchap978504e2017-04-06 01:03:53 -0700562 return nullptr;
danilchap1edb7ab2016-04-20 05:25:10 -0700563}
564
danilchap653063f2017-04-03 06:16:30 -0700565rtc::ArrayView<uint8_t> Packet::AllocateExtension(ExtensionType type,
566 size_t length) {
danilchap70f39a32016-12-16 05:48:18 -0800567 for (size_t i = 0; i < kMaxExtensionHeaders; ++i) {
568 if (extension_entries_[i].type == type) {
danilchap653063f2017-04-03 06:16:30 -0700569 int extension_id = i + 1;
570 return AllocateRawExtension(extension_id, length);
danilchap70f39a32016-12-16 05:48:18 -0800571 }
danilchap1edb7ab2016-04-20 05:25:10 -0700572 }
danilchap653063f2017-04-03 06:16:30 -0700573 // Extension not registered.
574 return nullptr;
danilchap1edb7ab2016-04-20 05:25:10 -0700575}
576
577uint8_t* Packet::WriteAt(size_t offset) {
578 return buffer_.data() + offset;
579}
580
581void Packet::WriteAt(size_t offset, uint8_t byte) {
582 buffer_.data()[offset] = byte;
583}
584
585} // namespace rtp
586} // namespace webrtc