diff options
Diffstat (limited to 'webrtc/modules/rtp_rtcp/source/rtcp_packet/bye.cc')
-rw-r--r-- | webrtc/modules/rtp_rtcp/source/rtcp_packet/bye.cc | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/bye.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/bye.cc new file mode 100644 index 0000000000..4cfc921ce5 --- /dev/null +++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/bye.cc @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/bye.h" + +#include "webrtc/base/checks.h" +#include "webrtc/base/logging.h" +#include "webrtc/modules/rtp_rtcp/source/byte_io.h" + +using webrtc::RTCPUtility::RtcpCommonHeader; + +namespace webrtc { +namespace rtcp { + +// Bye packet (BYE) (RFC 3550). +// +// 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 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |V=2|P| SC | PT=BYE=203 | length | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | SSRC/CSRC | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// : ... : +// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ +// (opt) | length | reason for leaving ... +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +Bye::Bye() : sender_ssrc_(0) {} + +bool Bye::Parse(const RtcpCommonHeader& header, const uint8_t* payload) { + RTC_DCHECK(header.packet_type == kPacketType); + + const uint8_t src_count = header.count_or_format; + // Validate packet. + if (header.payload_size_bytes < 4u * src_count) { + LOG(LS_WARNING) + << "Packet is too small to contain CSRCs it promise to have."; + return false; + } + bool has_reason = (header.payload_size_bytes > 4u * src_count); + uint8_t reason_length = 0; + if (has_reason) { + reason_length = payload[4u * src_count]; + if (header.payload_size_bytes - 4u * src_count < 1u + reason_length) { + LOG(LS_WARNING) << "Invalid reason length: " << reason_length; + return false; + } + } + // Once sure packet is valid, copy values. + if (src_count == 0) { // A count value of zero is valid, but useless. + sender_ssrc_ = 0; + csrcs_.clear(); + } else { + sender_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(payload); + csrcs_.resize(src_count - 1); + for (size_t i = 1; i < src_count; ++i) + csrcs_[i - 1] = ByteReader<uint32_t>::ReadBigEndian(&payload[4 * i]); + } + + if (has_reason) { + reason_.assign(reinterpret_cast<const char*>(&payload[4u * src_count + 1]), + reason_length); + } else { + reason_.clear(); + } + + return true; +} + +bool Bye::Create(uint8_t* packet, + size_t* index, + size_t max_length, + RtcpPacket::PacketReadyCallback* callback) const { + while (*index + BlockLength() > max_length) { + if (!OnBufferFull(packet, index, callback)) + return false; + } + const size_t index_end = *index + BlockLength(); + + CreateHeader(1 + csrcs_.size(), kPacketType, HeaderLength(), packet, index); + // Store srcs of the leaving clients. + ByteWriter<uint32_t>::WriteBigEndian(&packet[*index], sender_ssrc_); + *index += sizeof(uint32_t); + for (uint32_t csrc : csrcs_) { + ByteWriter<uint32_t>::WriteBigEndian(&packet[*index], csrc); + *index += sizeof(uint32_t); + } + // Store the reason to leave. + if (!reason_.empty()) { + uint8_t reason_length = reason_.size(); + packet[(*index)++] = reason_length; + memcpy(&packet[*index], reason_.data(), reason_length); + *index += reason_length; + // Add padding bytes if needed. + size_t bytes_to_pad = index_end - *index; + RTC_DCHECK_LE(bytes_to_pad, 3u); + if (bytes_to_pad > 0) { + memset(&packet[*index], 0, bytes_to_pad); + *index += bytes_to_pad; + } + } + RTC_DCHECK_EQ(index_end, *index); + return true; +} + +bool Bye::WithCsrc(uint32_t csrc) { + if (csrcs_.size() >= kMaxNumberOfCsrcs) { + LOG(LS_WARNING) << "Max CSRC size reached."; + return false; + } + csrcs_.push_back(csrc); + return true; +} + +void Bye::WithReason(const std::string& reason) { + RTC_DCHECK_LE(reason.size(), 0xffu); + reason_ = reason; +} + +size_t Bye::BlockLength() const { + size_t src_count = (1 + csrcs_.size()); + size_t reason_size_in_32bits = reason_.empty() ? 0 : (reason_.size() / 4 + 1); + return kHeaderLength + 4 * (src_count + reason_size_in_32bits); +} + +} // namespace rtcp +} // namespace webrtc |