blob: 878942b62f0bd35fbe7e27b40ff40622b799805e [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
Mirko Bonadei71207422017-09-15 13:58:09 +020016#include "common_types.h" // NOLINT(build/include)
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "modules/rtp_rtcp/include/rtp_header_extension_map.h"
18#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;
28constexpr uint16_t kOneByteExtensionId = 0xBEDE;
29constexpr size_t kOneByteHeaderSize = 1;
30constexpr size_t kDefaultPacketSize = 1500;
31} // namespace
danilchap653063f2017-04-03 06:16:30 -070032
Danil Chapovalov8769e172017-09-14 14:08:22 +020033constexpr int RtpPacket::kMaxExtensionHeaders;
34constexpr int RtpPacket::kMinExtensionId;
35constexpr int RtpPacket::kMaxExtensionId;
danilchap653063f2017-04-03 06:16:30 -070036
danilchap1edb7ab2016-04-20 05:25:10 -070037// 0 1 2 3
38// 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
39// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40// |V=2|P|X| CC |M| PT | sequence number |
41// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42// | timestamp |
43// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44// | synchronization source (SSRC) identifier |
45// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
46// | Contributing source (CSRC) identifiers |
47// | .... |
48// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
49// |One-byte eXtensions id = 0xbede| length in 32bits |
50// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51// | Extensions |
52// | .... |
53// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
54// | Payload |
55// | .... : padding... |
56// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
57// | padding | Padding size |
58// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Danil Chapovalov8769e172017-09-14 14:08:22 +020059RtpPacket::RtpPacket() : RtpPacket(nullptr, kDefaultPacketSize) {}
danilchap70f39a32016-12-16 05:48:18 -080060
Danil Chapovalov8769e172017-09-14 14:08:22 +020061RtpPacket::RtpPacket(const ExtensionManager* extensions)
62 : RtpPacket(extensions, kDefaultPacketSize) {}
danilchap1edb7ab2016-04-20 05:25:10 -070063
Danil Chapovalov8769e172017-09-14 14:08:22 +020064RtpPacket::RtpPacket(const RtpPacket&) = default;
nisse76e62b02017-05-31 02:24:52 -070065
Danil Chapovalov8769e172017-09-14 14:08:22 +020066RtpPacket::RtpPacket(const ExtensionManager* extensions, size_t capacity)
danilchap70f39a32016-12-16 05:48:18 -080067 : buffer_(capacity) {
danilchap1edb7ab2016-04-20 05:25:10 -070068 RTC_DCHECK_GE(capacity, kFixedHeaderSize);
69 Clear();
danilchap70f39a32016-12-16 05:48:18 -080070 if (extensions) {
71 IdentifyExtensions(*extensions);
72 } else {
73 for (size_t i = 0; i < kMaxExtensionHeaders; ++i)
74 extension_entries_[i].type = ExtensionManager::kInvalidType;
75 }
danilchap1edb7ab2016-04-20 05:25:10 -070076}
77
Danil Chapovalov8769e172017-09-14 14:08:22 +020078RtpPacket::~RtpPacket() {}
danilchap1edb7ab2016-04-20 05:25:10 -070079
Danil Chapovalov8769e172017-09-14 14:08:22 +020080void RtpPacket::IdentifyExtensions(const ExtensionManager& extensions) {
danilchap772bd8b2017-09-13 03:24:28 -070081 for (int i = 0; i < kMaxExtensionHeaders; ++i)
danilchap70f39a32016-12-16 05:48:18 -080082 extension_entries_[i].type = extensions.GetType(i + 1);
danilchap1edb7ab2016-04-20 05:25:10 -070083}
84
Danil Chapovalov8769e172017-09-14 14:08:22 +020085bool RtpPacket::Parse(const uint8_t* buffer, size_t buffer_size) {
danilchap1edb7ab2016-04-20 05:25:10 -070086 if (!ParseBuffer(buffer, buffer_size)) {
87 Clear();
88 return false;
89 }
danilchap1edb7ab2016-04-20 05:25:10 -070090 buffer_.SetData(buffer, buffer_size);
Danil Chapovalov31e4e802016-08-03 18:27:40 +020091 RTC_DCHECK_EQ(size(), buffer_size);
danilchap1edb7ab2016-04-20 05:25:10 -070092 return true;
93}
94
Danil Chapovalov8769e172017-09-14 14:08:22 +020095bool RtpPacket::Parse(rtc::ArrayView<const uint8_t> packet) {
brandtrb29e6522016-12-21 06:37:18 -080096 return Parse(packet.data(), packet.size());
97}
98
Danil Chapovalov8769e172017-09-14 14:08:22 +020099bool RtpPacket::Parse(rtc::CopyOnWriteBuffer buffer) {
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200100 if (!ParseBuffer(buffer.cdata(), buffer.size())) {
danilchap1edb7ab2016-04-20 05:25:10 -0700101 Clear();
102 return false;
103 }
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200104 size_t buffer_size = buffer.size();
danilchap1edb7ab2016-04-20 05:25:10 -0700105 buffer_ = std::move(buffer);
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200106 RTC_DCHECK_EQ(size(), buffer_size);
danilchap1edb7ab2016-04-20 05:25:10 -0700107 return true;
108}
109
Danil Chapovalov8769e172017-09-14 14:08:22 +0200110bool RtpPacket::Marker() const {
danilchap1edb7ab2016-04-20 05:25:10 -0700111 RTC_DCHECK_EQ(marker_, (data()[1] & 0x80) != 0);
112 return marker_;
113}
114
Danil Chapovalov8769e172017-09-14 14:08:22 +0200115uint8_t RtpPacket::PayloadType() const {
danilchap1edb7ab2016-04-20 05:25:10 -0700116 RTC_DCHECK_EQ(payload_type_, data()[1] & 0x7f);
117 return payload_type_;
118}
119
Danil Chapovalov8769e172017-09-14 14:08:22 +0200120uint16_t RtpPacket::SequenceNumber() const {
danilchap1edb7ab2016-04-20 05:25:10 -0700121 RTC_DCHECK_EQ(sequence_number_,
122 ByteReader<uint16_t>::ReadBigEndian(data() + 2));
123 return sequence_number_;
124}
125
Danil Chapovalov8769e172017-09-14 14:08:22 +0200126uint32_t RtpPacket::Timestamp() const {
danilchap1edb7ab2016-04-20 05:25:10 -0700127 RTC_DCHECK_EQ(timestamp_, ByteReader<uint32_t>::ReadBigEndian(data() + 4));
128 return timestamp_;
129}
130
Danil Chapovalov8769e172017-09-14 14:08:22 +0200131uint32_t RtpPacket::Ssrc() const {
danilchap1edb7ab2016-04-20 05:25:10 -0700132 RTC_DCHECK_EQ(ssrc_, ByteReader<uint32_t>::ReadBigEndian(data() + 8));
133 return ssrc_;
134}
135
Danil Chapovalov8769e172017-09-14 14:08:22 +0200136std::vector<uint32_t> RtpPacket::Csrcs() const {
danilchap1edb7ab2016-04-20 05:25:10 -0700137 size_t num_csrc = data()[0] & 0x0F;
138 RTC_DCHECK_GE(capacity(), kFixedHeaderSize + num_csrc * 4);
139 std::vector<uint32_t> csrcs(num_csrc);
140 for (size_t i = 0; i < num_csrc; ++i) {
141 csrcs[i] =
142 ByteReader<uint32_t>::ReadBigEndian(&data()[kFixedHeaderSize + i * 4]);
143 }
144 return csrcs;
145}
146
Danil Chapovalov8769e172017-09-14 14:08:22 +0200147size_t RtpPacket::headers_size() const {
danilchap1edb7ab2016-04-20 05:25:10 -0700148 return payload_offset_;
149}
150
Danil Chapovalov8769e172017-09-14 14:08:22 +0200151size_t RtpPacket::payload_size() const {
danilchap1edb7ab2016-04-20 05:25:10 -0700152 return payload_size_;
153}
154
Danil Chapovalov8769e172017-09-14 14:08:22 +0200155size_t RtpPacket::padding_size() const {
danilchap1edb7ab2016-04-20 05:25:10 -0700156 return padding_size_;
157}
158
Danil Chapovalov8769e172017-09-14 14:08:22 +0200159rtc::ArrayView<const uint8_t> RtpPacket::payload() const {
danilchap96c15872016-11-21 01:35:29 -0800160 return rtc::MakeArrayView(data() + payload_offset_, payload_size_);
danilchap1edb7ab2016-04-20 05:25:10 -0700161}
162
Danil Chapovalov8769e172017-09-14 14:08:22 +0200163rtc::CopyOnWriteBuffer RtpPacket::Buffer() const {
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200164 return buffer_;
165}
166
Danil Chapovalov8769e172017-09-14 14:08:22 +0200167size_t RtpPacket::capacity() const {
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200168 return buffer_.capacity();
danilchap1edb7ab2016-04-20 05:25:10 -0700169}
170
Danil Chapovalov8769e172017-09-14 14:08:22 +0200171size_t RtpPacket::size() const {
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200172 size_t ret = payload_offset_ + payload_size_ + padding_size_;
173 RTC_DCHECK_EQ(buffer_.size(), ret);
174 return ret;
danilchap1edb7ab2016-04-20 05:25:10 -0700175}
176
Danil Chapovalov8769e172017-09-14 14:08:22 +0200177const uint8_t* RtpPacket::data() const {
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200178 return buffer_.cdata();
danilchap1edb7ab2016-04-20 05:25:10 -0700179}
180
Danil Chapovalov8769e172017-09-14 14:08:22 +0200181size_t RtpPacket::FreeCapacity() const {
danilchap1edb7ab2016-04-20 05:25:10 -0700182 return capacity() - size();
183}
184
Danil Chapovalov8769e172017-09-14 14:08:22 +0200185size_t RtpPacket::MaxPayloadSize() const {
danilchap1edb7ab2016-04-20 05:25:10 -0700186 return capacity() - payload_offset_;
187}
188
Danil Chapovalov8769e172017-09-14 14:08:22 +0200189void RtpPacket::CopyHeaderFrom(const RtpPacket& packet) {
danilchap1edb7ab2016-04-20 05:25:10 -0700190 RTC_DCHECK_GE(capacity(), packet.headers_size());
191
192 marker_ = packet.marker_;
193 payload_type_ = packet.payload_type_;
194 sequence_number_ = packet.sequence_number_;
195 timestamp_ = packet.timestamp_;
196 ssrc_ = packet.ssrc_;
197 payload_offset_ = packet.payload_offset_;
danilchap70f39a32016-12-16 05:48:18 -0800198 for (size_t i = 0; i < kMaxExtensionHeaders; ++i) {
danilchap1edb7ab2016-04-20 05:25:10 -0700199 extension_entries_[i] = packet.extension_entries_[i];
200 }
201 extensions_size_ = packet.extensions_size_;
202 buffer_.SetData(packet.data(), packet.headers_size());
203 // Reset payload and padding.
204 payload_size_ = 0;
205 padding_size_ = 0;
206}
207
Danil Chapovalov8769e172017-09-14 14:08:22 +0200208void RtpPacket::SetMarker(bool marker_bit) {
danilchap1edb7ab2016-04-20 05:25:10 -0700209 marker_ = marker_bit;
210 if (marker_) {
211 WriteAt(1, data()[1] | 0x80);
212 } else {
213 WriteAt(1, data()[1] & 0x7F);
214 }
215}
216
Danil Chapovalov8769e172017-09-14 14:08:22 +0200217void RtpPacket::SetPayloadType(uint8_t payload_type) {
danilchap1edb7ab2016-04-20 05:25:10 -0700218 RTC_DCHECK_LE(payload_type, 0x7Fu);
219 payload_type_ = payload_type;
220 WriteAt(1, (data()[1] & 0x80) | payload_type);
221}
222
Danil Chapovalov8769e172017-09-14 14:08:22 +0200223void RtpPacket::SetSequenceNumber(uint16_t seq_no) {
danilchap1edb7ab2016-04-20 05:25:10 -0700224 sequence_number_ = seq_no;
225 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(2), seq_no);
226}
227
Danil Chapovalov8769e172017-09-14 14:08:22 +0200228void RtpPacket::SetTimestamp(uint32_t timestamp) {
danilchap1edb7ab2016-04-20 05:25:10 -0700229 timestamp_ = timestamp;
230 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(4), timestamp);
231}
232
Danil Chapovalov8769e172017-09-14 14:08:22 +0200233void RtpPacket::SetSsrc(uint32_t ssrc) {
danilchap1edb7ab2016-04-20 05:25:10 -0700234 ssrc_ = ssrc;
235 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(8), ssrc);
236}
237
Danil Chapovalov8769e172017-09-14 14:08:22 +0200238void RtpPacket::SetCsrcs(const std::vector<uint32_t>& csrcs) {
danilchap70f39a32016-12-16 05:48:18 -0800239 RTC_DCHECK_EQ(extensions_size_, 0);
kwibergaf476c72016-11-28 15:21:39 -0800240 RTC_DCHECK_EQ(payload_size_, 0);
241 RTC_DCHECK_EQ(padding_size_, 0);
danilchap1edb7ab2016-04-20 05:25:10 -0700242 RTC_DCHECK_LE(csrcs.size(), 0x0fu);
243 RTC_DCHECK_LE(kFixedHeaderSize + 4 * csrcs.size(), capacity());
244 payload_offset_ = kFixedHeaderSize + 4 * csrcs.size();
danilchap772bd8b2017-09-13 03:24:28 -0700245 WriteAt(0, (data()[0] & 0xF0) | rtc::dchecked_cast<uint8_t>(csrcs.size()));
danilchap1edb7ab2016-04-20 05:25:10 -0700246 size_t offset = kFixedHeaderSize;
247 for (uint32_t csrc : csrcs) {
248 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(offset), csrc);
249 offset += 4;
250 }
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200251 buffer_.SetSize(payload_offset_);
danilchap1edb7ab2016-04-20 05:25:10 -0700252}
253
Danil Chapovalov8769e172017-09-14 14:08:22 +0200254bool RtpPacket::HasRawExtension(int id) const {
danilchapc547e842017-04-10 01:31:49 -0700255 if (id == ExtensionManager::kInvalidId)
256 return false;
danilchap653063f2017-04-03 06:16:30 -0700257 RTC_DCHECK_GE(id, kMinExtensionId);
258 RTC_DCHECK_LE(id, kMaxExtensionId);
259 return extension_entries_[id - 1].offset != 0;
260}
261
Danil Chapovalov8769e172017-09-14 14:08:22 +0200262rtc::ArrayView<const uint8_t> RtpPacket::GetRawExtension(int id) const {
danilchapc547e842017-04-10 01:31:49 -0700263 if (id == ExtensionManager::kInvalidId)
264 return nullptr;
danilchap653063f2017-04-03 06:16:30 -0700265 RTC_DCHECK_GE(id, kMinExtensionId);
266 RTC_DCHECK_LE(id, kMaxExtensionId);
267 const ExtensionInfo& extension = extension_entries_[id - 1];
268 if (extension.offset == 0)
269 return nullptr;
270 return rtc::MakeArrayView(data() + extension.offset, extension.length);
271}
272
Danil Chapovalov8769e172017-09-14 14:08:22 +0200273bool RtpPacket::SetRawExtension(int id, rtc::ArrayView<const uint8_t> data) {
danilchap653063f2017-04-03 06:16:30 -0700274 auto buffer = AllocateRawExtension(id, data.size());
275 if (buffer.empty())
276 return false;
277 RTC_DCHECK_EQ(buffer.size(), data.size());
278 memcpy(buffer.data(), data.data(), data.size());
279 return true;
280}
281
Danil Chapovalov8769e172017-09-14 14:08:22 +0200282rtc::ArrayView<uint8_t> RtpPacket::AllocateRawExtension(int id, size_t length) {
danilchapc547e842017-04-10 01:31:49 -0700283 if (id == ExtensionManager::kInvalidId)
284 return nullptr;
danilchap653063f2017-04-03 06:16:30 -0700285 RTC_DCHECK_GE(id, kMinExtensionId);
286 RTC_DCHECK_LE(id, kMaxExtensionId);
287 RTC_DCHECK_GE(length, 1);
288 RTC_DCHECK_LE(length, 16);
289
290 ExtensionInfo* extension_entry = &extension_entries_[id - 1];
291 if (extension_entry->offset != 0) {
292 // Extension already reserved. Check if same length is used.
293 if (extension_entry->length == length)
294 return rtc::MakeArrayView(WriteAt(extension_entry->offset), length);
295
Mirko Bonadei675513b2017-11-09 11:09:25 +0100296 RTC_LOG(LS_ERROR) << "Length mismatch for extension id " << id << " type "
297 << static_cast<int>(extension_entry->type)
298 << ": expected "
299 << static_cast<int>(extension_entry->length)
300 << ". received " << length;
danilchap653063f2017-04-03 06:16:30 -0700301 return nullptr;
302 }
303 if (payload_size_ > 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100304 RTC_LOG(LS_ERROR) << "Can't add new extension id " << id
305 << " after payload was set.";
danilchap653063f2017-04-03 06:16:30 -0700306 return nullptr;
307 }
308 if (padding_size_ > 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100309 RTC_LOG(LS_ERROR) << "Can't add new extension id " << id
310 << " after padding was set.";
danilchap653063f2017-04-03 06:16:30 -0700311 return nullptr;
312 }
313
314 size_t num_csrc = data()[0] & 0x0F;
315 size_t extensions_offset = kFixedHeaderSize + (num_csrc * 4) + 4;
316 size_t new_extensions_size = extensions_size_ + kOneByteHeaderSize + length;
317 if (extensions_offset + new_extensions_size > capacity()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100318 RTC_LOG(LS_ERROR)
danilchap653063f2017-04-03 06:16:30 -0700319 << "Extension cannot be registered: Not enough space left in buffer.";
320 return nullptr;
321 }
322
323 // All checks passed, write down the extension headers.
324 if (extensions_size_ == 0) {
325 RTC_DCHECK_EQ(payload_offset_, kFixedHeaderSize + (num_csrc * 4));
326 WriteAt(0, data()[0] | 0x10); // Set extension bit.
327 // Profile specific ID always set to OneByteExtensionHeader.
328 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 4),
329 kOneByteExtensionId);
330 }
331
danilchap772bd8b2017-09-13 03:24:28 -0700332 uint8_t one_byte_header = rtc::dchecked_cast<uint8_t>(id) << 4;
333 one_byte_header |= rtc::dchecked_cast<uint8_t>(length - 1);
334 WriteAt(extensions_offset + extensions_size_, one_byte_header);
danilchap653063f2017-04-03 06:16:30 -0700335
danilchap772bd8b2017-09-13 03:24:28 -0700336 extension_entry->offset = rtc::dchecked_cast<uint16_t>(
337 extensions_offset + extensions_size_ + kOneByteHeaderSize);
338 extension_entry->length = rtc::dchecked_cast<uint8_t>(length);
Danil Chapovalov61405bc2018-02-13 13:55:30 +0100339 extensions_size_ = new_extensions_size;
danilchap653063f2017-04-03 06:16:30 -0700340
341 // Update header length field.
Danil Chapovalov61405bc2018-02-13 13:55:30 +0100342 uint16_t extensions_words = rtc::dchecked_cast<uint16_t>(
343 (extensions_size_ + 3) / 4); // Wrap up to 32bit.
danilchap653063f2017-04-03 06:16:30 -0700344 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 2),
345 extensions_words);
346 // Fill extension padding place with zeroes.
347 size_t extension_padding_size = 4 * extensions_words - extensions_size_;
348 memset(WriteAt(extensions_offset + extensions_size_), 0,
349 extension_padding_size);
350 payload_offset_ = extensions_offset + 4 * extensions_words;
351 buffer_.SetSize(payload_offset_);
352 return rtc::MakeArrayView(WriteAt(extension_entry->offset), length);
353}
354
Danil Chapovalov8769e172017-09-14 14:08:22 +0200355uint8_t* RtpPacket::AllocatePayload(size_t size_bytes) {
danilchap07a01b32017-03-29 07:33:13 -0700356 // Reset payload size to 0. If CopyOnWrite buffer_ was shared, this will cause
357 // reallocation and memcpy. Keeping just header reduces memcpy size.
358 SetPayloadSize(0);
359 return SetPayloadSize(size_bytes);
360}
361
Danil Chapovalov8769e172017-09-14 14:08:22 +0200362uint8_t* RtpPacket::SetPayloadSize(size_t size_bytes) {
kwibergaf476c72016-11-28 15:21:39 -0800363 RTC_DCHECK_EQ(padding_size_, 0);
danilchap1edb7ab2016-04-20 05:25:10 -0700364 if (payload_offset_ + size_bytes > capacity()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100365 RTC_LOG(LS_WARNING) << "Cannot set payload, not enough space in buffer.";
danilchap1edb7ab2016-04-20 05:25:10 -0700366 return nullptr;
367 }
368 payload_size_ = size_bytes;
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200369 buffer_.SetSize(payload_offset_ + payload_size_);
danilchap1edb7ab2016-04-20 05:25:10 -0700370 return WriteAt(payload_offset_);
371}
372
Danil Chapovalov8769e172017-09-14 14:08:22 +0200373bool RtpPacket::SetPadding(uint8_t size_bytes, Random* random) {
danilchap1edb7ab2016-04-20 05:25:10 -0700374 RTC_DCHECK(random);
375 if (payload_offset_ + payload_size_ + size_bytes > capacity()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100376 RTC_LOG(LS_WARNING) << "Cannot set padding size " << size_bytes << ", only "
377 << (capacity() - payload_offset_ - payload_size_)
378 << " bytes left in buffer.";
danilchap1edb7ab2016-04-20 05:25:10 -0700379 return false;
380 }
381 padding_size_ = size_bytes;
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200382 buffer_.SetSize(payload_offset_ + payload_size_ + padding_size_);
danilchap1edb7ab2016-04-20 05:25:10 -0700383 if (padding_size_ > 0) {
384 size_t padding_offset = payload_offset_ + payload_size_;
385 size_t padding_end = padding_offset + padding_size_;
386 for (size_t offset = padding_offset; offset < padding_end - 1; ++offset) {
387 WriteAt(offset, random->Rand<uint8_t>());
388 }
389 WriteAt(padding_end - 1, padding_size_);
390 WriteAt(0, data()[0] | 0x20); // Set padding bit.
391 } else {
392 WriteAt(0, data()[0] & ~0x20); // Clear padding bit.
393 }
394 return true;
395}
396
Danil Chapovalov8769e172017-09-14 14:08:22 +0200397void RtpPacket::Clear() {
danilchap1edb7ab2016-04-20 05:25:10 -0700398 marker_ = false;
399 payload_type_ = 0;
400 sequence_number_ = 0;
401 timestamp_ = 0;
402 ssrc_ = 0;
403 payload_offset_ = kFixedHeaderSize;
404 payload_size_ = 0;
405 padding_size_ = 0;
danilchap1edb7ab2016-04-20 05:25:10 -0700406 extensions_size_ = 0;
danilchap70f39a32016-12-16 05:48:18 -0800407 for (ExtensionInfo& location : extension_entries_) {
408 location.offset = 0;
409 location.length = 0;
410 }
danilchap1edb7ab2016-04-20 05:25:10 -0700411
412 memset(WriteAt(0), 0, kFixedHeaderSize);
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200413 buffer_.SetSize(kFixedHeaderSize);
danilchap1edb7ab2016-04-20 05:25:10 -0700414 WriteAt(0, kRtpVersion << 6);
415}
416
Danil Chapovalov8769e172017-09-14 14:08:22 +0200417bool RtpPacket::ParseBuffer(const uint8_t* buffer, size_t size) {
danilchap1edb7ab2016-04-20 05:25:10 -0700418 if (size < kFixedHeaderSize) {
419 return false;
420 }
421 const uint8_t version = buffer[0] >> 6;
422 if (version != kRtpVersion) {
423 return false;
424 }
425 const bool has_padding = (buffer[0] & 0x20) != 0;
426 const bool has_extension = (buffer[0] & 0x10) != 0;
427 const uint8_t number_of_crcs = buffer[0] & 0x0f;
428 marker_ = (buffer[1] & 0x80) != 0;
429 payload_type_ = buffer[1] & 0x7f;
430
431 sequence_number_ = ByteReader<uint16_t>::ReadBigEndian(&buffer[2]);
432 timestamp_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]);
433 ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]);
434 if (size < kFixedHeaderSize + number_of_crcs * 4) {
435 return false;
436 }
437 payload_offset_ = kFixedHeaderSize + number_of_crcs * 4;
438
439 if (has_padding) {
440 padding_size_ = buffer[size - 1];
441 if (padding_size_ == 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100442 RTC_LOG(LS_WARNING) << "Padding was set, but padding size is zero";
danilchap1edb7ab2016-04-20 05:25:10 -0700443 return false;
444 }
445 } else {
446 padding_size_ = 0;
447 }
448
danilchap1edb7ab2016-04-20 05:25:10 -0700449 extensions_size_ = 0;
danilchap70f39a32016-12-16 05:48:18 -0800450 for (ExtensionInfo& location : extension_entries_) {
451 location.offset = 0;
452 location.length = 0;
453 }
danilchap1edb7ab2016-04-20 05:25:10 -0700454 if (has_extension) {
455 /* RTP header extension, RFC 3550.
456 0 1 2 3
457 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
458 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
459 | defined by profile | length |
460 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
461 | header extension |
462 | .... |
463 */
464 size_t extension_offset = payload_offset_ + 4;
465 if (extension_offset > size) {
466 return false;
467 }
468 uint16_t profile =
469 ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_]);
470 size_t extensions_capacity =
471 ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_ + 2]);
472 extensions_capacity *= 4;
473 if (extension_offset + extensions_capacity > size) {
474 return false;
475 }
476 if (profile != kOneByteExtensionId) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100477 RTC_LOG(LS_WARNING) << "Unsupported rtp extension " << profile;
danilchap1edb7ab2016-04-20 05:25:10 -0700478 } else {
479 constexpr uint8_t kPaddingId = 0;
480 constexpr uint8_t kReservedId = 15;
481 while (extensions_size_ + kOneByteHeaderSize < extensions_capacity) {
danilchap70f39a32016-12-16 05:48:18 -0800482 int id = buffer[extension_offset + extensions_size_] >> 4;
danilchap1edb7ab2016-04-20 05:25:10 -0700483 if (id == kReservedId) {
484 break;
485 } else if (id == kPaddingId) {
486 extensions_size_++;
487 continue;
488 }
489 uint8_t length =
490 1 + (buffer[extension_offset + extensions_size_] & 0xf);
Danil Chapovalova64a2fb2016-09-12 11:41:35 +0200491 if (extensions_size_ + kOneByteHeaderSize + length >
492 extensions_capacity) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100493 RTC_LOG(LS_WARNING) << "Oversized rtp header extension.";
Danil Chapovalova64a2fb2016-09-12 11:41:35 +0200494 break;
danilchap1edb7ab2016-04-20 05:25:10 -0700495 }
danilchap70f39a32016-12-16 05:48:18 -0800496
497 size_t idx = id - 1;
498 if (extension_entries_[idx].length != 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100499 RTC_LOG(LS_VERBOSE)
500 << "Duplicate rtp header extension id " << id << ". Overwriting.";
Danil Chapovalova64a2fb2016-09-12 11:41:35 +0200501 }
danilchap70f39a32016-12-16 05:48:18 -0800502
Danil Chapovalovc2dd59c2018-02-06 11:29:35 +0100503 size_t offset =
504 extension_offset + extensions_size_ + kOneByteHeaderSize;
505 if (!rtc::IsValueInRangeForNumericType<uint16_t>(offset)) {
506 RTC_DLOG(LS_WARNING) << "Oversized rtp header extension.";
507 break;
508 }
509 extension_entries_[idx].offset = static_cast<uint16_t>(offset);
510 extension_entries_[idx].length = length;
511 extensions_size_ += kOneByteHeaderSize + length;
danilchap1edb7ab2016-04-20 05:25:10 -0700512 }
513 }
514 payload_offset_ = extension_offset + extensions_capacity;
515 }
516
517 if (payload_offset_ + padding_size_ > size) {
518 return false;
519 }
520 payload_size_ = size - payload_offset_ - padding_size_;
521 return true;
522}
523
Danil Chapovalov8769e172017-09-14 14:08:22 +0200524rtc::ArrayView<const uint8_t> RtpPacket::FindExtension(
525 ExtensionType type) const {
danilchap70f39a32016-12-16 05:48:18 -0800526 for (const ExtensionInfo& extension : extension_entries_) {
527 if (extension.type == type) {
528 if (extension.length == 0) {
529 // Extension is registered but not set.
danilchap978504e2017-04-06 01:03:53 -0700530 return nullptr;
danilchap07ec26d2016-06-17 04:18:54 -0700531 }
danilchap978504e2017-04-06 01:03:53 -0700532 return rtc::MakeArrayView(data() + extension.offset, extension.length);
danilchap1edb7ab2016-04-20 05:25:10 -0700533 }
534 }
danilchap978504e2017-04-06 01:03:53 -0700535 return nullptr;
danilchap1edb7ab2016-04-20 05:25:10 -0700536}
537
Danil Chapovalov8769e172017-09-14 14:08:22 +0200538rtc::ArrayView<uint8_t> RtpPacket::AllocateExtension(ExtensionType type,
539 size_t length) {
danilchap772bd8b2017-09-13 03:24:28 -0700540 for (int i = 0; i < kMaxExtensionHeaders; ++i) {
danilchap70f39a32016-12-16 05:48:18 -0800541 if (extension_entries_[i].type == type) {
danilchap653063f2017-04-03 06:16:30 -0700542 int extension_id = i + 1;
543 return AllocateRawExtension(extension_id, length);
danilchap70f39a32016-12-16 05:48:18 -0800544 }
danilchap1edb7ab2016-04-20 05:25:10 -0700545 }
danilchap653063f2017-04-03 06:16:30 -0700546 // Extension not registered.
547 return nullptr;
danilchap1edb7ab2016-04-20 05:25:10 -0700548}
549
Danil Chapovalov8769e172017-09-14 14:08:22 +0200550uint8_t* RtpPacket::WriteAt(size_t offset) {
danilchap1edb7ab2016-04-20 05:25:10 -0700551 return buffer_.data() + offset;
552}
553
Danil Chapovalov8769e172017-09-14 14:08:22 +0200554void RtpPacket::WriteAt(size_t offset, uint8_t byte) {
danilchap1edb7ab2016-04-20 05:25:10 -0700555 buffer_.data()[offset] = byte;
556}
557
danilchap1edb7ab2016-04-20 05:25:10 -0700558} // namespace webrtc