#include "common.hpp"
#include "RTC/RTCP/Packet.hpp"
#include "RTC/RTCP/Sdes.hpp"
#include <catch2/catch_test_macros.hpp>
#include <cstring>
#include <string>
SCENARIO("RTCP SDES", "[rtcp][sdes]")
{
alignas(4) uint8_t buffer1[] =
{
0x81, 0xca, 0x00, 0x06, 0x9f, 0x65, 0xe7, 0x42, 0x01, 0x10, 0x74, 0x37, 0x6d, 0x6b, 0x59, 0x6e,
0x43, 0x6d, 0x34, 0x36,
0x4f, 0x63, 0x49, 0x4e,
0x79, 0x2f, 0x00, 0x00 };
const uint32_t ssrc1{ 0x9f65e742 };
const RTC::RTCP::SdesItem::Type item1Type{ RTC::RTCP::SdesItem::Type::CNAME };
const std::string item1Value{ "t7mkYnCm46OcINy/" };
const size_t item1Length{ 16u };
alignas(4) uint8_t buffer2[] =
{
0xa2, 0xca, 0x00, 0x0d, 0x00, 0x00, 0x04, 0xd2, 0x01, 0x06, 0x71, 0x77, 0x65, 0x72, 0x74, 0x79,
0x06, 0x06, 0x69, 0xc3, 0xb1, 0x61, 0x6b, 0x69,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x2e, 0x05, 0x11, 0x73, 0x6f, 0x6d, 0x65, 0x77, 0x68,
0x65, 0x72, 0x65, 0x20,
0xc5, 0x93, 0xc3, 0xa6,
0xe2, 0x82, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00 };
const uint32_t ssrc2{ 1234 };
const RTC::RTCP::SdesItem::Type item2Type{ RTC::RTCP::SdesItem::Type::CNAME };
const std::string item2Value{ "qwerty" };
const size_t item2Length{ 6u };
const RTC::RTCP::SdesItem::Type item3Type{ RTC::RTCP::SdesItem::Type::TOOL };
const std::string item3Value{ "iƱaki" };
const size_t item3Length{ 6u };
const uint32_t ssrc3{ 5678 };
const RTC::RTCP::SdesItem::Type item4Type{ RTC::RTCP::SdesItem::Type::LOC };
const std::string item4Value{ "somewhere ÅƦā¬" };
const size_t item4Length{ 17u };
alignas(4) uint8_t buffer3[] =
{
0x81, 0xca, 0x00, 0x03, 0x11, 0x22, 0x33, 0x44, 0x05, 0x02, 0x61, 0x62, 0x00, 0x00, 0x00, 0x00 };
const uint32_t ssrc4{ 0x11223344 };
const RTC::RTCP::SdesItem::Type item5Type{ RTC::RTCP::SdesItem::Type::LOC };
const std::string item5Value{ "ab" };
const size_t item5Length{ 2u };
SECTION("alignof() RTCP structs")
{
REQUIRE(alignof(RTC::RTCP::SdesItem::Header) == 1);
}
SECTION("parse packet 1")
{
std::unique_ptr<RTC::RTCP::SdesPacket> packet{ RTC::RTCP::SdesPacket::Parse(
buffer1, sizeof(buffer1)) };
auto* header = reinterpret_cast<RTC::RTCP::Packet::CommonHeader*>(buffer1);
REQUIRE(packet);
REQUIRE(ntohs(header->length) == 6);
REQUIRE(packet->GetSize() == 28);
REQUIRE(packet->GetCount() == 1);
size_t chunkIdx{ 0u };
for (auto it = packet->Begin(); it != packet->End(); ++it, ++chunkIdx)
{
auto* chunk = *it;
switch (chunkIdx)
{
case 0:
{
REQUIRE(chunk->GetSize() == 24);
REQUIRE(chunk->GetSsrc() == ssrc1);
size_t itemIdx{ 0u };
for (auto it2 = chunk->Begin(); it2 != chunk->End(); ++it2, ++itemIdx)
{
auto* item = *it2;
switch (itemIdx)
{
case 0:
{
REQUIRE(item->GetType() == item1Type);
REQUIRE(item->GetLength() == item1Length);
REQUIRE(std::string(item->GetValue(), item1Length) == item1Value);
break;
}
default:;
}
}
REQUIRE(itemIdx == 1);
break;
}
default:;
}
}
REQUIRE(chunkIdx == 1);
SECTION("serialize SdesChunk instance")
{
auto it = packet->Begin();
auto* chunk1 = *it;
const uint8_t* chunk1Buffer = buffer1 + RTC::RTCP::Packet::CommonHeaderSize;
alignas(4) uint8_t serialized1[24] = { 0 };
chunk1->Serialize(serialized1);
REQUIRE(std::memcmp(chunk1Buffer, serialized1, 24) == 0);
}
}
SECTION("parse packet 2")
{
std::unique_ptr<RTC::RTCP::SdesPacket> packet{ RTC::RTCP::SdesPacket::Parse(
buffer2, sizeof(buffer2)) };
auto* header = reinterpret_cast<RTC::RTCP::Packet::CommonHeader*>(buffer2);
REQUIRE(packet);
REQUIRE(ntohs(header->length) == 13);
REQUIRE(packet->GetSize() == 52);
REQUIRE(packet->GetCount() == 2);
size_t chunkIdx{ 0u };
for (auto it = packet->Begin(); it != packet->End(); ++it, ++chunkIdx)
{
auto* chunk = *it;
switch (chunkIdx)
{
case 0:
{
REQUIRE(chunk->GetSize() == 24);
REQUIRE(chunk->GetSsrc() == ssrc2);
size_t itemIdx{ 0u };
for (auto it2 = chunk->Begin(); it2 != chunk->End(); ++it2, ++itemIdx)
{
auto* item = *it2;
switch (itemIdx)
{
case 0:
{
REQUIRE(item->GetType() == item2Type);
REQUIRE(item->GetLength() == item2Length);
REQUIRE(std::string(item->GetValue(), item2Length) == item2Value);
break;
}
case 1:
{
REQUIRE(item->GetType() == item3Type);
REQUIRE(item->GetLength() == item3Length);
REQUIRE(std::string(item->GetValue(), item3Length) == item3Value);
break;
}
default:;
}
}
REQUIRE(itemIdx == 2);
break;
}
case 1:
{
REQUIRE(chunk->GetSize() == 24);
REQUIRE(chunk->GetSsrc() == ssrc3);
size_t itemIdx{ 0u };
for (auto it2 = chunk->Begin(); it2 != chunk->End(); ++it2, ++itemIdx)
{
auto* item = *it2;
switch (itemIdx)
{
case 0:
{
REQUIRE(item->GetType() == item4Type);
REQUIRE(item->GetLength() == item4Length);
REQUIRE(std::string(item->GetValue(), item4Length) == item4Value);
break;
}
default:;
}
}
REQUIRE(itemIdx == 1);
break;
}
default:;
}
}
REQUIRE(chunkIdx == 2);
SECTION("serialize SdesChunk instances")
{
auto it = packet->Begin();
auto* chunk1 = *it;
const uint8_t* chunk1Buffer = buffer2 + RTC::RTCP::Packet::CommonHeaderSize;
alignas(4) uint8_t serialized1[24] = { 0 };
chunk1->Serialize(serialized1);
REQUIRE(std::memcmp(chunk1Buffer, serialized1, 24) == 0);
auto* chunk2 = *(++it);
const uint8_t* chunk2Buffer = buffer2 + RTC::RTCP::Packet::CommonHeaderSize + 24;
alignas(4) uint8_t serialized2[24] = { 0 };
chunk2->Serialize(serialized2);
REQUIRE(std::memcmp(chunk2Buffer, serialized2, 24) == 0);
}
}
SECTION("parse packet 3")
{
std::unique_ptr<RTC::RTCP::SdesPacket> packet{ RTC::RTCP::SdesPacket::Parse(
buffer3, sizeof(buffer3)) };
auto* header = reinterpret_cast<RTC::RTCP::Packet::CommonHeader*>(buffer3);
REQUIRE(packet);
REQUIRE(ntohs(header->length) == 3);
REQUIRE(packet->GetSize() == 16);
REQUIRE(packet->GetCount() == 1);
size_t chunkIdx{ 0u };
for (auto it = packet->Begin(); it != packet->End(); ++it, ++chunkIdx)
{
auto* chunk = *it;
switch (chunkIdx)
{
case 0:
{
REQUIRE(chunk->GetSize() == 12);
REQUIRE(chunk->GetSsrc() == ssrc4);
size_t itemIdx{ 0u };
for (auto it2 = chunk->Begin(); it2 != chunk->End(); ++it2, ++itemIdx)
{
auto* item = *it2;
switch (itemIdx)
{
case 0:
{
REQUIRE(item->GetType() == item5Type);
REQUIRE(item->GetLength() == item5Length);
REQUIRE(std::string(item->GetValue(), item5Length) == item5Value);
break;
}
default:;
}
}
REQUIRE(itemIdx == 1);
break;
}
default:;
}
}
REQUIRE(chunkIdx == 1);
SECTION("serialize SdesChunk instance")
{
auto it = packet->Begin();
auto* chunk1 = *it;
const uint8_t* chunk1Buffer = buffer3 + RTC::RTCP::Packet::CommonHeaderSize;
alignas(4) uint8_t serialized1[12] = { 0 };
chunk1->Serialize(serialized1);
REQUIRE(std::memcmp(chunk1Buffer, serialized1, 12) == 0);
}
}
SECTION("parsing a packet with missing null octects fails")
{
alignas(4) uint8_t buffer[] =
{
0x81, 0xca, 0x00, 0x02, 0x11, 0x22, 0x33, 0x44, 0x08, 0x02, 0x61, 0x62 };
const auto* packet = RTC::RTCP::SdesPacket::Parse(buffer, sizeof(buffer));
REQUIRE(!packet);
}
SECTION("create SDES packet with 31 chunks")
{
const size_t count = 31;
RTC::RTCP::SdesPacket packet;
auto chunk = std::make_unique<RTC::RTCP::SdesChunk>(1234 );
auto* item1 =
new RTC::RTCP::SdesItem(RTC::RTCP::SdesItem::Type::CNAME, item1Value.size(), item1Value.c_str());
chunk->AddItem(item1);
auto chunkSize = chunk->GetSize();
for (size_t i{ 1 }; i <= count; ++i)
{
auto* chunk = new RTC::RTCP::SdesChunk(i );
auto* item1 =
new RTC::RTCP::SdesItem(RTC::RTCP::SdesItem::Type::CNAME, item1Value.size(), item1Value.c_str());
chunk->AddItem(item1);
packet.AddChunk(chunk);
}
REQUIRE(packet.GetCount() == count);
REQUIRE(packet.GetSize() == RTC::RTCP::Packet::CommonHeaderSize + (count * chunkSize));
alignas(4) uint8_t buffer1[1500] = { 0 };
packet.Serialize(buffer1);
std::unique_ptr<RTC::RTCP::SdesPacket> packet2{static_cast<RTC::RTCP::SdesPacket*>(RTC::RTCP::Packet::Parse(buffer1, sizeof(buffer1)))};
REQUIRE(packet2 != nullptr);
REQUIRE(packet2->GetCount() == count);
REQUIRE(packet2->GetSize() == RTC::RTCP::Packet::CommonHeaderSize + (count * chunkSize));
auto reportIt = packet2->Begin();
for (size_t i{ 1 }; i <= 31; ++i, ++reportIt)
{
auto* chunk = *reportIt;
REQUIRE(chunk->GetSsrc() == i);
auto* item = *(chunk->Begin());
REQUIRE(item->GetType() == RTC::RTCP::SdesItem::Type::CNAME);
REQUIRE(item->GetSize() == 2 + item1Value.size());
REQUIRE(std::string(item->GetValue()) == item1Value);
}
std::unique_ptr<RTC::RTCP::SdesPacket> packet3{static_cast<RTC::RTCP::SdesPacket*>(packet2->GetNext())};
REQUIRE(packet3 == nullptr);
}
SECTION("create SDES packet with more than 31 chunks")
{
const size_t count = 33;
RTC::RTCP::SdesPacket packet;
auto chunk = std::make_unique<RTC::RTCP::SdesChunk>(1234 );
auto* item1 =
new RTC::RTCP::SdesItem(RTC::RTCP::SdesItem::Type::CNAME, item1Value.size(), item1Value.c_str());
chunk->AddItem(item1);
auto chunkSize = chunk->GetSize();
for (size_t i{ 1 }; i <= count; ++i)
{
auto* chunk = new RTC::RTCP::SdesChunk(i );
auto* item1 =
new RTC::RTCP::SdesItem(RTC::RTCP::SdesItem::Type::CNAME, item1Value.size(), item1Value.c_str());
chunk->AddItem(item1);
packet.AddChunk(chunk);
}
REQUIRE(packet.GetCount() == count);
REQUIRE(packet.GetSize() == RTC::RTCP::Packet::CommonHeaderSize + (31 * chunkSize) + RTC::RTCP::Packet::CommonHeaderSize + ((count - 31) * chunkSize));
alignas(4) uint8_t buffer1[1500] = { 0 };
packet.Serialize(buffer1);
std::unique_ptr<RTC::RTCP::SdesPacket> packet2 {static_cast<RTC::RTCP::SdesPacket*>(RTC::RTCP::Packet::Parse(buffer1, sizeof(buffer1)))};
REQUIRE(packet2 != nullptr);
REQUIRE(packet2->GetCount() == 31);
REQUIRE(packet2->GetSize() == RTC::RTCP::Packet::CommonHeaderSize + (31 * chunkSize));
auto reportIt = packet2->Begin();
for (size_t i{ 1 }; i <= 31; ++i, ++reportIt)
{
auto* chunk = *reportIt;
REQUIRE(chunk->GetSsrc() == i);
auto* item = *(chunk->Begin());
REQUIRE(item->GetType() == RTC::RTCP::SdesItem::Type::CNAME);
REQUIRE(item->GetSize() == 2 + item1Value.size());
REQUIRE(std::string(item->GetValue()) == item1Value);
}
auto* packet3 = static_cast<RTC::RTCP::SdesPacket*>(packet2->GetNext());
REQUIRE(packet3 != nullptr);
REQUIRE(packet3->GetCount() == count - 31);
REQUIRE(packet3->GetSize() == RTC::RTCP::Packet::CommonHeaderSize + ((count - 31) * chunkSize));
reportIt = packet3->Begin();
for (size_t i{ 1 }; i <= 2; ++i, ++reportIt)
{
auto* chunk = *reportIt;
REQUIRE(chunk->GetSsrc() == 31 + i);
auto* item = *(chunk->Begin());
REQUIRE(item->GetType() == RTC::RTCP::SdesItem::Type::CNAME);
REQUIRE(item->GetSize() == 2 + item1Value.size());
REQUIRE(std::string(item->GetValue()) == item1Value);
}
delete packet3;
}
SECTION("create SdesChunk")
{
auto* item = new RTC::RTCP::SdesItem(item1Type, item1Length, item1Value.c_str());
RTC::RTCP::SdesChunk chunk(ssrc1);
chunk.AddItem(item);
REQUIRE(chunk.GetSsrc() == ssrc1);
const RTC::RTCP::SdesItem* item1 = *(chunk.Begin());
REQUIRE(item1->GetType() == item1Type);
REQUIRE(item1->GetLength() == item1Length);
REQUIRE(std::string(item1->GetValue(), item1Length) == item1Value);
}
}