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

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: 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/modules/rtp_rtcp/source/rtp_header_extension.h"
19 #include "webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h"
20 #include "webrtc/modules/rtp_rtcp/source/byte_io.h"
21
22 namespace webrtc {
23 namespace rtp {
24 namespace {
25 const size_t kFixedHeaderSize = 12;
26 const uint8_t kRtpVersion = 2;
27 const uint16_t kOneByteExtensionId = 0xBEDE;
28 const size_t kDefaultPacketSize = 1500;
29 } // namespace
30 // 0 1 2 3
31 // 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
32 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
33 // |V=2|P|X| CC |M| PT | sequence number |
34 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
35 // | timestamp |
36 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
37 // | synchronization source (SSRC) identifier |
38 // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
39 // | Contributing source (CSRC) identifiers |
40 // | .... |
41 // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
42 // |One-byte eXtensions id = 0xbede| length in 32bits |
43 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44 // | Extensions |
45 // | .... |
46 // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
47 // | Payload |
48 // | .... : padding... |
49 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
50 // | padding | Padding size |
51 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
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 bool Packet::Parse(const uint8_t* buffer, size_t buffer_size) {
67 if (!ParseBuffer(buffer, buffer_size)) {
68 Clear();
69 return false;
70 }
71 RTC_DCHECK_EQ(size(), buffer_size);
72 buffer_.SetData(buffer, buffer_size);
73 return true;
74 }
75
76 bool Packet::Parse(rtc::Buffer buffer) {
77 if (!ParseBuffer(buffer.data(), buffer.size())) {
78 Clear();
79 return false;
80 }
81 RTC_DCHECK_EQ(size(), buffer.size());
82 buffer_ = std::move(buffer);
83 return true;
84 }
85
86 bool Packet::Marker() const {
philipel 2016/04/13 12:01:19 Functions with very low cost (if it is reasonable
danilchap 2016/04/13 16:18:33 I'm not sure current implementation would stay. Ma
philipel 2016/04/14 10:32:02 Acknowledged.
87 return marker_;
88 }
89
90 uint8_t Packet::PayloadType() const {
philipel 2016/04/13 12:01:19 payload_type()
91 return payload_type_;
92 }
93
94 uint16_t Packet::SequenceNumber() const {
95 return sequence_number_;
philipel 2016/04/13 12:01:18 sequence_number()
96 }
97
98 uint32_t Packet::Timestamp() const {
philipel 2016/04/13 12:01:18 timestamp()
99 return timestamp_;
100 }
101
102 uint32_t Packet::Ssrc() const {
philipel 2016/04/13 12:01:19 ssrc()
103 return ssrc_;
104 }
105
106 std::vector<uint32_t> Packet::Csrcs() const {
107 size_t num_csrc = data()[0] & 0x0F;
108 std::vector<uint32_t> csrcs(num_csrc);
109 for (size_t i = 0; i < num_csrc; ++i)
110 csrcs[i] = ByteReader<uint32_t>::ReadBigEndian(&data()[12 + 4 * i]);
111 return csrcs;
112 }
113
114 void Packet::GetHeader(RTPHeader* header) const {
115 header->markerBit = Marker();
116 header->payloadType = PayloadType();
117 header->sequenceNumber = SequenceNumber();
118 header->timestamp = Timestamp();
119 header->ssrc = Ssrc();
120 std::vector<uint32_t> csrcs = Csrcs();
121 header->numCSRCs = csrcs.size();
122 for (size_t i = 0; i < csrcs.size(); ++i)
123 header->arrOfCSRCs[i] = csrcs[i];
124 header->paddingLength = PaddingSize();
125 header->headerLength = HeadersSize();
126 header->payload_type_frequency = 0;
127 header->extension.hasTransmissionTimeOffset =
128 GetExtension<TransmissionOffset>(
129 &header->extension.transmissionTimeOffset);
130 header->extension.hasAbsoluteSendTime =
131 GetExtension<AbsoluteSendTime>(&header->extension.absoluteSendTime);
132 header->extension.hasTransportSequenceNumber =
133 GetExtension<TransportSequenceNumber>(
134 &header->extension.transportSequenceNumber);
135 header->extension.hasAudioLevel = GetExtension<AudioLevel>(
136 &header->extension.voiceActivity, &header->extension.audioLevel);
137 header->extension.hasVideoRotation =
138 GetExtension<VideoOrientation>(&header->extension.videoRotation);
139 }
140
141 size_t Packet::HeadersSize() const {
philipel 2016/04/13 12:01:19 header_size()
danilchap 2016/04/13 16:18:34 Done.
142 return payload_offset_;
143 }
144
145 size_t Packet::PayloadSize() const {
philipel 2016/04/13 12:01:19 payload_size()
danilchap 2016/04/13 16:18:34 Done.
146 return payload_size_;
147 }
148
149 size_t Packet::PaddingSize() const {
philipel 2016/04/13 12:01:18 padding_size()
danilchap 2016/04/13 16:18:34 Done.
150 return padding_size_;
151 }
152
153 const uint8_t* Packet::Payload() const {
154 return data() + payload_offset_;
155 }
156
157 size_t Packet::capacity() const {
158 return buffer_.capacity();
159 }
160
161 size_t Packet::size() const {
162 return payload_offset_ + payload_size_ + padding_size_;
163 }
164
165 const uint8_t* Packet::data() const {
166 return buffer_.data();
167 }
168
169 void Packet::CopyHeader(const Packet& packet) {
170 RTC_DCHECK_GE(capacity(), packet.HeadersSize());
171
172 marker_ = packet.marker_;
173 payload_type_ = packet.payload_type_;
174 sequence_number_ = packet.sequence_number_;
175 timestamp_ = packet.timestamp_;
176 ssrc_ = packet.ssrc_;
177 payload_offset_ = packet.payload_offset_;
178 num_extensions_ = packet.num_extensions_;
179 for (size_t i = 0; i < num_extensions_; ++i)
180 extension_entries_[i] = packet.extension_entries_[i];
181 extensions_size_ = packet.extensions_size_;
182 buffer_.SetData(packet.data(), packet.HeadersSize());
183 // Reset payload and padding.
184 payload_size_ = 0;
185 padding_size_ = 0;
186 }
187
188 void Packet::SetMarker(bool marker_bit) {
189 marker_ = marker_bit;
190 if (marker_) {
191 WriteAt(1, data()[1] | 0x80);
192 } else {
193 WriteAt(1, data()[1] & 0x7F);
194 }
195 }
196
197 void Packet::SetPayloadType(uint8_t payload_type) {
198 RTC_DCHECK_LE(payload_type, 0x7Fu);
199 payload_type_ = payload_type;
200 WriteAt(1, (data()[1] & 0x80) | payload_type);
201 }
202
203 void Packet::SetSequenceNumber(uint16_t seq_no) {
204 sequence_number_ = seq_no;
205 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(2), seq_no);
206 }
207
208 void Packet::SetTimestamp(uint32_t timestamp) {
209 timestamp_ = timestamp;
210 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(4), timestamp);
211 }
212
213 void Packet::SetSsrc(uint32_t ssrc) {
214 ssrc_ = ssrc;
215 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(8), ssrc);
216 }
217
218 void Packet::SetCsrcs(const std::vector<uint32_t>& csrcs) {
219 RTC_DCHECK_EQ(num_extensions_, 0u);
220 RTC_DCHECK_EQ(payload_size_, 0u);
221 RTC_DCHECK_EQ(padding_size_, 0u);
222 RTC_DCHECK_LE(csrcs.size(), 0x0fu);
223 RTC_DCHECK_LE(kFixedHeaderSize + 4 * csrcs.size(), capacity());
224 payload_offset_ = kFixedHeaderSize + 4 * csrcs.size();
225 WriteAt(0, (data()[0] & 0xF0) | csrcs.size());
226 size_t offset = kFixedHeaderSize;
227 for (uint32_t csrc : csrcs) {
228 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(offset), csrc);
229 offset += 4;
230 }
231 }
232
233 uint8_t* Packet::AllocatePayload(size_t size_bytes) {
234 RTC_DCHECK_EQ(padding_size_, 0u);
235 if (payload_offset_ + size_bytes > capacity()) {
236 LOG(LS_WARNING) << "Cannot set payload, not enough space in buffer.";
237 return nullptr;
238 }
239 payload_size_ = size_bytes;
240 return WriteAt(payload_offset_);
241 }
242
243 void Packet::SetPayloadSize(size_t size_bytes) {
244 RTC_DCHECK_EQ(padding_size_, 0u);
245 RTC_DCHECK_LE(size_bytes, payload_size_);
246 payload_size_ = size_bytes;
247 }
248
249 bool Packet::SetPadding(uint8_t size_bytes, Random* random) {
250 RTC_DCHECK(random);
251 if (payload_offset_ + payload_size_ + size_bytes > capacity()) {
252 LOG(LS_WARNING) << "Cannot set padding size " << size_bytes << ", only "
253 << (capacity() - payload_offset_ - payload_size_)
254 << " left in buffer.";
philipel 2016/04/13 12:01:18 " bytes left in buffer.";
danilchap 2016/04/13 16:18:33 Done.
255 return false;
256 }
257 padding_size_ = size_bytes;
258 if (padding_size_ > 0) {
259 auto padding_words = std::div(padding_size_, 4);
260 size_t offset = payload_offset_ + payload_size_;
261 size_t padding_end = offset + padding_size_;
262 for (int i = 0; i < padding_words.quot; ++i, offset += 4) {
263 *reinterpret_cast<uint32_t*>(WriteAt(offset)) = random->Rand<uint32_t>();
terelius 2016/04/13 13:17:00 Do you know that the destination is aligned to a 3
danilchap 2016/04/13 16:18:34 True, though usually it is, this code can't assume
264 }
265 for (; offset < padding_end - 1; ++offset) {
266 WriteAt(offset, random->Rand<uint8_t>());
philipel 2016/04/13 12:01:19 remove {}
terelius 2016/04/13 13:17:00 I believe different parts of the code use differen
philipel 2016/04/14 10:32:02 True, but then other parts of the code has to be u
danilchap 2016/04/14 11:07:49 Good point! Updated.
267 }
268 WriteAt(padding_end - 1, size_bytes);
269 WriteAt(0, data()[0] | 0x20); // Set padding bit.
270 } else {
271 WriteAt(0, data()[0] & ~0x20); // Clear padding bit.
272 }
273 return true;
274 }
275
276 void Packet::Clear() {
277 marker_ = false;
278 payload_type_ = 0;
279 sequence_number_ = 0;
280 timestamp_ = 0;
281 ssrc_ = 0;
282 payload_offset_ = kFixedHeaderSize;
283 payload_size_ = 0;
284 padding_size_ = 0;
285 num_extensions_ = 0;
286 extensions_size_ = 0;
287
288 memset(WriteAt(0), 0, kFixedHeaderSize);
289 WriteAt(0, kRtpVersion << 6);
290 }
291
292 bool Packet::ParseBuffer(const uint8_t* buffer, size_t size) {
293 if (size < kFixedHeaderSize)
294 return false;
295 const uint8_t version = buffer[0] >> 6;
296 if (version != kRtpVersion)
297 return false;
298 const bool has_padding = (buffer[0] & 0x20) != 0;
299 // eXtension
300 const bool has_extension = (buffer[0] & 0x10) != 0;
301 const uint8_t number_of_crcs = buffer[0] & 0x0f;
302 marker_ = (buffer[1] & 0x80) != 0;
303 payload_type_ = buffer[1] & 0x7f;
304
305 sequence_number_ = ByteReader<uint16_t>::ReadBigEndian(&buffer[2]);
306 timestamp_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]);
307 ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]);
308 if (size < kFixedHeaderSize + number_of_crcs * 4)
309 return false;
310 payload_offset_ = kFixedHeaderSize + number_of_crcs * 4;
311
312 if (has_padding) {
313 padding_size_ = buffer[size - 1];
314 if (padding_size_ == 0) {
315 LOG(LS_WARNING) << "Padding was set, but padding size is zero";
316 return false;
317 }
318 } else {
319 padding_size_ = 0;
320 }
321
322 num_extensions_ = 0;
323 extensions_size_ = 0;
324 if (has_extension) {
325 /* RTP header extension, RFC 3550.
326 0 1 2 3
327 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
328 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
329 | defined by profile | length |
330 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
331 | header extension |
332 | .... |
333 */
334 size_t extension_offset = payload_offset_ + 4;
335 if (extension_offset > size)
336 return false;
337 uint16_t profile =
338 ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_]);
339 size_t extensions_capacity =
340 ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_ + 2]);
341 extensions_capacity *= 4;
342 if (extension_offset + extensions_capacity > size)
343 return false;
344 if (profile == kOneByteExtensionId) {
345 const size_t kOneByteHeaderSize = 1;
346 const uint8_t kPaddingId = 0;
347 const uint8_t kReservedId = 15;
348 while (extensions_size_ + kOneByteHeaderSize < extensions_capacity) {
349 uint8_t id = buffer[extension_offset + extensions_size_] >> 4;
350 if (id == kReservedId) {
351 break;
352 } else if (id == kPaddingId) {
353 extensions_size_++;
354 continue;
355 }
356 uint8_t length =
357 1 + (buffer[extension_offset + extensions_size_] & 0xf);
358 extensions_size_ += kOneByteHeaderSize;
359 if (num_extensions_ >= kMaxExtensionHeaders)
360 break;
361 extension_entries_[num_extensions_].type =
362 extensions_ ? extensions_->GetType(id)
363 : ExtensionManager::kInvalidType;
364 extension_entries_[num_extensions_].length = length;
365 extension_entries_[num_extensions_].offset =
366 extension_offset + extensions_size_;
367 num_extensions_++;
368 extensions_size_ += length;
369 }
370 }
371 payload_offset_ = extension_offset + extensions_capacity;
372 }
373
374 if (payload_offset_ + padding_size_ > size)
375 return false;
376 payload_size_ = size - payload_offset_ - padding_size_;
377 return true;
378 }
379
380 bool Packet::FindExtension(ExtensionType type,
381 uint8_t length,
382 uint16_t* offset) const {
383 RTC_DCHECK(offset);
384 for (size_t i = 0; i < num_extensions_; ++i) {
385 if (extension_entries_[i].type == type) {
386 RTC_CHECK_EQ(length, extension_entries_[i].length)
387 << "Length mismatch for extension '" << type << "'"
388 << "should be " << length << ", received "
389 << extension_entries_[i].length;
390 *offset = extension_entries_[i].offset;
391 return true;
392 }
393 }
394 return false;
395 }
396
397 bool Packet::AllocateExtension(ExtensionType type,
398 uint8_t length,
399 uint16_t* offset) {
400 if (!extensions_)
401 return false;
402 if (FindExtension(type, length, offset))
403 return true;
404
405 // Can't add new extension after payload/paddin was set.
terelius 2016/04/13 13:17:00 nit: padding
danilchap 2016/04/13 16:18:33 Done.
406 if (payload_size_ > 0)
407 return false;
408 if (padding_size_ > 0)
409 return false;
410
411 uint8_t extension_id = extensions_->GetId(type);
412 if (extension_id == ExtensionManager::kInvalidId)
413 return false;
414 RTC_DCHECK(0 < length && length <= 16);
415
416 size_t num_csrc = data()[0] & 0x0F;
417 size_t extensions_offset = kFixedHeaderSize + (num_csrc * 4) + 4;
418 const uint8_t kExtensionHeaderSize = 1; // Using one-byte extensions only.
419 if (extensions_offset + extensions_size_ + kExtensionHeaderSize + length >
420 capacity()) {
421 LOG(LS_WARNING) << "Extension cannot be registered: "
422 "Not enough space left in buffer.";
423 return false;
424 }
425
426 uint16_t new_extensions_size =
427 extensions_size_ + kExtensionHeaderSize + length;
428 uint16_t extensions_words =
429 (new_extensions_size + 3) / 4; // Wrap up to 32bit.
430 if (extensions_words > 0xFFFF) {
431 LOG(LS_WARNING) << "Too much extension header data, exceeds 2^16 DWORDS.";
432 return false;
433 }
434
435 // All checks passed, write down the extension.
436 if (num_extensions_ == 0) {
437 RTC_DCHECK_EQ(payload_offset_, kFixedHeaderSize + (num_csrc * 4));
438 RTC_DCHECK_EQ(extensions_size_, 0);
439 WriteAt(0, data()[0] | 0x10); // Set extension bit.
440 // Profile specific ID always set to OneByteExtensionHeader.
441 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 4),
442 kOneByteExtensionId);
443 }
444
445 WriteAt(extensions_offset + extensions_size_,
446 (extension_id << 4) | (length - 1));
447 RTC_DCHECK(num_extensions_ < kMaxExtensionHeaders);
448 extension_entries_[num_extensions_].type = type;
449 extension_entries_[num_extensions_].length = length;
450 *offset = extensions_offset + kExtensionHeaderSize + extensions_size_;
451 extension_entries_[num_extensions_].offset = *offset;
452 ++num_extensions_;
453 extensions_size_ = new_extensions_size;
454
455 // Update header length field.
456 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 2),
457 extensions_words);
458 // Fill extension padding place with zeroes.
459 size_t extension_padding_size = 4 * extensions_words - extensions_size_;
460 memset(WriteAt(extensions_offset + extensions_size_), 0,
461 extension_padding_size);
462 payload_offset_ = extensions_offset + 4 * extensions_words;
463 return true;
464 }
465 } // namespace rtp
466
467 void ReceivedRtpPacket::GetHeader(RTPHeader* header) const {
468 Packet::GetHeader(header);
469 header->payload_type_frequency = payload_type_frequency();
470 }
471
472 } // namespace webrtc
OLDNEW
« webrtc/modules/rtp_rtcp/source/rtp_packet.h ('K') | « webrtc/modules/rtp_rtcp/source/rtp_packet.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698