#include "common.hpp"
#include "RTC/RTCP/FeedbackRtpNack.hpp"
#include "RTC/RTP/Codecs/AV1.hpp"
#include "RTC/RTP/Codecs/PayloadDescriptorHandler.hpp"
#include "RTC/RTP/Codecs/VP8.hpp"
#include "RTC/RTP/HeaderExtensionIds.hpp"
#include "RTC/RTP/Packet.hpp"
#include "RTC/RTP/RtpStream.hpp"
#include "RTC/RTP/RtpStreamSend.hpp"
#include "RTC/RTP/SharedPacket.hpp"
#include <catch2/catch_test_macros.hpp>
#include <cstring>
#include <vector>
SCENARIO("RtpStreamSend", "[rtp][rtcp][nack][rtpstream][rtpstreamsend]")
{
class TestRtpStreamListener : public RTC::RTP::RtpStreamSend::Listener
{
public:
void OnRtpStreamScore(
RTC::RTP::RtpStream* , uint8_t , uint8_t ) override
{
}
void OnRtpStreamRetransmitRtpPacket(
RTC::RTP::RtpStreamSend* , RTC::RTP::Packet* packet) override
{
this->retransmittedPackets.push_back(packet);
}
public:
std::vector<RTC::RTP::Packet*> retransmittedPackets;
};
auto createRtpPacket = [](uint8_t* buffer, size_t len, uint16_t seq, uint32_t timestamp)
{
auto* packet = RTC::RTP::Packet::Parse(buffer, len);
REQUIRE(packet);
packet->SetPayloadType(123);
packet->SetSequenceNumber(seq);
packet->SetTimestamp(timestamp);
return std::unique_ptr<RTC::RTP::Packet>(packet);
};
auto sendRtpPacket = [](
std::vector<std::pair<RTC::RTP::RtpStreamSend*, uint32_t>> streams,
RTC::RTP::Packet* packet)
{
RTC::RTP::SharedPacket sharedPacket;
for (auto& kv : streams)
{
auto* stream = kv.first;
auto ssrc = kv.second;
auto origSsrc = packet->GetSsrc();
packet->SetSsrc(ssrc);
auto result = stream->ReceivePacket(packet, sharedPacket);
packet->SetSsrc(origSsrc);
if (
result == RTC::RTP::RtpStreamSend::ReceivePacketResult::ACCEPTED_AND_STORED &&
!sharedPacket.HasPacket())
{
sharedPacket.Assign(packet);
}
}
};
auto checkRtxPacket = [](RTC::RTP::Packet* rtxPacket, RTC::RTP::Packet* origPacket)
{
REQUIRE(rtxPacket);
REQUIRE(rtxPacket->GetSequenceNumber() == origPacket->GetSequenceNumber());
REQUIRE(rtxPacket->GetTimestamp() == origPacket->GetTimestamp());
REQUIRE(rtxPacket->HasMarker() == origPacket->HasMarker());
};
auto parseAV1RtpPacket =
[](
RTC::RTP::Packet* packet,
std::unique_ptr<RTC::RTP::Codecs::DependencyDescriptor::TemplateDependencyStructure>&
templateDependencyStructure)
{
std::unique_ptr<RTC::RTP::Codecs::DependencyDescriptor> dependencyDescriptor;
packet->ReadDependencyDescriptor(dependencyDescriptor, templateDependencyStructure);
REQUIRE(dependencyDescriptor);
auto* payloadDescriptor = RTC::RTP::Codecs::AV1::Parse(dependencyDescriptor);
auto* payloadDescriptorHandler =
new RTC::RTP::Codecs::AV1::PayloadDescriptorHandler(payloadDescriptor);
packet->SetPayloadDescriptorHandler(payloadDescriptorHandler);
};
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, sizeof(rtpBuffer1), 21006, 1533790901));
auto packet2(createRtpPacket(rtpBuffer2, sizeof(rtpBuffer2), 21007, 1533790901));
packet2->SetMarker(true);
auto packet3(createRtpPacket(rtpBuffer3, sizeof(rtpBuffer3), 21008, 1533793871));
auto packet4(createRtpPacket(rtpBuffer4, sizeof(rtpBuffer4), 21009, 1533793871));
auto packet5(createRtpPacket(rtpBuffer5, sizeof(rtpBuffer5), 21010, 1533796931));
packet5->SetMarker(true);
TestRtpStreamListener testRtpStreamListener;
RTC::RTP::RtpStream::Params params;
params.ssrc = 1111;
params.clockRate = 90000;
params.useNack = true;
params.mimeType.type = RTC::RtpCodecMimeType::Type::VIDEO;
std::string mid;
auto stream = std::make_unique<RTC::RTP::RtpStreamSend>(&testRtpStreamListener, params, mid);
sendRtpPacket(
{
{ stream.get(), params.ssrc }
},
packet1.get());
sendRtpPacket(
{
{ stream.get(), params.ssrc }
},
packet3.get());
sendRtpPacket(
{
{ stream.get(), params.ssrc }
},
packet2.get());
sendRtpPacket(
{
{ stream.get(), params.ssrc }
},
packet3.get());
sendRtpPacket(
{
{ stream.get(), params.ssrc }
},
packet4.get());
sendRtpPacket(
{
{ stream.get(), params.ssrc }
},
packet5.get());
sendRtpPacket(
{
{ stream.get(), params.ssrc }
},
packet5.get());
RTC::RTCP::FeedbackRtpNackPacket nackPacket(0, params.ssrc);
auto* nackItem = new RTC::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.get());
checkRtxPacket(rtxPacket2, packet2.get());
checkRtxPacket(rtxPacket3, packet3.get());
checkRtxPacket(rtxPacket4, packet4.get());
checkRtxPacket(rtxPacket5, packet5.get());
}
SECTION("receive NACK and get zero retransmitted packets if useNack is not set")
{
auto packet1(createRtpPacket(rtpBuffer1, sizeof(rtpBuffer1), 21006, 1533790901));
auto packet2(createRtpPacket(rtpBuffer2, sizeof(rtpBuffer2), 21007, 1533790901));
auto packet3(createRtpPacket(rtpBuffer3, sizeof(rtpBuffer3), 21008, 1533793871));
auto packet4(createRtpPacket(rtpBuffer4, sizeof(rtpBuffer4), 21009, 1533793871));
auto packet5(createRtpPacket(rtpBuffer5, sizeof(rtpBuffer5), 21010, 1533796931));
TestRtpStreamListener testRtpStreamListener;
RTC::RTP::RtpStream::Params params;
params.ssrc = 1111;
params.clockRate = 90000;
params.useNack = false;
params.mimeType.type = RTC::RtpCodecMimeType::Type::VIDEO;
std::string mid;
auto stream = std::make_unique<RTC::RTP::RtpStreamSend>(&testRtpStreamListener, params, mid);
sendRtpPacket(
{
{ stream.get(), params.ssrc }
},
packet1.get());
sendRtpPacket(
{
{ stream.get(), params.ssrc }
},
packet3.get());
sendRtpPacket(
{
{ stream.get(), params.ssrc }
},
packet2.get());
sendRtpPacket(
{
{ stream.get(), params.ssrc }
},
packet3.get());
sendRtpPacket(
{
{ stream.get(), params.ssrc }
},
packet4.get());
sendRtpPacket(
{
{ stream.get(), params.ssrc }
},
packet5.get());
sendRtpPacket(
{
{ stream.get(), params.ssrc }
},
packet5.get());
RTC::RTCP::FeedbackRtpNackPacket nackPacket(0, params.ssrc);
auto* nackItem = new RTC::RTCP::FeedbackRtpNackItem(21006, 0b0000000000001111);
nackPacket.AddItem(nackItem);
REQUIRE(nackItem->GetPacketId() == 21006);
REQUIRE(nackItem->GetLostPacketBitmask() == 0b0000000000001111);
stream->ReceiveNack(&nackPacket);
REQUIRE(testRtpStreamListener.retransmittedPackets.empty());
testRtpStreamListener.retransmittedPackets.clear();
}
SECTION("receive NACK and get zero retransmitted packets for audio")
{
auto packet1(createRtpPacket(rtpBuffer1, sizeof(rtpBuffer1), 21006, 1533790901));
auto packet2(createRtpPacket(rtpBuffer2, sizeof(rtpBuffer2), 21007, 1533790901));
auto packet3(createRtpPacket(rtpBuffer3, sizeof(rtpBuffer3), 21008, 1533793871));
auto packet4(createRtpPacket(rtpBuffer4, sizeof(rtpBuffer4), 21009, 1533793871));
auto packet5(createRtpPacket(rtpBuffer5, sizeof(rtpBuffer5), 21010, 1533796931));
TestRtpStreamListener testRtpStreamListener;
RTC::RTP::RtpStream::Params params;
params.ssrc = 1111;
params.clockRate = 90000;
params.useNack = false;
params.mimeType.type = RTC::RtpCodecMimeType::Type::AUDIO;
std::string mid;
auto stream = std::make_unique<RTC::RTP::RtpStreamSend>(&testRtpStreamListener, params, mid);
sendRtpPacket(
{
{ stream.get(), params.ssrc }
},
packet1.get());
sendRtpPacket(
{
{ stream.get(), params.ssrc }
},
packet3.get());
sendRtpPacket(
{
{ stream.get(), params.ssrc }
},
packet2.get());
sendRtpPacket(
{
{ stream.get(), params.ssrc }
},
packet3.get());
sendRtpPacket(
{
{ stream.get(), params.ssrc }
},
packet4.get());
sendRtpPacket(
{
{ stream.get(), params.ssrc }
},
packet5.get());
sendRtpPacket(
{
{ stream.get(), params.ssrc }
},
packet5.get());
RTC::RTCP::FeedbackRtpNackPacket nackPacket(0, params.ssrc);
auto* nackItem = new RTC::RTCP::FeedbackRtpNackItem(21006, 0b0000000000001111);
nackPacket.AddItem(nackItem);
REQUIRE(nackItem->GetPacketId() == 21006);
REQUIRE(nackItem->GetLostPacketBitmask() == 0b0000000000001111);
stream->ReceiveNack(&nackPacket);
REQUIRE(testRtpStreamListener.retransmittedPackets.empty());
testRtpStreamListener.retransmittedPackets.clear();
}
SECTION("receive NACK in different RtpStreamSend instances and get retransmitted packets")
{
auto packet1(createRtpPacket(rtpBuffer1, sizeof(rtpBuffer1), 21006, 1533790901));
auto packet2(createRtpPacket(rtpBuffer2, sizeof(rtpBuffer2), 21007, 1533790901));
TestRtpStreamListener testRtpStreamListener1;
TestRtpStreamListener testRtpStreamListener2;
RTC::RTP::RtpStream::Params params1;
params1.ssrc = 1111;
params1.clockRate = 90000;
params1.useNack = true;
params1.mimeType.type = RTC::RtpCodecMimeType::Type::VIDEO;
std::string mid;
std::unique_ptr<RTC::RTP::RtpStreamSend> stream1(
new RTC::RTP::RtpStreamSend(&testRtpStreamListener1, params1, mid));
RTC::RTP::RtpStream::Params params2;
params2.ssrc = 2222;
params2.clockRate = 90000;
params2.useNack = true;
params2.mimeType.type = RTC::RtpCodecMimeType::Type::VIDEO;
std::unique_ptr<RTC::RTP::RtpStreamSend> stream2(
new RTC::RTP::RtpStreamSend(&testRtpStreamListener2, params2, mid));
sendRtpPacket(
{
{ stream1.get(), params1.ssrc },
{ stream2.get(), params2.ssrc }
},
packet1.get());
sendRtpPacket(
{
{ stream1.get(), params1.ssrc },
{ stream2.get(), params2.ssrc }
},
packet2.get());
RTC::RTCP::FeedbackRtpNackPacket nackPacket(0, params1.ssrc);
auto* nackItem = new RTC::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.get());
checkRtxPacket(rtxPacket2, packet2.get());
stream2->ReceiveNack(&nackPacket);
REQUIRE(testRtpStreamListener2.retransmittedPackets.size() == 2);
rtxPacket1 = testRtpStreamListener2.retransmittedPackets[0];
rtxPacket2 = testRtpStreamListener2.retransmittedPackets[1];
testRtpStreamListener2.retransmittedPackets.clear();
checkRtxPacket(rtxPacket1, packet1.get());
checkRtxPacket(rtxPacket2, packet2.get());
}
SECTION("retransmitted packets are correctly encoded [VP8]")
{
uint8_t rtpBuffer1[] =
{
0x80, 0x7b, 0x52, 0x0e,
0x5b, 0x6b, 0xca, 0xb5,
0x00, 0x00, 0x00, 0x02,
0x80, 0xe0, 0x80, 0x01,
0xe8, 0x40, 0x7a, 0xd8
};
uint8_t rtpBuffer2[] =
{
0x80, 0x7b, 0x52, 0x0e,
0x5b, 0x6b, 0xca, 0xb5,
0x00, 0x00, 0x00, 0x02,
0x80, 0xe0, 0x80, 0x02,
0xe9, 0x40, 0x7a, 0xd8
};
uint8_t rtpBuffer3[] =
{
0x80, 0x7b, 0x52, 0x0e,
0x5b, 0x6b, 0xca, 0xb5,
0x00, 0x00, 0x00, 0x02,
0x80, 0xe0, 0x80, 0x03,
0xea, 0x40, 0x7a, 0xd8
};
auto packet1(createRtpPacket(rtpBuffer1, sizeof(rtpBuffer1), 1, 1));
auto packet2(createRtpPacket(rtpBuffer2, sizeof(rtpBuffer2), 2, 1));
auto packet3(createRtpPacket(rtpBuffer3, sizeof(rtpBuffer3), 3, 1));
TestRtpStreamListener testRtpStreamListener1;
TestRtpStreamListener testRtpStreamListener2;
RTC::RTP::RtpStream::Params params1;
params1.ssrc = 1111;
params1.clockRate = 90000;
params1.useNack = true;
params1.mimeType.type = RTC::RtpCodecMimeType::Type::VIDEO;
std::string mid;
std::unique_ptr<RTC::RTP::RtpStreamSend> stream1(
new RTC::RTP::RtpStreamSend(&testRtpStreamListener1, params1, mid));
RTC::RTP::RtpStream::Params params2;
params2.ssrc = 2222;
params2.clockRate = 90000;
params2.useNack = true;
params2.mimeType.type = RTC::RtpCodecMimeType::Type::VIDEO;
std::unique_ptr<RTC::RTP::RtpStreamSend> stream2(
new RTC::RTP::RtpStreamSend(&testRtpStreamListener2, params2, mid));
RTC::RTP::Codecs::EncodingContext::Params params;
params.spatialLayers = 0;
params.temporalLayers = 3;
RTC::RTP::Codecs::VP8::EncodingContext context1(params);
context1.SetCurrentTemporalLayer(3);
context1.SetTargetTemporalLayer(3);
RTC::RTP::Codecs::VP8::EncodingContext context2(params);
context2.SetCurrentTemporalLayer(0);
context2.SetTargetTemporalLayer(0);
auto* payloadDescriptor1 =
RTC::RTP::Codecs::VP8::Parse(packet1->GetPayload(), packet1->GetPayloadLength());
REQUIRE(payloadDescriptor1->pictureId == 1);
auto* payloadDescriptorHandler1 =
new RTC::RTP::Codecs::VP8::PayloadDescriptorHandler(payloadDescriptor1);
packet1->SetPayloadDescriptorHandler(payloadDescriptorHandler1);
bool marker = false;
auto forwarded = payloadDescriptorHandler1->Process(&context1, packet1.get(), marker);
REQUIRE(forwarded);
auto* payloadDescriptor2 =
RTC::RTP::Codecs::VP8::Parse(packet2->GetPayload(), packet2->GetPayloadLength());
REQUIRE(payloadDescriptor2->pictureId == 2);
auto* payloadDescriptorHandler2 =
new RTC::RTP::Codecs::VP8::PayloadDescriptorHandler(payloadDescriptor2);
packet2->SetPayloadDescriptorHandler(payloadDescriptorHandler2);
forwarded = payloadDescriptorHandler2->Process(&context1, packet2.get(), marker);
REQUIRE(forwarded);
forwarded = payloadDescriptorHandler2->Process(&context2, packet2.get(), marker);
REQUIRE(!forwarded);
auto* payloadDescriptor3 =
RTC::RTP::Codecs::VP8::Parse(packet3->GetPayload(), packet3->GetPayloadLength());
REQUIRE(payloadDescriptor3->pictureId == 3);
auto* payloadDescriptorHandler3 =
new RTC::RTP::Codecs::VP8::PayloadDescriptorHandler(payloadDescriptor3);
packet2->SetPayloadDescriptorHandler(payloadDescriptorHandler3);
forwarded = payloadDescriptorHandler3->Process(&context1, packet3.get(), marker);
REQUIRE(forwarded);
sendRtpPacket(
{
{ stream1.get(), params1.ssrc }
},
packet3.get());
context2.SetCurrentTemporalLayer(3);
context2.SetTargetTemporalLayer(3);
forwarded = payloadDescriptorHandler3->Process(&context2, packet3.get(), marker);
REQUIRE(forwarded);
sendRtpPacket(
{
{ stream2.get(), params2.ssrc }
},
packet3.get());
RTC::RTCP::FeedbackRtpNackPacket nackPacket(0, params1.ssrc);
auto* nackItem = new RTC::RTCP::FeedbackRtpNackItem(3, 0b0000000000000000);
nackPacket.AddItem(nackItem);
REQUIRE(nackItem->GetPacketId() == 3);
REQUIRE(nackItem->GetLostPacketBitmask() == 0b0000000000000000);
stream1->ReceiveNack(&nackPacket);
REQUIRE(testRtpStreamListener1.retransmittedPackets.size() == 1);
auto* packet = testRtpStreamListener1.retransmittedPackets[0];
auto* payloadDescriptor4 =
RTC::RTP::Codecs::VP8::Parse(packet->GetPayload(), packet->GetPayloadLength());
REQUIRE(payloadDescriptor4->pictureId == 3);
stream2->ReceiveNack(&nackPacket);
REQUIRE(testRtpStreamListener2.retransmittedPackets.size() == 1);
packet = testRtpStreamListener2.retransmittedPackets[0];
auto* payloadDescriptor5 =
RTC::RTP::Codecs::VP8::Parse(packet->GetPayload(), packet->GetPayloadLength());
REQUIRE(payloadDescriptor5);
REQUIRE(payloadDescriptor5->pictureId == 2);
delete payloadDescriptor4;
delete payloadDescriptor5;
}
SECTION("retransmitted packets are correctly encoded [AV1]")
{
uint8_t rtpBuffer1[] =
{
0x90, 0x2D, 0x56, 0xA5,
0x8D, 0x76, 0xF5, 0x02,
0xDD, 0xD5, 0x4C, 0xB9,
0xBE, 0xDE, 0x00, 0x07,
0x22, 0x89, 0xDF, 0xFE,
0x31, 0x00, 0x07, 0x40,
0x31, 0xCE, 0x80, 0x00,
0x01, 0x80, 0x01, 0x1E,
0xA8, 0x51, 0x41, 0x01,
0x0C, 0x13, 0xFC, 0x0B,
0x3C, 0x00, 0x00, 0x00
};
uint8_t rtpBuffer2[] =
{
0x90, 0xAD, 0x56, 0xA9,
0x8D, 0x77, 0x02, 0xB8,
0xDD, 0xD5, 0x4C, 0xB9,
0xBE, 0xDE, 0x00, 0x04,
0x22, 0x8A, 0x07, 0xAB,
0x31, 0x00, 0x18, 0x40,
0x31, 0xC2, 0xC2, 0x00,
0x02, 0x00, 0x00, 0x00
};
uint8_t rtpBuffer3[] =
{
0x90, 0xAD, 0x56, 0xA8,
0x8D, 0x76, 0xF5, 0x02,
0xDD, 0xD5, 0x4C, 0xB9,
0xBE, 0xDE, 0x00, 0x04,
0x22, 0x8A, 0x03, 0xE5,
0xD0, 0x00, 0x31, 0x00,
0x17, 0xC2, 0x40, 0x00,
0x01, 0x40, 0x31, 0x00
};
RTC::RTP::HeaderExtensionIds headerExtensionIds{};
headerExtensionIds.dependencyDescriptor = 12;
auto packet1(createRtpPacket(rtpBuffer1, sizeof(rtpBuffer1), 1, 1));
packet1->AssignExtensionIds(headerExtensionIds);
auto packet2(createRtpPacket(rtpBuffer2, sizeof(rtpBuffer2), 2, 1));
packet2->AssignExtensionIds(headerExtensionIds);
auto packet3(createRtpPacket(rtpBuffer3, sizeof(rtpBuffer3), 3, 1));
packet3->AssignExtensionIds(headerExtensionIds);
TestRtpStreamListener testRtpStreamListener1;
TestRtpStreamListener testRtpStreamListener2;
RTC::RTP::RtpStream::Params params1;
params1.ssrc = 1111;
params1.clockRate = 90000;
params1.useNack = true;
params1.mimeType.type = RTC::RtpCodecMimeType::Type::VIDEO;
std::string mid;
std::unique_ptr<RTC::RTP::RtpStreamSend> stream1(
new RTC::RTP::RtpStreamSend(&testRtpStreamListener1, params1, mid));
RTC::RTP::RtpStream::Params params2;
params2.ssrc = 2222;
params2.clockRate = 90000;
params2.useNack = true;
params2.mimeType.type = RTC::RtpCodecMimeType::Type::VIDEO;
std::unique_ptr<RTC::RTP::RtpStreamSend> stream2(
new RTC::RTP::RtpStreamSend(&testRtpStreamListener2, params2, mid));
RTC::RTP::Codecs::EncodingContext::Params params;
params.spatialLayers = 1;
params.temporalLayers = 2;
RTC::RTP::Codecs::AV1::EncodingContext context1(params);
context1.SetCurrentSpatialLayer(0);
context1.SetCurrentTemporalLayer(0);
context1.SetTargetSpatialLayer(0);
context1.SetTargetTemporalLayer(0);
RTC::RTP::Codecs::AV1::EncodingContext context2(params);
context2.SetCurrentSpatialLayer(0);
context2.SetCurrentTemporalLayer(0);
context2.SetTargetSpatialLayer(0);
context2.SetTargetTemporalLayer(1);
std::unique_ptr<RTC::RTP::Codecs::DependencyDescriptor::TemplateDependencyStructure>
templateDependencyStructure;
parseAV1RtpPacket(packet1.get(), templateDependencyStructure);
parseAV1RtpPacket(packet2.get(), templateDependencyStructure);
bool marker = false;
bool forwarded = false;
forwarded = packet2->ProcessPayload(&context1, marker);
REQUIRE(!forwarded);
forwarded = packet2->ProcessPayload(&context2, marker);
REQUIRE(forwarded);
REQUIRE(context2.GetCurrentSpatialLayer() == 0);
REQUIRE(context2.GetCurrentTemporalLayer() == 1);
parseAV1RtpPacket(packet3.get(), templateDependencyStructure);
forwarded = packet3->ProcessPayload(&context1, marker);
REQUIRE(forwarded);
REQUIRE(context1.GetCurrentSpatialLayer() == 0);
REQUIRE(context1.GetCurrentTemporalLayer() == 0);
RTC::RTP::SharedPacket sharedPacket;
packet3->SetSsrc(params1.ssrc);
auto result = stream1->ReceivePacket(packet3.get(), sharedPacket);
REQUIRE(result == RTC::RTP::RtpStreamSend::ReceivePacketResult::ACCEPTED_AND_STORED);
sharedPacket.Assign(packet3.get());
forwarded = packet3->ProcessPayload(&context2, marker);
REQUIRE(forwarded);
REQUIRE(context2.GetCurrentSpatialLayer() == 0);
REQUIRE(context2.GetCurrentTemporalLayer() == 1);
packet3->SetSsrc(params2.ssrc);
stream2->ReceivePacket(packet3.get(), sharedPacket);
RTC::RTCP::FeedbackRtpNackPacket nackPacket(0, params1.ssrc);
auto* nackItem = new RTC::RTCP::FeedbackRtpNackItem(3, 0b0000000000000000);
nackPacket.AddItem(nackItem);
REQUIRE(nackItem->GetPacketId() == 3);
REQUIRE(nackItem->GetLostPacketBitmask() == 0b0000000000000000);
stream1->ReceiveNack(&nackPacket);
REQUIRE(testRtpStreamListener1.retransmittedPackets.size() == 1);
auto* packet = testRtpStreamListener1.retransmittedPackets[0];
std::unique_ptr<RTC::RTP::Codecs::DependencyDescriptor> dependencyDescriptor4;
packet->ReadDependencyDescriptor(dependencyDescriptor4, templateDependencyStructure);
REQUIRE(dependencyDescriptor4);
stream2->ReceiveNack(&nackPacket);
REQUIRE(testRtpStreamListener2.retransmittedPackets.size() == 1);
packet = testRtpStreamListener2.retransmittedPackets[0];
std::unique_ptr<RTC::RTP::Codecs::DependencyDescriptor> dependencyDescriptor5;
packet->ReadDependencyDescriptor(dependencyDescriptor5, templateDependencyStructure);
REQUIRE(dependencyDescriptor5);
}
SECTION("packets get retransmitted as long as they don't exceed MaxRetransmissionDelayForVideoMs")
{
const uint32_t clockRate = 90000;
const uint32_t firstTs = 1533790901;
const uint32_t diffTs =
RTC::RTP::RtpStreamSend::MaxRetransmissionDelayForVideoMs * clockRate / 1000;
const uint32_t secondTs = firstTs + diffTs;
auto packet1(createRtpPacket(rtpBuffer1, sizeof(rtpBuffer1), 21006, firstTs));
auto packet2(createRtpPacket(rtpBuffer2, sizeof(rtpBuffer2), 21007, secondTs - 1));
TestRtpStreamListener testRtpStreamListener;
RTC::RTP::RtpStream::Params params1;
params1.ssrc = 1111;
params1.clockRate = clockRate;
params1.useNack = true;
params1.mimeType.type = RTC::RtpCodecMimeType::Type::VIDEO;
std::string mid;
auto stream = std::make_unique<RTC::RTP::RtpStreamSend>(&testRtpStreamListener, params1, mid);
sendRtpPacket(
{
{ stream.get(), params1.ssrc }
},
packet1.get());
sendRtpPacket(
{
{ stream.get(), params1.ssrc }
},
packet2.get());
RTC::RTCP::FeedbackRtpNackPacket nackPacket(0, params1.ssrc);
auto* nackItem = new RTC::RTCP::FeedbackRtpNackItem(21006, 0b0000000000000001);
nackPacket.AddItem(nackItem);
REQUIRE(nackItem->GetPacketId() == 21006);
REQUIRE(nackItem->GetLostPacketBitmask() == 0b0000000000000001);
stream->ReceiveNack(&nackPacket);
REQUIRE(testRtpStreamListener.retransmittedPackets.size() == 2);
auto* rtxPacket1 = testRtpStreamListener.retransmittedPackets[0];
auto* rtxPacket2 = testRtpStreamListener.retransmittedPackets[1];
testRtpStreamListener.retransmittedPackets.clear();
checkRtxPacket(rtxPacket1, packet1.get());
checkRtxPacket(rtxPacket2, packet2.get());
}
SECTION("packets don't get retransmitted if MaxRetransmissionDelayForVideoMs is exceeded")
{
const uint32_t clockRate = 90000;
const uint32_t firstTs = 1533790901;
const uint32_t diffTs =
RTC::RTP::RtpStreamSend::MaxRetransmissionDelayForVideoMs * clockRate / 1000;
const uint32_t secondTs = firstTs + diffTs + 100;
const uint32_t thirdTs = firstTs + (2 * diffTs);
auto packet1(createRtpPacket(rtpBuffer1, sizeof(rtpBuffer1), 21006, firstTs));
auto packet2(createRtpPacket(rtpBuffer2, sizeof(rtpBuffer2), 21007, secondTs));
auto packet3(createRtpPacket(rtpBuffer3, sizeof(rtpBuffer3), 21008, thirdTs));
TestRtpStreamListener testRtpStreamListener;
RTC::RTP::RtpStream::Params params1;
params1.ssrc = 1111;
params1.clockRate = clockRate;
params1.useNack = true;
params1.mimeType.type = RTC::RtpCodecMimeType::Type::VIDEO;
std::string mid;
auto stream = std::make_unique<RTC::RTP::RtpStreamSend>(&testRtpStreamListener, params1, mid);
sendRtpPacket(
{
{ stream.get(), params1.ssrc }
},
packet1.get());
sendRtpPacket(
{
{ stream.get(), params1.ssrc }
},
packet2.get());
sendRtpPacket(
{
{ stream.get(), params1.ssrc }
},
packet3.get());
RTC::RTCP::FeedbackRtpNackPacket nackPacket(0, params1.ssrc);
auto* nackItem = new RTC::RTCP::FeedbackRtpNackItem(21006, 0b0000000000000001);
nackPacket.AddItem(nackItem);
REQUIRE(nackItem->GetPacketId() == 21006);
REQUIRE(nackItem->GetLostPacketBitmask() == 0b0000000000000001);
stream->ReceiveNack(&nackPacket);
REQUIRE(testRtpStreamListener.retransmittedPackets.size() == 1);
auto* rtxPacket2 = testRtpStreamListener.retransmittedPackets[0];
testRtpStreamListener.retransmittedPackets.clear();
checkRtxPacket(rtxPacket2, packet2.get());
}
SECTION("packets get removed from the retransmission buffer if seq number of the stream is reset")
{
auto packet1(createRtpPacket(rtpBuffer1, sizeof(rtpBuffer1), 50001, 1000001));
auto packet2(createRtpPacket(rtpBuffer2, sizeof(rtpBuffer2), 50002, 1000002));
auto packet3(createRtpPacket(rtpBuffer3, sizeof(rtpBuffer3), 40003, 1000003));
auto packet4(createRtpPacket(rtpBuffer4, sizeof(rtpBuffer4), 40004, 1000004));
TestRtpStreamListener testRtpStreamListener;
RTC::RTP::RtpStream::Params params1;
params1.ssrc = 1111;
params1.clockRate = 90000;
params1.useNack = true;
params1.mimeType.type = RTC::RtpCodecMimeType::Type::VIDEO;
std::string mid;
auto stream = std::make_unique<RTC::RTP::RtpStreamSend>(&testRtpStreamListener, params1, mid);
sendRtpPacket(
{
{ stream.get(), params1.ssrc }
},
packet1.get());
sendRtpPacket(
{
{ stream.get(), params1.ssrc }
},
packet2.get());
sendRtpPacket(
{
{ stream.get(), params1.ssrc }
},
packet3.get());
sendRtpPacket(
{
{ stream.get(), params1.ssrc }
},
packet4.get());
RTC::RTCP::FeedbackRtpNackPacket nackPacket2(0, params1.ssrc);
auto* nackItem2 = new RTC::RTCP::FeedbackRtpNackItem(50001, 0b0000000000000001);
nackPacket2.AddItem(nackItem2);
stream->ReceiveNack(&nackPacket2);
REQUIRE(testRtpStreamListener.retransmittedPackets.empty());
}
SECTION("duplicated packets are discarded")
{
auto packet(createRtpPacket(rtpBuffer1, sizeof(rtpBuffer1), 50001, 1000001));
TestRtpStreamListener testRtpStreamListener;
RTC::RTP::RtpStream::Params params;
params.ssrc = packet->GetSsrc();
params.clockRate = 90000;
params.useNack = true;
params.mimeType.type = RTC::RtpCodecMimeType::Type::VIDEO;
std::string mid;
auto stream = std::make_unique<RTC::RTP::RtpStreamSend>(&testRtpStreamListener, params, mid);
const RTC::RTP::SharedPacket sharedPacket;
auto result = stream->ReceivePacket(packet.get(), sharedPacket);
REQUIRE(result == RTC::RTP::RtpStreamSend::ReceivePacketResult::ACCEPTED_AND_STORED);
result = stream->ReceivePacket(packet.get(), sharedPacket);
REQUIRE(result == RTC::RTP::RtpStreamSend::ReceivePacketResult::DISCARDED);
}
#ifdef PERFORMANCE_TEST
SECTION("Performance")
{
TestRtpStreamListener testRtpStreamListener;
RTC::RTP::RtpStream::Params params;
params.ssrc = 1111;
params.clockRate = 90000;
params.useNack = true;
params.mimeType.type = RTC::RtpCodecMimeType::Type::VIDEO;
std::string mid;
std::unique_ptr<RTC::RTP::RtpStreamSend> stream1(
new RTC::RTP::RtpStreamSend(&testRtpStreamListener, params, mid));
size_t iterations = 10000000;
auto start = std::chrono::system_clock::now();
for (size_t i = 0; i < iterations; i++)
{
auto* packet = RTC::RTP::Packet::Parse(rtpBuffer1, 1500);
packet->SetSsrc(1111);
std::shared_ptr<RTC::RTP::Packet> sharedPacket(packet);
stream1->ReceivePacket(packet, sharedPacket);
}
std::chrono::duration<double> dur = std::chrono::system_clock::now() - start;
std::cout << "nullptr && initialized shared_ptr: \t" << dur.count() << " seconds" << std::endl;
params.mimeType.type = RTC::RtpCodecMimeType::Type::AUDIO;
std::unique_ptr<RTC::RTP::RtpStreamSend> stream2(
new RTC::RTP::RtpStreamSend(&testRtpStreamListener, params, mid));
start = std::chrono::system_clock::now();
for (size_t i = 0; i < iterations; i++)
{
std::shared_ptr<RTC::RTP::Packet> sharedPacket;
auto* packet = RTC::RTP::Packet::Parse(rtpBuffer1, 1500);
packet->SetSsrc(1111);
stream2->ReceivePacket(packet, sharedPacket);
}
dur = std::chrono::system_clock::now() - start;
std::cout << "raw && empty shared_ptr duration: \t" << dur.count() << " seconds" << std::endl;
}
#endif
}