| Index: webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc
|
| diff --git a/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc b/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc
|
| index 356263e96f1a4560e60c50fca38777218abed174..cce0075adef1cb8d56308861f7f0327896ed4676 100644
|
| --- a/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc
|
| +++ b/webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.cc
|
| @@ -12,38 +12,33 @@
|
|
|
| #include "webrtc/base/checks.h"
|
| #include "webrtc/base/logging.h"
|
| +#include "webrtc/modules/include/module_common_types.h"
|
| #include "webrtc/modules/rtp_rtcp/source/byte_io.h"
|
| -#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
|
| +#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/common_header.h"
|
|
|
| namespace webrtc {
|
| namespace rtcp {
|
| -
|
| +namespace {
|
| // Header size:
|
| -// * 12 bytes Common Packet Format for RTCP Feedback Messages
|
| +// * 4 bytes Common RTCP Packet Header
|
| +// * 8 bytes Common Packet Format for RTCP Feedback Messages
|
| // * 8 bytes FeedbackPacket header
|
| -static const uint32_t kHeaderSizeBytes = 12 + 8;
|
| -static const uint32_t kChunkSizeBytes = 2;
|
| -static const uint32_t kOneBitVectorCapacity = 14;
|
| -static const uint32_t kTwoBitVectorCapacity = 7;
|
| -static const uint32_t kRunLengthCapacity = 0x1FFF;
|
| +constexpr size_t kTransportFeedbackHeaderSizeBytes = 4 + 8 + 8;
|
| +constexpr size_t kChunkSizeBytes = 2;
|
| +constexpr size_t kRunLengthCapacity = 0x1FFF;
|
| // TODO(sprang): Add support for dynamic max size for easier fragmentation,
|
| // eg. set it to what's left in the buffer or IP_PACKET_SIZE.
|
| // Size constraint imposed by RTCP common header: 16bit size field interpreted
|
| // as number of four byte words minus the first header word.
|
| -static const uint32_t kMaxSizeBytes = (1 << 16) * 4;
|
| -static const uint32_t kMinSizeBytes = kHeaderSizeBytes + kChunkSizeBytes;
|
| -static const uint32_t kBaseScaleFactor =
|
| +constexpr size_t kMaxSizeBytes = (1 << 16) * 4;
|
| +// Payload size:
|
| +// * 8 bytes Common Packet Format for RTCP Feedback Messages
|
| +// * 8 bytes FeedbackPacket header.
|
| +// * 2 bytes for one chunk.
|
| +constexpr size_t kMinPayloadSizeBytes = 8 + 8 + 2;
|
| +constexpr size_t kBaseScaleFactor =
|
| TransportFeedback::kDeltaScaleFactor * (1 << 8);
|
|
|
| -class PacketStatusChunk {
|
| - public:
|
| - virtual ~PacketStatusChunk() {}
|
| - virtual uint16_t NumSymbols() const = 0;
|
| - virtual void AppendSymbolsTo(
|
| - std::vector<TransportFeedback::StatusSymbol>* vec) const = 0;
|
| - virtual void WriteTo(uint8_t* buffer) const = 0;
|
| -};
|
| -
|
| uint8_t EncodeSymbol(TransportFeedback::StatusSymbol symbol) {
|
| switch (symbol) {
|
| case TransportFeedback::StatusSymbol::kNotReceived:
|
| @@ -52,10 +47,9 @@ uint8_t EncodeSymbol(TransportFeedback::StatusSymbol symbol) {
|
| return 1;
|
| case TransportFeedback::StatusSymbol::kReceivedLargeDelta:
|
| return 2;
|
| - default:
|
| - RTC_NOTREACHED();
|
| - return 0;
|
| }
|
| + RTC_NOTREACHED();
|
| + return 0;
|
| }
|
|
|
| TransportFeedback::StatusSymbol DecodeSymbol(uint8_t value) {
|
| @@ -72,18 +66,27 @@ TransportFeedback::StatusSymbol DecodeSymbol(uint8_t value) {
|
| }
|
| }
|
|
|
| +} // namespace
|
| +constexpr uint8_t TransportFeedback::kFeedbackMessageType;
|
| +
|
| +class TransportFeedback::PacketStatusChunk {
|
| + public:
|
| + virtual ~PacketStatusChunk() {}
|
| + virtual uint16_t NumSymbols() const = 0;
|
| + virtual void AppendSymbolsTo(
|
| + std::vector<TransportFeedback::StatusSymbol>* vec) const = 0;
|
| + virtual void WriteTo(uint8_t* buffer) const = 0;
|
| +};
|
| +
|
| TransportFeedback::TransportFeedback()
|
| - : packet_sender_ssrc_(0),
|
| - media_source_ssrc_(0),
|
| - base_seq_(-1),
|
| + : base_seq_(-1),
|
| base_time_(-1),
|
| feedback_seq_(0),
|
| last_seq_(-1),
|
| last_timestamp_(-1),
|
| first_symbol_cardinality_(0),
|
| vec_needs_two_bit_symbols_(false),
|
| - size_bytes_(kHeaderSizeBytes) {
|
| -}
|
| + size_bytes_(kTransportFeedbackHeaderSizeBytes) {}
|
|
|
| TransportFeedback::~TransportFeedback() {
|
| for (PacketStatusChunk* chunk : status_chunks_)
|
| @@ -102,9 +105,9 @@ TransportFeedback::~TransportFeedback() {
|
| // S = 0
|
| // symbol list = 14 entries where 0 = not received, 1 = received
|
|
|
| -class OneBitVectorChunk : public PacketStatusChunk {
|
| +class OneBitVectorChunk : public TransportFeedback::PacketStatusChunk {
|
| public:
|
| - static const int kCapacity = 14;
|
| + static constexpr size_t kCapacity = 14;
|
|
|
| explicit OneBitVectorChunk(
|
| std::deque<TransportFeedback::StatusSymbol>* symbols) {
|
| @@ -119,7 +122,7 @@ class OneBitVectorChunk : public PacketStatusChunk {
|
| }
|
| }
|
|
|
| - virtual ~OneBitVectorChunk() {}
|
| + ~OneBitVectorChunk() override {}
|
|
|
| uint16_t NumSymbols() const override { return kCapacity; }
|
|
|
| @@ -129,8 +132,8 @@ class OneBitVectorChunk : public PacketStatusChunk {
|
| }
|
|
|
| void WriteTo(uint8_t* buffer) const override {
|
| - const int kSymbolsInFirstByte = 6;
|
| - const int kSymbolsInSecondByte = 8;
|
| + constexpr int kSymbolsInFirstByte = 6;
|
| + constexpr int kSymbolsInSecondByte = 8;
|
| buffer[0] = 0x80u;
|
| for (int i = 0; i < kSymbolsInFirstByte; ++i) {
|
| uint8_t encoded_symbol = EncodeSymbol(symbols_[i]);
|
| @@ -175,9 +178,9 @@ class OneBitVectorChunk : public PacketStatusChunk {
|
| // S = 1
|
| // symbol list = 7 entries of two bits each, see (Encode|Decode)Symbol
|
|
|
| -class TwoBitVectorChunk : public PacketStatusChunk {
|
| +class TwoBitVectorChunk : public TransportFeedback::PacketStatusChunk {
|
| public:
|
| - static const int kCapacity = 7;
|
| + static constexpr size_t kCapacity = 7;
|
|
|
| explicit TwoBitVectorChunk(
|
| std::deque<TransportFeedback::StatusSymbol>* symbols) {
|
| @@ -192,7 +195,7 @@ class TwoBitVectorChunk : public PacketStatusChunk {
|
| }
|
| }
|
|
|
| - virtual ~TwoBitVectorChunk() {}
|
| + ~TwoBitVectorChunk() override {}
|
|
|
| uint16_t NumSymbols() const override { return kCapacity; }
|
|
|
| @@ -244,14 +247,14 @@ class TwoBitVectorChunk : public PacketStatusChunk {
|
| // S = symbol, see (Encode|Decode)Symbol
|
| // Run Length = Unsigned integer denoting the run length of the symbol
|
|
|
| -class RunLengthChunk : public PacketStatusChunk {
|
| +class RunLengthChunk : public TransportFeedback::PacketStatusChunk {
|
| public:
|
| RunLengthChunk(TransportFeedback::StatusSymbol symbol, size_t size)
|
| : symbol_(symbol), size_(size) {
|
| RTC_DCHECK_LE(size, 0x1FFFu);
|
| }
|
|
|
| - virtual ~RunLengthChunk() {}
|
| + ~RunLengthChunk() override {}
|
|
|
| uint16_t NumSymbols() const override { return size_; }
|
|
|
| @@ -297,21 +300,6 @@ int64_t TransportFeedback::Unwrap(uint16_t sequence_number) {
|
| return last_seq_ + delta;
|
| }
|
|
|
| -void TransportFeedback::WithPacketSenderSsrc(uint32_t ssrc) {
|
| - packet_sender_ssrc_ = ssrc;
|
| -}
|
| -
|
| -void TransportFeedback::WithMediaSourceSsrc(uint32_t ssrc) {
|
| - media_source_ssrc_ = ssrc;
|
| -}
|
| -
|
| -uint32_t TransportFeedback::GetPacketSenderSsrc() const {
|
| - return packet_sender_ssrc_;
|
| -}
|
| -
|
| -uint32_t TransportFeedback::GetMediaSourceSsrc() const {
|
| - return media_source_ssrc_;
|
| -}
|
| void TransportFeedback::WithBase(uint16_t base_sequence,
|
| int64_t ref_timestamp_us) {
|
| RTC_DCHECK_EQ(-1, base_seq_);
|
| @@ -390,8 +378,8 @@ bool TransportFeedback::Encode(StatusSymbol symbol) {
|
| return false;
|
| }
|
|
|
| - bool is_two_bit;
|
| - int delta_size;
|
| + bool is_two_bit = false;
|
| + int delta_size = -1;
|
| switch (symbol) {
|
| case StatusSymbol::kReceivedSmallDelta:
|
| delta_size = 1;
|
| @@ -405,10 +393,8 @@ bool TransportFeedback::Encode(StatusSymbol symbol) {
|
| is_two_bit = false;
|
| delta_size = 0;
|
| break;
|
| - default:
|
| - RTC_NOTREACHED();
|
| - return false;
|
| }
|
| + RTC_DCHECK_GE(delta_size, 0);
|
|
|
| if (symbol_vec_.empty()) {
|
| if (size_bytes_ + delta_size + kChunkSizeBytes > kMaxSizeBytes)
|
| @@ -424,8 +410,8 @@ bool TransportFeedback::Encode(StatusSymbol symbol) {
|
| return false;
|
|
|
| // Capacity, in number of symbols, that a vector chunk could hold.
|
| - size_t capacity = vec_needs_two_bit_symbols_ ? kTwoBitVectorCapacity
|
| - : kOneBitVectorCapacity;
|
| + size_t capacity = vec_needs_two_bit_symbols_ ? TwoBitVectorChunk::kCapacity
|
| + : OneBitVectorChunk::kCapacity;
|
|
|
| // first_symbol_cardinality_ is the number of times the first symbol in
|
| // symbol_vec is repeated. So if that is equal to the size of symbol_vec,
|
| @@ -468,7 +454,7 @@ bool TransportFeedback::Encode(StatusSymbol symbol) {
|
| // If the symbols in symbol_vec can be encoded using a one-bit chunk but
|
| // the input symbol cannot, first check if we can simply change target type.
|
| vec_needs_two_bit_symbols_ = true;
|
| - if (symbol_vec_.size() >= kTwoBitVectorCapacity) {
|
| + if (symbol_vec_.size() >= TwoBitVectorChunk::kCapacity) {
|
| // symbol_vec contains more symbols than we can encode in a single
|
| // two-bit chunk. Emit a new vector append to the remains, if any.
|
| if (size_bytes_ + delta_size + kChunkSizeBytes > kMaxSizeBytes)
|
| @@ -481,7 +467,7 @@ bool TransportFeedback::Encode(StatusSymbol symbol) {
|
| return Encode(symbol);
|
| }
|
| // symbol_vec symbols fit within a single two-bit vector chunk.
|
| - capacity = kTwoBitVectorCapacity;
|
| + capacity = TwoBitVectorChunk::kCapacity;
|
| }
|
|
|
| symbol_vec_.push_back(symbol);
|
| @@ -498,8 +484,8 @@ void TransportFeedback::EmitRemaining() {
|
| if (symbol_vec_.empty())
|
| return;
|
|
|
| - size_t capacity = vec_needs_two_bit_symbols_ ? kTwoBitVectorCapacity
|
| - : kOneBitVectorCapacity;
|
| + size_t capacity = vec_needs_two_bit_symbols_ ? TwoBitVectorChunk::kCapacity
|
| + : OneBitVectorChunk::kCapacity;
|
| if (first_symbol_cardinality_ > capacity) {
|
| EmitRunLengthChunk();
|
| } else {
|
| @@ -531,7 +517,8 @@ void TransportFeedback::EmitRunLengthChunk() {
|
| }
|
|
|
| size_t TransportFeedback::BlockLength() const {
|
| - return size_bytes_;
|
| + // Round size_bytes_ up to multiple of 32bits.
|
| + return (size_bytes_ + 3) & (~static_cast<size_t>(3));
|
| }
|
|
|
| uint16_t TransportFeedback::GetBaseSequence() const {
|
| @@ -577,17 +564,16 @@ bool TransportFeedback::Create(uint8_t* packet,
|
| if (base_seq_ == -1)
|
| return false;
|
|
|
| - while (*position + size_bytes_ > max_length) {
|
| + while (*position + BlockLength() > max_length) {
|
| if (!OnBufferFull(packet, position, callback))
|
| return false;
|
| }
|
| + const size_t position_end = *position + BlockLength();
|
|
|
| - CreateHeader(kFeedbackMessageType, kPayloadType, HeaderLength(), packet,
|
| + CreateHeader(kFeedbackMessageType, kPacketType, HeaderLength(), packet,
|
| position);
|
| - ByteWriter<uint32_t>::WriteBigEndian(&packet[*position], packet_sender_ssrc_);
|
| - *position += 4;
|
| - ByteWriter<uint32_t>::WriteBigEndian(&packet[*position], media_source_ssrc_);
|
| - *position += 4;
|
| + CreateCommonFeedback(packet + *position);
|
| + *position += kCommonFeedbackLength;
|
|
|
| RTC_DCHECK_LE(base_seq_, 0xFFFF);
|
| ByteWriter<uint16_t>::WriteBigEndian(&packet[*position], base_seq_);
|
| @@ -623,6 +609,7 @@ bool TransportFeedback::Create(uint8_t* packet,
|
| while ((*position % 4) != 0)
|
| packet[(*position)++] = 0;
|
|
|
| + RTC_DCHECK_EQ(*position, position_end);
|
| return true;
|
| }
|
|
|
| @@ -633,15 +620,15 @@ bool TransportFeedback::Create(uint8_t* packet,
|
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
| // |V=2|P| FMT=15 | PT=205 | length |
|
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
| -// | SSRC of packet sender |
|
| +// 0 | SSRC of packet sender |
|
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
| -// | SSRC of media source |
|
| +// 4 | SSRC of media source |
|
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
| -// | base sequence number | packet status count |
|
| +// 8 | base sequence number | packet status count |
|
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
| -// | reference time | fb pkt. count |
|
| +// 12 | reference time | fb pkt. count |
|
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
| -// | packet chunk | packet chunk |
|
| +// 16 | packet chunk | packet chunk |
|
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
| // . .
|
| // . .
|
| @@ -655,68 +642,55 @@ bool TransportFeedback::Create(uint8_t* packet,
|
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
|
| // De-serialize packet.
|
| -std::unique_ptr<TransportFeedback> TransportFeedback::ParseFrom(
|
| - const uint8_t* buffer,
|
| - size_t length) {
|
| - std::unique_ptr<TransportFeedback> packet(new TransportFeedback());
|
| +bool TransportFeedback::Parse(const CommonHeader& packet) {
|
| + RTC_DCHECK_EQ(packet.type(), kPacketType);
|
| + RTC_DCHECK_EQ(packet.fmt(), kFeedbackMessageType);
|
|
|
| - if (length < kMinSizeBytes) {
|
| - LOG(LS_WARNING) << "Buffer too small (" << length
|
| + if (packet.payload_size_bytes() < kMinPayloadSizeBytes) {
|
| + LOG(LS_WARNING) << "Buffer too small (" << packet.payload_size_bytes()
|
| << " bytes) to fit a "
|
| - "FeedbackPacket. Minimum size = " << kMinSizeBytes;
|
| - return nullptr;
|
| + "FeedbackPacket. Minimum size = "
|
| + << kMinPayloadSizeBytes;
|
| + return false;
|
| }
|
| + // TODO(danilchap): Make parse work correctly with not new objects.
|
| + RTC_DCHECK(status_chunks_.empty()) << "Parse expects object to be new.";
|
|
|
| - RTCPUtility::RtcpCommonHeader header;
|
| - if (!RtcpParseCommonHeader(buffer, length, &header))
|
| - return nullptr;
|
| + const uint8_t* const payload = packet.payload();
|
|
|
| - if (header.count_or_format != kFeedbackMessageType) {
|
| - LOG(LS_WARNING) << "Invalid RTCP header: FMT must be "
|
| - << kFeedbackMessageType << " but was "
|
| - << header.count_or_format;
|
| - return nullptr;
|
| - }
|
| -
|
| - if (header.packet_type != kPayloadType) {
|
| - LOG(LS_WARNING) << "Invalid RTCP header: PT must be " << kPayloadType
|
| - << " but was " << header.packet_type;
|
| - return nullptr;
|
| - }
|
| + ParseCommonFeedback(payload);
|
|
|
| - packet->packet_sender_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[4]);
|
| - packet->media_source_ssrc_ = ByteReader<uint32_t>::ReadBigEndian(&buffer[8]);
|
| - packet->base_seq_ = ByteReader<uint16_t>::ReadBigEndian(&buffer[12]);
|
| - uint16_t num_packets = ByteReader<uint16_t>::ReadBigEndian(&buffer[14]);
|
| - packet->base_time_ = ByteReader<int32_t, 3>::ReadBigEndian(&buffer[16]);
|
| - packet->feedback_seq_ = buffer[19];
|
| - size_t index = 20;
|
| - const size_t end_index = kHeaderLength + header.payload_size_bytes;
|
| + base_seq_ = ByteReader<uint16_t>::ReadBigEndian(&payload[8]);
|
| + uint16_t num_packets = ByteReader<uint16_t>::ReadBigEndian(&payload[10]);
|
| + base_time_ = ByteReader<int32_t, 3>::ReadBigEndian(&payload[12]);
|
| + feedback_seq_ = payload[15];
|
| + size_t index = 16;
|
| + const size_t end_index = packet.payload_size_bytes();
|
|
|
| if (num_packets == 0) {
|
| LOG(LS_WARNING) << "Empty feedback messages not allowed.";
|
| - return nullptr;
|
| + return false;
|
| }
|
| - packet->last_seq_ = packet->base_seq_ + num_packets - 1;
|
| + last_seq_ = base_seq_ + num_packets - 1;
|
|
|
| size_t packets_read = 0;
|
| while (packets_read < num_packets) {
|
| if (index + 2 > end_index) {
|
| LOG(LS_WARNING) << "Buffer overflow while parsing packet.";
|
| - return nullptr;
|
| + return false;
|
| }
|
|
|
| PacketStatusChunk* chunk =
|
| - ParseChunk(&buffer[index], num_packets - packets_read);
|
| + ParseChunk(&payload[index], num_packets - packets_read);
|
| if (chunk == nullptr)
|
| - return nullptr;
|
| + return false;
|
|
|
| index += 2;
|
| - packet->status_chunks_.push_back(chunk);
|
| + status_chunks_.push_back(chunk);
|
| packets_read += chunk->NumSymbols();
|
| }
|
|
|
| - std::vector<StatusSymbol> symbols = packet->GetStatusVector();
|
| + std::vector<StatusSymbol> symbols = GetStatusVector();
|
|
|
| RTC_DCHECK_EQ(num_packets, symbols.size());
|
|
|
| @@ -725,36 +699,49 @@ std::unique_ptr<TransportFeedback> TransportFeedback::ParseFrom(
|
| case StatusSymbol::kReceivedSmallDelta:
|
| if (index + 1 > end_index) {
|
| LOG(LS_WARNING) << "Buffer overflow while parsing packet.";
|
| - return nullptr;
|
| + return false;
|
| }
|
| - packet->receive_deltas_.push_back(buffer[index]);
|
| + receive_deltas_.push_back(payload[index]);
|
| ++index;
|
| break;
|
| case StatusSymbol::kReceivedLargeDelta:
|
| if (index + 2 > end_index) {
|
| LOG(LS_WARNING) << "Buffer overflow while parsing packet.";
|
| - return nullptr;
|
| + return false;
|
| }
|
| - packet->receive_deltas_.push_back(
|
| - ByteReader<int16_t>::ReadBigEndian(&buffer[index]));
|
| + receive_deltas_.push_back(
|
| + ByteReader<int16_t>::ReadBigEndian(&payload[index]));
|
| index += 2;
|
| break;
|
| - default:
|
| + case StatusSymbol::kNotReceived:
|
| continue;
|
| }
|
| }
|
|
|
| - RTC_DCHECK_GE(index, end_index - 3);
|
| RTC_DCHECK_LE(index, end_index);
|
|
|
| - return packet;
|
| + return true;
|
| +}
|
| +
|
| +std::unique_ptr<TransportFeedback> TransportFeedback::ParseFrom(
|
| + const uint8_t* buffer,
|
| + size_t length) {
|
| + CommonHeader header;
|
| + if (!header.Parse(buffer, length))
|
| + return nullptr;
|
| + if (header.type() != kPacketType || header.fmt() != kFeedbackMessageType)
|
| + return nullptr;
|
| + std::unique_ptr<TransportFeedback> parsed(new TransportFeedback);
|
| + if (!parsed->Parse(header))
|
| + return nullptr;
|
| + return parsed;
|
| }
|
|
|
| -PacketStatusChunk* TransportFeedback::ParseChunk(const uint8_t* buffer,
|
| - size_t max_size) {
|
| +TransportFeedback::PacketStatusChunk* TransportFeedback::ParseChunk(
|
| + const uint8_t* buffer,
|
| + size_t max_size) {
|
| if (buffer[0] & 0x80) {
|
| // First bit set => vector chunk.
|
| - std::deque<StatusSymbol> symbols;
|
| if (buffer[0] & 0x40) {
|
| // Second bit set => two bits per symbol vector.
|
| return TwoBitVectorChunk::ParseFrom(buffer);
|
|
|