Add rtcp::TransportFeedback::GetReceivedPackets()

It combines and simplify use of GetStatusVector and GetReceiveDeltas accesors.

Replace use of all GetStatusVector/GetReceiveDeltasUs

BUG=None

Review-Url: https://codereview.webrtc.org/2633923003
Cr-Commit-Position: refs/heads/master@{#16139}
This commit is contained in:
danilchap 2017-01-18 02:40:30 -08:00 committed by Commit bot
parent e0e3bdfbbf
commit 4a0c76402e
5 changed files with 163 additions and 230 deletions

View File

@ -112,33 +112,24 @@ std::vector<PacketInfo> TransportFeedbackAdapter::GetPacketFeedbackVector(
}
last_timestamp_us_ = timestamp_us;
uint16_t sequence_number = feedback.GetBaseSequence();
std::vector<int64_t> delta_vec = feedback.GetReceiveDeltasUs();
auto delta_it = delta_vec.begin();
std::vector<PacketInfo> packet_feedback_vector;
packet_feedback_vector.reserve(delta_vec.size());
packet_feedback_vector.reserve(feedback.GetReceivedPackets().size());
{
rtc::CritScope cs(&lock_);
size_t failed_lookups = 0;
int64_t offset_us = 0;
for (auto symbol : feedback.GetStatusVector()) {
if (symbol != rtcp::TransportFeedback::StatusSymbol::kNotReceived) {
RTC_DCHECK(delta_it != delta_vec.end());
offset_us += *(delta_it++);
int64_t timestamp_ms = current_offset_ms_ + (offset_us / 1000);
PacketInfo info(timestamp_ms, sequence_number);
if (send_time_history_.GetInfo(&info, true) && info.send_time_ms >= 0) {
packet_feedback_vector.push_back(info);
} else {
++failed_lookups;
}
for (const auto& packet : feedback.GetReceivedPackets()) {
offset_us += packet.delta_us();
int64_t timestamp_ms = current_offset_ms_ + (offset_us / 1000);
PacketInfo info(timestamp_ms, packet.sequence_number());
if (send_time_history_.GetInfo(&info, true) && info.send_time_ms >= 0) {
packet_feedback_vector.push_back(info);
} else {
++failed_lookups;
}
++sequence_number;
}
std::sort(packet_feedback_vector.begin(), packet_feedback_vector.end(),
PacketInfoComparator());
RTC_DCHECK(delta_it == delta_vec.end());
if (failed_lookups > 0) {
LOG(LS_WARNING) << "Failed to lookup send time for " << failed_lookups
<< " packet" << (failed_lookups > 1 ? "s" : "")

View File

@ -16,15 +16,43 @@
#include "webrtc/test/gtest.h"
using ::testing::_;
using ::testing::InSequence;
using ::testing::ElementsAre;
using ::testing::Invoke;
using ::testing::Return;
namespace webrtc {
namespace {
constexpr size_t kDefaultPacketSize = 100;
constexpr uint32_t kMediaSsrc = 456;
constexpr uint16_t kBaseSeq = 10;
constexpr int64_t kBaseTimeMs = 123;
constexpr int64_t kMaxSmallDeltaMs =
(rtcp::TransportFeedback::kDeltaScaleFactor * 0xFF) / 1000;
std::vector<uint16_t> SequenceNumbers(
const rtcp::TransportFeedback& feedback_packet) {
std::vector<uint16_t> sequence_numbers;
for (const auto& rtp_packet_received : feedback_packet.GetReceivedPackets()) {
sequence_numbers.push_back(rtp_packet_received.sequence_number());
}
return sequence_numbers;
}
std::vector<int64_t> TimestampsMs(
const rtcp::TransportFeedback& feedback_packet) {
std::vector<int64_t> timestamps;
int64_t timestamp_us = feedback_packet.GetBaseTimeUs();
for (const auto& rtp_packet_received : feedback_packet.GetReceivedPackets()) {
timestamp_us += rtp_packet_received.delta_us();
timestamps.push_back(timestamp_us / 1000);
}
return timestamps;
}
class MockPacketRouter : public PacketRouter {
public:
MOCK_METHOD1(SendFeedback, bool(rtcp::TransportFeedback* packet));
MOCK_METHOD1(SendFeedback, bool(rtcp::TransportFeedback* feedback_packet));
};
class RemoteEstimatorProxyTest : public ::testing::Test {
@ -49,33 +77,18 @@ class RemoteEstimatorProxyTest : public ::testing::Test {
SimulatedClock clock_;
testing::StrictMock<MockPacketRouter> router_;
RemoteEstimatorProxy proxy_;
const size_t kDefaultPacketSize = 100;
const uint32_t kMediaSsrc = 456;
const uint16_t kBaseSeq = 10;
const int64_t kBaseTimeMs = 123;
const int64_t kMaxSmallDeltaMs =
(rtcp::TransportFeedback::kDeltaScaleFactor * 0xFF) / 1000;
};
TEST_F(RemoteEstimatorProxyTest, SendsSinglePacketFeedback) {
IncomingPacket(kBaseSeq, kBaseTimeMs);
EXPECT_CALL(router_, SendFeedback(_))
.Times(1)
.WillOnce(Invoke([this](rtcp::TransportFeedback* packet) {
packet->Build();
EXPECT_EQ(kBaseSeq, packet->GetBaseSequence());
EXPECT_EQ(kMediaSsrc, packet->media_ssrc());
.WillOnce(Invoke([](rtcp::TransportFeedback* feedback_packet) {
EXPECT_EQ(kBaseSeq, feedback_packet->GetBaseSequence());
EXPECT_EQ(kMediaSsrc, feedback_packet->media_ssrc());
std::vector<rtcp::TransportFeedback::StatusSymbol> status_vec =
packet->GetStatusVector();
EXPECT_EQ(1u, status_vec.size());
EXPECT_EQ(rtcp::TransportFeedback::StatusSymbol::kReceivedSmallDelta,
status_vec[0]);
std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
EXPECT_EQ(1u, delta_vec.size());
EXPECT_EQ(kBaseTimeMs, (packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
EXPECT_THAT(SequenceNumbers(*feedback_packet), ElementsAre(kBaseSeq));
EXPECT_THAT(TimestampsMs(*feedback_packet), ElementsAre(kBaseTimeMs));
return true;
}));
@ -87,20 +100,12 @@ TEST_F(RemoteEstimatorProxyTest, DuplicatedPackets) {
IncomingPacket(kBaseSeq, kBaseTimeMs + 1000);
EXPECT_CALL(router_, SendFeedback(_))
.Times(1)
.WillOnce(Invoke([this](rtcp::TransportFeedback* packet) {
packet->Build();
EXPECT_EQ(kBaseSeq, packet->GetBaseSequence());
EXPECT_EQ(kMediaSsrc, packet->media_ssrc());
.WillOnce(Invoke([](rtcp::TransportFeedback* feedback_packet) {
EXPECT_EQ(kBaseSeq, feedback_packet->GetBaseSequence());
EXPECT_EQ(kMediaSsrc, feedback_packet->media_ssrc());
std::vector<rtcp::TransportFeedback::StatusSymbol> status_vec =
packet->GetStatusVector();
EXPECT_EQ(1u, status_vec.size());
EXPECT_EQ(rtcp::TransportFeedback::StatusSymbol::kReceivedSmallDelta,
status_vec[0]);
std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
EXPECT_EQ(1u, delta_vec.size());
EXPECT_EQ(kBaseTimeMs, (packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
EXPECT_THAT(SequenceNumbers(*feedback_packet), ElementsAre(kBaseSeq));
EXPECT_THAT(TimestampsMs(*feedback_packet), ElementsAre(kBaseTimeMs));
return true;
}));
@ -111,30 +116,21 @@ TEST_F(RemoteEstimatorProxyTest, FeedbackWithMissingStart) {
// First feedback.
IncomingPacket(kBaseSeq, kBaseTimeMs);
IncomingPacket(kBaseSeq + 1, kBaseTimeMs + 1000);
EXPECT_CALL(router_, SendFeedback(_)).Times(1).WillOnce(Return(true));
EXPECT_CALL(router_, SendFeedback(_)).WillOnce(Return(true));
Process();
// Second feedback starts with a missing packet (DROP kBaseSeq + 2).
IncomingPacket(kBaseSeq + 3, kBaseTimeMs + 3000);
EXPECT_CALL(router_, SendFeedback(_))
.Times(1)
.WillOnce(Invoke([this](rtcp::TransportFeedback* packet) {
packet->Build();
EXPECT_EQ(kBaseSeq + 2, packet->GetBaseSequence());
EXPECT_EQ(kMediaSsrc, packet->media_ssrc());
.WillOnce(Invoke([](rtcp::TransportFeedback* feedback_packet) {
EXPECT_EQ(kBaseSeq + 2, feedback_packet->GetBaseSequence());
EXPECT_EQ(kMediaSsrc, feedback_packet->media_ssrc());
std::vector<rtcp::TransportFeedback::StatusSymbol> status_vec =
packet->GetStatusVector();
EXPECT_EQ(2u, status_vec.size());
EXPECT_EQ(rtcp::TransportFeedback::StatusSymbol::kNotReceived,
status_vec[0]);
EXPECT_EQ(rtcp::TransportFeedback::StatusSymbol::kReceivedSmallDelta,
status_vec[1]);
std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
EXPECT_EQ(1u, delta_vec.size());
EXPECT_EQ(kBaseTimeMs + 3000,
(packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
EXPECT_THAT(SequenceNumbers(*feedback_packet),
ElementsAre(kBaseSeq + 3));
EXPECT_THAT(TimestampsMs(*feedback_packet),
ElementsAre(kBaseTimeMs + 3000));
return true;
}));
@ -147,27 +143,15 @@ TEST_F(RemoteEstimatorProxyTest, SendsFeedbackWithVaryingDeltas) {
IncomingPacket(kBaseSeq + 2, kBaseTimeMs + (2 * kMaxSmallDeltaMs) + 1);
EXPECT_CALL(router_, SendFeedback(_))
.Times(1)
.WillOnce(Invoke([this](rtcp::TransportFeedback* packet) {
packet->Build();
EXPECT_EQ(kBaseSeq, packet->GetBaseSequence());
EXPECT_EQ(kMediaSsrc, packet->media_ssrc());
.WillOnce(Invoke([](rtcp::TransportFeedback* feedback_packet) {
EXPECT_EQ(kBaseSeq, feedback_packet->GetBaseSequence());
EXPECT_EQ(kMediaSsrc, feedback_packet->media_ssrc());
std::vector<rtcp::TransportFeedback::StatusSymbol> status_vec =
packet->GetStatusVector();
EXPECT_EQ(3u, status_vec.size());
EXPECT_EQ(rtcp::TransportFeedback::StatusSymbol::kReceivedSmallDelta,
status_vec[0]);
EXPECT_EQ(rtcp::TransportFeedback::StatusSymbol::kReceivedSmallDelta,
status_vec[1]);
EXPECT_EQ(rtcp::TransportFeedback::StatusSymbol::kReceivedLargeDelta,
status_vec[2]);
std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
EXPECT_EQ(3u, delta_vec.size());
EXPECT_EQ(kBaseTimeMs, (packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
EXPECT_EQ(kMaxSmallDeltaMs, delta_vec[1] / 1000);
EXPECT_EQ(kMaxSmallDeltaMs + 1, delta_vec[2] / 1000);
EXPECT_THAT(SequenceNumbers(*feedback_packet),
ElementsAre(kBaseSeq, kBaseSeq + 1, kBaseSeq + 2));
EXPECT_THAT(TimestampsMs(*feedback_packet),
ElementsAre(kBaseTimeMs, kBaseTimeMs + kMaxSmallDeltaMs,
kBaseTimeMs + (2 * kMaxSmallDeltaMs) + 1));
return true;
}));
@ -175,51 +159,31 @@ TEST_F(RemoteEstimatorProxyTest, SendsFeedbackWithVaryingDeltas) {
}
TEST_F(RemoteEstimatorProxyTest, SendsFragmentedFeedback) {
const int64_t kTooLargeDelta =
static constexpr int64_t kTooLargeDelta =
rtcp::TransportFeedback::kDeltaScaleFactor * (1 << 16);
IncomingPacket(kBaseSeq, kBaseTimeMs);
IncomingPacket(kBaseSeq + 1, kBaseTimeMs + kTooLargeDelta);
InSequence s;
EXPECT_CALL(router_, SendFeedback(_))
.Times(1)
.WillOnce(Invoke([kTooLargeDelta, this](rtcp::TransportFeedback* packet) {
packet->Build();
EXPECT_EQ(kBaseSeq, packet->GetBaseSequence());
EXPECT_EQ(kMediaSsrc, packet->media_ssrc());
.WillOnce(Invoke([](rtcp::TransportFeedback* feedback_packet) {
EXPECT_EQ(kBaseSeq, feedback_packet->GetBaseSequence());
EXPECT_EQ(kMediaSsrc, feedback_packet->media_ssrc());
std::vector<rtcp::TransportFeedback::StatusSymbol> status_vec =
packet->GetStatusVector();
EXPECT_EQ(1u, status_vec.size());
EXPECT_EQ(rtcp::TransportFeedback::StatusSymbol::kReceivedSmallDelta,
status_vec[0]);
std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
EXPECT_EQ(1u, delta_vec.size());
EXPECT_EQ(kBaseTimeMs, (packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
EXPECT_THAT(SequenceNumbers(*feedback_packet), ElementsAre(kBaseSeq));
EXPECT_THAT(TimestampsMs(*feedback_packet), ElementsAre(kBaseTimeMs));
return true;
}))
.RetiresOnSaturation();
.WillOnce(Invoke([](rtcp::TransportFeedback* feedback_packet) {
EXPECT_EQ(kBaseSeq + 1, feedback_packet->GetBaseSequence());
EXPECT_EQ(kMediaSsrc, feedback_packet->media_ssrc());
EXPECT_CALL(router_, SendFeedback(_))
.Times(1)
.WillOnce(Invoke([kTooLargeDelta, this](rtcp::TransportFeedback* packet) {
packet->Build();
EXPECT_EQ(kBaseSeq + 1, packet->GetBaseSequence());
EXPECT_EQ(kMediaSsrc, packet->media_ssrc());
std::vector<rtcp::TransportFeedback::StatusSymbol> status_vec =
packet->GetStatusVector();
EXPECT_EQ(1u, status_vec.size());
EXPECT_EQ(rtcp::TransportFeedback::StatusSymbol::kReceivedSmallDelta,
status_vec[0]);
std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
EXPECT_EQ(1u, delta_vec.size());
EXPECT_EQ(kBaseTimeMs + kTooLargeDelta,
(packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
EXPECT_THAT(SequenceNumbers(*feedback_packet),
ElementsAre(kBaseSeq + 1));
EXPECT_THAT(TimestampsMs(*feedback_packet),
ElementsAre(kBaseTimeMs + kTooLargeDelta));
return true;
}))
.RetiresOnSaturation();
}));
Process();
}
@ -231,15 +195,11 @@ TEST_F(RemoteEstimatorProxyTest, GracefullyHandlesReorderingAndWrap) {
IncomingPacket(kLargeSeq, kBaseTimeMs + kDeltaMs);
EXPECT_CALL(router_, SendFeedback(_))
.Times(1)
.WillOnce(Invoke([this](rtcp::TransportFeedback* packet) {
packet->Build();
EXPECT_EQ(kBaseSeq, packet->GetBaseSequence());
EXPECT_EQ(kMediaSsrc, packet->media_ssrc());
.WillOnce(Invoke([](rtcp::TransportFeedback* feedback_packet) {
EXPECT_EQ(kBaseSeq, feedback_packet->GetBaseSequence());
EXPECT_EQ(kMediaSsrc, feedback_packet->media_ssrc());
std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
EXPECT_EQ(1u, delta_vec.size());
EXPECT_EQ(kBaseTimeMs, (packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
EXPECT_THAT(TimestampsMs(*feedback_packet), ElementsAre(kBaseTimeMs));
return true;
}));
@ -251,16 +211,14 @@ TEST_F(RemoteEstimatorProxyTest, ResendsTimestampsOnReordering) {
IncomingPacket(kBaseSeq + 2, kBaseTimeMs + 2);
EXPECT_CALL(router_, SendFeedback(_))
.Times(1)
.WillOnce(Invoke([this](rtcp::TransportFeedback* packet) {
packet->Build();
EXPECT_EQ(kBaseSeq, packet->GetBaseSequence());
EXPECT_EQ(kMediaSsrc, packet->media_ssrc());
.WillOnce(Invoke([](rtcp::TransportFeedback* feedback_packet) {
EXPECT_EQ(kBaseSeq, feedback_packet->GetBaseSequence());
EXPECT_EQ(kMediaSsrc, feedback_packet->media_ssrc());
std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
EXPECT_EQ(2u, delta_vec.size());
EXPECT_EQ(kBaseTimeMs, (packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
EXPECT_EQ(2, delta_vec[1] / 1000);
EXPECT_THAT(SequenceNumbers(*feedback_packet),
ElementsAre(kBaseSeq, kBaseSeq + 2));
EXPECT_THAT(TimestampsMs(*feedback_packet),
ElementsAre(kBaseTimeMs, kBaseTimeMs + 2));
return true;
}));
@ -269,17 +227,14 @@ TEST_F(RemoteEstimatorProxyTest, ResendsTimestampsOnReordering) {
IncomingPacket(kBaseSeq + 1, kBaseTimeMs + 1);
EXPECT_CALL(router_, SendFeedback(_))
.Times(1)
.WillOnce(Invoke([this](rtcp::TransportFeedback* packet) {
packet->Build();
EXPECT_EQ(kBaseSeq + 1, packet->GetBaseSequence());
EXPECT_EQ(kMediaSsrc, packet->media_ssrc());
.WillOnce(Invoke([](rtcp::TransportFeedback* feedback_packet) {
EXPECT_EQ(kBaseSeq + 1, feedback_packet->GetBaseSequence());
EXPECT_EQ(kMediaSsrc, feedback_packet->media_ssrc());
std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
EXPECT_EQ(2u, delta_vec.size());
EXPECT_EQ(kBaseTimeMs + 1,
(packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
EXPECT_EQ(1, delta_vec[1] / 1000);
EXPECT_THAT(SequenceNumbers(*feedback_packet),
ElementsAre(kBaseSeq + 1, kBaseSeq + 2));
EXPECT_THAT(TimestampsMs(*feedback_packet),
ElementsAre(kBaseTimeMs + 1, kBaseTimeMs + 2));
return true;
}));
@ -293,14 +248,10 @@ TEST_F(RemoteEstimatorProxyTest, RemovesTimestampsOutOfScope) {
IncomingPacket(kBaseSeq + 2, kBaseTimeMs);
EXPECT_CALL(router_, SendFeedback(_))
.Times(1)
.WillOnce(Invoke([kTimeoutTimeMs, this](rtcp::TransportFeedback* packet) {
packet->Build();
EXPECT_EQ(kBaseSeq + 2, packet->GetBaseSequence());
.WillOnce(Invoke([](rtcp::TransportFeedback* feedback_packet) {
EXPECT_EQ(kBaseSeq + 2, feedback_packet->GetBaseSequence());
std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
EXPECT_EQ(1u, delta_vec.size());
EXPECT_EQ(kBaseTimeMs, (packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
EXPECT_THAT(TimestampsMs(*feedback_packet), ElementsAre(kBaseTimeMs));
return true;
}));
@ -309,17 +260,14 @@ TEST_F(RemoteEstimatorProxyTest, RemovesTimestampsOutOfScope) {
IncomingPacket(kBaseSeq + 3, kTimeoutTimeMs); // kBaseSeq + 2 times out here.
EXPECT_CALL(router_, SendFeedback(_))
.Times(1)
.WillOnce(Invoke([kTimeoutTimeMs, this](rtcp::TransportFeedback* packet) {
packet->Build();
EXPECT_EQ(kBaseSeq + 3, packet->GetBaseSequence());
.WillOnce(
Invoke([kTimeoutTimeMs](rtcp::TransportFeedback* feedback_packet) {
EXPECT_EQ(kBaseSeq + 3, feedback_packet->GetBaseSequence());
std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
EXPECT_EQ(1u, delta_vec.size());
EXPECT_EQ(kTimeoutTimeMs,
(packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
return true;
}));
EXPECT_THAT(TimestampsMs(*feedback_packet),
ElementsAre(kTimeoutTimeMs));
return true;
}));
Process();
@ -329,23 +277,17 @@ TEST_F(RemoteEstimatorProxyTest, RemovesTimestampsOutOfScope) {
IncomingPacket(kBaseSeq + 1, kTimeoutTimeMs - 1);
EXPECT_CALL(router_, SendFeedback(_))
.Times(1)
.WillOnce(Invoke([kTimeoutTimeMs, this](rtcp::TransportFeedback* packet) {
packet->Build();
EXPECT_EQ(kBaseSeq, packet->GetBaseSequence());
.WillOnce(
Invoke([kTimeoutTimeMs](rtcp::TransportFeedback* feedback_packet) {
EXPECT_EQ(kBaseSeq, feedback_packet->GetBaseSequence());
// Four status entries (kBaseSeq + 3 missing).
EXPECT_EQ(4u, packet->GetStatusVector().size());
// Only three actual timestamps.
std::vector<int64_t> delta_vec = packet->GetReceiveDeltasUs();
EXPECT_EQ(3u, delta_vec.size());
EXPECT_EQ(kBaseTimeMs - 1,
(packet->GetBaseTimeUs() + delta_vec[0]) / 1000);
EXPECT_EQ(kTimeoutTimeMs - kBaseTimeMs, delta_vec[1] / 1000);
EXPECT_EQ(1, delta_vec[2] / 1000);
return true;
}));
EXPECT_THAT(SequenceNumbers(*feedback_packet),
ElementsAre(kBaseSeq, kBaseSeq + 1, kBaseSeq + 3));
EXPECT_THAT(TimestampsMs(*feedback_packet),
ElementsAre(kBaseTimeMs - 1, kTimeoutTimeMs - 1,
kTimeoutTimeMs));
return true;
}));
Process();
}
@ -391,4 +333,5 @@ TEST_F(RemoteEstimatorProxyTest, TwccReportsUse5PercentOfAvailableBandwidth) {
EXPECT_EQ(136, proxy_.TimeUntilNextProcess());
}
} // namespace
} // namespace webrtc

View File

@ -366,6 +366,11 @@ bool TransportFeedback::AddReceivedPacket(uint16_t sequence_number,
return true;
}
const std::vector<TransportFeedback::ReceivedPacket>&
TransportFeedback::GetReceivedPackets() const {
return packets_;
}
uint16_t TransportFeedback::GetBaseSequence() const {
return base_seq_no_;
}
@ -375,9 +380,9 @@ TransportFeedback::GetStatusVector() const {
std::vector<TransportFeedback::StatusSymbol> symbols;
uint16_t seq_no = GetBaseSequence();
for (const auto& packet : packets_) {
for (; seq_no != packet.sequence_number; ++seq_no)
for (; seq_no != packet.sequence_number(); ++seq_no)
symbols.push_back(StatusSymbol::kNotReceived);
if (packet.delta_ticks >= 0x00 && packet.delta_ticks <= 0xff) {
if (packet.delta_ticks() >= 0x00 && packet.delta_ticks() <= 0xff) {
symbols.push_back(StatusSymbol::kReceivedSmallDelta);
} else {
symbols.push_back(StatusSymbol::kReceivedLargeDelta);
@ -390,7 +395,7 @@ TransportFeedback::GetStatusVector() const {
std::vector<int16_t> TransportFeedback::GetReceiveDeltas() const {
std::vector<int16_t> deltas;
for (const auto& packet : packets_)
deltas.push_back(packet.delta_ticks);
deltas.push_back(packet.delta_ticks());
return deltas;
}
@ -401,7 +406,7 @@ int64_t TransportFeedback::GetBaseTimeUs() const {
std::vector<int64_t> TransportFeedback::GetReceiveDeltasUs() const {
std::vector<int64_t> us_deltas;
for (const auto& packet : packets_)
us_deltas.push_back(packet.delta_ticks * kDeltaScaleFactor);
us_deltas.push_back(packet.delta_us());
return us_deltas;
}
@ -534,18 +539,18 @@ bool TransportFeedback::IsConsistent() const {
LOG(LS_ERROR) << "Failed to find delta for seq_no " << seq_no;
return false;
}
if (packet_it->sequence_number != seq_no) {
if (packet_it->sequence_number() != seq_no) {
LOG(LS_ERROR) << "Expected to find delta for seq_no " << seq_no
<< ". Next delta is for " << packet_it->sequence_number;
<< ". Next delta is for " << packet_it->sequence_number();
return false;
}
if (delta_size == 1 &&
(packet_it->delta_ticks < 0 || packet_it->delta_ticks > 0xff)) {
LOG(LS_ERROR) << "Delta " << packet_it->delta_ticks << " for seq_no "
(packet_it->delta_ticks() < 0 || packet_it->delta_ticks() > 0xff)) {
LOG(LS_ERROR) << "Delta " << packet_it->delta_ticks() << " for seq_no "
<< seq_no << " doesn't fit into one byte";
return false;
}
timestamp_us += packet_it->delta_ticks * kDeltaScaleFactor;
timestamp_us += packet_it->delta_us();
++packet_it;
}
packet_size += delta_size;
@ -553,7 +558,7 @@ bool TransportFeedback::IsConsistent() const {
}
if (packet_it != packets_.end()) {
LOG(LS_ERROR) << "Unencoded delta for seq_no "
<< packet_it->sequence_number;
<< packet_it->sequence_number();
return false;
}
if (timestamp_us != last_timestamp_us_) {
@ -610,7 +615,7 @@ bool TransportFeedback::Create(uint8_t* packet,
}
for (const auto& received_packet : packets_) {
int16_t delta = received_packet.delta_ticks;
int16_t delta = received_packet.delta_ticks();
if (delta >= 0 && delta <= 0xFF) {
packet[(*position)++] = delta;
} else {

View File

@ -23,6 +23,21 @@ class CommonHeader;
class TransportFeedback : public Rtpfb {
public:
class ReceivedPacket {
public:
ReceivedPacket(uint16_t sequence_number, int16_t delta_ticks)
: sequence_number_(sequence_number), delta_ticks_(delta_ticks) {}
ReceivedPacket(const ReceivedPacket&) = default;
ReceivedPacket& operator=(const ReceivedPacket&) = default;
uint16_t sequence_number() const { return sequence_number_; }
int16_t delta_ticks() const { return delta_ticks_; }
int32_t delta_us() const { return delta_ticks_ * kDeltaScaleFactor; }
private:
uint16_t sequence_number_;
int16_t delta_ticks_;
};
// TODO(sprang): IANA reg?
static constexpr uint8_t kFeedbackMessageType = 15;
// Convert to multiples of 0.25ms.
@ -38,6 +53,7 @@ class TransportFeedback : public Rtpfb {
void SetFeedbackSequenceNumber(uint8_t feedback_sequence);
// NOTE: This method requires increasing sequence numbers (excepting wraps).
bool AddReceivedPacket(uint16_t sequence_number, int64_t timestamp_us);
const std::vector<ReceivedPacket>& GetReceivedPackets() const;
enum class StatusSymbol {
kNotReceived,
@ -76,12 +92,6 @@ class TransportFeedback : public Rtpfb {
using DeltaSize = uint8_t;
// Keeps DeltaSizes that can be encoded into single chunk if it is last chunk.
class LastChunk;
struct ReceivedPacket {
ReceivedPacket(uint16_t sequence_number, int16_t delta_ticks)
: sequence_number(sequence_number), delta_ticks(delta_ticks) {}
uint16_t sequence_number;
int16_t delta_ticks;
};
// Reset packet to consistent empty state.
void Clear();

View File

@ -14,13 +14,15 @@
#include <memory>
#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
#include "webrtc/test/gmock.h"
#include "webrtc/test/gtest.h"
using webrtc::rtcp::TransportFeedback;
namespace webrtc {
namespace {
using ::testing::ElementsAreArray;
using rtcp::TransportFeedback;
static const int kHeaderSize = 20;
static const int kStatusChunkSize = 2;
static const int kSmallDeltaSize = 1;
@ -94,31 +96,14 @@ class FeedbackTester {
EXPECT_EQ(expected_size_bytes, serialized_.size());
}
std::vector<TransportFeedback::StatusSymbol> symbols =
feedback_->GetStatusVector();
uint16_t seq = feedback_->GetBaseSequence();
auto seq_it = expected_seq_.begin();
for (TransportFeedback::StatusSymbol symbol : symbols) {
bool received =
(symbol == TransportFeedback::StatusSymbol::kReceivedSmallDelta ||
symbol == TransportFeedback::StatusSymbol::kReceivedLargeDelta);
if (seq_it != expected_seq_.end()) {
if (seq == *seq_it) {
ASSERT_NE(expected_seq_.end(), seq_it);
ASSERT_TRUE(received) << "Expected received packet @ " << seq;
++seq_it;
} else {
ASSERT_FALSE(received) << "Did not expect received packet @ " << seq;
}
}
++seq;
std::vector<uint16_t> actual_seq_nos;
std::vector<int64_t> actual_deltas_us;
for (const auto& packet : feedback_->GetReceivedPackets()) {
actual_seq_nos.push_back(packet.sequence_number());
actual_deltas_us.push_back(packet.delta_us());
}
ASSERT_EQ(expected_seq_.end(), seq_it);
std::vector<int64_t> deltas = feedback_->GetReceiveDeltasUs();
ASSERT_EQ(expected_deltas_.size(), deltas.size());
for (size_t i = 0; i < expected_deltas_.size(); ++i)
EXPECT_EQ(expected_deltas_[i], deltas[i]) << "Delta mismatch @ " << i;
EXPECT_THAT(actual_seq_nos, ElementsAreArray(expected_seq_));
EXPECT_THAT(actual_deltas_us, ElementsAreArray(expected_deltas_));
}
void GenerateDeltas(const uint16_t seq[],
@ -344,12 +329,11 @@ TEST(RtcpPacketTest, TransportFeedback_Aliasing) {
feedback.AddReceivedPacket(i, i * kTooSmallDelta);
feedback.Build();
std::vector<int64_t> deltas = feedback.GetReceiveDeltasUs();
int64_t accumulated_delta = 0;
int num_samples = 0;
for (int64_t delta : deltas) {
accumulated_delta += delta;
for (const auto& packet : feedback.GetReceivedPackets()) {
accumulated_delta += packet.delta_us();
int64_t expected_time = num_samples * kTooSmallDelta;
++num_samples;