blob: 0b9ed80af56ed867a54c9580fcbcc6344b3ecdc8 [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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/rtp_rtcp/source/rtp_packet.h"
danilchap1edb7ab2016-04-20 05:25:10 -070012
13#include <cstring>
Danil Chapovalova64a2fb2016-09-12 11:41:35 +020014#include <utility>
danilchap1edb7ab2016-04-20 05:25:10 -070015
Johannes Kron07ba2b92018-09-26 13:33:35 +020016#include "api/rtpparameters.h"
Mirko Bonadei71207422017-09-15 13:58:09 +020017#include "common_types.h" // NOLINT(build/include)
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "modules/rtp_rtcp/source/byte_io.h"
19#include "rtc_base/checks.h"
20#include "rtc_base/logging.h"
Karl Wiberge40468b2017-11-22 10:42:26 +010021#include "rtc_base/numerics/safe_conversions.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "rtc_base/random.h"
danilchap1edb7ab2016-04-20 05:25:10 -070023
24namespace webrtc {
danilchap1edb7ab2016-04-20 05:25:10 -070025namespace {
26constexpr size_t kFixedHeaderSize = 12;
27constexpr uint8_t kRtpVersion = 2;
Johannes Kron07ba2b92018-09-26 13:33:35 +020028constexpr uint16_t kOneByteExtensionProfileId = 0xBEDE;
29constexpr uint16_t kTwoByteExtensionProfileId = 0x1000;
30constexpr size_t kOneByteExtensionHeaderLength = 1;
31constexpr size_t kTwoByteExtensionHeaderLength = 2;
danilchap1edb7ab2016-04-20 05:25:10 -070032constexpr size_t kDefaultPacketSize = 1500;
33} // namespace
danilchap653063f2017-04-03 06:16:30 -070034
danilchap1edb7ab2016-04-20 05:25:10 -070035// 0 1 2 3
36// 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
37// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38// |V=2|P|X| CC |M| PT | sequence number |
39// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40// | timestamp |
41// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42// | synchronization source (SSRC) identifier |
43// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
44// | Contributing source (CSRC) identifiers |
45// | .... |
46// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
Johannes Kron07ba2b92018-09-26 13:33:35 +020047// | header eXtension profile id | length in 32bits |
danilchap1edb7ab2016-04-20 05:25:10 -070048// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
49// | Extensions |
50// | .... |
51// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
52// | Payload |
53// | .... : padding... |
54// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
55// | padding | Padding size |
56// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Danil Chapovalov8769e172017-09-14 14:08:22 +020057RtpPacket::RtpPacket() : RtpPacket(nullptr, kDefaultPacketSize) {}
danilchap70f39a32016-12-16 05:48:18 -080058
Danil Chapovalov8769e172017-09-14 14:08:22 +020059RtpPacket::RtpPacket(const ExtensionManager* extensions)
60 : RtpPacket(extensions, kDefaultPacketSize) {}
danilchap1edb7ab2016-04-20 05:25:10 -070061
Danil Chapovalov8769e172017-09-14 14:08:22 +020062RtpPacket::RtpPacket(const RtpPacket&) = default;
nisse76e62b02017-05-31 02:24:52 -070063
Danil Chapovalov8769e172017-09-14 14:08:22 +020064RtpPacket::RtpPacket(const ExtensionManager* extensions, size_t capacity)
danilchap70f39a32016-12-16 05:48:18 -080065 : buffer_(capacity) {
danilchap1edb7ab2016-04-20 05:25:10 -070066 RTC_DCHECK_GE(capacity, kFixedHeaderSize);
67 Clear();
danilchap70f39a32016-12-16 05:48:18 -080068 if (extensions) {
Johannes Kronc5744b82018-09-24 14:50:48 +020069 extensions_ = *extensions;
danilchap70f39a32016-12-16 05:48:18 -080070 }
danilchap1edb7ab2016-04-20 05:25:10 -070071}
72
Danil Chapovalov8769e172017-09-14 14:08:22 +020073RtpPacket::~RtpPacket() {}
danilchap1edb7ab2016-04-20 05:25:10 -070074
Danil Chapovalov8769e172017-09-14 14:08:22 +020075void RtpPacket::IdentifyExtensions(const ExtensionManager& extensions) {
Johannes Kronc5744b82018-09-24 14:50:48 +020076 extensions_ = extensions;
danilchap1edb7ab2016-04-20 05:25:10 -070077}
78
Danil Chapovalov8769e172017-09-14 14:08:22 +020079bool RtpPacket::Parse(const uint8_t* buffer, size_t buffer_size) {
danilchap1edb7ab2016-04-20 05:25:10 -070080 if (!ParseBuffer(buffer, buffer_size)) {
81 Clear();
82 return false;
83 }
danilchap1edb7ab2016-04-20 05:25:10 -070084 buffer_.SetData(buffer, buffer_size);
Danil Chapovalov31e4e802016-08-03 18:27:40 +020085 RTC_DCHECK_EQ(size(), buffer_size);
danilchap1edb7ab2016-04-20 05:25:10 -070086 return true;
87}
88
Danil Chapovalov8769e172017-09-14 14:08:22 +020089bool RtpPacket::Parse(rtc::ArrayView<const uint8_t> packet) {
brandtrb29e6522016-12-21 06:37:18 -080090 return Parse(packet.data(), packet.size());
91}
92
Danil Chapovalov8769e172017-09-14 14:08:22 +020093bool RtpPacket::Parse(rtc::CopyOnWriteBuffer buffer) {
Danil Chapovalov31e4e802016-08-03 18:27:40 +020094 if (!ParseBuffer(buffer.cdata(), buffer.size())) {
danilchap1edb7ab2016-04-20 05:25:10 -070095 Clear();
96 return false;
97 }
Danil Chapovalov31e4e802016-08-03 18:27:40 +020098 size_t buffer_size = buffer.size();
danilchap1edb7ab2016-04-20 05:25:10 -070099 buffer_ = std::move(buffer);
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200100 RTC_DCHECK_EQ(size(), buffer_size);
danilchap1edb7ab2016-04-20 05:25:10 -0700101 return true;
102}
103
Danil Chapovalov8769e172017-09-14 14:08:22 +0200104std::vector<uint32_t> RtpPacket::Csrcs() const {
danilchap1edb7ab2016-04-20 05:25:10 -0700105 size_t num_csrc = data()[0] & 0x0F;
106 RTC_DCHECK_GE(capacity(), kFixedHeaderSize + num_csrc * 4);
107 std::vector<uint32_t> csrcs(num_csrc);
108 for (size_t i = 0; i < num_csrc; ++i) {
109 csrcs[i] =
110 ByteReader<uint32_t>::ReadBigEndian(&data()[kFixedHeaderSize + i * 4]);
111 }
112 return csrcs;
113}
114
Danil Chapovalov8769e172017-09-14 14:08:22 +0200115void RtpPacket::CopyHeaderFrom(const RtpPacket& packet) {
danilchap1edb7ab2016-04-20 05:25:10 -0700116 RTC_DCHECK_GE(capacity(), packet.headers_size());
117
118 marker_ = packet.marker_;
119 payload_type_ = packet.payload_type_;
120 sequence_number_ = packet.sequence_number_;
121 timestamp_ = packet.timestamp_;
122 ssrc_ = packet.ssrc_;
123 payload_offset_ = packet.payload_offset_;
Johannes Kronc5744b82018-09-24 14:50:48 +0200124 extensions_ = packet.extensions_;
125 extension_entries_ = packet.extension_entries_;
danilchap1edb7ab2016-04-20 05:25:10 -0700126 extensions_size_ = packet.extensions_size_;
127 buffer_.SetData(packet.data(), packet.headers_size());
128 // Reset payload and padding.
129 payload_size_ = 0;
130 padding_size_ = 0;
131}
132
Danil Chapovalov8769e172017-09-14 14:08:22 +0200133void RtpPacket::SetMarker(bool marker_bit) {
danilchap1edb7ab2016-04-20 05:25:10 -0700134 marker_ = marker_bit;
135 if (marker_) {
136 WriteAt(1, data()[1] | 0x80);
137 } else {
138 WriteAt(1, data()[1] & 0x7F);
139 }
140}
141
Danil Chapovalov8769e172017-09-14 14:08:22 +0200142void RtpPacket::SetPayloadType(uint8_t payload_type) {
danilchap1edb7ab2016-04-20 05:25:10 -0700143 RTC_DCHECK_LE(payload_type, 0x7Fu);
144 payload_type_ = payload_type;
145 WriteAt(1, (data()[1] & 0x80) | payload_type);
146}
147
Danil Chapovalov8769e172017-09-14 14:08:22 +0200148void RtpPacket::SetSequenceNumber(uint16_t seq_no) {
danilchap1edb7ab2016-04-20 05:25:10 -0700149 sequence_number_ = seq_no;
150 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(2), seq_no);
151}
152
Danil Chapovalov8769e172017-09-14 14:08:22 +0200153void RtpPacket::SetTimestamp(uint32_t timestamp) {
danilchap1edb7ab2016-04-20 05:25:10 -0700154 timestamp_ = timestamp;
155 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(4), timestamp);
156}
157
Danil Chapovalov8769e172017-09-14 14:08:22 +0200158void RtpPacket::SetSsrc(uint32_t ssrc) {
danilchap1edb7ab2016-04-20 05:25:10 -0700159 ssrc_ = ssrc;
160 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(8), ssrc);
161}
162
Danil Chapovalov7d2df3f2018-08-14 17:18:07 +0200163void RtpPacket::SetCsrcs(rtc::ArrayView<const uint32_t> csrcs) {
danilchap70f39a32016-12-16 05:48:18 -0800164 RTC_DCHECK_EQ(extensions_size_, 0);
kwibergaf476c72016-11-28 15:21:39 -0800165 RTC_DCHECK_EQ(payload_size_, 0);
166 RTC_DCHECK_EQ(padding_size_, 0);
danilchap1edb7ab2016-04-20 05:25:10 -0700167 RTC_DCHECK_LE(csrcs.size(), 0x0fu);
168 RTC_DCHECK_LE(kFixedHeaderSize + 4 * csrcs.size(), capacity());
169 payload_offset_ = kFixedHeaderSize + 4 * csrcs.size();
danilchap772bd8b2017-09-13 03:24:28 -0700170 WriteAt(0, (data()[0] & 0xF0) | rtc::dchecked_cast<uint8_t>(csrcs.size()));
danilchap1edb7ab2016-04-20 05:25:10 -0700171 size_t offset = kFixedHeaderSize;
172 for (uint32_t csrc : csrcs) {
173 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(offset), csrc);
174 offset += 4;
175 }
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200176 buffer_.SetSize(payload_offset_);
danilchap1edb7ab2016-04-20 05:25:10 -0700177}
178
Danil Chapovalov8769e172017-09-14 14:08:22 +0200179rtc::ArrayView<uint8_t> RtpPacket::AllocateRawExtension(int id, size_t length) {
Johannes Kron07ba2b92018-09-26 13:33:35 +0200180 RTC_DCHECK_GE(id, RtpExtension::kMinId);
Johannes Kron78cdde32018-10-05 10:00:46 +0200181 RTC_DCHECK_LE(id, RtpExtension::kMaxId);
danilchap653063f2017-04-03 06:16:30 -0700182 RTC_DCHECK_GE(length, 1);
Johannes Kron78cdde32018-10-05 10:00:46 +0200183 RTC_DCHECK_LE(length, RtpExtension::kMaxValueSize);
Johannes Kronc5744b82018-09-24 14:50:48 +0200184 const ExtensionInfo* extension_entry = FindExtensionInfo(id);
185 if (extension_entry != nullptr) {
danilchap653063f2017-04-03 06:16:30 -0700186 // Extension already reserved. Check if same length is used.
187 if (extension_entry->length == length)
188 return rtc::MakeArrayView(WriteAt(extension_entry->offset), length);
189
Johannes Kronc5744b82018-09-24 14:50:48 +0200190 RTC_LOG(LS_ERROR) << "Length mismatch for extension id " << id
Mirko Bonadei675513b2017-11-09 11:09:25 +0100191 << ": expected "
192 << static_cast<int>(extension_entry->length)
193 << ". received " << length;
danilchap653063f2017-04-03 06:16:30 -0700194 return nullptr;
195 }
196 if (payload_size_ > 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100197 RTC_LOG(LS_ERROR) << "Can't add new extension id " << id
198 << " after payload was set.";
danilchap653063f2017-04-03 06:16:30 -0700199 return nullptr;
200 }
201 if (padding_size_ > 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100202 RTC_LOG(LS_ERROR) << "Can't add new extension id " << id
203 << " after padding was set.";
danilchap653063f2017-04-03 06:16:30 -0700204 return nullptr;
205 }
206
Johannes Kron78cdde32018-10-05 10:00:46 +0200207 const size_t num_csrc = data()[0] & 0x0F;
208 const size_t extensions_offset = kFixedHeaderSize + (num_csrc * 4) + 4;
209 // Determine if two-byte header is required for the extension based on id and
210 // length. Please note that a length of 0 also requires two-byte header
211 // extension. See RFC8285 Section 4.2-4.3.
212 const bool two_byte_header_required =
213 id > RtpExtension::kOneByteHeaderExtensionMaxId ||
214 length > RtpExtension::kOneByteHeaderExtensionMaxValueSize || length == 0;
215 RTC_CHECK(!two_byte_header_required ||
216 extensions_.IsMixedOneTwoByteHeaderSupported());
217
218 uint16_t profile_id;
219 if (extensions_size_ > 0) {
220 profile_id =
221 ByteReader<uint16_t>::ReadBigEndian(data() + extensions_offset - 4);
222 if (profile_id == kOneByteExtensionProfileId && two_byte_header_required) {
223 // Is buffer size big enough to fit promotion and new data field?
224 // The header extension will grow with one byte per already allocated
225 // extension + the size of the extension that is about to be allocated.
226 size_t expected_new_extensions_size =
227 extensions_size_ + extension_entries_.size() +
228 kTwoByteExtensionHeaderLength + length;
229 if (extensions_offset + expected_new_extensions_size > capacity()) {
230 RTC_LOG(LS_ERROR)
231 << "Extension cannot be registered: Not enough space left in "
232 "buffer to change to two-byte header extension and add new "
233 "extension.";
234 return nullptr;
235 }
236 // Promote already written data to two-byte header format.
237 PromoteToTwoByteHeaderExtension();
238 profile_id = kTwoByteExtensionProfileId;
239 }
240 } else {
241 // Profile specific ID, set to OneByteExtensionHeader unless
242 // TwoByteExtensionHeader is required.
243 profile_id = two_byte_header_required ? kTwoByteExtensionProfileId
244 : kOneByteExtensionProfileId;
245 }
246
247 const size_t extension_header_size = profile_id == kOneByteExtensionProfileId
248 ? kOneByteExtensionHeaderLength
249 : kTwoByteExtensionHeaderLength;
Johannes Kron07ba2b92018-09-26 13:33:35 +0200250 size_t new_extensions_size =
Johannes Kron78cdde32018-10-05 10:00:46 +0200251 extensions_size_ + extension_header_size + length;
danilchap653063f2017-04-03 06:16:30 -0700252 if (extensions_offset + new_extensions_size > capacity()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100253 RTC_LOG(LS_ERROR)
danilchap653063f2017-04-03 06:16:30 -0700254 << "Extension cannot be registered: Not enough space left in buffer.";
255 return nullptr;
256 }
257
258 // All checks passed, write down the extension headers.
259 if (extensions_size_ == 0) {
260 RTC_DCHECK_EQ(payload_offset_, kFixedHeaderSize + (num_csrc * 4));
261 WriteAt(0, data()[0] | 0x10); // Set extension bit.
danilchap653063f2017-04-03 06:16:30 -0700262 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 4),
Johannes Kron78cdde32018-10-05 10:00:46 +0200263 profile_id);
danilchap653063f2017-04-03 06:16:30 -0700264 }
265
Johannes Kron78cdde32018-10-05 10:00:46 +0200266 if (profile_id == kOneByteExtensionProfileId) {
267 uint8_t one_byte_header = rtc::dchecked_cast<uint8_t>(id) << 4;
268 one_byte_header |= rtc::dchecked_cast<uint8_t>(length - 1);
269 WriteAt(extensions_offset + extensions_size_, one_byte_header);
270 } else {
271 // TwoByteHeaderExtension.
272 uint8_t extension_id = rtc::dchecked_cast<uint8_t>(id);
273 WriteAt(extensions_offset + extensions_size_, extension_id);
274 uint8_t extension_length = rtc::dchecked_cast<uint8_t>(length);
275 WriteAt(extensions_offset + extensions_size_ + 1, extension_length);
276 }
danilchap653063f2017-04-03 06:16:30 -0700277
Johannes Kronc5744b82018-09-24 14:50:48 +0200278 const uint16_t extension_info_offset = rtc::dchecked_cast<uint16_t>(
Johannes Kron78cdde32018-10-05 10:00:46 +0200279 extensions_offset + extensions_size_ + extension_header_size);
Johannes Kronc5744b82018-09-24 14:50:48 +0200280 const uint8_t extension_info_length = rtc::dchecked_cast<uint8_t>(length);
281 extension_entries_.emplace_back(id, extension_info_length,
282 extension_info_offset);
Johannes Kron78cdde32018-10-05 10:00:46 +0200283
Danil Chapovalov61405bc2018-02-13 13:55:30 +0100284 extensions_size_ = new_extensions_size;
danilchap653063f2017-04-03 06:16:30 -0700285
Johannes Kron78cdde32018-10-05 10:00:46 +0200286 uint16_t extensions_size_padded =
287 SetExtensionLengthMaybeAddZeroPadding(extensions_offset);
288 payload_offset_ = extensions_offset + extensions_size_padded;
289 buffer_.SetSize(payload_offset_);
290 return rtc::MakeArrayView(WriteAt(extension_info_offset),
291 extension_info_length);
292}
293
294void RtpPacket::PromoteToTwoByteHeaderExtension() {
295 size_t num_csrc = data()[0] & 0x0F;
296 size_t extensions_offset = kFixedHeaderSize + (num_csrc * 4) + 4;
297
298 RTC_CHECK_GT(extension_entries_.size(), 0);
299 RTC_CHECK_EQ(payload_size_, 0);
300 RTC_CHECK_EQ(kOneByteExtensionProfileId, ByteReader<uint16_t>::ReadBigEndian(
301 data() + extensions_offset - 4));
302 // Rewrite data.
303 // Each extension adds one to the offset. The write-read delta for the last
304 // extension is therefore the same as the number of extension entries.
305 size_t write_read_delta = extension_entries_.size();
306 for (auto extension_entry = extension_entries_.rbegin();
307 extension_entry != extension_entries_.rend(); ++extension_entry) {
308 size_t read_index = extension_entry->offset;
309 size_t write_index = read_index + write_read_delta;
310 // Update offset.
311 extension_entry->offset = rtc::dchecked_cast<uint16_t>(write_index);
312 // Copy data. Use memmove since read/write regions may overlap.
313 memmove(WriteAt(write_index), data() + read_index, extension_entry->length);
314 // Rewrite id and length.
315 WriteAt(--write_index, extension_entry->length);
316 WriteAt(--write_index, extension_entry->id);
317 --write_read_delta;
318 }
319
320 // Update profile header, extensions length, and zero padding.
321 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 4),
322 kTwoByteExtensionProfileId);
323 extensions_size_ += extension_entries_.size();
324 uint16_t extensions_size_padded =
325 SetExtensionLengthMaybeAddZeroPadding(extensions_offset);
326 payload_offset_ = extensions_offset + extensions_size_padded;
327 buffer_.SetSize(payload_offset_);
328}
329
330uint16_t RtpPacket::SetExtensionLengthMaybeAddZeroPadding(
331 size_t extensions_offset) {
danilchap653063f2017-04-03 06:16:30 -0700332 // Update header length field.
Danil Chapovalov61405bc2018-02-13 13:55:30 +0100333 uint16_t extensions_words = rtc::dchecked_cast<uint16_t>(
334 (extensions_size_ + 3) / 4); // Wrap up to 32bit.
danilchap653063f2017-04-03 06:16:30 -0700335 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 2),
336 extensions_words);
337 // Fill extension padding place with zeroes.
338 size_t extension_padding_size = 4 * extensions_words - extensions_size_;
339 memset(WriteAt(extensions_offset + extensions_size_), 0,
340 extension_padding_size);
Johannes Kron78cdde32018-10-05 10:00:46 +0200341 return 4 * extensions_words;
danilchap653063f2017-04-03 06:16:30 -0700342}
343
Danil Chapovalov8769e172017-09-14 14:08:22 +0200344uint8_t* RtpPacket::AllocatePayload(size_t size_bytes) {
danilchap07a01b32017-03-29 07:33:13 -0700345 // Reset payload size to 0. If CopyOnWrite buffer_ was shared, this will cause
346 // reallocation and memcpy. Keeping just header reduces memcpy size.
347 SetPayloadSize(0);
348 return SetPayloadSize(size_bytes);
349}
350
Danil Chapovalov8769e172017-09-14 14:08:22 +0200351uint8_t* RtpPacket::SetPayloadSize(size_t size_bytes) {
kwibergaf476c72016-11-28 15:21:39 -0800352 RTC_DCHECK_EQ(padding_size_, 0);
danilchap1edb7ab2016-04-20 05:25:10 -0700353 if (payload_offset_ + size_bytes > capacity()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100354 RTC_LOG(LS_WARNING) << "Cannot set payload, not enough space in buffer.";
danilchap1edb7ab2016-04-20 05:25:10 -0700355 return nullptr;
356 }
357 payload_size_ = size_bytes;
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200358 buffer_.SetSize(payload_offset_ + payload_size_);
danilchap1edb7ab2016-04-20 05:25:10 -0700359 return WriteAt(payload_offset_);
360}
361
Danil Chapovalov8769e172017-09-14 14:08:22 +0200362bool RtpPacket::SetPadding(uint8_t size_bytes, Random* random) {
danilchap1edb7ab2016-04-20 05:25:10 -0700363 RTC_DCHECK(random);
364 if (payload_offset_ + payload_size_ + size_bytes > capacity()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100365 RTC_LOG(LS_WARNING) << "Cannot set padding size " << size_bytes << ", only "
366 << (capacity() - payload_offset_ - payload_size_)
367 << " bytes left in buffer.";
danilchap1edb7ab2016-04-20 05:25:10 -0700368 return false;
369 }
370 padding_size_ = size_bytes;
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200371 buffer_.SetSize(payload_offset_ + payload_size_ + padding_size_);
danilchap1edb7ab2016-04-20 05:25:10 -0700372 if (padding_size_ > 0) {
373 size_t padding_offset = payload_offset_ + payload_size_;
374 size_t padding_end = padding_offset + padding_size_;
375 for (size_t offset = padding_offset; offset < padding_end - 1; ++offset) {
376 WriteAt(offset, random->Rand<uint8_t>());
377 }
378 WriteAt(padding_end - 1, padding_size_);
379 WriteAt(0, data()[0] | 0x20); // Set padding bit.
380 } else {
381 WriteAt(0, data()[0] & ~0x20); // Clear padding bit.
382 }
383 return true;
384}
385
Danil Chapovalov8769e172017-09-14 14:08:22 +0200386void RtpPacket::Clear() {
danilchap1edb7ab2016-04-20 05:25:10 -0700387 marker_ = false;
388 payload_type_ = 0;
389 sequence_number_ = 0;
390 timestamp_ = 0;
391 ssrc_ = 0;
392 payload_offset_ = kFixedHeaderSize;
393 payload_size_ = 0;
394 padding_size_ = 0;
danilchap1edb7ab2016-04-20 05:25:10 -0700395 extensions_size_ = 0;
Johannes Kronc5744b82018-09-24 14:50:48 +0200396 extension_entries_.clear();
danilchap1edb7ab2016-04-20 05:25:10 -0700397
398 memset(WriteAt(0), 0, kFixedHeaderSize);
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200399 buffer_.SetSize(kFixedHeaderSize);
danilchap1edb7ab2016-04-20 05:25:10 -0700400 WriteAt(0, kRtpVersion << 6);
401}
402
Danil Chapovalov8769e172017-09-14 14:08:22 +0200403bool RtpPacket::ParseBuffer(const uint8_t* buffer, size_t size) {
danilchap1edb7ab2016-04-20 05:25:10 -0700404 if (size < kFixedHeaderSize) {
405 return false;
406 }
407 const uint8_t version = buffer[0] >> 6;
408 if (version != kRtpVersion) {
409 return false;
410 }
411 const bool has_padding = (buffer[0] & 0x20) != 0;
412 const bool has_extension = (buffer[0] & 0x10) != 0;
413 const uint8_t number_of_crcs = buffer[0] & 0x0f;
414 marker_ = (buffer[1] & 0x80) != 0;
415 payload_type_ = buffer[1] & 0x7f;
416
417 sequence_number_ = ByteReader<uint16_t>::ReadBigEndian(&buffer[2]);
418 timestamp_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]);
419 ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]);
420 if (size < kFixedHeaderSize + number_of_crcs * 4) {
421 return false;
422 }
423 payload_offset_ = kFixedHeaderSize + number_of_crcs * 4;
424
425 if (has_padding) {
426 padding_size_ = buffer[size - 1];
427 if (padding_size_ == 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100428 RTC_LOG(LS_WARNING) << "Padding was set, but padding size is zero";
danilchap1edb7ab2016-04-20 05:25:10 -0700429 return false;
430 }
431 } else {
432 padding_size_ = 0;
433 }
434
danilchap1edb7ab2016-04-20 05:25:10 -0700435 extensions_size_ = 0;
Johannes Kron6ea77192018-09-24 17:19:52 +0200436 extension_entries_.clear();
danilchap1edb7ab2016-04-20 05:25:10 -0700437 if (has_extension) {
438 /* RTP header extension, RFC 3550.
439 0 1 2 3
440 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
441 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
442 | defined by profile | length |
443 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
444 | header extension |
445 | .... |
446 */
447 size_t extension_offset = payload_offset_ + 4;
448 if (extension_offset > size) {
449 return false;
450 }
451 uint16_t profile =
452 ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_]);
453 size_t extensions_capacity =
454 ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_ + 2]);
455 extensions_capacity *= 4;
456 if (extension_offset + extensions_capacity > size) {
457 return false;
458 }
Johannes Kron07ba2b92018-09-26 13:33:35 +0200459 if (profile != kOneByteExtensionProfileId &&
460 profile != kTwoByteExtensionProfileId) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100461 RTC_LOG(LS_WARNING) << "Unsupported rtp extension " << profile;
danilchap1edb7ab2016-04-20 05:25:10 -0700462 } else {
Johannes Kron07ba2b92018-09-26 13:33:35 +0200463 size_t extension_header_length = profile == kOneByteExtensionProfileId
464 ? kOneByteExtensionHeaderLength
465 : kTwoByteExtensionHeaderLength;
466 constexpr uint8_t kPaddingByte = 0;
danilchap1edb7ab2016-04-20 05:25:10 -0700467 constexpr uint8_t kPaddingId = 0;
Johannes Kron07ba2b92018-09-26 13:33:35 +0200468 constexpr uint8_t kOneByteHeaderExtensionReservedId = 15;
469 while (extensions_size_ + extension_header_length < extensions_capacity) {
470 if (buffer[extension_offset + extensions_size_] == kPaddingByte) {
danilchap1edb7ab2016-04-20 05:25:10 -0700471 extensions_size_++;
472 continue;
473 }
Johannes Kron07ba2b92018-09-26 13:33:35 +0200474 int id;
475 uint8_t length;
476 if (profile == kOneByteExtensionProfileId) {
477 id = buffer[extension_offset + extensions_size_] >> 4;
478 length = 1 + (buffer[extension_offset + extensions_size_] & 0xf);
479 if (id == kOneByteHeaderExtensionReservedId ||
480 (id == kPaddingId && length != 1)) {
481 break;
482 }
483 } else {
484 id = buffer[extension_offset + extensions_size_];
485 length = buffer[extension_offset + extensions_size_ + 1];
486 }
487
488 if (extensions_size_ + extension_header_length + length >
Danil Chapovalova64a2fb2016-09-12 11:41:35 +0200489 extensions_capacity) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100490 RTC_LOG(LS_WARNING) << "Oversized rtp header extension.";
Danil Chapovalova64a2fb2016-09-12 11:41:35 +0200491 break;
danilchap1edb7ab2016-04-20 05:25:10 -0700492 }
danilchap70f39a32016-12-16 05:48:18 -0800493
Johannes Kronc5744b82018-09-24 14:50:48 +0200494 ExtensionInfo& extension_info = FindOrCreateExtensionInfo(id);
495 if (extension_info.length != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100496 RTC_LOG(LS_VERBOSE)
497 << "Duplicate rtp header extension id " << id << ". Overwriting.";
Danil Chapovalova64a2fb2016-09-12 11:41:35 +0200498 }
danilchap70f39a32016-12-16 05:48:18 -0800499
Danil Chapovalovc2dd59c2018-02-06 11:29:35 +0100500 size_t offset =
Johannes Kron07ba2b92018-09-26 13:33:35 +0200501 extension_offset + extensions_size_ + extension_header_length;
Danil Chapovalovc2dd59c2018-02-06 11:29:35 +0100502 if (!rtc::IsValueInRangeForNumericType<uint16_t>(offset)) {
503 RTC_DLOG(LS_WARNING) << "Oversized rtp header extension.";
504 break;
505 }
Johannes Kronc5744b82018-09-24 14:50:48 +0200506 extension_info.offset = static_cast<uint16_t>(offset);
507 extension_info.length = length;
Johannes Kron07ba2b92018-09-26 13:33:35 +0200508 extensions_size_ += extension_header_length + length;
danilchap1edb7ab2016-04-20 05:25:10 -0700509 }
510 }
511 payload_offset_ = extension_offset + extensions_capacity;
512 }
513
514 if (payload_offset_ + padding_size_ > size) {
515 return false;
516 }
517 payload_size_ = size - payload_offset_ - padding_size_;
518 return true;
519}
520
Johannes Kronc5744b82018-09-24 14:50:48 +0200521const RtpPacket::ExtensionInfo* RtpPacket::FindExtensionInfo(int id) const {
danilchap70f39a32016-12-16 05:48:18 -0800522 for (const ExtensionInfo& extension : extension_entries_) {
Johannes Kronc5744b82018-09-24 14:50:48 +0200523 if (extension.id == id) {
524 return &extension;
danilchap1edb7ab2016-04-20 05:25:10 -0700525 }
526 }
danilchap978504e2017-04-06 01:03:53 -0700527 return nullptr;
danilchap1edb7ab2016-04-20 05:25:10 -0700528}
529
Johannes Kronc5744b82018-09-24 14:50:48 +0200530RtpPacket::ExtensionInfo& RtpPacket::FindOrCreateExtensionInfo(int id) {
531 for (ExtensionInfo& extension : extension_entries_) {
532 if (extension.id == id) {
533 return extension;
danilchap70f39a32016-12-16 05:48:18 -0800534 }
danilchap1edb7ab2016-04-20 05:25:10 -0700535 }
Johannes Kronc5744b82018-09-24 14:50:48 +0200536 extension_entries_.emplace_back(id);
537 return extension_entries_.back();
538}
539
540rtc::ArrayView<const uint8_t> RtpPacket::FindExtension(
541 ExtensionType type) const {
542 uint8_t id = extensions_.GetId(type);
543 if (id == ExtensionManager::kInvalidId) {
544 // Extension not registered.
545 return nullptr;
546 }
547 ExtensionInfo const* extension_info = FindExtensionInfo(id);
548 if (extension_info == nullptr) {
549 return nullptr;
550 }
551 return rtc::MakeArrayView(data() + extension_info->offset,
552 extension_info->length);
553}
554
555rtc::ArrayView<uint8_t> RtpPacket::AllocateExtension(ExtensionType type,
556 size_t length) {
Johannes Kron78cdde32018-10-05 10:00:46 +0200557 // TODO(webrtc:7990): Add support for empty extensions (length==0).
558 if (length == 0 || length > RtpExtension::kMaxValueSize ||
559 (!extensions_.IsMixedOneTwoByteHeaderSupported() &&
560 length > RtpExtension::kOneByteHeaderExtensionMaxValueSize)) {
561 return nullptr;
562 }
563
Johannes Kronc5744b82018-09-24 14:50:48 +0200564 uint8_t id = extensions_.GetId(type);
565 if (id == ExtensionManager::kInvalidId) {
566 // Extension not registered.
567 return nullptr;
568 }
Johannes Kron78cdde32018-10-05 10:00:46 +0200569 if (!extensions_.IsMixedOneTwoByteHeaderSupported() &&
570 id > RtpExtension::kOneByteHeaderExtensionMaxId) {
571 return nullptr;
572 }
Johannes Kronc5744b82018-09-24 14:50:48 +0200573 return AllocateRawExtension(id, length);
danilchap1edb7ab2016-04-20 05:25:10 -0700574}
575
danilchap1edb7ab2016-04-20 05:25:10 -0700576} // namespace webrtc