blob: 41039d179c1b57e8461bc31e7e2e839aa9b5239a [file] [edit]
/*
* 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_packetizer_sframe.h"
#include <bitset>
#include <cstddef>
#include <cstdint>
#include <vector>
#include "api/media_types.h"
#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
#include "modules/rtp_rtcp/source/sframe_descriptor.h"
#include "test/gmock.h"
#include "test/gtest.h"
namespace webrtc {
namespace {
using ::testing::ElementsAreArray;
uint8_t MakeDescriptorByte(bool s, bool e, bool t) {
std::bitset<SframeDescriptor::kNumBits> bits;
bits.set(SframeDescriptor::kSBit, s);
bits.set(SframeDescriptor::kEBit, e);
bits.set(SframeDescriptor::kTBit, t);
return static_cast<uint8_t>(bits.to_ulong());
}
RtpPacketToSend MakeSendPacket(std::vector<uint8_t> payload) {
RtpPacketToSend packet(/*extensions=*/nullptr);
packet.SetSequenceNumber(0x4242);
packet.SetTimestamp(0xDEADBEEF);
packet.SetPayloadType(96);
packet.SetPayload(payload);
return packet;
}
TEST(PacketizeSframeRtpPacketOrErrorTest, PrependsDescriptorByteToPayload) {
const std::vector<uint8_t> payload = {0x01, 0x02, 0x03, 0x04, 0x05};
RtpPacketToSend packet = MakeSendPacket(payload);
packet.set_first_packet_of_frame(true);
packet.set_last_packet_of_frame(true);
ASSERT_TRUE(PacketizeSframeRtpPacketOrError(MediaType::VIDEO, &packet,
SframeEncryptionLevel::kFrame)
.ok());
std::vector<uint8_t> expected = payload;
expected.insert(expected.begin(),
MakeDescriptorByte(/*s=*/true, /*e=*/true, /*t=*/false));
EXPECT_THAT(packet.payload(), ElementsAreArray(expected));
}
TEST(PacketizeSframeRtpPacketOrErrorTest, EncodesTBitAsPacketEncryptionLevel) {
RtpPacketToSend packet = MakeSendPacket({0xAA});
packet.set_first_packet_of_frame(true);
packet.set_last_packet_of_frame(true);
ASSERT_TRUE(PacketizeSframeRtpPacketOrError(MediaType::VIDEO, &packet,
SframeEncryptionLevel::kPacket)
.ok());
EXPECT_EQ(packet.payload()[0],
MakeDescriptorByte(/*s=*/true, /*e=*/true, /*t=*/true));
}
TEST(PacketizeSframeRtpPacketOrErrorTest, AcceptsEmptyPayload) {
RtpPacketToSend packet = MakeSendPacket({});
packet.set_first_packet_of_frame(true);
packet.set_last_packet_of_frame(true);
ASSERT_TRUE(PacketizeSframeRtpPacketOrError(MediaType::VIDEO, &packet,
SframeEncryptionLevel::kFrame)
.ok());
EXPECT_THAT(packet.payload(),
ElementsAreArray(std::vector<uint8_t>{MakeDescriptorByte(
/*s=*/true, /*e=*/true, /*t=*/false)}));
}
TEST(PacketizeSframeRtpPacketOrErrorTest, PreservesRtpHeaderFields) {
RtpPacketToSend packet = MakeSendPacket({0xAB, 0xCD});
packet.set_first_packet_of_frame(true);
packet.set_last_packet_of_frame(false);
ASSERT_TRUE(PacketizeSframeRtpPacketOrError(MediaType::VIDEO, &packet,
SframeEncryptionLevel::kFrame)
.ok());
EXPECT_EQ(packet.SequenceNumber(), 0x4242);
EXPECT_EQ(packet.Timestamp(), 0xDEADBEEFu);
EXPECT_EQ(packet.PayloadType(), 96);
}
TEST(PacketizeSframeRtpPacketOrErrorTest, PreservesMarkerBit) {
for (bool marker : {false, true}) {
SCOPED_TRACE(marker);
RtpPacketToSend packet = MakeSendPacket({0xAA});
packet.SetMarker(marker);
packet.set_first_packet_of_frame(true);
packet.set_last_packet_of_frame(true);
ASSERT_TRUE(PacketizeSframeRtpPacketOrError(MediaType::VIDEO, &packet,
SframeEncryptionLevel::kFrame)
.ok());
EXPECT_EQ(packet.Marker(), marker);
}
}
TEST(PacketizeSframeRtpPacketOrErrorTest, PreservesSsrc) {
RtpPacketToSend packet = MakeSendPacket({0xAA});
packet.SetSsrc(0xCAFEBABE);
packet.set_first_packet_of_frame(true);
packet.set_last_packet_of_frame(true);
ASSERT_TRUE(PacketizeSframeRtpPacketOrError(MediaType::VIDEO, &packet,
SframeEncryptionLevel::kFrame)
.ok());
EXPECT_EQ(packet.Ssrc(), 0xCAFEBABEu);
}
TEST(PacketizeSframeRtpPacketOrErrorTest, ShrinksPaddingByOneWhenPresent) {
const std::vector<uint8_t> payload = {0xAB, 0xCD};
RtpPacketToSend packet = MakeSendPacket(payload);
ASSERT_TRUE(packet.SetPadding(4));
const size_t size_before = packet.size();
packet.set_first_packet_of_frame(true);
packet.set_last_packet_of_frame(true);
ASSERT_TRUE(PacketizeSframeRtpPacketOrError(MediaType::VIDEO, &packet,
SframeEncryptionLevel::kFrame)
.ok());
EXPECT_EQ(packet.padding_size(), 3u);
EXPECT_EQ(packet.size(), size_before);
std::vector<uint8_t> expected = payload;
expected.insert(expected.begin(),
MakeDescriptorByte(/*s=*/true, /*e=*/true, /*t=*/false));
EXPECT_THAT(packet.payload(), ElementsAreArray(expected));
}
TEST(PacketizeSframeRtpPacketOrErrorTest, ClearsPaddingWhenOnlyOneBytePresent) {
RtpPacketToSend packet = MakeSendPacket({0xAB});
ASSERT_TRUE(packet.SetPadding(1));
packet.set_first_packet_of_frame(true);
packet.set_last_packet_of_frame(true);
ASSERT_TRUE(PacketizeSframeRtpPacketOrError(MediaType::VIDEO, &packet,
SframeEncryptionLevel::kFrame)
.ok());
EXPECT_EQ(packet.padding_size(), 0u);
EXPECT_FALSE(packet.has_padding());
}
TEST(PacketizeSframeRtpPacketOrErrorTest, FailsWhenNoRoomForDescriptor) {
RtpPacketToSend packet(/*extensions=*/nullptr, /*capacity=*/12 + 1);
packet.SetSequenceNumber(1);
packet.SetTimestamp(2);
packet.SetPayloadType(96);
packet.SetPayload(std::vector<uint8_t>{0x01});
packet.set_first_packet_of_frame(true);
packet.set_last_packet_of_frame(true);
EXPECT_FALSE(PacketizeSframeRtpPacketOrError(MediaType::VIDEO, &packet,
SframeEncryptionLevel::kFrame)
.ok());
}
TEST(PacketizeSframeRtpPacketOrErrorTest,
SucceedsForPaddedPacketAtCapacityByShrinkingPadding) {
RtpPacketToSend packet(/*extensions=*/nullptr, /*capacity=*/12 + 2 + 4);
packet.SetSequenceNumber(1);
packet.SetTimestamp(2);
packet.SetPayloadType(96);
packet.SetPayload(std::vector<uint8_t>{0x01, 0x02});
ASSERT_TRUE(packet.SetPadding(4));
packet.set_first_packet_of_frame(true);
packet.set_last_packet_of_frame(true);
EXPECT_TRUE(PacketizeSframeRtpPacketOrError(MediaType::VIDEO, &packet,
SframeEncryptionLevel::kFrame)
.ok());
EXPECT_EQ(packet.padding_size(), 3u);
EXPECT_EQ(packet.size(), 12u + 2u + 4u);
}
TEST(PacketizeSframeRtpPacketOrErrorTest, AudioForcesStartAndEndBits) {
RtpPacketToSend packet = MakeSendPacket({0x55});
packet.set_first_packet_of_frame(false);
packet.set_last_packet_of_frame(false);
ASSERT_TRUE(PacketizeSframeRtpPacketOrError(MediaType::AUDIO, &packet,
SframeEncryptionLevel::kPacket)
.ok());
EXPECT_EQ(packet.payload()[0],
MakeDescriptorByte(/*s=*/true, /*e=*/true, /*t=*/true));
}
} // namespace
} // namespace webrtc