webrtc/modules/congestion_controller/transport_feedback_adapter_unittest.cc
Sebastian Jansson 56da2f7868 Added unit tests for new congestion controller.
This CL activates unit tests for the task queue based send side
congestion controller that will replace the current one in the future.

To be able to have the tests run side by side with the tests of the old
congestion controller, the old tests have been prefixed with "Legacy".

This CL also contains some minor fixes to the new congestion controller
code.

Bug: webrtc:8415
Change-Id: I5e7474d42f17fcbfef402e26f638846fa3424695
Reviewed-on: https://webrtc-review.googlesource.com/55381
Reviewed-by: Philip Eliasson <philipel@webrtc.org>
Reviewed-by: Björn Terelius <terelius@webrtc.org>
Commit-Queue: Sebastian Jansson <srte@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#22229}
2018-02-28 14:03:48 +00:00

394 lines
15 KiB
C++

/*
* 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 <limits>
#include <memory>
#include <vector>
#include "modules/bitrate_controller/include/mock/mock_bitrate_controller.h"
#include "modules/congestion_controller/congestion_controller_unittests_helper.h"
#include "modules/congestion_controller/transport_feedback_adapter.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
#include "rtc_base/checks.h"
#include "rtc_base/numerics/safe_conversions.h"
#include "system_wrappers/include/clock.h"
#include "test/gmock.h"
#include "test/gtest.h"
using ::testing::_;
using ::testing::Invoke;
namespace webrtc {
namespace {
const PacedPacketInfo kPacingInfo0(0, 5, 2000);
const PacedPacketInfo kPacingInfo1(1, 8, 4000);
const PacedPacketInfo kPacingInfo2(2, 14, 7000);
const PacedPacketInfo kPacingInfo3(3, 20, 10000);
const PacedPacketInfo kPacingInfo4(4, 22, 10000);
}
namespace test {
class MockPacketFeedbackObserver : public webrtc::PacketFeedbackObserver {
public:
MOCK_METHOD2(OnPacketAdded, void(uint32_t ssrc, uint16_t seq_num));
MOCK_METHOD1(OnPacketFeedbackVector,
void(const std::vector<PacketFeedback>& packet_feedback_vector));
};
class LegacyTransportFeedbackAdapterTest : public ::testing::Test {
public:
LegacyTransportFeedbackAdapterTest() : clock_(0) {}
virtual ~LegacyTransportFeedbackAdapterTest() {}
virtual void SetUp() {
adapter_.reset(new TransportFeedbackAdapter(&clock_));
}
virtual void TearDown() { adapter_.reset(); }
protected:
void OnReceivedEstimatedBitrate(uint32_t bitrate) {}
void OnReceivedRtcpReceiverReport(const ReportBlockList& report_blocks,
int64_t rtt,
int64_t now_ms) {}
void OnSentPacket(const PacketFeedback& packet_feedback) {
adapter_->AddPacket(kSsrc, packet_feedback.sequence_number,
packet_feedback.payload_size,
packet_feedback.pacing_info);
adapter_->OnSentPacket(packet_feedback.sequence_number,
packet_feedback.send_time_ms);
}
static constexpr uint32_t kSsrc = 8492;
SimulatedClock clock_;
std::unique_ptr<TransportFeedbackAdapter> adapter_;
};
TEST_F(LegacyTransportFeedbackAdapterTest, ObserverSanity) {
MockPacketFeedbackObserver mock;
adapter_->RegisterPacketFeedbackObserver(&mock);
const std::vector<PacketFeedback> packets = {
PacketFeedback(100, 200, 0, 1000, kPacingInfo0),
PacketFeedback(110, 210, 1, 2000, kPacingInfo0),
PacketFeedback(120, 220, 2, 3000, kPacingInfo0)
};
rtcp::TransportFeedback feedback;
feedback.SetBase(packets[0].sequence_number,
packets[0].arrival_time_ms * 1000);
for (const PacketFeedback& packet : packets) {
EXPECT_CALL(mock, OnPacketAdded(kSsrc, packet.sequence_number)).Times(1);
OnSentPacket(packet);
EXPECT_TRUE(feedback.AddReceivedPacket(packet.sequence_number,
packet.arrival_time_ms * 1000));
}
EXPECT_CALL(mock, OnPacketFeedbackVector(_)).Times(1);
adapter_->OnTransportFeedback(feedback);
adapter_->DeRegisterPacketFeedbackObserver(&mock);
// After deregistration, the observer no longers gets indications.
EXPECT_CALL(mock, OnPacketAdded(_, _)).Times(0);
const PacketFeedback new_packet(130, 230, 3, 4000, kPacingInfo0);
OnSentPacket(new_packet);
rtcp::TransportFeedback second_feedback;
second_feedback.SetBase(new_packet.sequence_number,
new_packet.arrival_time_ms * 1000);
EXPECT_TRUE(feedback.AddReceivedPacket(new_packet.sequence_number,
new_packet.arrival_time_ms * 1000));
EXPECT_CALL(mock, OnPacketFeedbackVector(_)).Times(0);
adapter_->OnTransportFeedback(second_feedback);
}
#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
TEST_F(LegacyTransportFeedbackAdapterTest,
ObserverDoubleRegistrationDeathTest) {
MockPacketFeedbackObserver mock;
adapter_->RegisterPacketFeedbackObserver(&mock);
EXPECT_DEATH(adapter_->RegisterPacketFeedbackObserver(&mock), "");
adapter_->DeRegisterPacketFeedbackObserver(&mock);
}
TEST_F(LegacyTransportFeedbackAdapterTest,
ObserverMissingDeRegistrationDeathTest) {
MockPacketFeedbackObserver mock;
adapter_->RegisterPacketFeedbackObserver(&mock);
EXPECT_DEATH(adapter_.reset(), "");
adapter_->DeRegisterPacketFeedbackObserver(&mock);
}
#endif
TEST_F(LegacyTransportFeedbackAdapterTest,
AdaptsFeedbackAndPopulatesSendTimes) {
std::vector<PacketFeedback> packets;
packets.push_back(PacketFeedback(100, 200, 0, 1500, kPacingInfo0));
packets.push_back(PacketFeedback(110, 210, 1, 1500, kPacingInfo0));
packets.push_back(PacketFeedback(120, 220, 2, 1500, kPacingInfo0));
packets.push_back(PacketFeedback(130, 230, 3, 1500, kPacingInfo1));
packets.push_back(PacketFeedback(140, 240, 4, 1500, kPacingInfo1));
for (const PacketFeedback& packet : packets)
OnSentPacket(packet);
rtcp::TransportFeedback feedback;
feedback.SetBase(packets[0].sequence_number,
packets[0].arrival_time_ms * 1000);
for (const PacketFeedback& packet : packets) {
EXPECT_TRUE(feedback.AddReceivedPacket(packet.sequence_number,
packet.arrival_time_ms * 1000));
}
feedback.Build();
adapter_->OnTransportFeedback(feedback);
ComparePacketFeedbackVectors(packets, adapter_->GetTransportFeedbackVector());
}
TEST_F(LegacyTransportFeedbackAdapterTest, FeedbackVectorReportsUnreceived) {
std::vector<PacketFeedback> sent_packets = {
PacketFeedback(100, 220, 0, 1500, kPacingInfo0),
PacketFeedback(110, 210, 1, 1500, kPacingInfo0),
PacketFeedback(120, 220, 2, 1500, kPacingInfo0),
PacketFeedback(130, 230, 3, 1500, kPacingInfo0),
PacketFeedback(140, 240, 4, 1500, kPacingInfo0),
PacketFeedback(150, 250, 5, 1500, kPacingInfo0),
PacketFeedback(160, 260, 6, 1500, kPacingInfo0)
};
for (const PacketFeedback& packet : sent_packets)
OnSentPacket(packet);
// Note: Important to include the last packet, as only unreceived packets in
// between received packets can be inferred.
std::vector<PacketFeedback> received_packets = {
sent_packets[0], sent_packets[2], sent_packets[6]
};
rtcp::TransportFeedback feedback;
feedback.SetBase(received_packets[0].sequence_number,
received_packets[0].arrival_time_ms * 1000);
for (const PacketFeedback& packet : received_packets) {
EXPECT_TRUE(feedback.AddReceivedPacket(packet.sequence_number,
packet.arrival_time_ms * 1000));
}
feedback.Build();
adapter_->OnTransportFeedback(feedback);
ComparePacketFeedbackVectors(sent_packets,
adapter_->GetTransportFeedbackVector());
}
TEST_F(LegacyTransportFeedbackAdapterTest, HandlesDroppedPackets) {
std::vector<PacketFeedback> packets;
packets.push_back(PacketFeedback(100, 200, 0, 1500, kPacingInfo0));
packets.push_back(PacketFeedback(110, 210, 1, 1500, kPacingInfo1));
packets.push_back(PacketFeedback(120, 220, 2, 1500, kPacingInfo2));
packets.push_back(PacketFeedback(130, 230, 3, 1500, kPacingInfo3));
packets.push_back(PacketFeedback(140, 240, 4, 1500, kPacingInfo4));
const uint16_t kSendSideDropBefore = 1;
const uint16_t kReceiveSideDropAfter = 3;
for (const PacketFeedback& packet : packets) {
if (packet.sequence_number >= kSendSideDropBefore)
OnSentPacket(packet);
}
rtcp::TransportFeedback feedback;
feedback.SetBase(packets[0].sequence_number,
packets[0].arrival_time_ms * 1000);
for (const PacketFeedback& packet : packets) {
if (packet.sequence_number <= kReceiveSideDropAfter) {
EXPECT_TRUE(feedback.AddReceivedPacket(packet.sequence_number,
packet.arrival_time_ms * 1000));
}
}
feedback.Build();
std::vector<PacketFeedback> expected_packets(
packets.begin(), packets.begin() + kReceiveSideDropAfter + 1);
// Packets that have timed out on the send-side have lost the
// information stored on the send-side.
for (size_t i = 0; i < kSendSideDropBefore; ++i) {
expected_packets[i].send_time_ms = -1;
expected_packets[i].payload_size = 0;
expected_packets[i].pacing_info = PacedPacketInfo();
}
adapter_->OnTransportFeedback(feedback);
ComparePacketFeedbackVectors(expected_packets,
adapter_->GetTransportFeedbackVector());
}
TEST_F(LegacyTransportFeedbackAdapterTest, SendTimeWrapsBothWays) {
int64_t kHighArrivalTimeMs = rtcp::TransportFeedback::kDeltaScaleFactor *
static_cast<int64_t>(1 << 8) *
static_cast<int64_t>((1 << 23) - 1) / 1000;
std::vector<PacketFeedback> packets;
packets.push_back(
PacketFeedback(kHighArrivalTimeMs - 64, 200, 0, 1500, PacedPacketInfo()));
packets.push_back(
PacketFeedback(kHighArrivalTimeMs + 64, 210, 1, 1500, PacedPacketInfo()));
packets.push_back(
PacketFeedback(kHighArrivalTimeMs, 220, 2, 1500, PacedPacketInfo()));
for (const PacketFeedback& packet : packets)
OnSentPacket(packet);
for (size_t i = 0; i < packets.size(); ++i) {
std::unique_ptr<rtcp::TransportFeedback> feedback(
new rtcp::TransportFeedback());
feedback->SetBase(packets[i].sequence_number,
packets[i].arrival_time_ms * 1000);
EXPECT_TRUE(feedback->AddReceivedPacket(packets[i].sequence_number,
packets[i].arrival_time_ms * 1000));
rtc::Buffer raw_packet = feedback->Build();
feedback = rtcp::TransportFeedback::ParseFrom(raw_packet.data(),
raw_packet.size());
std::vector<PacketFeedback> expected_packets;
expected_packets.push_back(packets[i]);
adapter_->OnTransportFeedback(*feedback.get());
ComparePacketFeedbackVectors(expected_packets,
adapter_->GetTransportFeedbackVector());
}
}
TEST_F(LegacyTransportFeedbackAdapterTest, HandlesArrivalReordering) {
std::vector<PacketFeedback> packets;
packets.push_back(PacketFeedback(120, 200, 0, 1500, kPacingInfo0));
packets.push_back(PacketFeedback(110, 210, 1, 1500, kPacingInfo0));
packets.push_back(PacketFeedback(100, 220, 2, 1500, kPacingInfo0));
for (const PacketFeedback& packet : packets)
OnSentPacket(packet);
rtcp::TransportFeedback feedback;
feedback.SetBase(packets[0].sequence_number,
packets[0].arrival_time_ms * 1000);
for (const PacketFeedback& packet : packets) {
EXPECT_TRUE(feedback.AddReceivedPacket(packet.sequence_number,
packet.arrival_time_ms * 1000));
}
feedback.Build();
// Adapter keeps the packets ordered by sequence number (which is itself
// assigned by the order of transmission). Reordering by some other criteria,
// eg. arrival time, is up to the observers.
adapter_->OnTransportFeedback(feedback);
ComparePacketFeedbackVectors(packets, adapter_->GetTransportFeedbackVector());
}
TEST_F(LegacyTransportFeedbackAdapterTest, TimestampDeltas) {
std::vector<PacketFeedback> sent_packets;
const int64_t kSmallDeltaUs =
rtcp::TransportFeedback::kDeltaScaleFactor * ((1 << 8) - 1);
const int64_t kLargePositiveDeltaUs =
rtcp::TransportFeedback::kDeltaScaleFactor *
std::numeric_limits<int16_t>::max();
const int64_t kLargeNegativeDeltaUs =
rtcp::TransportFeedback::kDeltaScaleFactor *
std::numeric_limits<int16_t>::min();
PacketFeedback packet_feedback(100, 200, 0, 1500, true, 0, 0,
PacedPacketInfo());
sent_packets.push_back(packet_feedback);
packet_feedback.send_time_ms += kSmallDeltaUs / 1000;
packet_feedback.arrival_time_ms += kSmallDeltaUs / 1000;
++packet_feedback.sequence_number;
sent_packets.push_back(packet_feedback);
packet_feedback.send_time_ms += kLargePositiveDeltaUs / 1000;
packet_feedback.arrival_time_ms += kLargePositiveDeltaUs / 1000;
++packet_feedback.sequence_number;
sent_packets.push_back(packet_feedback);
packet_feedback.send_time_ms += kLargeNegativeDeltaUs / 1000;
packet_feedback.arrival_time_ms += kLargeNegativeDeltaUs / 1000;
++packet_feedback.sequence_number;
sent_packets.push_back(packet_feedback);
// Too large, delta - will need two feedback messages.
packet_feedback.send_time_ms += (kLargePositiveDeltaUs + 1000) / 1000;
packet_feedback.arrival_time_ms += (kLargePositiveDeltaUs + 1000) / 1000;
++packet_feedback.sequence_number;
// Packets will be added to send history.
for (const PacketFeedback& packet : sent_packets)
OnSentPacket(packet);
OnSentPacket(packet_feedback);
// Create expected feedback and send into adapter.
std::unique_ptr<rtcp::TransportFeedback> feedback(
new rtcp::TransportFeedback());
feedback->SetBase(sent_packets[0].sequence_number,
sent_packets[0].arrival_time_ms * 1000);
for (const PacketFeedback& packet : sent_packets) {
EXPECT_TRUE(feedback->AddReceivedPacket(packet.sequence_number,
packet.arrival_time_ms * 1000));
}
EXPECT_FALSE(feedback->AddReceivedPacket(
packet_feedback.sequence_number, packet_feedback.arrival_time_ms * 1000));
rtc::Buffer raw_packet = feedback->Build();
feedback =
rtcp::TransportFeedback::ParseFrom(raw_packet.data(), raw_packet.size());
std::vector<PacketFeedback> received_feedback;
EXPECT_TRUE(feedback.get() != nullptr);
adapter_->OnTransportFeedback(*feedback.get());
ComparePacketFeedbackVectors(sent_packets,
adapter_->GetTransportFeedbackVector());
// Create a new feedback message and add the trailing item.
feedback.reset(new rtcp::TransportFeedback());
feedback->SetBase(packet_feedback.sequence_number,
packet_feedback.arrival_time_ms * 1000);
EXPECT_TRUE(feedback->AddReceivedPacket(
packet_feedback.sequence_number, packet_feedback.arrival_time_ms * 1000));
raw_packet = feedback->Build();
feedback =
rtcp::TransportFeedback::ParseFrom(raw_packet.data(), raw_packet.size());
EXPECT_TRUE(feedback.get() != nullptr);
adapter_->OnTransportFeedback(*feedback.get());
{
std::vector<PacketFeedback> expected_packets;
expected_packets.push_back(packet_feedback);
ComparePacketFeedbackVectors(expected_packets,
adapter_->GetTransportFeedbackVector());
}
}
} // namespace test
} // namespace webrtc