#include "common.hpp"
#include "RTC/RTCP/FeedbackRtpNack.hpp"
#include "RTC/RtpPacket.hpp"
#include "RTC/RtpStream.hpp"
#include "RTC/RtpStreamSend.hpp"
#include <catch2/catch.hpp>
#include <vector>
using namespace RTC;
static std::shared_ptr<RtpPacket> CreateRtpPacket(uint8_t* buffer, uint16_t seq, uint32_t timestamp)
{
auto* packet = RtpPacket::Parse(buffer, 1500);
packet->SetSequenceNumber(seq);
packet->SetTimestamp(timestamp);
std::shared_ptr<RtpPacket> shared(packet);
return shared;
}
static void SendRtpPacket(RtpStreamSend* stream, std::shared_ptr<RtpPacket> packet, uint32_t ssrc)
{
packet->SetSsrc(ssrc);
stream->ReceivePacket(packet);
}
static void CheckRtxPacket(RtpPacket* packet, uint16_t seq, uint32_t timestamp)
{
REQUIRE(packet);
REQUIRE(packet->GetSequenceNumber() == seq);
REQUIRE(packet->GetTimestamp() == timestamp);
}
SCENARIO("NACK and RTP packets retransmission", "[rtp][rtcp][nack]")
{
class TestRtpStreamListener : public RtpStreamSend::Listener
{
public:
void OnRtpStreamScore(RtpStream* , uint8_t , uint8_t ) override
{
}
void OnRtpStreamRetransmitRtpPacket(RtpStreamSend* , RtpPacket* packet) override
{
this->retransmittedPackets.push_back(packet);
}
public:
std::vector<RtpPacket*> retransmittedPackets;
};
uint8_t rtpBuffer1[] =
{
0b10000000, 0b01111011, 0b01010010, 0b00001110,
0b01011011, 0b01101011, 0b11001010, 0b10110101,
0, 0, 0, 2
};
uint8_t rtpBuffer2[1500];
uint8_t rtpBuffer3[1500];
uint8_t rtpBuffer4[1500];
uint8_t rtpBuffer5[1500];
std::memcpy(rtpBuffer2, rtpBuffer1, sizeof(rtpBuffer1));
std::memcpy(rtpBuffer3, rtpBuffer1, sizeof(rtpBuffer1));
std::memcpy(rtpBuffer4, rtpBuffer1, sizeof(rtpBuffer1));
std::memcpy(rtpBuffer5, rtpBuffer1, sizeof(rtpBuffer1));
SECTION("receive NACK and get retransmitted packets")
{
auto packet1 = CreateRtpPacket(rtpBuffer1, 21006, 1533790901);
auto packet2 = CreateRtpPacket(rtpBuffer2, 21007, 1533790901);
auto packet3 = CreateRtpPacket(rtpBuffer3, 21008, 1533793871);
auto packet4 = CreateRtpPacket(rtpBuffer4, 21009, 1533793871);
auto packet5 = CreateRtpPacket(rtpBuffer5, 21010, 1533796931);
TestRtpStreamListener testRtpStreamListener;
RtpStream::Params params;
params.ssrc = 1111;
params.clockRate = 90000;
params.useNack = true;
std::string mid;
RtpStreamSend* stream = new RtpStreamSend(&testRtpStreamListener, params, mid);
SendRtpPacket(stream, packet1, params.ssrc);
SendRtpPacket(stream, packet3, params.ssrc);
SendRtpPacket(stream, packet2, params.ssrc);
SendRtpPacket(stream, packet3, params.ssrc);
SendRtpPacket(stream, packet4, params.ssrc);
SendRtpPacket(stream, packet5, params.ssrc);
SendRtpPacket(stream, packet5, params.ssrc);
RTCP::FeedbackRtpNackPacket nackPacket(0, params.ssrc);
auto* nackItem = new RTCP::FeedbackRtpNackItem(21006, 0b0000000000001111);
nackPacket.AddItem(nackItem);
REQUIRE(nackItem->GetPacketId() == 21006);
REQUIRE(nackItem->GetLostPacketBitmask() == 0b0000000000001111);
stream->ReceiveNack(&nackPacket);
REQUIRE(testRtpStreamListener.retransmittedPackets.size() == 5);
auto rtxPacket1 = testRtpStreamListener.retransmittedPackets[0];
auto rtxPacket2 = testRtpStreamListener.retransmittedPackets[1];
auto rtxPacket3 = testRtpStreamListener.retransmittedPackets[2];
auto rtxPacket4 = testRtpStreamListener.retransmittedPackets[3];
auto rtxPacket5 = testRtpStreamListener.retransmittedPackets[4];
testRtpStreamListener.retransmittedPackets.clear();
CheckRtxPacket(rtxPacket1, packet1->GetSequenceNumber(), packet1->GetTimestamp());
CheckRtxPacket(rtxPacket2, packet2->GetSequenceNumber(), packet2->GetTimestamp());
CheckRtxPacket(rtxPacket3, packet3->GetSequenceNumber(), packet3->GetTimestamp());
CheckRtxPacket(rtxPacket4, packet4->GetSequenceNumber(), packet4->GetTimestamp());
CheckRtxPacket(rtxPacket5, packet5->GetSequenceNumber(), packet5->GetTimestamp());
delete stream;
}
SECTION("receive NACK in different RtpStreamSend instances and get retransmitted packets")
{
auto packet1 = CreateRtpPacket(rtpBuffer1, 21006, 1533790901);
auto packet2 = CreateRtpPacket(rtpBuffer2, 21007, 1533790901);
TestRtpStreamListener testRtpStreamListener1;
TestRtpStreamListener testRtpStreamListener2;
RtpStream::Params params1;
params1.ssrc = 1111;
params1.clockRate = 90000;
params1.useNack = true;
std::string mid;
RtpStreamSend* stream1 = new RtpStreamSend(&testRtpStreamListener1, params1, mid);
RtpStream::Params params2;
params2.ssrc = 2222;
params2.clockRate = 90000;
params2.useNack = true;
RtpStreamSend* stream2 = new RtpStreamSend(&testRtpStreamListener2, params2, mid);
SendRtpPacket(stream1, packet1, params1.ssrc);
SendRtpPacket(stream2, packet1, params2.ssrc);
SendRtpPacket(stream1, packet2, params1.ssrc);
SendRtpPacket(stream2, packet2, params2.ssrc);
RTCP::FeedbackRtpNackPacket nackPacket(0, params1.ssrc);
auto* nackItem = new RTCP::FeedbackRtpNackItem(21006, 0b0000000000000001);
nackPacket.AddItem(nackItem);
REQUIRE(nackItem->GetPacketId() == 21006);
REQUIRE(nackItem->GetLostPacketBitmask() == 0b0000000000000001);
stream1->ReceiveNack(&nackPacket);
REQUIRE(testRtpStreamListener1.retransmittedPackets.size() == 2);
auto rtxPacket1 = testRtpStreamListener1.retransmittedPackets[0];
auto rtxPacket2 = testRtpStreamListener1.retransmittedPackets[1];
testRtpStreamListener1.retransmittedPackets.clear();
CheckRtxPacket(rtxPacket1, packet1->GetSequenceNumber(), packet1->GetTimestamp());
CheckRtxPacket(rtxPacket2, packet2->GetSequenceNumber(), packet2->GetTimestamp());
stream2->ReceiveNack(&nackPacket);
REQUIRE(testRtpStreamListener2.retransmittedPackets.size() == 2);
rtxPacket1 = testRtpStreamListener2.retransmittedPackets[0];
rtxPacket2 = testRtpStreamListener2.retransmittedPackets[1];
testRtpStreamListener2.retransmittedPackets.clear();
CheckRtxPacket(rtxPacket1, packet1->GetSequenceNumber(), packet1->GetTimestamp());
CheckRtxPacket(rtxPacket2, packet2->GetSequenceNumber(), packet2->GetTimestamp());
delete stream1;
delete stream2;
}
SECTION("packets get retransmitted as long as they don't exceed MaxRetransmissionDelay")
{
uint32_t clockRate = 90000;
uint32_t firstTs = 1533790901;
uint32_t diffTs = RtpStreamSend::MaxRetransmissionDelay * clockRate / 1000;
uint32_t secondTs = firstTs + diffTs;
auto packet1 = CreateRtpPacket(rtpBuffer1, 21006, firstTs);
auto packet2 = CreateRtpPacket(rtpBuffer2, 21007, secondTs - 1);
TestRtpStreamListener testRtpStreamListener1;
RtpStream::Params params1;
params1.ssrc = 1111;
params1.clockRate = clockRate;
params1.useNack = true;
std::string mid;
RtpStreamSend* stream1 = new RtpStreamSend(&testRtpStreamListener1, params1, mid);
SendRtpPacket(stream1, packet1, params1.ssrc);
SendRtpPacket(stream1, packet2, params1.ssrc);
RTCP::FeedbackRtpNackPacket nackPacket(0, params1.ssrc);
auto* nackItem = new RTCP::FeedbackRtpNackItem(21006, 0b0000000000000001);
nackPacket.AddItem(nackItem);
REQUIRE(nackItem->GetPacketId() == 21006);
REQUIRE(nackItem->GetLostPacketBitmask() == 0b0000000000000001);
stream1->ReceiveNack(&nackPacket);
REQUIRE(testRtpStreamListener1.retransmittedPackets.size() == 2);
auto rtxPacket1 = testRtpStreamListener1.retransmittedPackets[0];
auto rtxPacket2 = testRtpStreamListener1.retransmittedPackets[1];
testRtpStreamListener1.retransmittedPackets.clear();
CheckRtxPacket(rtxPacket1, packet1->GetSequenceNumber(), packet1->GetTimestamp());
CheckRtxPacket(rtxPacket2, packet2->GetSequenceNumber(), packet2->GetTimestamp());
delete stream1;
}
SECTION("packets don't get retransmitted if MaxRetransmissionDelay is exceeded")
{
uint32_t clockRate = 90000;
uint32_t firstTs = 1533790901;
uint32_t diffTs = RtpStreamSend::MaxRetransmissionDelay * clockRate / 1000;
uint32_t secondTs = firstTs + diffTs;
auto packet1 = CreateRtpPacket(rtpBuffer1, 21006, firstTs);
auto packet2 = CreateRtpPacket(rtpBuffer2, 21007, secondTs);
TestRtpStreamListener testRtpStreamListener1;
RtpStream::Params params1;
params1.ssrc = 1111;
params1.clockRate = clockRate;
params1.useNack = true;
std::string mid;
RtpStreamSend* stream1 = new RtpStreamSend(&testRtpStreamListener1, params1, mid);
SendRtpPacket(stream1, packet1, params1.ssrc);
SendRtpPacket(stream1, packet2, params1.ssrc);
RTCP::FeedbackRtpNackPacket nackPacket(0, params1.ssrc);
auto* nackItem = new RTCP::FeedbackRtpNackItem(21006, 0b0000000000000001);
nackPacket.AddItem(nackItem);
REQUIRE(nackItem->GetPacketId() == 21006);
REQUIRE(nackItem->GetLostPacketBitmask() == 0b0000000000000001);
stream1->ReceiveNack(&nackPacket);
REQUIRE(testRtpStreamListener1.retransmittedPackets.size() == 1);
auto rtxPacket2 = testRtpStreamListener1.retransmittedPackets[0];
testRtpStreamListener1.retransmittedPackets.clear();
CheckRtxPacket(rtxPacket2, packet2->GetSequenceNumber(), packet2->GetTimestamp());
delete stream1;
}
}