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