Line data Source code
1 : /*
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>
14 : #include <utility>
15 :
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 :
24 : namespace webrtc {
25 : namespace rtp {
26 : namespace {
27 : constexpr size_t kFixedHeaderSize = 12;
28 : constexpr uint8_t kRtpVersion = 2;
29 : constexpr uint16_t kOneByteExtensionId = 0xBEDE;
30 : constexpr size_t kOneByteHeaderSize = 1;
31 : constexpr 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 : // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
55 0 : Packet::Packet() : Packet(nullptr, kDefaultPacketSize) {}
56 :
57 0 : Packet::Packet(const ExtensionManager* extensions)
58 0 : : Packet(extensions, kDefaultPacketSize) {}
59 :
60 0 : Packet::Packet(const ExtensionManager* extensions, size_t capacity)
61 0 : : buffer_(capacity) {
62 0 : RTC_DCHECK_GE(capacity, kFixedHeaderSize);
63 0 : Clear();
64 0 : if (extensions) {
65 0 : IdentifyExtensions(*extensions);
66 : } else {
67 0 : for (size_t i = 0; i < kMaxExtensionHeaders; ++i)
68 0 : extension_entries_[i].type = ExtensionManager::kInvalidType;
69 : }
70 0 : }
71 :
72 0 : Packet::~Packet() {}
73 :
74 0 : void Packet::IdentifyExtensions(const ExtensionManager& extensions) {
75 0 : for (size_t i = 0; i < kMaxExtensionHeaders; ++i)
76 0 : extension_entries_[i].type = extensions.GetType(i + 1);
77 0 : }
78 :
79 0 : bool Packet::Parse(const uint8_t* buffer, size_t buffer_size) {
80 0 : if (!ParseBuffer(buffer, buffer_size)) {
81 0 : Clear();
82 0 : return false;
83 : }
84 0 : buffer_.SetData(buffer, buffer_size);
85 0 : RTC_DCHECK_EQ(size(), buffer_size);
86 0 : return true;
87 : }
88 :
89 0 : bool Packet::Parse(rtc::ArrayView<const uint8_t> packet) {
90 0 : return Parse(packet.data(), packet.size());
91 : }
92 :
93 0 : bool Packet::Parse(rtc::CopyOnWriteBuffer buffer) {
94 0 : if (!ParseBuffer(buffer.cdata(), buffer.size())) {
95 0 : Clear();
96 0 : return false;
97 : }
98 0 : size_t buffer_size = buffer.size();
99 0 : buffer_ = std::move(buffer);
100 0 : RTC_DCHECK_EQ(size(), buffer_size);
101 0 : return true;
102 : }
103 :
104 0 : bool Packet::Marker() const {
105 0 : RTC_DCHECK_EQ(marker_, (data()[1] & 0x80) != 0);
106 0 : return marker_;
107 : }
108 :
109 0 : uint8_t Packet::PayloadType() const {
110 0 : RTC_DCHECK_EQ(payload_type_, data()[1] & 0x7f);
111 0 : return payload_type_;
112 : }
113 :
114 0 : uint16_t Packet::SequenceNumber() const {
115 0 : RTC_DCHECK_EQ(sequence_number_,
116 0 : ByteReader<uint16_t>::ReadBigEndian(data() + 2));
117 0 : return sequence_number_;
118 : }
119 :
120 0 : uint32_t Packet::Timestamp() const {
121 0 : RTC_DCHECK_EQ(timestamp_, ByteReader<uint32_t>::ReadBigEndian(data() + 4));
122 0 : return timestamp_;
123 : }
124 :
125 0 : uint32_t Packet::Ssrc() const {
126 0 : RTC_DCHECK_EQ(ssrc_, ByteReader<uint32_t>::ReadBigEndian(data() + 8));
127 0 : return ssrc_;
128 : }
129 :
130 0 : std::vector<uint32_t> Packet::Csrcs() const {
131 0 : size_t num_csrc = data()[0] & 0x0F;
132 0 : RTC_DCHECK_GE(capacity(), kFixedHeaderSize + num_csrc * 4);
133 0 : std::vector<uint32_t> csrcs(num_csrc);
134 0 : for (size_t i = 0; i < num_csrc; ++i) {
135 0 : csrcs[i] =
136 0 : ByteReader<uint32_t>::ReadBigEndian(&data()[kFixedHeaderSize + i * 4]);
137 : }
138 0 : return csrcs;
139 : }
140 :
141 0 : void Packet::GetHeader(RTPHeader* header) const {
142 0 : header->markerBit = Marker();
143 0 : header->payloadType = PayloadType();
144 0 : header->sequenceNumber = SequenceNumber();
145 0 : header->timestamp = Timestamp();
146 0 : header->ssrc = Ssrc();
147 0 : std::vector<uint32_t> csrcs = Csrcs();
148 0 : header->numCSRCs = csrcs.size();
149 0 : for (size_t i = 0; i < csrcs.size(); ++i) {
150 0 : header->arrOfCSRCs[i] = csrcs[i];
151 : }
152 0 : header->paddingLength = padding_size();
153 0 : header->headerLength = headers_size();
154 0 : header->payload_type_frequency = 0;
155 0 : header->extension.hasTransmissionTimeOffset =
156 0 : GetExtension<TransmissionOffset>(
157 : &header->extension.transmissionTimeOffset);
158 0 : header->extension.hasAbsoluteSendTime =
159 0 : GetExtension<AbsoluteSendTime>(&header->extension.absoluteSendTime);
160 0 : header->extension.hasTransportSequenceNumber =
161 0 : GetExtension<TransportSequenceNumber>(
162 : &header->extension.transportSequenceNumber);
163 0 : header->extension.hasAudioLevel = GetExtension<AudioLevel>(
164 : &header->extension.voiceActivity, &header->extension.audioLevel);
165 0 : header->extension.hasVideoRotation =
166 0 : GetExtension<VideoOrientation>(&header->extension.videoRotation);
167 0 : }
168 :
169 0 : size_t Packet::headers_size() const {
170 0 : return payload_offset_;
171 : }
172 :
173 0 : size_t Packet::payload_size() const {
174 0 : return payload_size_;
175 : }
176 :
177 0 : size_t Packet::padding_size() const {
178 0 : return padding_size_;
179 : }
180 :
181 0 : rtc::ArrayView<const uint8_t> Packet::payload() const {
182 0 : return rtc::MakeArrayView(data() + payload_offset_, payload_size_);
183 : }
184 :
185 0 : rtc::CopyOnWriteBuffer Packet::Buffer() const {
186 0 : return buffer_;
187 : }
188 :
189 0 : size_t Packet::capacity() const {
190 0 : return buffer_.capacity();
191 : }
192 :
193 0 : size_t Packet::size() const {
194 0 : size_t ret = payload_offset_ + payload_size_ + padding_size_;
195 0 : RTC_DCHECK_EQ(buffer_.size(), ret);
196 0 : return ret;
197 : }
198 :
199 0 : const uint8_t* Packet::data() const {
200 0 : return buffer_.cdata();
201 : }
202 :
203 0 : size_t Packet::FreeCapacity() const {
204 0 : return capacity() - size();
205 : }
206 :
207 0 : size_t Packet::MaxPayloadSize() const {
208 0 : return capacity() - payload_offset_;
209 : }
210 :
211 0 : void Packet::CopyHeaderFrom(const Packet& packet) {
212 0 : RTC_DCHECK_GE(capacity(), packet.headers_size());
213 :
214 0 : marker_ = packet.marker_;
215 0 : payload_type_ = packet.payload_type_;
216 0 : sequence_number_ = packet.sequence_number_;
217 0 : timestamp_ = packet.timestamp_;
218 0 : ssrc_ = packet.ssrc_;
219 0 : payload_offset_ = packet.payload_offset_;
220 0 : for (size_t i = 0; i < kMaxExtensionHeaders; ++i) {
221 0 : extension_entries_[i] = packet.extension_entries_[i];
222 : }
223 0 : extensions_size_ = packet.extensions_size_;
224 0 : buffer_.SetData(packet.data(), packet.headers_size());
225 : // Reset payload and padding.
226 0 : payload_size_ = 0;
227 0 : padding_size_ = 0;
228 0 : }
229 :
230 0 : void Packet::SetMarker(bool marker_bit) {
231 0 : marker_ = marker_bit;
232 0 : if (marker_) {
233 0 : WriteAt(1, data()[1] | 0x80);
234 : } else {
235 0 : WriteAt(1, data()[1] & 0x7F);
236 : }
237 0 : }
238 :
239 0 : void Packet::SetPayloadType(uint8_t payload_type) {
240 0 : RTC_DCHECK_LE(payload_type, 0x7Fu);
241 0 : payload_type_ = payload_type;
242 0 : WriteAt(1, (data()[1] & 0x80) | payload_type);
243 0 : }
244 :
245 0 : void Packet::SetSequenceNumber(uint16_t seq_no) {
246 0 : sequence_number_ = seq_no;
247 0 : ByteWriter<uint16_t>::WriteBigEndian(WriteAt(2), seq_no);
248 0 : }
249 :
250 0 : void Packet::SetTimestamp(uint32_t timestamp) {
251 0 : timestamp_ = timestamp;
252 0 : ByteWriter<uint32_t>::WriteBigEndian(WriteAt(4), timestamp);
253 0 : }
254 :
255 0 : void Packet::SetSsrc(uint32_t ssrc) {
256 0 : ssrc_ = ssrc;
257 0 : ByteWriter<uint32_t>::WriteBigEndian(WriteAt(8), ssrc);
258 0 : }
259 :
260 0 : void Packet::SetCsrcs(const std::vector<uint32_t>& csrcs) {
261 0 : RTC_DCHECK_EQ(extensions_size_, 0);
262 0 : RTC_DCHECK_EQ(payload_size_, 0);
263 0 : RTC_DCHECK_EQ(padding_size_, 0);
264 0 : RTC_DCHECK_LE(csrcs.size(), 0x0fu);
265 0 : RTC_DCHECK_LE(kFixedHeaderSize + 4 * csrcs.size(), capacity());
266 0 : payload_offset_ = kFixedHeaderSize + 4 * csrcs.size();
267 0 : WriteAt(0, (data()[0] & 0xF0) | csrcs.size());
268 0 : size_t offset = kFixedHeaderSize;
269 0 : for (uint32_t csrc : csrcs) {
270 0 : ByteWriter<uint32_t>::WriteBigEndian(WriteAt(offset), csrc);
271 0 : offset += 4;
272 : }
273 0 : buffer_.SetSize(payload_offset_);
274 0 : }
275 :
276 0 : uint8_t* Packet::AllocatePayload(size_t size_bytes) {
277 0 : RTC_DCHECK_EQ(padding_size_, 0);
278 0 : if (payload_offset_ + size_bytes > capacity()) {
279 0 : LOG(LS_WARNING) << "Cannot set payload, not enough space in buffer.";
280 0 : return nullptr;
281 : }
282 : // 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 0 : buffer_.SetSize(payload_offset_);
285 0 : payload_size_ = size_bytes;
286 0 : buffer_.SetSize(payload_offset_ + payload_size_);
287 0 : return WriteAt(payload_offset_);
288 : }
289 :
290 0 : void Packet::SetPayloadSize(size_t size_bytes) {
291 0 : RTC_DCHECK_EQ(padding_size_, 0);
292 0 : RTC_DCHECK_LE(size_bytes, payload_size_);
293 0 : payload_size_ = size_bytes;
294 0 : buffer_.SetSize(payload_offset_ + payload_size_);
295 0 : }
296 :
297 0 : bool Packet::SetPadding(uint8_t size_bytes, Random* random) {
298 0 : RTC_DCHECK(random);
299 0 : if (payload_offset_ + payload_size_ + size_bytes > capacity()) {
300 0 : LOG(LS_WARNING) << "Cannot set padding size " << size_bytes << ", only "
301 0 : << (capacity() - payload_offset_ - payload_size_)
302 0 : << " bytes left in buffer.";
303 0 : return false;
304 : }
305 0 : padding_size_ = size_bytes;
306 0 : buffer_.SetSize(payload_offset_ + payload_size_ + padding_size_);
307 0 : if (padding_size_ > 0) {
308 0 : size_t padding_offset = payload_offset_ + payload_size_;
309 0 : size_t padding_end = padding_offset + padding_size_;
310 0 : for (size_t offset = padding_offset; offset < padding_end - 1; ++offset) {
311 0 : WriteAt(offset, random->Rand<uint8_t>());
312 : }
313 0 : WriteAt(padding_end - 1, padding_size_);
314 0 : WriteAt(0, data()[0] | 0x20); // Set padding bit.
315 : } else {
316 0 : WriteAt(0, data()[0] & ~0x20); // Clear padding bit.
317 : }
318 0 : return true;
319 : }
320 :
321 0 : void Packet::Clear() {
322 0 : marker_ = false;
323 0 : payload_type_ = 0;
324 0 : sequence_number_ = 0;
325 0 : timestamp_ = 0;
326 0 : ssrc_ = 0;
327 0 : payload_offset_ = kFixedHeaderSize;
328 0 : payload_size_ = 0;
329 0 : padding_size_ = 0;
330 0 : extensions_size_ = 0;
331 0 : for (ExtensionInfo& location : extension_entries_) {
332 0 : location.offset = 0;
333 0 : location.length = 0;
334 : }
335 :
336 0 : memset(WriteAt(0), 0, kFixedHeaderSize);
337 0 : buffer_.SetSize(kFixedHeaderSize);
338 0 : WriteAt(0, kRtpVersion << 6);
339 0 : }
340 :
341 0 : bool Packet::ParseBuffer(const uint8_t* buffer, size_t size) {
342 0 : if (size < kFixedHeaderSize) {
343 0 : return false;
344 : }
345 0 : const uint8_t version = buffer[0] >> 6;
346 0 : if (version != kRtpVersion) {
347 0 : return false;
348 : }
349 0 : const bool has_padding = (buffer[0] & 0x20) != 0;
350 0 : const bool has_extension = (buffer[0] & 0x10) != 0;
351 0 : const uint8_t number_of_crcs = buffer[0] & 0x0f;
352 0 : marker_ = (buffer[1] & 0x80) != 0;
353 0 : payload_type_ = buffer[1] & 0x7f;
354 :
355 0 : sequence_number_ = ByteReader<uint16_t>::ReadBigEndian(&buffer[2]);
356 0 : timestamp_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]);
357 0 : ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]);
358 0 : if (size < kFixedHeaderSize + number_of_crcs * 4) {
359 0 : return false;
360 : }
361 0 : payload_offset_ = kFixedHeaderSize + number_of_crcs * 4;
362 :
363 0 : if (has_padding) {
364 0 : padding_size_ = buffer[size - 1];
365 0 : if (padding_size_ == 0) {
366 0 : LOG(LS_WARNING) << "Padding was set, but padding size is zero";
367 0 : return false;
368 : }
369 : } else {
370 0 : padding_size_ = 0;
371 : }
372 :
373 0 : extensions_size_ = 0;
374 0 : for (ExtensionInfo& location : extension_entries_) {
375 0 : location.offset = 0;
376 0 : location.length = 0;
377 : }
378 0 : 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 0 : size_t extension_offset = payload_offset_ + 4;
389 0 : if (extension_offset > size) {
390 0 : return false;
391 : }
392 : uint16_t profile =
393 0 : ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_]);
394 : size_t extensions_capacity =
395 0 : ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_ + 2]);
396 0 : extensions_capacity *= 4;
397 0 : if (extension_offset + extensions_capacity > size) {
398 0 : return false;
399 : }
400 0 : if (profile != kOneByteExtensionId) {
401 0 : LOG(LS_WARNING) << "Unsupported rtp extension " << profile;
402 : } else {
403 0 : constexpr uint8_t kPaddingId = 0;
404 0 : constexpr uint8_t kReservedId = 15;
405 0 : while (extensions_size_ + kOneByteHeaderSize < extensions_capacity) {
406 0 : int id = buffer[extension_offset + extensions_size_] >> 4;
407 0 : if (id == kReservedId) {
408 0 : break;
409 0 : } else if (id == kPaddingId) {
410 0 : extensions_size_++;
411 0 : continue;
412 : }
413 : uint8_t length =
414 0 : 1 + (buffer[extension_offset + extensions_size_] & 0xf);
415 0 : if (extensions_size_ + kOneByteHeaderSize + length >
416 : extensions_capacity) {
417 0 : LOG(LS_WARNING) << "Oversized rtp header extension.";
418 0 : break;
419 : }
420 :
421 0 : size_t idx = id - 1;
422 0 : if (extension_entries_[idx].length != 0) {
423 0 : LOG(LS_VERBOSE) << "Duplicate rtp header extension id " << id
424 0 : << ". Overwriting.";
425 : }
426 :
427 0 : extensions_size_ += kOneByteHeaderSize;
428 0 : extension_entries_[idx].offset = extension_offset + extensions_size_;
429 0 : extension_entries_[idx].length = length;
430 0 : extensions_size_ += length;
431 : }
432 : }
433 0 : payload_offset_ = extension_offset + extensions_capacity;
434 : }
435 :
436 0 : if (payload_offset_ + padding_size_ > size) {
437 0 : return false;
438 : }
439 0 : payload_size_ = size - payload_offset_ - padding_size_;
440 0 : return true;
441 : }
442 :
443 0 : bool Packet::FindExtension(ExtensionType type,
444 : uint8_t length,
445 : uint16_t* offset) const {
446 0 : RTC_DCHECK(offset);
447 0 : for (const ExtensionInfo& extension : extension_entries_) {
448 0 : if (extension.type == type) {
449 0 : if (extension.length == 0) {
450 : // Extension is registered but not set.
451 0 : return false;
452 : }
453 0 : if (length != extension.length) {
454 0 : LOG(LS_WARNING) << "Length mismatch for extension '" << type
455 0 : << "': expected " << static_cast<int>(length)
456 0 : << ", received " << static_cast<int>(extension.length);
457 0 : return false;
458 : }
459 0 : *offset = extension.offset;
460 0 : return true;
461 : }
462 : }
463 0 : return false;
464 : }
465 :
466 0 : bool Packet::AllocateExtension(ExtensionType type,
467 : uint8_t length,
468 : uint16_t* offset) {
469 0 : uint8_t extension_id = ExtensionManager::kInvalidId;
470 0 : ExtensionInfo* extension_entry = nullptr;
471 0 : for (size_t i = 0; i < kMaxExtensionHeaders; ++i) {
472 0 : if (extension_entries_[i].type == type) {
473 0 : extension_id = i + 1;
474 0 : extension_entry = &extension_entries_[i];
475 0 : break;
476 : }
477 : }
478 :
479 0 : if (!extension_entry) // Extension not registered.
480 0 : return false;
481 :
482 0 : if (extension_entry->length != 0) { // Already allocated.
483 0 : if (length != extension_entry->length) {
484 0 : LOG(LS_WARNING) << "Length mismatch for extension '" << type
485 0 : << "': expected " << static_cast<int>(length)
486 0 : << ", received "
487 0 : << static_cast<int>(extension_entry->length);
488 0 : return false;
489 : }
490 0 : *offset = extension_entry->offset;
491 0 : return true;
492 : }
493 :
494 : // Can't add new extension after payload/padding was set.
495 0 : if (payload_size_ > 0) {
496 0 : return false;
497 : }
498 0 : if (padding_size_ > 0) {
499 0 : return false;
500 : }
501 :
502 0 : RTC_DCHECK_GT(length, 0);
503 0 : RTC_DCHECK_LE(length, 16);
504 :
505 0 : size_t num_csrc = data()[0] & 0x0F;
506 0 : size_t extensions_offset = kFixedHeaderSize + (num_csrc * 4) + 4;
507 0 : if (extensions_offset + extensions_size_ + kOneByteHeaderSize + length >
508 0 : capacity()) {
509 0 : LOG(LS_WARNING) << "Extension cannot be registered: "
510 0 : "Not enough space left in buffer.";
511 0 : return false;
512 : }
513 :
514 : uint16_t new_extensions_size =
515 0 : extensions_size_ + kOneByteHeaderSize + length;
516 : uint16_t extensions_words =
517 0 : (new_extensions_size + 3) / 4; // Wrap up to 32bit.
518 :
519 : // All checks passed, write down the extension.
520 0 : if (extensions_size_ == 0) {
521 0 : RTC_DCHECK_EQ(payload_offset_, kFixedHeaderSize + (num_csrc * 4));
522 0 : WriteAt(0, data()[0] | 0x10); // Set extension bit.
523 : // Profile specific ID always set to OneByteExtensionHeader.
524 0 : ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 4),
525 0 : kOneByteExtensionId);
526 : }
527 :
528 0 : WriteAt(extensions_offset + extensions_size_,
529 0 : (extension_id << 4) | (length - 1));
530 :
531 0 : extension_entry->length = length;
532 0 : *offset = extensions_offset + kOneByteHeaderSize + extensions_size_;
533 0 : extension_entry->offset = *offset;
534 0 : extensions_size_ = new_extensions_size;
535 :
536 : // Update header length field.
537 0 : ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 2),
538 0 : extensions_words);
539 : // Fill extension padding place with zeroes.
540 0 : size_t extension_padding_size = 4 * extensions_words - extensions_size_;
541 0 : memset(WriteAt(extensions_offset + extensions_size_), 0,
542 0 : extension_padding_size);
543 0 : payload_offset_ = extensions_offset + 4 * extensions_words;
544 0 : buffer_.SetSize(payload_offset_);
545 0 : return true;
546 : }
547 :
548 0 : uint8_t* Packet::WriteAt(size_t offset) {
549 0 : return buffer_.data() + offset;
550 : }
551 :
552 0 : void Packet::WriteAt(size_t offset, uint8_t byte) {
553 0 : buffer_.data()[offset] = byte;
554 0 : }
555 :
556 : } // namespace rtp
557 : } // namespace webrtc
|