blob: 621f140cf256dfaf8621a0fc2e770e6c1e107e10 [file]
/*
* Copyright 2026 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_depacketizer_sframe.h"
#include <bitset>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <vector>
#include "modules/rtp_rtcp/source/rtp_packet_received.h"
#include "modules/rtp_rtcp/source/sframe_descriptor.h"
#include "modules/rtp_rtcp/source/sframe_rtp_packet_received.h"
#include "test/gmock.h"
#include "test/gtest.h"
namespace webrtc {
namespace {
using ::testing::ElementsAreArray;
// Compose a wire-format SFrame descriptor byte from S/E/T flags using the
// bit indices declared on `SframeDescriptor`.
uint8_t MakeDescriptorByte(bool s, bool e, bool t) {
std::bitset<8> bits;
bits.set(SframeDescriptor::kSBit, s);
bits.set(SframeDescriptor::kEBit, e);
bits.set(SframeDescriptor::kTBit, t);
return static_cast<uint8_t>(bits.to_ulong());
}
RtpPacketReceived MakeReceivedPacket(uint8_t descriptor,
std::vector<uint8_t> inner_payload) {
RtpPacketReceived packet;
packet.SetSequenceNumber(0x4242);
packet.SetTimestamp(0xDEADBEEF);
packet.SetPayloadType(96);
std::vector<uint8_t> payload;
payload.reserve(1 + inner_payload.size());
payload.push_back(descriptor);
payload.insert(payload.end(), inner_payload.begin(), inner_payload.end());
packet.SetPayload(payload);
return packet;
}
TEST(ParseSframeRtpPacketOrErrorTest, FailsOnEmptyPayload) {
RtpPacketReceived packet;
packet.SetSequenceNumber(1);
packet.SetTimestamp(2);
packet.SetPayloadType(96);
packet.SetPayload({});
EXPECT_FALSE(ParseSframeRtpPacketOrError(packet).ok());
}
TEST(ParseSframeRtpPacketOrErrorTest, ParsesTBitAsPacketEncryptionLevel) {
RtpPacketReceived packet = MakeReceivedPacket(
MakeDescriptorByte(/*s=*/true, /*e=*/true, /*t=*/true), {0xAA});
auto result = ParseSframeRtpPacketOrError(packet);
ASSERT_TRUE(result.ok());
auto parsed = result.MoveValue();
EXPECT_TRUE(parsed->descriptor().start);
EXPECT_TRUE(parsed->descriptor().end);
EXPECT_EQ(parsed->descriptor().encryption_level,
SframeEncryptionLevel::kPacket);
}
TEST(ParseSframeRtpPacketOrErrorTest, StripsDescriptorByteFromPayload) {
const std::vector<uint8_t> inner = {0x01, 0x02, 0x03, 0x04, 0x05};
RtpPacketReceived packet = MakeReceivedPacket(
MakeDescriptorByte(/*s=*/true, /*e=*/true, /*t=*/false), inner);
auto result = ParseSframeRtpPacketOrError(packet);
ASSERT_TRUE(result.ok());
auto parsed = result.MoveValue();
EXPECT_THAT(parsed->packet().payload(), ElementsAreArray(inner));
}
TEST(ParseSframeRtpPacketOrErrorTest, AcceptsDescriptorOnlyPayload) {
RtpPacketReceived packet = MakeReceivedPacket(
MakeDescriptorByte(/*s=*/true, /*e=*/true, /*t=*/false), {});
auto result = ParseSframeRtpPacketOrError(packet);
ASSERT_TRUE(result.ok());
auto parsed = result.MoveValue();
EXPECT_EQ(parsed->packet().payload().size(), 0u);
EXPECT_TRUE(parsed->descriptor().start);
EXPECT_TRUE(parsed->descriptor().end);
}
TEST(ParseSframeRtpPacketOrErrorTest, IgnoresReservedBits) {
// Set all five reserved low bits in addition to S=1, E=1, T=0.
const uint8_t descriptor =
MakeDescriptorByte(/*s=*/true, /*e=*/true, /*t=*/false) | 0x1F;
RtpPacketReceived packet = MakeReceivedPacket(descriptor, {0xFF});
auto result = ParseSframeRtpPacketOrError(packet);
ASSERT_TRUE(result.ok());
auto parsed = result.MoveValue();
EXPECT_TRUE(parsed->descriptor().start);
EXPECT_TRUE(parsed->descriptor().end);
EXPECT_EQ(parsed->descriptor().encryption_level,
SframeEncryptionLevel::kFrame);
}
TEST(ParseSframeRtpPacketOrErrorTest, PreservesRtpHeaderFields) {
RtpPacketReceived packet = MakeReceivedPacket(
MakeDescriptorByte(/*s=*/true, /*e=*/true, /*t=*/false), {0xAB, 0xCD});
auto result = ParseSframeRtpPacketOrError(packet);
ASSERT_TRUE(result.ok());
auto parsed = result.MoveValue();
EXPECT_EQ(parsed->SequenceNumber(), 0x4242);
EXPECT_EQ(parsed->Timestamp(), 0xDEADBEEFu);
EXPECT_EQ(parsed->PayloadType(), 96);
}
TEST(ParseSframeRtpPacketOrErrorTest, ParsesAllEightSETCombinations) {
// Exhaustively walk the 2^3 = 8 (S, E, T) descriptor combinations.
for (uint8_t bits = 0; bits < 8; ++bits) {
const bool expect_s = (bits & 0b100) != 0;
const bool expect_e = (bits & 0b010) != 0;
const bool expect_t = (bits & 0b001) != 0;
const uint8_t descriptor = MakeDescriptorByte(expect_s, expect_e, expect_t);
SCOPED_TRACE(static_cast<int>(descriptor));
RtpPacketReceived packet = MakeReceivedPacket(descriptor, {0x55});
auto result = ParseSframeRtpPacketOrError(packet);
ASSERT_TRUE(result.ok());
auto parsed = result.MoveValue();
EXPECT_EQ(parsed->descriptor().start, expect_s);
EXPECT_EQ(parsed->descriptor().end, expect_e);
EXPECT_EQ(parsed->descriptor().encryption_level,
expect_t ? SframeEncryptionLevel::kPacket
: SframeEncryptionLevel::kFrame);
}
}
TEST(ParseSframeRtpPacketOrErrorTest, PreservesLargePayloadBytes) {
std::vector<uint8_t> inner_payload(1000);
for (size_t i = 0; i < inner_payload.size(); ++i) {
inner_payload[i] = static_cast<uint8_t>((i * 17) & 0xFF);
}
RtpPacketReceived packet = MakeReceivedPacket(
MakeDescriptorByte(/*s=*/true, /*e=*/true, /*t=*/false), inner_payload);
auto result = ParseSframeRtpPacketOrError(packet);
ASSERT_TRUE(result.ok());
auto parsed = result.MoveValue();
EXPECT_THAT(parsed->packet().payload(), ElementsAreArray(inner_payload));
}
TEST(ParseSframeRtpPacketOrErrorTest, PreservesMarkerBit) {
for (bool marker : {false, true}) {
SCOPED_TRACE(marker);
RtpPacketReceived packet = MakeReceivedPacket(
MakeDescriptorByte(/*s=*/true, /*e=*/true, /*t=*/false), {0xAA});
packet.SetMarker(marker);
auto result = ParseSframeRtpPacketOrError(packet);
ASSERT_TRUE(result.ok());
auto parsed = result.MoveValue();
EXPECT_EQ(parsed->packet().Marker(), marker);
}
}
TEST(ParseSframeRtpPacketOrErrorTest, PreservesSsrc) {
RtpPacketReceived packet = MakeReceivedPacket(
MakeDescriptorByte(/*s=*/true, /*e=*/true, /*t=*/false), {0xAA});
packet.SetSsrc(0xCAFEBABE);
auto result = ParseSframeRtpPacketOrError(packet);
ASSERT_TRUE(result.ok());
auto parsed = result.MoveValue();
EXPECT_EQ(parsed->packet().Ssrc(), 0xCAFEBABEu);
}
TEST(ParseSframeRtpPacketOrErrorTest, PreservesPadding) {
// RTP packets with padding must not crash inside the depacketizer and the
// padding must round-trip through the rebuilt wire buffer.
RtpPacketReceived packet = MakeReceivedPacket(
MakeDescriptorByte(/*s=*/true, /*e=*/true, /*t=*/false), {0xAB, 0xCD});
ASSERT_TRUE(packet.SetPadding(4));
auto result = ParseSframeRtpPacketOrError(packet);
ASSERT_TRUE(result.ok());
auto parsed = result.MoveValue();
EXPECT_EQ(parsed->packet().padding_size(), 4u);
EXPECT_THAT(parsed->packet().payload(), ElementsAreArray({0xAB, 0xCD}));
}
TEST(ParseSframeRtpPacketOrErrorTest, ReturnedPacketIsIndependentCopy) {
// The returned object must own a copy independent of the source packet.
RtpPacketReceived packet = MakeReceivedPacket(
MakeDescriptorByte(/*s=*/true, /*e=*/true, /*t=*/false), {0x11, 0x22});
auto result = ParseSframeRtpPacketOrError(packet);
ASSERT_TRUE(result.ok());
auto parsed = result.MoveValue();
const uint16_t original_seq = parsed->packet().SequenceNumber();
const uint32_t original_ts = parsed->packet().Timestamp();
packet.SetSequenceNumber(0xFFFF);
packet.SetTimestamp(0xFFFFFFFF);
packet.SetPayload(std::vector<uint8_t>{0x00});
EXPECT_EQ(parsed->packet().SequenceNumber(), original_seq);
EXPECT_EQ(parsed->packet().Timestamp(), original_ts);
EXPECT_THAT(parsed->packet().payload(), ElementsAreArray({0x11, 0x22}));
}
} // namespace
} // namespace webrtc