Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1026)

Side by Side Diff: webrtc/modules/rtp_rtcp/source/rtp_packet.cc

Issue 1841453004: RtpPacket class introduced. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: style fixes Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
15 #include "webrtc/base/checks.h"
16 #include "webrtc/base/logging.h"
17 #include "webrtc/base/random.h"
18 #include "webrtc/common_types.h"
19 #include "webrtc/modules/rtp_rtcp/source/rtp_header_extension.h"
20 #include "webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h"
21 #include "webrtc/modules/rtp_rtcp/source/byte_io.h"
22
23 namespace webrtc {
24 namespace rtp {
25 namespace {
26 const size_t kFixedHeaderSize = 12;
27 const uint8_t kRtpVersion = 2;
28 const uint16_t kOneByteExtensionId = 0xBEDE;
29 const size_t kDefaultPacketSize = 1500;
30 } // namespace
31 // 0 1 2 3
32 // 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
33 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
34 // |V=2|P|X| CC |M| PT | sequence number |
35 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36 // | timestamp |
37 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38 // | synchronization source (SSRC) identifier |
39 // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
40 // | Contributing source (CSRC) identifiers |
41 // | .... |
42 // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
43 // |One-byte eXtensions id = 0xbede| length in 32bits |
44 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
45 // | Extensions |
46 // | .... |
47 // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
48 // | Payload |
49 // | .... : padding... |
50 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51 // | padding | Padding size |
52 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
53 Packet::Packet(const ExtensionManager* extensions)
54 : extensions_(extensions), buffer_(kDefaultPacketSize) {
55 Clear();
56 }
57
58 Packet::Packet(const ExtensionManager* extensions, size_t capacity)
59 : extensions_(extensions), buffer_(capacity) {
60 RTC_DCHECK_GE(capacity, kFixedHeaderSize);
61 Clear();
62 }
63
64 Packet::~Packet() {}
65
66 void Packet::SetExtensionManager(const ExtensionManager* extensions) {
67 RTC_DCHECK(extensions);
68 extensions_ = extensions;
69 for (size_t i = 0; i < num_extensions_; ++i) {
70 uint8_t id = data()[extension_entries_[i].offset - 1] >> 4;
71 extension_entries_[i].type = extensions_->GetType(id);
72 }
73 }
74
75 bool Packet::Parse(const uint8_t* buffer, size_t buffer_size) {
76 if (!ParseBuffer(buffer, buffer_size)) {
77 Clear();
78 return false;
79 }
80 RTC_DCHECK_EQ(size(), buffer_size);
81 buffer_.SetData(buffer, buffer_size);
82 return true;
83 }
84
85 bool Packet::Parse(rtc::Buffer buffer) {
86 if (!ParseBuffer(buffer.data(), buffer.size())) {
87 Clear();
88 return false;
89 }
90 RTC_DCHECK_EQ(size(), buffer.size());
91 buffer_ = std::move(buffer);
92 return true;
93 }
94
95 bool Packet::Marker() const {
96 RTC_DCHECK_EQ(marker_, (data()[1] & 0x80) != 0);
97 return marker_;
98 }
99
100 uint8_t Packet::PayloadType() const {
101 RTC_DCHECK_EQ(payload_type_, data()[1] & 0x7f);
102 return payload_type_;
103 }
104
105 uint16_t Packet::SequenceNumber() const {
106 RTC_DCHECK_EQ(sequence_number_,
107 ByteReader<uint16_t>::ReadBigEndian(data() + 2));
108 return sequence_number_;
109 }
110
111 uint32_t Packet::Timestamp() const {
112 RTC_DCHECK_EQ(sequence_number_,
113 ByteReader<uint32_t>::ReadBigEndian(data() + 4));
114 return timestamp_;
115 }
116
117 uint32_t Packet::Ssrc() const {
118 RTC_DCHECK_EQ(sequence_number_,
119 ByteReader<uint32_t>::ReadBigEndian(data() + 8));
120 return ssrc_;
121 }
122
123 std::vector<uint32_t> Packet::Csrcs() const {
124 size_t num_csrc = data()[0] & 0x0F;
125 RTC_DCHECK_GE(capacity(), kFixedHeaderSize + num_csrc * 4);
126 std::vector<uint32_t> csrcs(num_csrc);
127 for (size_t i = 0; i < num_csrc; ++i) {
128 csrcs[i] =
129 ByteReader<uint32_t>::ReadBigEndian(&data()[kFixedHeaderSize + i * 4]);
130 }
131 return csrcs;
132 }
133
134 void Packet::GetHeader(RTPHeader* header) const {
135 header->markerBit = Marker();
136 header->payloadType = PayloadType();
137 header->sequenceNumber = SequenceNumber();
138 header->timestamp = Timestamp();
139 header->ssrc = Ssrc();
140 std::vector<uint32_t> csrcs = Csrcs();
141 header->numCSRCs = csrcs.size();
142 for (size_t i = 0; i < csrcs.size(); ++i) {
143 header->arrOfCSRCs[i] = csrcs[i];
144 }
145 header->paddingLength = padding_size();
146 header->headerLength = headers_size();
147 header->payload_type_frequency = 0;
148 header->extension.hasTransmissionTimeOffset =
149 GetExtension<TransmissionOffset>(
150 &header->extension.transmissionTimeOffset);
151 header->extension.hasAbsoluteSendTime =
152 GetExtension<AbsoluteSendTime>(&header->extension.absoluteSendTime);
153 header->extension.hasTransportSequenceNumber =
154 GetExtension<TransportSequenceNumber>(
155 &header->extension.transportSequenceNumber);
156 header->extension.hasAudioLevel = GetExtension<AudioLevel>(
157 &header->extension.voiceActivity, &header->extension.audioLevel);
158 header->extension.hasVideoRotation =
159 GetExtension<VideoOrientation>(&header->extension.videoRotation);
160 }
161
162 size_t Packet::headers_size() const {
163 return payload_offset_;
164 }
165
166 size_t Packet::payload_size() const {
167 return payload_size_;
168 }
169
170 size_t Packet::padding_size() const {
171 return padding_size_;
172 }
173
174 const uint8_t* Packet::payload() const {
175 return data() + payload_offset_;
176 }
177
178 size_t Packet::capacity() const {
179 return buffer_.capacity();
180 }
181
182 size_t Packet::size() const {
183 return payload_offset_ + payload_size_ + padding_size_;
184 }
185
186 const uint8_t* Packet::data() const {
187 return buffer_.data();
188 }
189
190 size_t Packet::FreeCapacity() const {
191 return capacity() - size();
192 }
193
194 size_t Packet::MaxPayloadSize() const {
195 return capacity() - payload_offset_;
196 }
197
198 void Packet::CopyHeader(const Packet& packet) {
199 RTC_DCHECK_GE(capacity(), packet.headers_size());
200
201 marker_ = packet.marker_;
202 payload_type_ = packet.payload_type_;
203 sequence_number_ = packet.sequence_number_;
204 timestamp_ = packet.timestamp_;
205 ssrc_ = packet.ssrc_;
206 payload_offset_ = packet.payload_offset_;
207 num_extensions_ = packet.num_extensions_;
208 for (size_t i = 0; i < num_extensions_; ++i) {
209 extension_entries_[i] = packet.extension_entries_[i];
210 }
211 extensions_size_ = packet.extensions_size_;
212 buffer_.SetData(packet.data(), packet.headers_size());
213 // Reset payload and padding.
214 payload_size_ = 0;
215 padding_size_ = 0;
216 }
217
218 void Packet::SetMarker(bool marker_bit) {
219 marker_ = marker_bit;
220 if (marker_) {
221 WriteAt(1, data()[1] | 0x80);
stefan-webrtc 2016/04/14 13:00:29 Would it make sense to instead have a Serialize fu
sprang_webrtc 2016/04/14 13:41:50 I tried that once it quickly became difficult, esp
danilchap 2016/04/14 14:13:19 Packet class is all about serializing/deserializin
222 } else {
223 WriteAt(1, data()[1] & 0x7F);
224 }
225 }
226
227 void Packet::SetPayloadType(uint8_t payload_type) {
228 RTC_DCHECK_LE(payload_type, 0x7Fu);
229 payload_type_ = payload_type;
230 WriteAt(1, (data()[1] & 0x80) | payload_type);
231 }
232
233 void Packet::SetSequenceNumber(uint16_t seq_no) {
234 sequence_number_ = seq_no;
235 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(2), seq_no);
236 }
237
238 void Packet::SetTimestamp(uint32_t timestamp) {
239 timestamp_ = timestamp;
240 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(4), timestamp);
241 }
242
243 void Packet::SetSsrc(uint32_t ssrc) {
244 ssrc_ = ssrc;
245 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(8), ssrc);
246 }
247
248 void Packet::SetCsrcs(const std::vector<uint32_t>& csrcs) {
249 RTC_DCHECK_EQ(num_extensions_, 0u);
250 RTC_DCHECK_EQ(payload_size_, 0u);
251 RTC_DCHECK_EQ(padding_size_, 0u);
252 RTC_DCHECK_LE(csrcs.size(), 0x0fu);
253 RTC_DCHECK_LE(kFixedHeaderSize + 4 * csrcs.size(), capacity());
254 payload_offset_ = kFixedHeaderSize + 4 * csrcs.size();
255 WriteAt(0, (data()[0] & 0xF0) | csrcs.size());
256 size_t offset = kFixedHeaderSize;
257 for (uint32_t csrc : csrcs) {
258 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(offset), csrc);
259 offset += 4;
260 }
261 }
262
263 uint8_t* Packet::AllocatePayload(size_t size_bytes) {
264 RTC_DCHECK_EQ(padding_size_, 0u);
265 if (payload_offset_ + size_bytes > capacity()) {
266 LOG(LS_WARNING) << "Cannot set payload, not enough space in buffer.";
267 return nullptr;
268 }
269 payload_size_ = size_bytes;
270 return WriteAt(payload_offset_);
271 }
272
273 void Packet::SetPayloadSize(size_t size_bytes) {
274 RTC_DCHECK_EQ(padding_size_, 0u);
275 RTC_DCHECK_LE(size_bytes, payload_size_);
276 payload_size_ = size_bytes;
277 }
278
279 bool Packet::SetPadding(uint8_t size_bytes, Random* random) {
280 RTC_DCHECK(random);
281 if (payload_offset_ + payload_size_ + size_bytes > capacity()) {
282 LOG(LS_WARNING) << "Cannot set padding size " << size_bytes << ", only "
283 << (capacity() - payload_offset_ - payload_size_)
284 << " bytes left in buffer.";
285 return false;
286 }
287 padding_size_ = size_bytes;
288 if (padding_size_ > 0) {
289 size_t padding_offset = payload_offset_ + payload_size_;
290 size_t padding_end = padding_offset + padding_size_;
291 for (size_t offset = padding_offset; offset < padding_end - 1; ++offset) {
292 WriteAt(offset, random->Rand<uint8_t>());
293 }
294 WriteAt(padding_end - 1, padding_size_);
295 WriteAt(0, data()[0] | 0x20); // Set padding bit.
296 } else {
297 WriteAt(0, data()[0] & ~0x20); // Clear padding bit.
298 }
299 return true;
300 }
301
302 void Packet::Clear() {
303 marker_ = false;
304 payload_type_ = 0;
305 sequence_number_ = 0;
306 timestamp_ = 0;
307 ssrc_ = 0;
308 payload_offset_ = kFixedHeaderSize;
309 payload_size_ = 0;
310 padding_size_ = 0;
311 num_extensions_ = 0;
312 extensions_size_ = 0;
313
314 memset(WriteAt(0), 0, kFixedHeaderSize);
315 WriteAt(0, kRtpVersion << 6);
316 }
317
318 bool Packet::ParseBuffer(const uint8_t* buffer, size_t size) {
319 if (size < kFixedHeaderSize) {
320 return false;
321 }
322 const uint8_t version = buffer[0] >> 6;
323 if (version != kRtpVersion) {
324 return false;
325 }
326 const bool has_padding = (buffer[0] & 0x20) != 0;
327 // eXtension
sprang_webrtc 2016/04/14 13:41:50 remove comment
danilchap 2016/04/14 14:13:19 Done.
328 const bool has_extension = (buffer[0] & 0x10) != 0;
329 const uint8_t number_of_crcs = buffer[0] & 0x0f;
330 marker_ = (buffer[1] & 0x80) != 0;
331 payload_type_ = buffer[1] & 0x7f;
332
333 sequence_number_ = ByteReader<uint16_t>::ReadBigEndian(&buffer[2]);
334 timestamp_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]);
335 ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]);
336 if (size < kFixedHeaderSize + number_of_crcs * 4) {
337 return false;
338 }
339 payload_offset_ = kFixedHeaderSize + number_of_crcs * 4;
340
341 if (has_padding) {
342 padding_size_ = buffer[size - 1];
343 if (padding_size_ == 0) {
344 LOG(LS_WARNING) << "Padding was set, but padding size is zero";
345 return false;
346 }
347 } else {
348 padding_size_ = 0;
349 }
350
351 num_extensions_ = 0;
352 extensions_size_ = 0;
353 if (has_extension) {
354 /* RTP header extension, RFC 3550.
355 0 1 2 3
356 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
357 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
358 | defined by profile | length |
359 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
360 | header extension |
361 | .... |
362 */
363 size_t extension_offset = payload_offset_ + 4;
364 if (extension_offset > size) {
365 return false;
366 }
367 uint16_t profile =
368 ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_]);
369 size_t extensions_capacity =
370 ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_ + 2]);
371 extensions_capacity *= 4;
372 if (extension_offset + extensions_capacity > size) {
373 return false;
374 }
375 if (profile == kOneByteExtensionId) {
376 const size_t kOneByteHeaderSize = 1;
377 const uint8_t kPaddingId = 0;
378 const uint8_t kReservedId = 15;
379 while (extensions_size_ + kOneByteHeaderSize < extensions_capacity) {
380 uint8_t id = buffer[extension_offset + extensions_size_] >> 4;
381 if (id == kReservedId) {
382 break;
383 } else if (id == kPaddingId) {
384 extensions_size_++;
385 continue;
386 }
387 uint8_t length =
388 1 + (buffer[extension_offset + extensions_size_] & 0xf);
389 extensions_size_ += kOneByteHeaderSize;
390 if (num_extensions_ >= kMaxExtensionHeaders)
philipel 2016/04/14 11:15:16 {} :)
sprang_webrtc 2016/04/14 13:41:50 Should we really silently ignore this? maybe log w
danilchap 2016/04/14 14:13:19 Done: so many extensions means packet is invalid,
391 break;
392 extension_entries_[num_extensions_].type =
393 extensions_ ? extensions_->GetType(id)
394 : ExtensionManager::kInvalidType;
395 extension_entries_[num_extensions_].length = length;
396 extension_entries_[num_extensions_].offset =
397 extension_offset + extensions_size_;
398 num_extensions_++;
399 extensions_size_ += length;
400 }
401 }
sprang_webrtc 2016/04/14 13:41:50 Log warning if profile isn't one byte extension he
danilchap 2016/04/14 14:13:19 Done.
402 payload_offset_ = extension_offset + extensions_capacity;
403 }
404
405 if (payload_offset_ + padding_size_ > size) {
406 return false;
407 }
408 payload_size_ = size - payload_offset_ - padding_size_;
409 return true;
410 }
411
412 bool Packet::FindExtension(ExtensionType type,
413 uint8_t length,
414 uint16_t* offset) const {
415 RTC_DCHECK(offset);
416 for (size_t i = 0; i < num_extensions_; ++i) {
417 if (extension_entries_[i].type == type) {
418 RTC_CHECK_EQ(length, extension_entries_[i].length)
419 << "Length mismatch for extension '" << type << "'"
420 << "should be " << length << ", received "
421 << extension_entries_[i].length;
422 *offset = extension_entries_[i].offset;
423 return true;
424 }
425 }
426 return false;
427 }
428
429 bool Packet::AllocateExtension(ExtensionType type,
430 uint8_t length,
431 uint16_t* offset) {
432 if (!extensions_) {
433 return false;
434 }
435 if (FindExtension(type, length, offset)) {
436 return true;
437 }
438
439 // Can't add new extension after payload/padding was set.
440 if (payload_size_ > 0) {
441 return false;
442 }
443 if (padding_size_ > 0) {
444 return false;
445 }
446
447 uint8_t extension_id = extensions_->GetId(type);
448 if (extension_id == ExtensionManager::kInvalidId) {
449 return false;
450 }
451 RTC_DCHECK_GT(length, 0u);
452 RTC_DCHECK_LE(length, 16u);
453
454 size_t num_csrc = data()[0] & 0x0F;
455 size_t extensions_offset = kFixedHeaderSize + (num_csrc * 4) + 4;
456 const uint8_t kExtensionHeaderSize = 1; // Using one-byte extensions only.
457 if (extensions_offset + extensions_size_ + kExtensionHeaderSize + length >
458 capacity()) {
459 LOG(LS_WARNING) << "Extension cannot be registered: "
460 "Not enough space left in buffer.";
461 return false;
462 }
463
464 uint16_t new_extensions_size =
465 extensions_size_ + kExtensionHeaderSize + length;
466 uint16_t extensions_words =
467 (new_extensions_size + 3) / 4; // Wrap up to 32bit.
468 if (extensions_words > 0xFFFF) {
469 LOG(LS_WARNING) << "Too much extension header data, exceeds 2^16 DWORDS.";
470 return false;
471 }
472
473 // All checks passed, write down the extension.
474 if (num_extensions_ == 0) {
475 RTC_DCHECK_EQ(payload_offset_, kFixedHeaderSize + (num_csrc * 4));
476 RTC_DCHECK_EQ(extensions_size_, 0);
477 WriteAt(0, data()[0] | 0x10); // Set extension bit.
478 // Profile specific ID always set to OneByteExtensionHeader.
479 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 4),
480 kOneByteExtensionId);
481 }
482
483 WriteAt(extensions_offset + extensions_size_,
484 (extension_id << 4) | (length - 1));
485 RTC_DCHECK_LT(num_extensions_, kMaxExtensionHeaders);
486 extension_entries_[num_extensions_].type = type;
487 extension_entries_[num_extensions_].length = length;
488 *offset = extensions_offset + kExtensionHeaderSize + extensions_size_;
489 extension_entries_[num_extensions_].offset = *offset;
490 ++num_extensions_;
491 extensions_size_ = new_extensions_size;
492
493 // Update header length field.
494 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 2),
495 extensions_words);
496 // Fill extension padding place with zeroes.
497 size_t extension_padding_size = 4 * extensions_words - extensions_size_;
498 memset(WriteAt(extensions_offset + extensions_size_), 0,
499 extension_padding_size);
500 payload_offset_ = extensions_offset + 4 * extensions_words;
501 return true;
502 }
503
504 uint8_t* Packet::WriteAt(size_t offset) {
505 return buffer_.data() + offset;
506 }
507
508 void Packet::WriteAt(size_t offset, uint8_t byte) {
509 buffer_.data()[offset] = byte;
510 }
511
512 } // namespace rtp
513 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698