got member read accessors, got Parse function. BUG=webrtc:5260 R=åsapersson Review URL: https://codereview.webrtc.org/1552773002 Cr-Commit-Position: refs/heads/master@{#11324}
134 lines
5.0 KiB
C++
134 lines
5.0 KiB
C++
/*
|
|
* Copyright (c) 2016 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/remb.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 {
|
|
// Receiver Estimated Max Bitrate (REMB) (draft-alvestrand-rmcat-remb).
|
|
//
|
|
// 0 1 2 3
|
|
// 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| FMT=15 | PT=206 | length |
|
|
// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
|
// 0 | SSRC of packet sender |
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// 4 | Unused = 0 |
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// 8 | Unique identifier 'R' 'E' 'M' 'B' |
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// 12 | Num SSRC | BR Exp | BR Mantissa |
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// 16 | SSRC feedback |
|
|
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
// : ... :
|
|
bool Remb::Parse(const RtcpCommonHeader& header, const uint8_t* payload) {
|
|
RTC_DCHECK(header.packet_type == kPacketType);
|
|
RTC_DCHECK(header.count_or_format == kFeedbackMessageType);
|
|
|
|
if (header.payload_size_bytes < 16) {
|
|
LOG(LS_WARNING) << "Payload length " << header.payload_size_bytes
|
|
<< " is too small for Remb packet.";
|
|
return false;
|
|
}
|
|
if (kUniqueIdentifier != ByteReader<uint32_t>::ReadBigEndian(&payload[8])) {
|
|
LOG(LS_WARNING) << "REMB identifier not found, not a REMB packet.";
|
|
return false;
|
|
}
|
|
uint8_t number_of_ssrcs = payload[12];
|
|
if (header.payload_size_bytes !=
|
|
kCommonFeedbackLength + (2 + number_of_ssrcs) * 4) {
|
|
LOG(LS_WARNING) << "Payload size " << header.payload_size_bytes
|
|
<< " does not match " << number_of_ssrcs << " ssrcs.";
|
|
return false;
|
|
}
|
|
|
|
ParseCommonFeedback(payload);
|
|
uint8_t exponenta = payload[13] >> 2;
|
|
uint32_t mantissa = (static_cast<uint32_t>(payload[13] & 0x03) << 16) |
|
|
ByteReader<uint16_t>::ReadBigEndian(&payload[14]);
|
|
bitrate_bps_ = (mantissa << exponenta);
|
|
|
|
const uint8_t* next_ssrc = payload + 16;
|
|
ssrcs_.clear();
|
|
ssrcs_.reserve(number_of_ssrcs);
|
|
for (uint8_t i = 0; i < number_of_ssrcs; ++i) {
|
|
ssrcs_.push_back(ByteReader<uint32_t>::ReadBigEndian(next_ssrc));
|
|
next_ssrc += sizeof(uint32_t);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Remb::AppliesTo(uint32_t ssrc) {
|
|
if (ssrcs_.size() >= kMaxNumberOfSsrcs) {
|
|
LOG(LS_WARNING) << "Max number of REMB feedback SSRCs reached.";
|
|
return false;
|
|
}
|
|
ssrcs_.push_back(ssrc);
|
|
return true;
|
|
}
|
|
|
|
bool Remb::AppliesToMany(const std::vector<uint32_t>& ssrcs) {
|
|
if (ssrcs_.size() + ssrcs.size() > kMaxNumberOfSsrcs) {
|
|
LOG(LS_WARNING) << "Not enough space for all given SSRCs.";
|
|
return false;
|
|
}
|
|
// Append.
|
|
ssrcs_.insert(ssrcs_.end(), ssrcs.begin(), ssrcs.end());
|
|
return true;
|
|
}
|
|
|
|
bool Remb::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;
|
|
}
|
|
size_t index_end = *index + BlockLength();
|
|
CreateHeader(kFeedbackMessageType, kPacketType, HeaderLength(), packet,
|
|
index);
|
|
RTC_DCHECK_EQ(0u, Psfb::media_ssrc());
|
|
CreateCommonFeedback(packet + *index);
|
|
*index += kCommonFeedbackLength;
|
|
|
|
ByteWriter<uint32_t>::WriteBigEndian(packet + *index, kUniqueIdentifier);
|
|
*index += sizeof(uint32_t);
|
|
const uint32_t kMaxMantissa = 0x3ffff; // 18 bits.
|
|
uint32_t mantissa = bitrate_bps_;
|
|
uint8_t exponenta = 0;
|
|
while (mantissa > kMaxMantissa) {
|
|
mantissa >>= 1;
|
|
++exponenta;
|
|
}
|
|
packet[(*index)++] = ssrcs_.size();
|
|
packet[(*index)++] = (exponenta << 2) | (mantissa >> 16);
|
|
ByteWriter<uint16_t>::WriteBigEndian(packet + *index, mantissa & 0xffff);
|
|
*index += sizeof(uint16_t);
|
|
|
|
for (uint32_t ssrc : ssrcs_) {
|
|
ByteWriter<uint32_t>::WriteBigEndian(packet + *index, ssrc);
|
|
*index += sizeof(uint32_t);
|
|
}
|
|
RTC_DCHECK_EQ(index_end, *index);
|
|
return true;
|
|
}
|
|
} // namespace rtcp
|
|
} // namespace webrtc
|