blob: cdfd3a0a25eb889a0b55ffcbec152cdd5dc69ca2 [file] [log] [blame]
/*
* Copyright (c) 2012 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 "modules/rtp_rtcp/source/rtp_packet_history.h"
#include <memory>
#include <utility>
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
#include "system_wrappers/include/clock.h"
#include "test/gtest.h"
#include "typedefs.h" // NOLINT(build/include)
namespace webrtc {
class RtpPacketHistoryTest : public ::testing::Test {
protected:
static constexpr uint16_t kSeqNum = 88;
RtpPacketHistoryTest() : fake_clock_(123456), hist_(&fake_clock_) {}
SimulatedClock fake_clock_;
RtpPacketHistory hist_;
std::unique_ptr<RtpPacketToSend> CreateRtpPacket(uint16_t seq_num) {
// Payload, ssrc, timestamp and extensions are irrelevant for this tests.
std::unique_ptr<RtpPacketToSend> packet(new RtpPacketToSend(nullptr));
packet->SetSequenceNumber(seq_num);
packet->set_capture_time_ms(fake_clock_.TimeInMilliseconds());
return packet;
}
};
TEST_F(RtpPacketHistoryTest, SetStoreStatus) {
EXPECT_FALSE(hist_.StorePackets());
hist_.SetStorePacketsStatus(true, 10);
EXPECT_TRUE(hist_.StorePackets());
hist_.SetStorePacketsStatus(false, 0);
EXPECT_FALSE(hist_.StorePackets());
}
TEST_F(RtpPacketHistoryTest, NoStoreStatus) {
EXPECT_FALSE(hist_.StorePackets());
std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum);
hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false);
// Packet should not be stored.
EXPECT_FALSE(hist_.GetPacketAndSetSendTime(kSeqNum, 0, false));
}
TEST_F(RtpPacketHistoryTest, GetRtpPacket_NotStored) {
hist_.SetStorePacketsStatus(true, 10);
EXPECT_FALSE(hist_.GetPacketAndSetSendTime(0, 0, false));
}
TEST_F(RtpPacketHistoryTest, PutRtpPacket) {
hist_.SetStorePacketsStatus(true, 10);
std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum);
EXPECT_FALSE(hist_.HasRtpPacket(kSeqNum));
hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false);
EXPECT_TRUE(hist_.HasRtpPacket(kSeqNum));
}
TEST_F(RtpPacketHistoryTest, GetRtpPacket) {
hist_.SetStorePacketsStatus(true, 10);
int64_t capture_time_ms = 1;
std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum);
packet->set_capture_time_ms(capture_time_ms);
rtc::CopyOnWriteBuffer buffer = packet->Buffer();
hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false);
std::unique_ptr<RtpPacketToSend> packet_out =
hist_.GetPacketAndSetSendTime(kSeqNum, 0, false);
EXPECT_TRUE(packet_out);
EXPECT_EQ(buffer, packet_out->Buffer());
EXPECT_EQ(capture_time_ms, packet_out->capture_time_ms());
}
TEST_F(RtpPacketHistoryTest, NoCaptureTime) {
hist_.SetStorePacketsStatus(true, 10);
fake_clock_.AdvanceTimeMilliseconds(1);
int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum);
packet->set_capture_time_ms(-1);
rtc::CopyOnWriteBuffer buffer = packet->Buffer();
hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false);
std::unique_ptr<RtpPacketToSend> packet_out =
hist_.GetPacketAndSetSendTime(kSeqNum, 0, false);
EXPECT_TRUE(packet_out);
EXPECT_EQ(buffer, packet_out->Buffer());
EXPECT_EQ(capture_time_ms, packet_out->capture_time_ms());
}
TEST_F(RtpPacketHistoryTest, DontRetransmit) {
hist_.SetStorePacketsStatus(true, 10);
int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum);
rtc::CopyOnWriteBuffer buffer = packet->Buffer();
hist_.PutRtpPacket(std::move(packet), kDontRetransmit, false);
std::unique_ptr<RtpPacketToSend> packet_out;
packet_out = hist_.GetPacketAndSetSendTime(kSeqNum, 0, true);
EXPECT_FALSE(packet_out);
packet_out = hist_.GetPacketAndSetSendTime(kSeqNum, 0, false);
EXPECT_TRUE(packet_out);
EXPECT_EQ(buffer.size(), packet_out->size());
EXPECT_EQ(capture_time_ms, packet_out->capture_time_ms());
}
TEST_F(RtpPacketHistoryTest, MinResendTime) {
static const int64_t kMinRetransmitIntervalMs = 100;
hist_.SetStorePacketsStatus(true, 10);
int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum);
size_t len = packet->size();
hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false);
// First transmission: TimeToSendPacket() call from pacer.
EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kSeqNum, 0, false));
fake_clock_.AdvanceTimeMilliseconds(kMinRetransmitIntervalMs);
// Time has elapsed.
std::unique_ptr<RtpPacketToSend> packet_out =
hist_.GetPacketAndSetSendTime(kSeqNum, kMinRetransmitIntervalMs, true);
EXPECT_TRUE(packet_out);
EXPECT_EQ(len, packet_out->size());
EXPECT_EQ(capture_time_ms, packet_out->capture_time_ms());
fake_clock_.AdvanceTimeMilliseconds(kMinRetransmitIntervalMs - 1);
// Time has not elapsed. Packet should be found, but no bytes copied.
EXPECT_TRUE(hist_.HasRtpPacket(kSeqNum));
EXPECT_FALSE(
hist_.GetPacketAndSetSendTime(kSeqNum, kMinRetransmitIntervalMs, true));
}
TEST_F(RtpPacketHistoryTest, EarlyFirstResend) {
static const int64_t kMinRetransmitIntervalMs = 100;
hist_.SetStorePacketsStatus(true, 10);
int64_t capture_time_ms = fake_clock_.TimeInMilliseconds();
std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum);
rtc::CopyOnWriteBuffer buffer = packet->Buffer();
hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false);
// First transmission: TimeToSendPacket() call from pacer.
EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kSeqNum, 0, false));
fake_clock_.AdvanceTimeMilliseconds(kMinRetransmitIntervalMs - 1);
// Time has not elapsed, but this is the first retransmission request so
// allow anyway.
std::unique_ptr<RtpPacketToSend> packet_out =
hist_.GetPacketAndSetSendTime(kSeqNum, kMinRetransmitIntervalMs, true);
EXPECT_TRUE(packet_out);
EXPECT_EQ(buffer, packet_out->Buffer());
EXPECT_EQ(capture_time_ms, packet_out->capture_time_ms());
fake_clock_.AdvanceTimeMilliseconds(kMinRetransmitIntervalMs - 1);
// Time has not elapsed. Packet should be found, but no bytes copied.
EXPECT_TRUE(hist_.HasRtpPacket(kSeqNum));
EXPECT_FALSE(
hist_.GetPacketAndSetSendTime(kSeqNum, kMinRetransmitIntervalMs, true));
}
TEST_F(RtpPacketHistoryTest, DynamicExpansion) {
hist_.SetStorePacketsStatus(true, 10);
// Add 4 packets, and then send them.
for (int i = 0; i < 4; ++i) {
std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum + i);
hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false);
}
for (int i = 0; i < 4; ++i) {
EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kSeqNum + i, 100, false));
}
fake_clock_.AdvanceTimeMilliseconds(33);
// Add 16 packets, and then send them. History should expand to make this
// work.
for (int i = 4; i < 20; ++i) {
std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum + i);
hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false);
}
for (int i = 4; i < 20; ++i) {
EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kSeqNum + i, 100, false));
}
fake_clock_.AdvanceTimeMilliseconds(100);
// Retransmit last 16 packets.
for (int i = 4; i < 20; ++i) {
EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kSeqNum + i, 100, false));
}
}
TEST_F(RtpPacketHistoryTest, FullExpansion) {
static const int kSendSidePacketHistorySize = 600;
hist_.SetStorePacketsStatus(true, kSendSidePacketHistorySize);
for (size_t i = 0; i < RtpPacketHistory::kMaxCapacity + 1; ++i) {
std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum + i);
hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false);
}
fake_clock_.AdvanceTimeMilliseconds(100);
// Retransmit all packets currently in buffer.
for (size_t i = 1; i < RtpPacketHistory::kMaxCapacity + 1; ++i) {
EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kSeqNum + i, 100, false));
}
}
TEST_F(RtpPacketHistoryTest, DontExpandIfPacketIsOldEnough) {
const size_t kSendSidePacketHistorySize = 600;
const int64_t kRttMs = 334;
hist_.SetStorePacketsStatus(true, kSendSidePacketHistorySize);
hist_.SetRtt(kRttMs);
// Fill up the buffer with packets.
for (size_t i = 0; i < kSendSidePacketHistorySize; ++i) {
std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum + i);
hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false);
EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kSeqNum + i, 100, false));
}
// Move clock forward past expiration time.
fake_clock_.AdvanceTimeMilliseconds(kRttMs * 3 + 1);
// Insert a new packet and check that the old one for this index has been
// overwritten.
std::unique_ptr<RtpPacketToSend> packet =
CreateRtpPacket(kSeqNum + kSendSidePacketHistorySize);
hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, true);
EXPECT_FALSE(hist_.HasRtpPacket(kSeqNum));
}
TEST_F(RtpPacketHistoryTest, ExpandIfPacketTooRecentlyTransmitted) {
const size_t kSendSidePacketHistorySize = 600;
const int64_t kRttMs = 334;
hist_.SetStorePacketsStatus(true, kSendSidePacketHistorySize);
hist_.SetRtt(kRttMs);
// Fill up the buffer with packets.
for (size_t i = 0; i < kSendSidePacketHistorySize; ++i) {
std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum + i);
hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false);
EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kSeqNum + i, kRttMs, false));
}
// Move clock forward to just before expiration time.
fake_clock_.AdvanceTimeMilliseconds(kRttMs * 3);
// Insert a new packet and verify that the old one for this index still
// exists - ie the buffer has been expanded.
std::unique_ptr<RtpPacketToSend> packet =
CreateRtpPacket(kSeqNum + kSendSidePacketHistorySize);
hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, true);
EXPECT_TRUE(hist_.HasRtpPacket(kSeqNum));
}
TEST_F(RtpPacketHistoryTest, ExpandIfPacketTooRecentlyTransmittedOnFastLink) {
const size_t kSendSidePacketHistorySize = 600;
const int64_t kRttMs = 5;
hist_.SetStorePacketsStatus(true, kSendSidePacketHistorySize);
hist_.SetRtt(kRttMs);
// Fill up the buffer with packets.
for (size_t i = 0; i < kSendSidePacketHistorySize; ++i) {
std::unique_ptr<RtpPacketToSend> packet = CreateRtpPacket(kSeqNum + i);
hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, false);
EXPECT_TRUE(hist_.GetPacketAndSetSendTime(kSeqNum + i, kRttMs, false));
}
// Move clock forward after expiration time based on RTT, but before
// expiration time based on absolute time.
fake_clock_.AdvanceTimeMilliseconds(999);
// Insert a new packet and verify that the old one for this index still
// exists - ie the buffer has been expanded.
std::unique_ptr<RtpPacketToSend> packet =
CreateRtpPacket(kSeqNum + kSendSidePacketHistorySize);
hist_.PutRtpPacket(std::move(packet), kAllowRetransmission, true);
EXPECT_TRUE(hist_.HasRtpPacket(kSeqNum));
}
} // namespace webrtc