blob: e720eebc4aff88a9d0242a07c3017048f4adfb99 [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
33// 0 1 2 3
34// 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
35// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36// |V=2|P|X| CC |M| PT | sequence number |
37// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38// | timestamp |
39// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40// | synchronization source (SSRC) identifier |
41// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
42// | Contributing source (CSRC) identifiers |
43// | .... |
44// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
45// |One-byte eXtensions id = 0xbede| length in 32bits |
46// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
47// | Extensions |
48// | .... |
49// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
50// | Payload |
51// | .... : padding... |
52// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
53// | padding | Padding size |
54// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchap70f39a32016-12-16 05:48:18 -080055Packet::Packet() : Packet(nullptr, kDefaultPacketSize) {}
56
danilchap1edb7ab2016-04-20 05:25:10 -070057Packet::Packet(const ExtensionManager* extensions)
danilchap70f39a32016-12-16 05:48:18 -080058 : Packet(extensions, kDefaultPacketSize) {}
danilchap1edb7ab2016-04-20 05:25:10 -070059
60Packet::Packet(const ExtensionManager* extensions, size_t capacity)
danilchap70f39a32016-12-16 05:48:18 -080061 : buffer_(capacity) {
danilchap1edb7ab2016-04-20 05:25:10 -070062 RTC_DCHECK_GE(capacity, kFixedHeaderSize);
63 Clear();
danilchap70f39a32016-12-16 05:48:18 -080064 if (extensions) {
65 IdentifyExtensions(*extensions);
66 } else {
67 for (size_t i = 0; i < kMaxExtensionHeaders; ++i)
68 extension_entries_[i].type = ExtensionManager::kInvalidType;
69 }
danilchap1edb7ab2016-04-20 05:25:10 -070070}
71
72Packet::~Packet() {}
73
danilchap70f39a32016-12-16 05:48:18 -080074void Packet::IdentifyExtensions(const ExtensionManager& extensions) {
75 for (size_t i = 0; i < kMaxExtensionHeaders; ++i)
76 extension_entries_[i].type = extensions.GetType(i + 1);
danilchap1edb7ab2016-04-20 05:25:10 -070077}
78
79bool Packet::Parse(const uint8_t* buffer, size_t buffer_size) {
80 if (!ParseBuffer(buffer, buffer_size)) {
81 Clear();
82 return false;
83 }
danilchap1edb7ab2016-04-20 05:25:10 -070084 buffer_.SetData(buffer, buffer_size);
Danil Chapovalov31e4e802016-08-03 18:27:40 +020085 RTC_DCHECK_EQ(size(), buffer_size);
danilchap1edb7ab2016-04-20 05:25:10 -070086 return true;
87}
88
brandtrb29e6522016-12-21 06:37:18 -080089bool Packet::Parse(rtc::ArrayView<const uint8_t> packet) {
90 return Parse(packet.data(), packet.size());
91}
92
Danil Chapovalov31e4e802016-08-03 18:27:40 +020093bool Packet::Parse(rtc::CopyOnWriteBuffer buffer) {
94 if (!ParseBuffer(buffer.cdata(), buffer.size())) {
danilchap1edb7ab2016-04-20 05:25:10 -070095 Clear();
96 return false;
97 }
Danil Chapovalov31e4e802016-08-03 18:27:40 +020098 size_t buffer_size = buffer.size();
danilchap1edb7ab2016-04-20 05:25:10 -070099 buffer_ = std::move(buffer);
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200100 RTC_DCHECK_EQ(size(), buffer_size);
danilchap1edb7ab2016-04-20 05:25:10 -0700101 return true;
102}
103
104bool Packet::Marker() const {
105 RTC_DCHECK_EQ(marker_, (data()[1] & 0x80) != 0);
106 return marker_;
107}
108
109uint8_t Packet::PayloadType() const {
110 RTC_DCHECK_EQ(payload_type_, data()[1] & 0x7f);
111 return payload_type_;
112}
113
114uint16_t Packet::SequenceNumber() const {
115 RTC_DCHECK_EQ(sequence_number_,
116 ByteReader<uint16_t>::ReadBigEndian(data() + 2));
117 return sequence_number_;
118}
119
120uint32_t Packet::Timestamp() const {
121 RTC_DCHECK_EQ(timestamp_, ByteReader<uint32_t>::ReadBigEndian(data() + 4));
122 return timestamp_;
123}
124
125uint32_t Packet::Ssrc() const {
126 RTC_DCHECK_EQ(ssrc_, ByteReader<uint32_t>::ReadBigEndian(data() + 8));
127 return ssrc_;
128}
129
130std::vector<uint32_t> Packet::Csrcs() const {
131 size_t num_csrc = data()[0] & 0x0F;
132 RTC_DCHECK_GE(capacity(), kFixedHeaderSize + num_csrc * 4);
133 std::vector<uint32_t> csrcs(num_csrc);
134 for (size_t i = 0; i < num_csrc; ++i) {
135 csrcs[i] =
136 ByteReader<uint32_t>::ReadBigEndian(&data()[kFixedHeaderSize + i * 4]);
137 }
138 return csrcs;
139}
140
141void Packet::GetHeader(RTPHeader* header) const {
142 header->markerBit = Marker();
143 header->payloadType = PayloadType();
144 header->sequenceNumber = SequenceNumber();
145 header->timestamp = Timestamp();
146 header->ssrc = Ssrc();
147 std::vector<uint32_t> csrcs = Csrcs();
148 header->numCSRCs = csrcs.size();
149 for (size_t i = 0; i < csrcs.size(); ++i) {
150 header->arrOfCSRCs[i] = csrcs[i];
151 }
152 header->paddingLength = padding_size();
153 header->headerLength = headers_size();
154 header->payload_type_frequency = 0;
155 header->extension.hasTransmissionTimeOffset =
156 GetExtension<TransmissionOffset>(
157 &header->extension.transmissionTimeOffset);
158 header->extension.hasAbsoluteSendTime =
159 GetExtension<AbsoluteSendTime>(&header->extension.absoluteSendTime);
160 header->extension.hasTransportSequenceNumber =
161 GetExtension<TransportSequenceNumber>(
162 &header->extension.transportSequenceNumber);
163 header->extension.hasAudioLevel = GetExtension<AudioLevel>(
164 &header->extension.voiceActivity, &header->extension.audioLevel);
165 header->extension.hasVideoRotation =
166 GetExtension<VideoOrientation>(&header->extension.videoRotation);
167}
168
169size_t Packet::headers_size() const {
170 return payload_offset_;
171}
172
173size_t Packet::payload_size() const {
174 return payload_size_;
175}
176
177size_t Packet::padding_size() const {
178 return padding_size_;
179}
180
danilchap96c15872016-11-21 01:35:29 -0800181rtc::ArrayView<const uint8_t> Packet::payload() const {
182 return rtc::MakeArrayView(data() + payload_offset_, payload_size_);
danilchap1edb7ab2016-04-20 05:25:10 -0700183}
184
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200185rtc::CopyOnWriteBuffer Packet::Buffer() const {
186 return buffer_;
187}
188
danilchap1edb7ab2016-04-20 05:25:10 -0700189size_t Packet::capacity() const {
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200190 return buffer_.capacity();
danilchap1edb7ab2016-04-20 05:25:10 -0700191}
192
193size_t Packet::size() const {
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200194 size_t ret = payload_offset_ + payload_size_ + padding_size_;
195 RTC_DCHECK_EQ(buffer_.size(), ret);
196 return ret;
danilchap1edb7ab2016-04-20 05:25:10 -0700197}
198
199const uint8_t* Packet::data() const {
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200200 return buffer_.cdata();
danilchap1edb7ab2016-04-20 05:25:10 -0700201}
202
203size_t Packet::FreeCapacity() const {
204 return capacity() - size();
205}
206
207size_t Packet::MaxPayloadSize() const {
208 return capacity() - payload_offset_;
209}
210
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200211void Packet::CopyHeaderFrom(const Packet& packet) {
danilchap1edb7ab2016-04-20 05:25:10 -0700212 RTC_DCHECK_GE(capacity(), packet.headers_size());
213
214 marker_ = packet.marker_;
215 payload_type_ = packet.payload_type_;
216 sequence_number_ = packet.sequence_number_;
217 timestamp_ = packet.timestamp_;
218 ssrc_ = packet.ssrc_;
219 payload_offset_ = packet.payload_offset_;
danilchap70f39a32016-12-16 05:48:18 -0800220 for (size_t i = 0; i < kMaxExtensionHeaders; ++i) {
danilchap1edb7ab2016-04-20 05:25:10 -0700221 extension_entries_[i] = packet.extension_entries_[i];
222 }
223 extensions_size_ = packet.extensions_size_;
224 buffer_.SetData(packet.data(), packet.headers_size());
225 // Reset payload and padding.
226 payload_size_ = 0;
227 padding_size_ = 0;
228}
229
230void Packet::SetMarker(bool marker_bit) {
231 marker_ = marker_bit;
232 if (marker_) {
233 WriteAt(1, data()[1] | 0x80);
234 } else {
235 WriteAt(1, data()[1] & 0x7F);
236 }
237}
238
239void Packet::SetPayloadType(uint8_t payload_type) {
240 RTC_DCHECK_LE(payload_type, 0x7Fu);
241 payload_type_ = payload_type;
242 WriteAt(1, (data()[1] & 0x80) | payload_type);
243}
244
245void Packet::SetSequenceNumber(uint16_t seq_no) {
246 sequence_number_ = seq_no;
247 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(2), seq_no);
248}
249
250void Packet::SetTimestamp(uint32_t timestamp) {
251 timestamp_ = timestamp;
252 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(4), timestamp);
253}
254
255void Packet::SetSsrc(uint32_t ssrc) {
256 ssrc_ = ssrc;
257 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(8), ssrc);
258}
259
260void Packet::SetCsrcs(const std::vector<uint32_t>& csrcs) {
danilchap70f39a32016-12-16 05:48:18 -0800261 RTC_DCHECK_EQ(extensions_size_, 0);
kwibergaf476c72016-11-28 15:21:39 -0800262 RTC_DCHECK_EQ(payload_size_, 0);
263 RTC_DCHECK_EQ(padding_size_, 0);
danilchap1edb7ab2016-04-20 05:25:10 -0700264 RTC_DCHECK_LE(csrcs.size(), 0x0fu);
265 RTC_DCHECK_LE(kFixedHeaderSize + 4 * csrcs.size(), capacity());
266 payload_offset_ = kFixedHeaderSize + 4 * csrcs.size();
267 WriteAt(0, (data()[0] & 0xF0) | csrcs.size());
268 size_t offset = kFixedHeaderSize;
269 for (uint32_t csrc : csrcs) {
270 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(offset), csrc);
271 offset += 4;
272 }
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200273 buffer_.SetSize(payload_offset_);
danilchap1edb7ab2016-04-20 05:25:10 -0700274}
275
276uint8_t* Packet::AllocatePayload(size_t size_bytes) {
kwibergaf476c72016-11-28 15:21:39 -0800277 RTC_DCHECK_EQ(padding_size_, 0);
danilchap1edb7ab2016-04-20 05:25:10 -0700278 if (payload_offset_ + size_bytes > capacity()) {
279 LOG(LS_WARNING) << "Cannot set payload, not enough space in buffer.";
280 return nullptr;
281 }
danilchap74110612016-10-02 10:54:29 -0700282 // Reset payload size to 0. If CopyOnWrite buffer_ was shared, this will cause
283 // reallocation and memcpy. Setting size to just headers reduces memcpy size.
284 buffer_.SetSize(payload_offset_);
danilchap1edb7ab2016-04-20 05:25:10 -0700285 payload_size_ = size_bytes;
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200286 buffer_.SetSize(payload_offset_ + payload_size_);
danilchap1edb7ab2016-04-20 05:25:10 -0700287 return WriteAt(payload_offset_);
288}
289
290void Packet::SetPayloadSize(size_t size_bytes) {
kwibergaf476c72016-11-28 15:21:39 -0800291 RTC_DCHECK_EQ(padding_size_, 0);
danilchap1edb7ab2016-04-20 05:25:10 -0700292 RTC_DCHECK_LE(size_bytes, payload_size_);
293 payload_size_ = size_bytes;
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200294 buffer_.SetSize(payload_offset_ + payload_size_);
danilchap1edb7ab2016-04-20 05:25:10 -0700295}
296
297bool Packet::SetPadding(uint8_t size_bytes, Random* random) {
298 RTC_DCHECK(random);
299 if (payload_offset_ + payload_size_ + size_bytes > capacity()) {
300 LOG(LS_WARNING) << "Cannot set padding size " << size_bytes << ", only "
301 << (capacity() - payload_offset_ - payload_size_)
302 << " bytes left in buffer.";
303 return false;
304 }
305 padding_size_ = size_bytes;
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200306 buffer_.SetSize(payload_offset_ + payload_size_ + padding_size_);
danilchap1edb7ab2016-04-20 05:25:10 -0700307 if (padding_size_ > 0) {
308 size_t padding_offset = payload_offset_ + payload_size_;
309 size_t padding_end = padding_offset + padding_size_;
310 for (size_t offset = padding_offset; offset < padding_end - 1; ++offset) {
311 WriteAt(offset, random->Rand<uint8_t>());
312 }
313 WriteAt(padding_end - 1, padding_size_);
314 WriteAt(0, data()[0] | 0x20); // Set padding bit.
315 } else {
316 WriteAt(0, data()[0] & ~0x20); // Clear padding bit.
317 }
318 return true;
319}
320
321void Packet::Clear() {
322 marker_ = false;
323 payload_type_ = 0;
324 sequence_number_ = 0;
325 timestamp_ = 0;
326 ssrc_ = 0;
327 payload_offset_ = kFixedHeaderSize;
328 payload_size_ = 0;
329 padding_size_ = 0;
danilchap1edb7ab2016-04-20 05:25:10 -0700330 extensions_size_ = 0;
danilchap70f39a32016-12-16 05:48:18 -0800331 for (ExtensionInfo& location : extension_entries_) {
332 location.offset = 0;
333 location.length = 0;
334 }
danilchap1edb7ab2016-04-20 05:25:10 -0700335
336 memset(WriteAt(0), 0, kFixedHeaderSize);
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200337 buffer_.SetSize(kFixedHeaderSize);
danilchap1edb7ab2016-04-20 05:25:10 -0700338 WriteAt(0, kRtpVersion << 6);
339}
340
341bool Packet::ParseBuffer(const uint8_t* buffer, size_t size) {
342 if (size < kFixedHeaderSize) {
343 return false;
344 }
345 const uint8_t version = buffer[0] >> 6;
346 if (version != kRtpVersion) {
347 return false;
348 }
349 const bool has_padding = (buffer[0] & 0x20) != 0;
350 const bool has_extension = (buffer[0] & 0x10) != 0;
351 const uint8_t number_of_crcs = buffer[0] & 0x0f;
352 marker_ = (buffer[1] & 0x80) != 0;
353 payload_type_ = buffer[1] & 0x7f;
354
355 sequence_number_ = ByteReader<uint16_t>::ReadBigEndian(&buffer[2]);
356 timestamp_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]);
357 ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]);
358 if (size < kFixedHeaderSize + number_of_crcs * 4) {
359 return false;
360 }
361 payload_offset_ = kFixedHeaderSize + number_of_crcs * 4;
362
363 if (has_padding) {
364 padding_size_ = buffer[size - 1];
365 if (padding_size_ == 0) {
366 LOG(LS_WARNING) << "Padding was set, but padding size is zero";
367 return false;
368 }
369 } else {
370 padding_size_ = 0;
371 }
372
danilchap1edb7ab2016-04-20 05:25:10 -0700373 extensions_size_ = 0;
danilchap70f39a32016-12-16 05:48:18 -0800374 for (ExtensionInfo& location : extension_entries_) {
375 location.offset = 0;
376 location.length = 0;
377 }
danilchap1edb7ab2016-04-20 05:25:10 -0700378 if (has_extension) {
379 /* RTP header extension, RFC 3550.
380 0 1 2 3
381 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
382 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
383 | defined by profile | length |
384 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
385 | header extension |
386 | .... |
387 */
388 size_t extension_offset = payload_offset_ + 4;
389 if (extension_offset > size) {
390 return false;
391 }
392 uint16_t profile =
393 ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_]);
394 size_t extensions_capacity =
395 ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_ + 2]);
396 extensions_capacity *= 4;
397 if (extension_offset + extensions_capacity > size) {
398 return false;
399 }
400 if (profile != kOneByteExtensionId) {
401 LOG(LS_WARNING) << "Unsupported rtp extension " << profile;
402 } else {
403 constexpr uint8_t kPaddingId = 0;
404 constexpr uint8_t kReservedId = 15;
405 while (extensions_size_ + kOneByteHeaderSize < extensions_capacity) {
danilchap70f39a32016-12-16 05:48:18 -0800406 int id = buffer[extension_offset + extensions_size_] >> 4;
danilchap1edb7ab2016-04-20 05:25:10 -0700407 if (id == kReservedId) {
408 break;
409 } else if (id == kPaddingId) {
410 extensions_size_++;
411 continue;
412 }
413 uint8_t length =
414 1 + (buffer[extension_offset + extensions_size_] & 0xf);
Danil Chapovalova64a2fb2016-09-12 11:41:35 +0200415 if (extensions_size_ + kOneByteHeaderSize + length >
416 extensions_capacity) {
417 LOG(LS_WARNING) << "Oversized rtp header extension.";
418 break;
danilchap1edb7ab2016-04-20 05:25:10 -0700419 }
danilchap70f39a32016-12-16 05:48:18 -0800420
421 size_t idx = id - 1;
422 if (extension_entries_[idx].length != 0) {
423 LOG(LS_VERBOSE) << "Duplicate rtp header extension id " << id
424 << ". Overwriting.";
Danil Chapovalova64a2fb2016-09-12 11:41:35 +0200425 }
danilchap70f39a32016-12-16 05:48:18 -0800426
Danil Chapovalova64a2fb2016-09-12 11:41:35 +0200427 extensions_size_ += kOneByteHeaderSize;
danilchap70f39a32016-12-16 05:48:18 -0800428 extension_entries_[idx].offset = extension_offset + extensions_size_;
429 extension_entries_[idx].length = length;
danilchap1edb7ab2016-04-20 05:25:10 -0700430 extensions_size_ += length;
431 }
432 }
433 payload_offset_ = extension_offset + extensions_capacity;
434 }
435
436 if (payload_offset_ + padding_size_ > size) {
437 return false;
438 }
439 payload_size_ = size - payload_offset_ - padding_size_;
440 return true;
441}
442
443bool Packet::FindExtension(ExtensionType type,
444 uint8_t length,
445 uint16_t* offset) const {
446 RTC_DCHECK(offset);
danilchap70f39a32016-12-16 05:48:18 -0800447 for (const ExtensionInfo& extension : extension_entries_) {
448 if (extension.type == type) {
449 if (extension.length == 0) {
450 // Extension is registered but not set.
danilchap07ec26d2016-06-17 04:18:54 -0700451 return false;
452 }
danilchap70f39a32016-12-16 05:48:18 -0800453 if (length != extension.length) {
454 LOG(LS_WARNING) << "Length mismatch for extension '" << type
455 << "': expected " << static_cast<int>(length)
456 << ", received " << static_cast<int>(extension.length);
457 return false;
458 }
459 *offset = extension.offset;
danilchap1edb7ab2016-04-20 05:25:10 -0700460 return true;
461 }
462 }
463 return false;
464}
465
466bool Packet::AllocateExtension(ExtensionType type,
467 uint8_t length,
468 uint16_t* offset) {
danilchap70f39a32016-12-16 05:48:18 -0800469 uint8_t extension_id = ExtensionManager::kInvalidId;
470 ExtensionInfo* extension_entry = nullptr;
471 for (size_t i = 0; i < kMaxExtensionHeaders; ++i) {
472 if (extension_entries_[i].type == type) {
473 extension_id = i + 1;
474 extension_entry = &extension_entries_[i];
475 break;
476 }
danilchap1edb7ab2016-04-20 05:25:10 -0700477 }
danilchap70f39a32016-12-16 05:48:18 -0800478
479 if (!extension_entry) // Extension not registered.
480 return false;
481
482 if (extension_entry->length != 0) { // Already allocated.
483 if (length != extension_entry->length) {
484 LOG(LS_WARNING) << "Length mismatch for extension '" << type
485 << "': expected " << static_cast<int>(length)
486 << ", received "
487 << static_cast<int>(extension_entry->length);
488 return false;
489 }
490 *offset = extension_entry->offset;
danilchap1edb7ab2016-04-20 05:25:10 -0700491 return true;
492 }
493
494 // Can't add new extension after payload/padding was set.
495 if (payload_size_ > 0) {
496 return false;
497 }
498 if (padding_size_ > 0) {
499 return false;
500 }
501
kwibergaf476c72016-11-28 15:21:39 -0800502 RTC_DCHECK_GT(length, 0);
503 RTC_DCHECK_LE(length, 16);
danilchap1edb7ab2016-04-20 05:25:10 -0700504
505 size_t num_csrc = data()[0] & 0x0F;
506 size_t extensions_offset = kFixedHeaderSize + (num_csrc * 4) + 4;
507 if (extensions_offset + extensions_size_ + kOneByteHeaderSize + length >
508 capacity()) {
509 LOG(LS_WARNING) << "Extension cannot be registered: "
510 "Not enough space left in buffer.";
511 return false;
512 }
513
514 uint16_t new_extensions_size =
515 extensions_size_ + kOneByteHeaderSize + length;
516 uint16_t extensions_words =
517 (new_extensions_size + 3) / 4; // Wrap up to 32bit.
518
519 // All checks passed, write down the extension.
danilchap70f39a32016-12-16 05:48:18 -0800520 if (extensions_size_ == 0) {
danilchap1edb7ab2016-04-20 05:25:10 -0700521 RTC_DCHECK_EQ(payload_offset_, kFixedHeaderSize + (num_csrc * 4));
danilchap1edb7ab2016-04-20 05:25:10 -0700522 WriteAt(0, data()[0] | 0x10); // Set extension bit.
523 // Profile specific ID always set to OneByteExtensionHeader.
524 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 4),
525 kOneByteExtensionId);
526 }
527
528 WriteAt(extensions_offset + extensions_size_,
529 (extension_id << 4) | (length - 1));
danilchap70f39a32016-12-16 05:48:18 -0800530
531 extension_entry->length = length;
danilchap1edb7ab2016-04-20 05:25:10 -0700532 *offset = extensions_offset + kOneByteHeaderSize + extensions_size_;
danilchap70f39a32016-12-16 05:48:18 -0800533 extension_entry->offset = *offset;
danilchap1edb7ab2016-04-20 05:25:10 -0700534 extensions_size_ = new_extensions_size;
535
536 // Update header length field.
537 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 2),
538 extensions_words);
539 // Fill extension padding place with zeroes.
540 size_t extension_padding_size = 4 * extensions_words - extensions_size_;
541 memset(WriteAt(extensions_offset + extensions_size_), 0,
542 extension_padding_size);
543 payload_offset_ = extensions_offset + 4 * extensions_words;
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200544 buffer_.SetSize(payload_offset_);
danilchap1edb7ab2016-04-20 05:25:10 -0700545 return true;
546}
547
548uint8_t* Packet::WriteAt(size_t offset) {
549 return buffer_.data() + offset;
550}
551
552void Packet::WriteAt(size_t offset, uint8_t byte) {
553 buffer_.data()[offset] = byte;
554}
555
556} // namespace rtp
557} // namespace webrtc