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::IdentifyExtensions(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(timestamp_, ByteReader<uint32_t>::ReadBigEndian(data() + 4)); | |
| 113 return timestamp_; | |
| 114 } | |
| 115 | |
| 116 uint32_t Packet::Ssrc() const { | |
| 117 RTC_DCHECK_EQ(ssrc_, ByteReader<uint32_t>::ReadBigEndian(data() + 8)); | |
| 118 return ssrc_; | |
| 119 } | |
| 120 | |
| 121 std::vector<uint32_t> Packet::Csrcs() const { | |
| 122 size_t num_csrc = data()[0] & 0x0F; | |
| 123 RTC_DCHECK_GE(capacity(), kFixedHeaderSize + num_csrc * 4); | |
| 124 std::vector<uint32_t> csrcs(num_csrc); | |
| 125 for (size_t i = 0; i < num_csrc; ++i) { | |
| 126 csrcs[i] = | |
| 127 ByteReader<uint32_t>::ReadBigEndian(&data()[kFixedHeaderSize + i * 4]); | |
| 128 } | |
| 129 return csrcs; | |
| 130 } | |
| 131 | |
| 132 void Packet::GetHeader(RTPHeader* header) const { | |
| 133 header->markerBit = Marker(); | |
| 134 header->payloadType = PayloadType(); | |
| 135 header->sequenceNumber = SequenceNumber(); | |
| 136 header->timestamp = Timestamp(); | |
| 137 header->ssrc = Ssrc(); | |
| 138 std::vector<uint32_t> csrcs = Csrcs(); | |
| 139 header->numCSRCs = csrcs.size(); | |
| 140 for (size_t i = 0; i < csrcs.size(); ++i) { | |
| 141 header->arrOfCSRCs[i] = csrcs[i]; | |
| 142 } | |
| 143 header->paddingLength = padding_size(); | |
| 144 header->headerLength = headers_size(); | |
| 145 header->payload_type_frequency = 0; | |
| 146 header->extension.hasTransmissionTimeOffset = | |
| 147 GetExtension<TransmissionOffset>( | |
| 148 &header->extension.transmissionTimeOffset); | |
| 149 header->extension.hasAbsoluteSendTime = | |
| 150 GetExtension<AbsoluteSendTime>(&header->extension.absoluteSendTime); | |
| 151 header->extension.hasTransportSequenceNumber = | |
| 152 GetExtension<TransportSequenceNumber>( | |
| 153 &header->extension.transportSequenceNumber); | |
| 154 header->extension.hasAudioLevel = GetExtension<AudioLevel>( | |
| 155 &header->extension.voiceActivity, &header->extension.audioLevel); | |
| 156 header->extension.hasVideoRotation = | |
| 157 GetExtension<VideoOrientation>(&header->extension.videoRotation); | |
| 158 } | |
| 159 | |
| 160 size_t Packet::headers_size() const { | |
| 161 return payload_offset_; | |
| 162 } | |
| 163 | |
| 164 size_t Packet::payload_size() const { | |
| 165 return payload_size_; | |
| 166 } | |
| 167 | |
| 168 size_t Packet::padding_size() const { | |
| 169 return padding_size_; | |
| 170 } | |
| 171 | |
| 172 const uint8_t* Packet::payload() const { | |
| 173 return data() + payload_offset_; | |
| 174 } | |
| 175 | |
| 176 size_t Packet::capacity() const { | |
| 177 return buffer_.size(); | |
|
terelius
2016/04/19 14:18:20
Whats the reason for changing to .size() instead o
| |
| 178 } | |
| 179 | |
| 180 size_t Packet::size() const { | |
| 181 return payload_offset_ + payload_size_ + padding_size_; | |
| 182 } | |
| 183 | |
| 184 const uint8_t* Packet::data() const { | |
| 185 return buffer_.data(); | |
| 186 } | |
| 187 | |
| 188 size_t Packet::FreeCapacity() const { | |
| 189 return capacity() - size(); | |
| 190 } | |
| 191 | |
| 192 size_t Packet::MaxPayloadSize() const { | |
| 193 return capacity() - payload_offset_; | |
| 194 } | |
| 195 | |
| 196 void Packet::CopyHeader(const Packet& packet) { | |
| 197 RTC_DCHECK_GE(capacity(), packet.headers_size()); | |
| 198 | |
| 199 marker_ = packet.marker_; | |
| 200 payload_type_ = packet.payload_type_; | |
| 201 sequence_number_ = packet.sequence_number_; | |
| 202 timestamp_ = packet.timestamp_; | |
| 203 ssrc_ = packet.ssrc_; | |
| 204 payload_offset_ = packet.payload_offset_; | |
| 205 num_extensions_ = packet.num_extensions_; | |
| 206 for (size_t i = 0; i < num_extensions_; ++i) { | |
| 207 extension_entries_[i] = packet.extension_entries_[i]; | |
| 208 } | |
| 209 extensions_size_ = packet.extensions_size_; | |
| 210 buffer_.SetData(packet.data(), packet.headers_size()); | |
| 211 // Reset payload and padding. | |
| 212 payload_size_ = 0; | |
| 213 padding_size_ = 0; | |
| 214 } | |
| 215 | |
| 216 void Packet::SetMarker(bool marker_bit) { | |
| 217 marker_ = marker_bit; | |
| 218 if (marker_) { | |
| 219 WriteAt(1, data()[1] | 0x80); | |
| 220 } else { | |
| 221 WriteAt(1, data()[1] & 0x7F); | |
| 222 } | |
| 223 } | |
| 224 | |
| 225 void Packet::SetPayloadType(uint8_t payload_type) { | |
| 226 RTC_DCHECK_LE(payload_type, 0x7Fu); | |
| 227 payload_type_ = payload_type; | |
| 228 WriteAt(1, (data()[1] & 0x80) | payload_type); | |
| 229 } | |
| 230 | |
| 231 void Packet::SetSequenceNumber(uint16_t seq_no) { | |
| 232 sequence_number_ = seq_no; | |
| 233 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(2), seq_no); | |
| 234 } | |
| 235 | |
| 236 void Packet::SetTimestamp(uint32_t timestamp) { | |
| 237 timestamp_ = timestamp; | |
| 238 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(4), timestamp); | |
| 239 } | |
| 240 | |
| 241 void Packet::SetSsrc(uint32_t ssrc) { | |
| 242 ssrc_ = ssrc; | |
| 243 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(8), ssrc); | |
| 244 } | |
| 245 | |
| 246 void Packet::SetCsrcs(const std::vector<uint32_t>& csrcs) { | |
| 247 RTC_DCHECK_EQ(num_extensions_, 0u); | |
| 248 RTC_DCHECK_EQ(payload_size_, 0u); | |
| 249 RTC_DCHECK_EQ(padding_size_, 0u); | |
| 250 RTC_DCHECK_LE(csrcs.size(), 0x0fu); | |
| 251 RTC_DCHECK_LE(kFixedHeaderSize + 4 * csrcs.size(), capacity()); | |
| 252 payload_offset_ = kFixedHeaderSize + 4 * csrcs.size(); | |
| 253 WriteAt(0, (data()[0] & 0xF0) | csrcs.size()); | |
| 254 size_t offset = kFixedHeaderSize; | |
| 255 for (uint32_t csrc : csrcs) { | |
| 256 ByteWriter<uint32_t>::WriteBigEndian(WriteAt(offset), csrc); | |
| 257 offset += 4; | |
| 258 } | |
| 259 } | |
| 260 | |
| 261 uint8_t* Packet::AllocatePayload(size_t size_bytes) { | |
| 262 RTC_DCHECK_EQ(padding_size_, 0u); | |
| 263 if (payload_offset_ + size_bytes > capacity()) { | |
| 264 LOG(LS_WARNING) << "Cannot set payload, not enough space in buffer."; | |
| 265 return nullptr; | |
| 266 } | |
| 267 payload_size_ = size_bytes; | |
| 268 return WriteAt(payload_offset_); | |
| 269 } | |
| 270 | |
| 271 void Packet::SetPayloadSize(size_t size_bytes) { | |
| 272 RTC_DCHECK_EQ(padding_size_, 0u); | |
| 273 RTC_DCHECK_LE(size_bytes, payload_size_); | |
| 274 payload_size_ = size_bytes; | |
| 275 } | |
| 276 | |
| 277 bool Packet::SetPadding(uint8_t size_bytes, Random* random) { | |
| 278 RTC_DCHECK(random); | |
| 279 if (payload_offset_ + payload_size_ + size_bytes > capacity()) { | |
| 280 LOG(LS_WARNING) << "Cannot set padding size " << size_bytes << ", only " | |
| 281 << (capacity() - payload_offset_ - payload_size_) | |
| 282 << " bytes left in buffer."; | |
| 283 return false; | |
| 284 } | |
| 285 padding_size_ = size_bytes; | |
| 286 if (padding_size_ > 0) { | |
| 287 size_t padding_offset = payload_offset_ + payload_size_; | |
| 288 size_t padding_end = padding_offset + padding_size_; | |
| 289 for (size_t offset = padding_offset; offset < padding_end - 1; ++offset) { | |
| 290 WriteAt(offset, random->Rand<uint8_t>()); | |
| 291 } | |
| 292 WriteAt(padding_end - 1, padding_size_); | |
| 293 WriteAt(0, data()[0] | 0x20); // Set padding bit. | |
| 294 } else { | |
| 295 WriteAt(0, data()[0] & ~0x20); // Clear padding bit. | |
| 296 } | |
| 297 return true; | |
| 298 } | |
| 299 | |
| 300 void Packet::Clear() { | |
| 301 marker_ = false; | |
| 302 payload_type_ = 0; | |
| 303 sequence_number_ = 0; | |
| 304 timestamp_ = 0; | |
| 305 ssrc_ = 0; | |
| 306 payload_offset_ = kFixedHeaderSize; | |
| 307 payload_size_ = 0; | |
| 308 padding_size_ = 0; | |
| 309 num_extensions_ = 0; | |
| 310 extensions_size_ = 0; | |
| 311 | |
| 312 memset(WriteAt(0), 0, kFixedHeaderSize); | |
| 313 WriteAt(0, kRtpVersion << 6); | |
| 314 } | |
| 315 | |
| 316 bool Packet::ParseBuffer(const uint8_t* buffer, size_t size) { | |
| 317 if (size < kFixedHeaderSize) { | |
| 318 return false; | |
| 319 } | |
| 320 const uint8_t version = buffer[0] >> 6; | |
| 321 if (version != kRtpVersion) { | |
| 322 return false; | |
| 323 } | |
| 324 const bool has_padding = (buffer[0] & 0x20) != 0; | |
| 325 const bool has_extension = (buffer[0] & 0x10) != 0; | |
| 326 const uint8_t number_of_crcs = buffer[0] & 0x0f; | |
| 327 marker_ = (buffer[1] & 0x80) != 0; | |
| 328 payload_type_ = buffer[1] & 0x7f; | |
| 329 | |
| 330 sequence_number_ = ByteReader<uint16_t>::ReadBigEndian(&buffer[2]); | |
| 331 timestamp_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]); | |
| 332 ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]); | |
| 333 if (size < kFixedHeaderSize + number_of_crcs * 4) { | |
| 334 return false; | |
| 335 } | |
| 336 payload_offset_ = kFixedHeaderSize + number_of_crcs * 4; | |
| 337 | |
| 338 if (has_padding) { | |
| 339 padding_size_ = buffer[size - 1]; | |
| 340 if (padding_size_ == 0) { | |
| 341 LOG(LS_WARNING) << "Padding was set, but padding size is zero"; | |
| 342 return false; | |
| 343 } | |
| 344 } else { | |
| 345 padding_size_ = 0; | |
| 346 } | |
| 347 | |
| 348 num_extensions_ = 0; | |
| 349 extensions_size_ = 0; | |
| 350 if (has_extension) { | |
| 351 /* RTP header extension, RFC 3550. | |
| 352 0 1 2 3 | |
| 353 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 | |
| 354 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| 355 | defined by profile | length | | |
| 356 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| 357 | header extension | | |
| 358 | .... | | |
| 359 */ | |
| 360 size_t extension_offset = payload_offset_ + 4; | |
| 361 if (extension_offset > size) { | |
| 362 return false; | |
| 363 } | |
| 364 uint16_t profile = | |
| 365 ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_]); | |
| 366 size_t extensions_capacity = | |
| 367 ByteReader<uint16_t>::ReadBigEndian(&buffer[payload_offset_ + 2]); | |
| 368 extensions_capacity *= 4; | |
| 369 if (extension_offset + extensions_capacity > size) { | |
| 370 return false; | |
| 371 } | |
| 372 if (profile != kOneByteExtensionId) { | |
| 373 LOG(LS_WARNING) << "Unsupported rtp extension " << profile; | |
| 374 } else { | |
| 375 const size_t kOneByteHeaderSize = 1; | |
| 376 const uint8_t kPaddingId = 0; | |
| 377 const uint8_t kReservedId = 15; | |
| 378 while (extensions_size_ + kOneByteHeaderSize < extensions_capacity) { | |
| 379 uint8_t id = buffer[extension_offset + extensions_size_] >> 4; | |
| 380 if (id == kReservedId) { | |
| 381 break; | |
| 382 } else if (id == kPaddingId) { | |
| 383 extensions_size_++; | |
| 384 continue; | |
| 385 } | |
| 386 uint8_t length = | |
| 387 1 + (buffer[extension_offset + extensions_size_] & 0xf); | |
| 388 extensions_size_ += kOneByteHeaderSize; | |
| 389 if (num_extensions_ >= kMaxExtensionHeaders) { | |
| 390 LOG(LS_WARNING) << "Too many extensions."; | |
| 391 return false; | |
| 392 } | |
| 393 extension_entries_[num_extensions_].type = | |
| 394 extensions_ ? extensions_->GetType(id) | |
| 395 : ExtensionManager::kInvalidType; | |
| 396 extension_entries_[num_extensions_].length = length; | |
| 397 extension_entries_[num_extensions_].offset = | |
| 398 extension_offset + extensions_size_; | |
| 399 num_extensions_++; | |
| 400 extensions_size_ += length; | |
| 401 } | |
| 402 } | |
| 403 payload_offset_ = extension_offset + extensions_capacity; | |
| 404 } | |
| 405 | |
| 406 if (payload_offset_ + padding_size_ > size) { | |
| 407 return false; | |
| 408 } | |
| 409 payload_size_ = size - payload_offset_ - padding_size_; | |
| 410 return true; | |
| 411 } | |
| 412 | |
| 413 bool Packet::FindExtension(ExtensionType type, | |
| 414 uint8_t length, | |
| 415 uint16_t* offset) const { | |
| 416 RTC_DCHECK(offset); | |
| 417 for (size_t i = 0; i < num_extensions_; ++i) { | |
| 418 if (extension_entries_[i].type == type) { | |
| 419 RTC_CHECK_EQ(length, extension_entries_[i].length) | |
| 420 << "Length mismatch for extension '" << type << "'" | |
| 421 << "should be " << length << ", received " | |
| 422 << extension_entries_[i].length; | |
| 423 *offset = extension_entries_[i].offset; | |
| 424 return true; | |
| 425 } | |
| 426 } | |
| 427 return false; | |
| 428 } | |
| 429 | |
| 430 bool Packet::AllocateExtension(ExtensionType type, | |
| 431 uint8_t length, | |
| 432 uint16_t* offset) { | |
| 433 if (!extensions_) { | |
| 434 return false; | |
| 435 } | |
| 436 if (FindExtension(type, length, offset)) { | |
| 437 return true; | |
| 438 } | |
| 439 | |
| 440 // Can't add new extension after payload/padding was set. | |
| 441 if (payload_size_ > 0) { | |
| 442 return false; | |
| 443 } | |
| 444 if (padding_size_ > 0) { | |
| 445 return false; | |
| 446 } | |
| 447 | |
| 448 uint8_t extension_id = extensions_->GetId(type); | |
| 449 if (extension_id == ExtensionManager::kInvalidId) { | |
| 450 return false; | |
| 451 } | |
| 452 RTC_DCHECK_GT(length, 0u); | |
| 453 RTC_DCHECK_LE(length, 16u); | |
| 454 | |
| 455 size_t num_csrc = data()[0] & 0x0F; | |
| 456 size_t extensions_offset = kFixedHeaderSize + (num_csrc * 4) + 4; | |
| 457 const uint8_t kExtensionHeaderSize = 1; // Using one-byte extensions only. | |
| 458 if (extensions_offset + extensions_size_ + kExtensionHeaderSize + length > | |
| 459 capacity()) { | |
| 460 LOG(LS_WARNING) << "Extension cannot be registered: " | |
| 461 "Not enough space left in buffer."; | |
| 462 return false; | |
| 463 } | |
| 464 | |
| 465 uint16_t new_extensions_size = | |
| 466 extensions_size_ + kExtensionHeaderSize + length; | |
| 467 uint16_t extensions_words = | |
| 468 (new_extensions_size + 3) / 4; // Wrap up to 32bit. | |
| 469 if (extensions_words > 0xFFFF) { | |
| 470 LOG(LS_WARNING) << "Too much extension header data, exceeds 2^16 DWORDS."; | |
| 471 return false; | |
| 472 } | |
| 473 | |
| 474 // All checks passed, write down the extension. | |
| 475 if (num_extensions_ == 0) { | |
| 476 RTC_DCHECK_EQ(payload_offset_, kFixedHeaderSize + (num_csrc * 4)); | |
| 477 RTC_DCHECK_EQ(extensions_size_, 0); | |
| 478 WriteAt(0, data()[0] | 0x10); // Set extension bit. | |
| 479 // Profile specific ID always set to OneByteExtensionHeader. | |
| 480 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 4), | |
| 481 kOneByteExtensionId); | |
| 482 } | |
| 483 | |
| 484 WriteAt(extensions_offset + extensions_size_, | |
| 485 (extension_id << 4) | (length - 1)); | |
| 486 RTC_DCHECK(num_extensions_ < kMaxExtensionHeaders); | |
|
terelius
2016/04/19 14:18:20
Why not use DCHECK_LT here?
| |
| 487 extension_entries_[num_extensions_].type = type; | |
| 488 extension_entries_[num_extensions_].length = length; | |
| 489 *offset = extensions_offset + kExtensionHeaderSize + extensions_size_; | |
| 490 extension_entries_[num_extensions_].offset = *offset; | |
| 491 ++num_extensions_; | |
| 492 extensions_size_ = new_extensions_size; | |
| 493 | |
| 494 // Update header length field. | |
| 495 ByteWriter<uint16_t>::WriteBigEndian(WriteAt(extensions_offset - 2), | |
| 496 extensions_words); | |
| 497 // Fill extension padding place with zeroes. | |
| 498 size_t extension_padding_size = 4 * extensions_words - extensions_size_; | |
| 499 memset(WriteAt(extensions_offset + extensions_size_), 0, | |
| 500 extension_padding_size); | |
| 501 payload_offset_ = extensions_offset + 4 * extensions_words; | |
| 502 return true; | |
| 503 } | |
| 504 | |
| 505 uint8_t* Packet::WriteAt(size_t offset) { | |
| 506 return buffer_.data() + offset; | |
| 507 } | |
| 508 | |
| 509 void Packet::WriteAt(size_t offset, uint8_t byte) { | |
| 510 buffer_.data()[offset] = byte; | |
| 511 } | |
| 512 | |
| 513 } // namespace rtp | |
| 514 } // namespace webrtc | |
| OLD | NEW |