blob: 72fd7892b235f1c1118b07457d18f87f9e83e1e7 [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// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
55Packet::Packet(const ExtensionManager* extensions)
56 : extensions_(extensions), buffer_(kDefaultPacketSize) {
57 Clear();
58}
59
60Packet::Packet(const ExtensionManager* extensions, size_t capacity)
61 : extensions_(extensions), buffer_(capacity) {
62 RTC_DCHECK_GE(capacity, kFixedHeaderSize);
63 Clear();
64}
65
66Packet::~Packet() {}
67
68void Packet::IdentifyExtensions(const ExtensionManager* extensions) {
69 RTC_DCHECK(extensions);
70 extensions_ = extensions;
71 for (size_t i = 0; i < num_extensions_; ++i) {
72 uint8_t id = data()[extension_entries_[i].offset - 1] >> 4;
73 extension_entries_[i].type = extensions_->GetType(id);
74 }
75}
76
77bool Packet::Parse(const uint8_t* buffer, size_t buffer_size) {
78 if (!ParseBuffer(buffer, buffer_size)) {
79 Clear();
80 return false;
81 }
danilchap1edb7ab2016-04-20 05:25:10 -070082 buffer_.SetData(buffer, buffer_size);
Danil Chapovalov31e4e802016-08-03 18:27:40 +020083 RTC_DCHECK_EQ(size(), buffer_size);
danilchap1edb7ab2016-04-20 05:25:10 -070084 return true;
85}
86
Danil Chapovalov31e4e802016-08-03 18:27:40 +020087bool Packet::Parse(rtc::CopyOnWriteBuffer buffer) {
88 if (!ParseBuffer(buffer.cdata(), buffer.size())) {
danilchap1edb7ab2016-04-20 05:25:10 -070089 Clear();
90 return false;
91 }
Danil Chapovalov31e4e802016-08-03 18:27:40 +020092 size_t buffer_size = buffer.size();
danilchap1edb7ab2016-04-20 05:25:10 -070093 buffer_ = std::move(buffer);
Danil Chapovalov31e4e802016-08-03 18:27:40 +020094 RTC_DCHECK_EQ(size(), buffer_size);
danilchap1edb7ab2016-04-20 05:25:10 -070095 return true;
96}
97
98bool Packet::Marker() const {
99 RTC_DCHECK_EQ(marker_, (data()[1] & 0x80) != 0);
100 return marker_;
101}
102
103uint8_t Packet::PayloadType() const {
104 RTC_DCHECK_EQ(payload_type_, data()[1] & 0x7f);
105 return payload_type_;
106}
107
108uint16_t Packet::SequenceNumber() const {
109 RTC_DCHECK_EQ(sequence_number_,
110 ByteReader<uint16_t>::ReadBigEndian(data() + 2));
111 return sequence_number_;
112}
113
114uint32_t Packet::Timestamp() const {
115 RTC_DCHECK_EQ(timestamp_, ByteReader<uint32_t>::ReadBigEndian(data() + 4));
116 return timestamp_;
117}
118
119uint32_t Packet::Ssrc() const {
120 RTC_DCHECK_EQ(ssrc_, ByteReader<uint32_t>::ReadBigEndian(data() + 8));
121 return ssrc_;
122}
123
124std::vector<uint32_t> Packet::Csrcs() const {
125 size_t num_csrc = data()[0] & 0x0F;
126 RTC_DCHECK_GE(capacity(), kFixedHeaderSize + num_csrc * 4);
127 std::vector<uint32_t> csrcs(num_csrc);
128 for (size_t i = 0; i < num_csrc; ++i) {
129 csrcs[i] =
130 ByteReader<uint32_t>::ReadBigEndian(&data()[kFixedHeaderSize + i * 4]);
131 }
132 return csrcs;
133}
134
135void Packet::GetHeader(RTPHeader* header) const {
136 header->markerBit = Marker();
137 header->payloadType = PayloadType();
138 header->sequenceNumber = SequenceNumber();
139 header->timestamp = Timestamp();
140 header->ssrc = Ssrc();
141 std::vector<uint32_t> csrcs = Csrcs();
142 header->numCSRCs = csrcs.size();
143 for (size_t i = 0; i < csrcs.size(); ++i) {
144 header->arrOfCSRCs[i] = csrcs[i];
145 }
146 header->paddingLength = padding_size();
147 header->headerLength = headers_size();
148 header->payload_type_frequency = 0;
149 header->extension.hasTransmissionTimeOffset =
150 GetExtension<TransmissionOffset>(
151 &header->extension.transmissionTimeOffset);
152 header->extension.hasAbsoluteSendTime =
153 GetExtension<AbsoluteSendTime>(&header->extension.absoluteSendTime);
154 header->extension.hasTransportSequenceNumber =
155 GetExtension<TransportSequenceNumber>(
156 &header->extension.transportSequenceNumber);
157 header->extension.hasAudioLevel = GetExtension<AudioLevel>(
158 &header->extension.voiceActivity, &header->extension.audioLevel);
159 header->extension.hasVideoRotation =
160 GetExtension<VideoOrientation>(&header->extension.videoRotation);
161}
162
163size_t Packet::headers_size() const {
164 return payload_offset_;
165}
166
167size_t Packet::payload_size() const {
168 return payload_size_;
169}
170
171size_t Packet::padding_size() const {
172 return padding_size_;
173}
174
danilchap96c15872016-11-21 01:35:29 -0800175rtc::ArrayView<const uint8_t> Packet::payload() const {
176 return rtc::MakeArrayView(data() + payload_offset_, payload_size_);
danilchap1edb7ab2016-04-20 05:25:10 -0700177}
178
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200179rtc::CopyOnWriteBuffer Packet::Buffer() const {
180 return buffer_;
181}
182
danilchap1edb7ab2016-04-20 05:25:10 -0700183size_t Packet::capacity() const {
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200184 return buffer_.capacity();
danilchap1edb7ab2016-04-20 05:25:10 -0700185}
186
187size_t Packet::size() const {
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200188 size_t ret = payload_offset_ + payload_size_ + padding_size_;
189 RTC_DCHECK_EQ(buffer_.size(), ret);
190 return ret;
danilchap1edb7ab2016-04-20 05:25:10 -0700191}
192
193const uint8_t* Packet::data() const {
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200194 return buffer_.cdata();
danilchap1edb7ab2016-04-20 05:25:10 -0700195}
196
197size_t Packet::FreeCapacity() const {
198 return capacity() - size();
199}
200
201size_t Packet::MaxPayloadSize() const {
202 return capacity() - payload_offset_;
203}
204
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200205void Packet::CopyHeaderFrom(const Packet& packet) {
danilchap1edb7ab2016-04-20 05:25:10 -0700206 RTC_DCHECK_GE(capacity(), packet.headers_size());
207
208 marker_ = packet.marker_;
209 payload_type_ = packet.payload_type_;
210 sequence_number_ = packet.sequence_number_;
211 timestamp_ = packet.timestamp_;
212 ssrc_ = packet.ssrc_;
213 payload_offset_ = packet.payload_offset_;
214 num_extensions_ = packet.num_extensions_;
215 for (size_t i = 0; i < num_extensions_; ++i) {
216 extension_entries_[i] = packet.extension_entries_[i];
217 }
218 extensions_size_ = packet.extensions_size_;
219 buffer_.SetData(packet.data(), packet.headers_size());
220 // Reset payload and padding.
221 payload_size_ = 0;
222 padding_size_ = 0;
223}
224
225void Packet::SetMarker(bool marker_bit) {
226 marker_ = marker_bit;
227 if (marker_) {
228 WriteAt(1, data()[1] | 0x80);
229 } else {
230 WriteAt(1, data()[1] & 0x7F);
231 }
232}
233
234void Packet::SetPayloadType(uint8_t payload_type) {
235 RTC_DCHECK_LE(payload_type, 0x7Fu);
236 payload_type_ = payload_type;
237 WriteAt(1, (data()[1] & 0x80) | payload_type);
238}
239
240void Packet::SetSequenceNumber(uint16_t seq_no) {
241 sequence_number_ = seq_no;
242 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(2), seq_no);
243}
244
245void Packet::SetTimestamp(uint32_t timestamp) {
246 timestamp_ = timestamp;
247 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(4), timestamp);
248}
249
250void Packet::SetSsrc(uint32_t ssrc) {
251 ssrc_ = ssrc;
252 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(8), ssrc);
253}
254
255void Packet::SetCsrcs(const std::vector<uint32_t>& csrcs) {
kwibergaf476c72016-11-28 15:21:39 -0800256 RTC_DCHECK_EQ(num_extensions_, 0);
257 RTC_DCHECK_EQ(payload_size_, 0);
258 RTC_DCHECK_EQ(padding_size_, 0);
danilchap1edb7ab2016-04-20 05:25:10 -0700259 RTC_DCHECK_LE(csrcs.size(), 0x0fu);
260 RTC_DCHECK_LE(kFixedHeaderSize + 4 * csrcs.size(), capacity());
261 payload_offset_ = kFixedHeaderSize + 4 * csrcs.size();
262 WriteAt(0, (data()[0] & 0xF0) | csrcs.size());
263 size_t offset = kFixedHeaderSize;
264 for (uint32_t csrc : csrcs) {
265 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(offset), csrc);
266 offset += 4;
267 }
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200268 buffer_.SetSize(payload_offset_);
danilchap1edb7ab2016-04-20 05:25:10 -0700269}
270
271uint8_t* Packet::AllocatePayload(size_t size_bytes) {
kwibergaf476c72016-11-28 15:21:39 -0800272 RTC_DCHECK_EQ(padding_size_, 0);
danilchap1edb7ab2016-04-20 05:25:10 -0700273 if (payload_offset_ + size_bytes > capacity()) {
274 LOG(LS_WARNING) << "Cannot set payload, not enough space in buffer.";
275 return nullptr;
276 }
danilchap74110612016-10-02 10:54:29 -0700277 // Reset payload size to 0. If CopyOnWrite buffer_ was shared, this will cause
278 // reallocation and memcpy. Setting size to just headers reduces memcpy size.
279 buffer_.SetSize(payload_offset_);
danilchap1edb7ab2016-04-20 05:25:10 -0700280 payload_size_ = size_bytes;
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200281 buffer_.SetSize(payload_offset_ + payload_size_);
danilchap1edb7ab2016-04-20 05:25:10 -0700282 return WriteAt(payload_offset_);
283}
284
285void Packet::SetPayloadSize(size_t size_bytes) {
kwibergaf476c72016-11-28 15:21:39 -0800286 RTC_DCHECK_EQ(padding_size_, 0);
danilchap1edb7ab2016-04-20 05:25:10 -0700287 RTC_DCHECK_LE(size_bytes, payload_size_);
288 payload_size_ = size_bytes;
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200289 buffer_.SetSize(payload_offset_ + payload_size_);
danilchap1edb7ab2016-04-20 05:25:10 -0700290}
291
292bool Packet::SetPadding(uint8_t size_bytes, Random* random) {
293 RTC_DCHECK(random);
294 if (payload_offset_ + payload_size_ + size_bytes > capacity()) {
295 LOG(LS_WARNING) << "Cannot set padding size " << size_bytes << ", only "
296 << (capacity() - payload_offset_ - payload_size_)
297 << " bytes left in buffer.";
298 return false;
299 }
300 padding_size_ = size_bytes;
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200301 buffer_.SetSize(payload_offset_ + payload_size_ + padding_size_);
danilchap1edb7ab2016-04-20 05:25:10 -0700302 if (padding_size_ > 0) {
303 size_t padding_offset = payload_offset_ + payload_size_;
304 size_t padding_end = padding_offset + padding_size_;
305 for (size_t offset = padding_offset; offset < padding_end - 1; ++offset) {
306 WriteAt(offset, random->Rand<uint8_t>());
307 }
308 WriteAt(padding_end - 1, padding_size_);
309 WriteAt(0, data()[0] | 0x20); // Set padding bit.
310 } else {
311 WriteAt(0, data()[0] & ~0x20); // Clear padding bit.
312 }
313 return true;
314}
315
316void Packet::Clear() {
317 marker_ = false;
318 payload_type_ = 0;
319 sequence_number_ = 0;
320 timestamp_ = 0;
321 ssrc_ = 0;
322 payload_offset_ = kFixedHeaderSize;
323 payload_size_ = 0;
324 padding_size_ = 0;
325 num_extensions_ = 0;
326 extensions_size_ = 0;
327
328 memset(WriteAt(0), 0, kFixedHeaderSize);
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200329 buffer_.SetSize(kFixedHeaderSize);
danilchap1edb7ab2016-04-20 05:25:10 -0700330 WriteAt(0, kRtpVersion << 6);
331}
332
333bool Packet::ParseBuffer(const uint8_t* buffer, size_t size) {
334 if (size < kFixedHeaderSize) {
335 return false;
336 }
337 const uint8_t version = buffer[0] >> 6;
338 if (version != kRtpVersion) {
339 return false;
340 }
341 const bool has_padding = (buffer[0] & 0x20) != 0;
342 const bool has_extension = (buffer[0] & 0x10) != 0;
343 const uint8_t number_of_crcs = buffer[0] & 0x0f;
344 marker_ = (buffer[1] & 0x80) != 0;
345 payload_type_ = buffer[1] & 0x7f;
346
347 sequence_number_ = ByteReader<uint16_t>::ReadBigEndian(&buffer[2]);
348 timestamp_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]);
349 ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]);
350 if (size < kFixedHeaderSize + number_of_crcs * 4) {
351 return false;
352 }
353 payload_offset_ = kFixedHeaderSize + number_of_crcs * 4;
354
355 if (has_padding) {
356 padding_size_ = buffer[size - 1];
357 if (padding_size_ == 0) {
358 LOG(LS_WARNING) << "Padding was set, but padding size is zero";
359 return false;
360 }
361 } else {
362 padding_size_ = 0;
363 }
364
365 num_extensions_ = 0;
366 extensions_size_ = 0;
367 if (has_extension) {
368 /* RTP header extension, RFC 3550.
369 0 1 2 3
370 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
371 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
372 | defined by profile | length |
373 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
374 | header extension |
375 | .... |
376 */
377 size_t extension_offset = payload_offset_ + 4;
378 if (extension_offset > size) {
379 return false;
380 }
381 uint16_t profile =
382 ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_]);
383 size_t extensions_capacity =
384 ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_ + 2]);
385 extensions_capacity *= 4;
386 if (extension_offset + extensions_capacity > size) {
387 return false;
388 }
389 if (profile != kOneByteExtensionId) {
390 LOG(LS_WARNING) << "Unsupported rtp extension " << profile;
391 } else {
392 constexpr uint8_t kPaddingId = 0;
393 constexpr uint8_t kReservedId = 15;
394 while (extensions_size_ + kOneByteHeaderSize < extensions_capacity) {
395 uint8_t id = buffer[extension_offset + extensions_size_] >> 4;
396 if (id == kReservedId) {
397 break;
398 } else if (id == kPaddingId) {
399 extensions_size_++;
400 continue;
401 }
402 uint8_t length =
403 1 + (buffer[extension_offset + extensions_size_] & 0xf);
Danil Chapovalova64a2fb2016-09-12 11:41:35 +0200404 if (extensions_size_ + kOneByteHeaderSize + length >
405 extensions_capacity) {
406 LOG(LS_WARNING) << "Oversized rtp header extension.";
407 break;
danilchap1edb7ab2016-04-20 05:25:10 -0700408 }
Danil Chapovalova64a2fb2016-09-12 11:41:35 +0200409 if (num_extensions_ >= kMaxExtensionHeaders) {
410 LOG(LS_WARNING) << "Too many rtp header extensions.";
411 break;
412 }
413 extensions_size_ += kOneByteHeaderSize;
danilchap1edb7ab2016-04-20 05:25:10 -0700414 extension_entries_[num_extensions_].type =
415 extensions_ ? extensions_->GetType(id)
416 : ExtensionManager::kInvalidType;
417 extension_entries_[num_extensions_].length = length;
418 extension_entries_[num_extensions_].offset =
419 extension_offset + extensions_size_;
420 num_extensions_++;
421 extensions_size_ += length;
422 }
423 }
424 payload_offset_ = extension_offset + extensions_capacity;
425 }
426
427 if (payload_offset_ + padding_size_ > size) {
428 return false;
429 }
430 payload_size_ = size - payload_offset_ - padding_size_;
431 return true;
432}
433
434bool Packet::FindExtension(ExtensionType type,
435 uint8_t length,
436 uint16_t* offset) const {
437 RTC_DCHECK(offset);
438 for (size_t i = 0; i < num_extensions_; ++i) {
439 if (extension_entries_[i].type == type) {
danilchap07ec26d2016-06-17 04:18:54 -0700440 if (length != extension_entries_[i].length) {
441 LOG(LS_WARNING) << "Length mismatch for extension '" << type
442 << "': expected " << static_cast<int>(length)
443 << ", received "
444 << static_cast<int>(extension_entries_[i].length);
445 return false;
446 }
danilchap1edb7ab2016-04-20 05:25:10 -0700447 *offset = extension_entries_[i].offset;
448 return true;
449 }
450 }
451 return false;
452}
453
454bool Packet::AllocateExtension(ExtensionType type,
455 uint8_t length,
456 uint16_t* offset) {
457 if (!extensions_) {
458 return false;
459 }
460 if (FindExtension(type, length, offset)) {
461 return true;
462 }
463
464 // Can't add new extension after payload/padding was set.
465 if (payload_size_ > 0) {
466 return false;
467 }
468 if (padding_size_ > 0) {
469 return false;
470 }
471
472 uint8_t extension_id = extensions_->GetId(type);
473 if (extension_id == ExtensionManager::kInvalidId) {
474 return false;
475 }
kwibergaf476c72016-11-28 15:21:39 -0800476 RTC_DCHECK_GT(length, 0);
477 RTC_DCHECK_LE(length, 16);
danilchap1edb7ab2016-04-20 05:25:10 -0700478
479 size_t num_csrc = data()[0] & 0x0F;
480 size_t extensions_offset = kFixedHeaderSize + (num_csrc * 4) + 4;
481 if (extensions_offset + extensions_size_ + kOneByteHeaderSize + length >
482 capacity()) {
483 LOG(LS_WARNING) << "Extension cannot be registered: "
484 "Not enough space left in buffer.";
485 return false;
486 }
487
488 uint16_t new_extensions_size =
489 extensions_size_ + kOneByteHeaderSize + length;
490 uint16_t extensions_words =
491 (new_extensions_size + 3) / 4; // Wrap up to 32bit.
492
493 // All checks passed, write down the extension.
494 if (num_extensions_ == 0) {
495 RTC_DCHECK_EQ(payload_offset_, kFixedHeaderSize + (num_csrc * 4));
496 RTC_DCHECK_EQ(extensions_size_, 0);
497 WriteAt(0, data()[0] | 0x10); // Set extension bit.
498 // Profile specific ID always set to OneByteExtensionHeader.
499 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 4),
500 kOneByteExtensionId);
501 }
502
503 WriteAt(extensions_offset + extensions_size_,
504 (extension_id << 4) | (length - 1));
505 RTC_DCHECK(num_extensions_ < kMaxExtensionHeaders);
506 extension_entries_[num_extensions_].type = type;
507 extension_entries_[num_extensions_].length = length;
508 *offset = extensions_offset + kOneByteHeaderSize + extensions_size_;
509 extension_entries_[num_extensions_].offset = *offset;
510 ++num_extensions_;
511 extensions_size_ = new_extensions_size;
512
513 // Update header length field.
514 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 2),
515 extensions_words);
516 // Fill extension padding place with zeroes.
517 size_t extension_padding_size = 4 * extensions_words - extensions_size_;
518 memset(WriteAt(extensions_offset + extensions_size_), 0,
519 extension_padding_size);
520 payload_offset_ = extensions_offset + 4 * extensions_words;
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200521 buffer_.SetSize(payload_offset_);
danilchap1edb7ab2016-04-20 05:25:10 -0700522 return true;
523}
524
525uint8_t* Packet::WriteAt(size_t offset) {
526 return buffer_.data() + offset;
527}
528
529void Packet::WriteAt(size_t offset, uint8_t byte) {
530 buffer_.data()[offset] = byte;
531}
532
533} // namespace rtp
534} // namespace webrtc