OLD | NEW |
---|---|
(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 | |
OLD | NEW |