Make rtcp::TransportFeedback copyable.

Bug: webrtc:8111
Change-Id: I2a71eb7ab5a913427adfab6f71703850a48fbd03
Reviewed-on: https://webrtc-review.googlesource.com/57181
Commit-Queue: Björn Terelius <terelius@webrtc.org>
Reviewed-by: Danil Chapovalov <danilchap@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#22218}
This commit is contained in:
Bjorn Terelius
2018-02-27 17:04:33 +01:00
committed by Commit Bot
parent 7ca6311e14
commit b6a7fc0f03
3 changed files with 105 additions and 62 deletions

View File

@ -11,6 +11,7 @@
#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
#include <algorithm>
#include <utility>
#include "modules/include/module_common_types.h"
#include "modules/rtp_rtcp/source/byte_io.h"
@ -73,53 +74,6 @@ constexpr int64_t kTimeWrapPeriodUs = (1ll << 24) * kBaseScaleFactor;
constexpr uint8_t TransportFeedback::kFeedbackMessageType;
constexpr size_t TransportFeedback::kMaxReportedPackets;
// Keep delta_sizes that can be encoded into single chunk if it is last chunk.
class TransportFeedback::LastChunk {
public:
using DeltaSize = TransportFeedback::DeltaSize;
LastChunk();
bool Empty() const;
void Clear();
// Return if delta sizes still can be encoded into single chunk with added
// |delta_size|.
bool CanAdd(DeltaSize delta_size) const;
// Add |delta_size|, assumes |CanAdd(delta_size)|,
void Add(DeltaSize delta_size);
// Encode chunk as large as possible removing encoded delta sizes.
// Assume CanAdd() == false for some valid delta_size.
uint16_t Emit();
// Encode all stored delta_sizes into single chunk, pad with 0s if needed.
uint16_t EncodeLast() const;
// Decode up to |max_size| delta sizes from |chunk|.
void Decode(uint16_t chunk, size_t max_size);
// Appends content of the Lastchunk to |deltas|.
void AppendTo(std::vector<DeltaSize>* deltas) const;
private:
static constexpr size_t kMaxRunLengthCapacity = 0x1fff;
static constexpr size_t kMaxOneBitCapacity = 14;
static constexpr size_t kMaxTwoBitCapacity = 7;
static constexpr size_t kMaxVectorCapacity = kMaxOneBitCapacity;
static constexpr DeltaSize kLarge = 2;
uint16_t EncodeOneBit() const;
void DecodeOneBit(uint16_t chunk, size_t max_size);
uint16_t EncodeTwoBit(size_t size) const;
void DecodeTwoBit(uint16_t chunk, size_t max_size);
uint16_t EncodeRunLength() const;
void DecodeRunLength(uint16_t chunk, size_t max_size);
DeltaSize delta_sizes_[kMaxVectorCapacity];
size_t size_;
bool all_same_;
bool has_large_delta_;
};
constexpr size_t TransportFeedback::LastChunk::kMaxRunLengthCapacity;
constexpr size_t TransportFeedback::LastChunk::kMaxOneBitCapacity;
constexpr size_t TransportFeedback::LastChunk::kMaxTwoBitCapacity;
@ -312,9 +266,23 @@ TransportFeedback::TransportFeedback()
base_time_ticks_(0),
feedback_seq_(0),
last_timestamp_us_(0),
last_chunk_(new LastChunk()),
size_bytes_(kTransportFeedbackHeaderSizeBytes) {}
TransportFeedback::TransportFeedback(const TransportFeedback&) = default;
TransportFeedback::TransportFeedback(TransportFeedback&& other)
: base_seq_no_(other.base_seq_no_),
num_seq_no_(other.num_seq_no_),
base_time_ticks_(other.base_time_ticks_),
feedback_seq_(other.feedback_seq_),
last_timestamp_us_(other.last_timestamp_us_),
packets_(std::move(other.packets_)),
encoded_chunks_(std::move(other.encoded_chunks_)),
last_chunk_(other.last_chunk_),
size_bytes_(other.size_bytes_) {
other.Clear();
}
TransportFeedback::~TransportFeedback() {}
void TransportFeedback::SetBase(uint16_t base_sequence,
@ -422,8 +390,8 @@ bool TransportFeedback::Parse(const CommonHeader& packet) {
uint16_t chunk = ByteReader<uint16_t>::ReadBigEndian(&payload[index]);
index += kChunkSizeBytes;
encoded_chunks_.push_back(chunk);
last_chunk_->Decode(chunk, status_count - delta_sizes.size());
last_chunk_->AppendTo(&delta_sizes);
last_chunk_.Decode(chunk, status_count - delta_sizes.size());
last_chunk_.AppendTo(&delta_sizes);
}
// Last chunk is stored in the |last_chunk_|.
encoded_chunks_.pop_back();
@ -492,8 +460,8 @@ bool TransportFeedback::IsConsistent() const {
chunk_decoder.AppendTo(&delta_sizes);
packet_size += kChunkSizeBytes;
}
if (!last_chunk_->Empty()) {
last_chunk_->AppendTo(&delta_sizes);
if (!last_chunk_.Empty()) {
last_chunk_.AppendTo(&delta_sizes);
packet_size += kChunkSizeBytes;
}
if (num_seq_no_ != delta_sizes.size()) {
@ -586,8 +554,8 @@ bool TransportFeedback::Create(uint8_t* packet,
ByteWriter<uint16_t>::WriteBigEndian(&packet[*position], chunk);
*position += 2;
}
if (!last_chunk_->Empty()) {
uint16_t chunk = last_chunk_->EncodeLast();
if (!last_chunk_.Empty()) {
uint16_t chunk = last_chunk_.EncodeLast();
ByteWriter<uint16_t>::WriteBigEndian(&packet[*position], chunk);
*position += 2;
}
@ -614,29 +582,29 @@ void TransportFeedback::Clear() {
last_timestamp_us_ = GetBaseTimeUs();
packets_.clear();
encoded_chunks_.clear();
last_chunk_->Clear();
last_chunk_.Clear();
size_bytes_ = kTransportFeedbackHeaderSizeBytes;
}
bool TransportFeedback::AddDeltaSize(DeltaSize delta_size) {
if (num_seq_no_ == kMaxReportedPackets)
return false;
size_t add_chunk_size = last_chunk_->Empty() ? kChunkSizeBytes : 0;
size_t add_chunk_size = last_chunk_.Empty() ? kChunkSizeBytes : 0;
if (size_bytes_ + delta_size + add_chunk_size > kMaxSizeBytes)
return false;
if (last_chunk_->CanAdd(delta_size)) {
if (last_chunk_.CanAdd(delta_size)) {
size_bytes_ += add_chunk_size;
last_chunk_->Add(delta_size);
last_chunk_.Add(delta_size);
++num_seq_no_;
return true;
}
if (size_bytes_ + delta_size + kChunkSizeBytes > kMaxSizeBytes)
return false;
encoded_chunks_.push_back(last_chunk_->Emit());
encoded_chunks_.push_back(last_chunk_.Emit());
size_bytes_ += kChunkSizeBytes;
last_chunk_->Add(delta_size);
last_chunk_.Add(delta_size);
++num_seq_no_;
return true;
}

View File

@ -45,6 +45,9 @@ class TransportFeedback : public Rtpfb {
static constexpr size_t kMaxReportedPackets = 0xffff;
TransportFeedback();
TransportFeedback(const TransportFeedback&);
TransportFeedback(TransportFeedback&&);
~TransportFeedback() override;
void SetBase(uint16_t base_sequence, // Seq# of first packet in this msg.
@ -81,7 +84,52 @@ class TransportFeedback : public Rtpfb {
// Valid values are 0 (packet wasn't received), 1 or 2.
using DeltaSize = uint8_t;
// Keeps DeltaSizes that can be encoded into single chunk if it is last chunk.
class LastChunk;
class LastChunk {
public:
using DeltaSize = TransportFeedback::DeltaSize;
LastChunk();
bool Empty() const;
void Clear();
// Return if delta sizes still can be encoded into single chunk with added
// |delta_size|.
bool CanAdd(DeltaSize delta_size) const;
// Add |delta_size|, assumes |CanAdd(delta_size)|,
void Add(DeltaSize delta_size);
// Encode chunk as large as possible removing encoded delta sizes.
// Assume CanAdd() == false for some valid delta_size.
uint16_t Emit();
// Encode all stored delta_sizes into single chunk, pad with 0s if needed.
uint16_t EncodeLast() const;
// Decode up to |max_size| delta sizes from |chunk|.
void Decode(uint16_t chunk, size_t max_size);
// Appends content of the Lastchunk to |deltas|.
void AppendTo(std::vector<DeltaSize>* deltas) const;
private:
static constexpr size_t kMaxRunLengthCapacity = 0x1fff;
static constexpr size_t kMaxOneBitCapacity = 14;
static constexpr size_t kMaxTwoBitCapacity = 7;
static constexpr size_t kMaxVectorCapacity = kMaxOneBitCapacity;
static constexpr DeltaSize kLarge = 2;
uint16_t EncodeOneBit() const;
void DecodeOneBit(uint16_t chunk, size_t max_size);
uint16_t EncodeTwoBit(size_t size) const;
void DecodeTwoBit(uint16_t chunk, size_t max_size);
uint16_t EncodeRunLength() const;
void DecodeRunLength(uint16_t chunk, size_t max_size);
DeltaSize delta_sizes_[kMaxVectorCapacity];
size_t size_;
bool all_same_;
bool has_large_delta_;
};
// Reset packet to consistent empty state.
void Clear();
@ -97,7 +145,7 @@ class TransportFeedback : public Rtpfb {
std::vector<ReceivedPacket> packets_;
// All but last encoded packet chunks.
std::vector<uint16_t> encoded_chunks_;
const std::unique_ptr<LastChunk> last_chunk_;
LastChunk last_chunk_;
size_t size_bytes_;
};

View File

@ -12,6 +12,7 @@
#include <limits>
#include <memory>
#include <utility>
#include "modules/rtp_rtcp/source/byte_io.h"
#include "test/gmock.h"
@ -466,5 +467,31 @@ TEST(RtcpPacketTest, TransportFeedback_CorrectlySplitsVectorChunks) {
}
}
TEST(RtcpPacketTest, TransportFeedback_MoveConstructor) {
const int kSamples = 100;
const int64_t kDelta = TransportFeedback::kDeltaScaleFactor;
const uint16_t kBaseSeqNo = 7531;
const int64_t kBaseTimestampUs = 123456789;
const uint8_t kFeedbackSeqNo = 90;
TransportFeedback feedback;
feedback.SetBase(kBaseSeqNo, kBaseTimestampUs);
feedback.SetFeedbackSequenceNumber(kFeedbackSeqNo);
for (int i = 0; i < kSamples; ++i) {
feedback.AddReceivedPacket(kBaseSeqNo + i, kBaseTimestampUs + i * kDelta);
}
EXPECT_TRUE(feedback.IsConsistent());
TransportFeedback feedback_copy(feedback);
EXPECT_TRUE(feedback_copy.IsConsistent());
EXPECT_TRUE(feedback.IsConsistent());
EXPECT_EQ(feedback_copy.Build(), feedback.Build());
TransportFeedback moved(std::move(feedback));
EXPECT_TRUE(moved.IsConsistent());
EXPECT_TRUE(feedback.IsConsistent());
EXPECT_EQ(moved.Build(), feedback_copy.Build());
}
} // namespace
} // namespace webrtc