#include "common.hpp"
#include "RTC/RTP/Packet.hpp"
#include "RTC/RTP/RetransmissionBuffer.hpp"
#include "RTC/RTP/SharedPacket.hpp"
#include <catch2/catch_test_macros.hpp>
#include <vector>
SCENARIO("RTP RetransmissionBuffer", "[rtp][rtx]")
{
class RtpMyRetransmissionBuffer : public RTC::RTP::RetransmissionBuffer
{
public:
struct VerificationItem
{
bool isPresent;
uint16_t sequenceNumber;
uint32_t timestamp;
};
public:
RtpMyRetransmissionBuffer(uint16_t maxItems, uint32_t maxRetransmissionDelayMs, uint32_t clockRate)
: RTC::RTP::RetransmissionBuffer(maxItems, maxRetransmissionDelayMs, clockRate)
{
}
public:
void Insert(uint16_t seq, uint32_t timestamp)
{
uint8_t rtpBuffer[] =
{
0b10000000, 0b01111011, 0b01010010, 0b00001110,
0b01011011, 0b01101011, 0b11001010, 0b10110101,
0, 0, 0, 2
};
std::unique_ptr<RTC::RTP::Packet> packet{ RTC::RTP::Packet::Parse(rtpBuffer, sizeof(rtpBuffer)) };
packet->SetSequenceNumber(seq);
packet->SetTimestamp(timestamp);
const RTC::RTP::SharedPacket sharedPacket;
RTC::RTP::RetransmissionBuffer::Insert(packet.get(), sharedPacket);
}
void AssertBuffer(std::vector<VerificationItem> verificationBuffer)
{
REQUIRE(verificationBuffer.size() == this->buffer.size());
for (size_t idx{ 0u }; idx < verificationBuffer.size(); ++idx)
{
auto& verificationItem = verificationBuffer.at(idx);
auto* item = this->buffer.at(idx);
REQUIRE(verificationItem.isPresent == !!item);
if (item)
{
REQUIRE(verificationItem.sequenceNumber == item->sequenceNumber);
REQUIRE(verificationItem.timestamp == item->timestamp);
}
}
}
};
SECTION("proper packets received in order")
{
const uint16_t maxItems{ 4 };
const uint32_t maxRetransmissionDelayMs{ 2000u };
const uint32_t clockRate{ 90000 };
RtpMyRetransmissionBuffer myRetransmissionBuffer(maxItems, maxRetransmissionDelayMs, clockRate);
myRetransmissionBuffer.Insert(10001, 1000000000);
myRetransmissionBuffer.Insert(10002, 1000000000);
myRetransmissionBuffer.Insert(10003, 1000000200);
myRetransmissionBuffer.Insert(10004, 1000000200);
myRetransmissionBuffer.AssertBuffer(
{
{ true, 10001, 1000000000 },
{ true, 10002, 1000000000 },
{ true, 10003, 1000000200 },
{ true, 10004, 1000000200 }
}
);
}
SECTION("proper packets received out of order")
{
const uint16_t maxItems{ 4 };
const uint32_t maxRetransmissionDelayMs{ 2000u };
const uint32_t clockRate{ 90000 };
RtpMyRetransmissionBuffer myRetransmissionBuffer(maxItems, maxRetransmissionDelayMs, clockRate);
myRetransmissionBuffer.Insert(20004, 2000000200);
myRetransmissionBuffer.Insert(20001, 2000000000);
myRetransmissionBuffer.Insert(20003, 2000000200);
myRetransmissionBuffer.Insert(20002, 2000000000);
myRetransmissionBuffer.AssertBuffer(
{
{ true, 20001, 2000000000 },
{ true, 20002, 2000000000 },
{ true, 20003, 2000000200 },
{ true, 20004, 2000000200 }
}
);
}
SECTION("packet with too new sequence number produces buffer emptying")
{
const uint16_t maxItems{ 4 };
const uint32_t maxRetransmissionDelayMs{ 2000u };
const uint32_t clockRate{ 90000 };
RtpMyRetransmissionBuffer myRetransmissionBuffer(maxItems, maxRetransmissionDelayMs, clockRate);
myRetransmissionBuffer.Insert(30001, 3000000000);
myRetransmissionBuffer.Insert(30002, 3000000000);
myRetransmissionBuffer.Insert(30003, 3000000200);
myRetransmissionBuffer.Insert(40000, 3000003000);
myRetransmissionBuffer.AssertBuffer(
{
{ true, 40000, 3000003000 }
}
);
}
SECTION("blank slots are properly created")
{
const uint16_t maxItems{ 10 };
const uint32_t maxRetransmissionDelayMs{ 2000u };
const uint32_t clockRate{ 90000 };
RtpMyRetransmissionBuffer myRetransmissionBuffer(maxItems, maxRetransmissionDelayMs, clockRate);
myRetransmissionBuffer.Insert(40002, 4000000002);
myRetransmissionBuffer.Insert(40003, 4000000001);
myRetransmissionBuffer.Insert(40004, 4000000004);
myRetransmissionBuffer.Insert(40002, 4000000002);
myRetransmissionBuffer.Insert(40008, 4000000008);
myRetransmissionBuffer.Insert(40006, 4000000006);
myRetransmissionBuffer.Insert(40000, 4000000000);
myRetransmissionBuffer.AssertBuffer(
{
{ true, 40000, 4000000000 },
{ false, 0, 0 },
{ true, 40002, 4000000002 },
{ false, 0, 0 },
{ true, 40004, 4000000004 },
{ false, 0, 0 },
{ true, 40006, 4000000006 },
{ false, 0, 0 },
{ true, 40008, 4000000008 }
}
);
}
SECTION("packet with too old sequence number is discarded")
{
const uint16_t maxItems{ 4 };
const uint32_t maxRetransmissionDelayMs{ 2000u };
const uint32_t clockRate{ 90000 };
RtpMyRetransmissionBuffer myRetransmissionBuffer(maxItems, maxRetransmissionDelayMs, clockRate);
myRetransmissionBuffer.Insert(10001, 1000000001);
myRetransmissionBuffer.Insert(10002, 1000000002);
myRetransmissionBuffer.Insert(10003, 1000000003);
myRetransmissionBuffer.Insert(40000, 1000000000);
myRetransmissionBuffer.AssertBuffer(
{
{ true, 10001, 1000000001 },
{ true, 10002, 1000000002 },
{ true, 10003, 1000000003 }
}
);
}
SECTION("packet with too old timestamp is discarded")
{
const uint16_t maxItems{ 4 };
const uint32_t maxRetransmissionDelayMs{ 2000u };
const uint32_t clockRate{ 90000 };
RtpMyRetransmissionBuffer myRetransmissionBuffer(maxItems, maxRetransmissionDelayMs, clockRate);
auto maxDiffTs = static_cast<uint32_t>(maxRetransmissionDelayMs * clockRate / 1000);
myRetransmissionBuffer.Insert(10001, 1000000001);
myRetransmissionBuffer.Insert(10002, 1000000002);
myRetransmissionBuffer.Insert(10003, 1000000003);
myRetransmissionBuffer.Insert(10000, 1000000003 - maxDiffTs - 100);
myRetransmissionBuffer.AssertBuffer(
{
{ true, 10001, 1000000001 },
{ true, 10002, 1000000002 },
{ true, 10003, 1000000003 }
}
);
}
SECTION("packet with very newest timestamp is inserted as newest item despite its seq is old")
{
const uint16_t maxItems{ 4 };
const uint32_t maxRetransmissionDelayMs{ 2000u };
const uint32_t clockRate{ 90000 };
RtpMyRetransmissionBuffer myRetransmissionBuffer(maxItems, maxRetransmissionDelayMs, clockRate);
myRetransmissionBuffer.Insert(24816, 1024930187);
myRetransmissionBuffer.Insert(24980, 1025106407);
myRetransmissionBuffer.Insert(18365, 1026593387);
myRetransmissionBuffer.AssertBuffer(
{
{ true, 18365, 1026593387 }
}
);
}
SECTION(
"packet with lower seq than newest packet in the buffer and higher timestamp forces buffer emptying")
{
const uint16_t maxItems{ 4 };
const uint32_t maxRetransmissionDelayMs{ 2000u };
const uint32_t clockRate{ 90000 };
RtpMyRetransmissionBuffer myRetransmissionBuffer(maxItems, maxRetransmissionDelayMs, clockRate);
myRetransmissionBuffer.Insert(33331, 1000000001);
myRetransmissionBuffer.Insert(33332, 1000000002);
myRetransmissionBuffer.Insert(33330, 1000000003);
myRetransmissionBuffer.AssertBuffer(
{
{ true, 33330, 1000000003 }
}
);
}
SECTION("fuzzer generated packets")
{
const uint16_t maxItems{ 2500u };
const uint32_t maxRetransmissionDelayMs{ 2000u };
const uint32_t clockRate{ 90000 };
RtpMyRetransmissionBuffer myRetransmissionBuffer(maxItems, maxRetransmissionDelayMs, clockRate);
myRetransmissionBuffer.Insert(12645, 828702743);
myRetransmissionBuffer.Insert(33998, 2228092928);
myRetransmissionBuffer.Insert(33998, 2228092928);
}
}