srs/trunk/src/utest/srs_utest_ai04.cpp
2025-10-23 07:30:53 -04:00

332 lines
12 KiB
C++

//
// Copyright (c) 2013-2025 The SRS Authors
//
// SPDX-License-Identifier: MIT
//
#include <srs_utest_ai04.hpp>
#include <srs_app_rtc_source.hpp>
#include <srs_core_autofree.hpp>
#include <srs_kernel_rtc_rtp.hpp>
#include <srs_protocol_st.hpp>
#include <srs_utest_kernel.hpp>
// Helper function to create a mock RTP packet for testing
SrsRtpPacket *mock_create_audio_rtp_packet(uint16_t sequence, uint32_t timestamp, const char *payload_data = NULL, int payload_size = 10)
{
SrsRtpPacket *pkt = new SrsRtpPacket();
// Set RTP header
pkt->header_.set_padding(false);
pkt->header_.set_marker(false);
pkt->header_.set_payload_type(111); // Audio payload type
pkt->header_.set_sequence(sequence);
pkt->header_.set_timestamp(timestamp);
pkt->header_.set_ssrc(0x12345678);
// For audio cache testing, we don't need actual payload data or avsync time
// The cache is only concerned with sequence numbers and system time for jitter buffer logic
// We're not testing the downstream transcoding, just the cache reordering behavior
// Set frame type for audio
pkt->frame_type_ = SrsFrameTypeAudio;
return pkt;
}
// Helper function to free a vector of RTP packets
void free_audio_packets(std::vector<SrsRtpPacket *> &packets)
{
for (size_t i = 0; i < packets.size(); ++i) {
srs_freep(packets[i]);
}
packets.clear();
}
VOID TEST(RTC3AudioCacheTest, BasicPacketProcessing)
{
srs_error_t err;
// Test basic packet processing in order
if (true) {
SrsRtcFrameBuilderAudioPacketCache cache;
std::vector<SrsRtpPacket *> ready_packets;
// Process first packet
SrsUniquePtr<SrsRtpPacket> pkt1(mock_create_audio_rtp_packet(100, 1000));
HELPER_EXPECT_SUCCESS(cache.process_packet(pkt1.get(), ready_packets));
// First packet should be processed immediately
EXPECT_EQ(1, (int)ready_packets.size());
EXPECT_EQ(100, ready_packets[0]->header_.get_sequence());
free_audio_packets(ready_packets);
// Process second packet in sequence
SrsUniquePtr<SrsRtpPacket> pkt2(mock_create_audio_rtp_packet(101, 1020));
HELPER_EXPECT_SUCCESS(cache.process_packet(pkt2.get(), ready_packets));
// Second packet should be processed immediately
EXPECT_EQ(1, (int)ready_packets.size());
EXPECT_EQ(101, ready_packets[0]->header_.get_sequence());
free_audio_packets(ready_packets);
}
}
VOID TEST(RTC3AudioCacheTest, OutOfOrderPackets)
{
srs_error_t err;
// Test out-of-order packet handling
if (true) {
SrsRtcFrameBuilderAudioPacketCache cache;
std::vector<SrsRtpPacket *> ready_packets;
// Process first packet 100 to initialize
SrsUniquePtr<SrsRtpPacket> pkt1(mock_create_audio_rtp_packet(100, 1000));
HELPER_EXPECT_SUCCESS(cache.process_packet(pkt1.get(), ready_packets));
EXPECT_EQ(1, (int)ready_packets.size());
free_audio_packets(ready_packets);
// Process packet 103 (out of order - missing 101, 102)
SrsUniquePtr<SrsRtpPacket> pkt3(mock_create_audio_rtp_packet(103, 1060));
HELPER_EXPECT_SUCCESS(cache.process_packet(pkt3.get(), ready_packets));
// Should not process yet, waiting for missing packets
EXPECT_EQ(0, (int)ready_packets.size());
// Process packet 101 (fills gap)
SrsUniquePtr<SrsRtpPacket> pkt2(mock_create_audio_rtp_packet(101, 1020));
HELPER_EXPECT_SUCCESS(cache.process_packet(pkt2.get(), ready_packets));
// Should process packet 101 now
EXPECT_EQ(1, (int)ready_packets.size());
EXPECT_EQ(101, ready_packets[0]->header_.get_sequence());
free_audio_packets(ready_packets);
// Process packet 102 (completes sequence)
SrsUniquePtr<SrsRtpPacket> pkt4(mock_create_audio_rtp_packet(102, 1040));
HELPER_EXPECT_SUCCESS(cache.process_packet(pkt4.get(), ready_packets));
// Should process both 102 and 103
EXPECT_EQ(2, (int)ready_packets.size());
EXPECT_EQ(102, ready_packets[0]->header_.get_sequence());
EXPECT_EQ(103, ready_packets[1]->header_.get_sequence());
free_audio_packets(ready_packets);
}
}
VOID TEST(RTC3AudioCacheTest, LatePacketHandling)
{
srs_error_t err;
// Test late packet detection and discard
if (true) {
SrsRtcFrameBuilderAudioPacketCache cache;
std::vector<SrsRtpPacket *> ready_packets;
// Process packets 100, 101, 102 in order
for (uint16_t seq = 100; seq <= 102; seq++) {
SrsUniquePtr<SrsRtpPacket> pkt(mock_create_audio_rtp_packet(seq, 1000 + (seq - 100) * 20));
HELPER_EXPECT_SUCCESS(cache.process_packet(pkt.get(), ready_packets));
EXPECT_EQ(1, (int)ready_packets.size());
EXPECT_EQ(seq, ready_packets[0]->header_.get_sequence());
free_audio_packets(ready_packets);
}
// Try to process packet 99 (late packet - already processed)
SrsUniquePtr<SrsRtpPacket> late_pkt(mock_create_audio_rtp_packet(99, 980));
HELPER_EXPECT_SUCCESS(cache.process_packet(late_pkt.get(), ready_packets));
// Late packet should be discarded, no packets ready
EXPECT_EQ(0, (int)ready_packets.size());
}
}
VOID TEST(RTC3AudioCacheTest, SequenceNumberWrapAround)
{
srs_error_t err;
// Test sequence number wrap-around (16-bit overflow)
if (true) {
SrsRtcFrameBuilderAudioPacketCache cache;
std::vector<SrsRtpPacket *> ready_packets;
// Process packets near the 16-bit boundary
uint16_t seq_near_max = 65534;
SrsUniquePtr<SrsRtpPacket> pkt1(mock_create_audio_rtp_packet(seq_near_max, 1000));
HELPER_EXPECT_SUCCESS(cache.process_packet(pkt1.get(), ready_packets));
EXPECT_EQ(1, (int)ready_packets.size());
EXPECT_EQ(seq_near_max, ready_packets[0]->header_.get_sequence());
free_audio_packets(ready_packets);
// Process packet 65535
SrsUniquePtr<SrsRtpPacket> pkt2(mock_create_audio_rtp_packet(65535, 1020));
HELPER_EXPECT_SUCCESS(cache.process_packet(pkt2.get(), ready_packets));
EXPECT_EQ(1, (int)ready_packets.size());
EXPECT_EQ(65535, ready_packets[0]->header_.get_sequence());
free_audio_packets(ready_packets);
// Process packet 0 (after wrap-around)
SrsUniquePtr<SrsRtpPacket> pkt3(mock_create_audio_rtp_packet(0, 1040));
HELPER_EXPECT_SUCCESS(cache.process_packet(pkt3.get(), ready_packets));
EXPECT_EQ(1, (int)ready_packets.size());
EXPECT_EQ(0, ready_packets[0]->header_.get_sequence());
free_audio_packets(ready_packets);
// Process packet 1
SrsUniquePtr<SrsRtpPacket> pkt4(mock_create_audio_rtp_packet(1, 1060));
HELPER_EXPECT_SUCCESS(cache.process_packet(pkt4.get(), ready_packets));
EXPECT_EQ(1, (int)ready_packets.size());
EXPECT_EQ(1, ready_packets[0]->header_.get_sequence());
free_audio_packets(ready_packets);
}
}
VOID TEST(RTC3AudioCacheTest, PacketLossWithTimeout)
{
srs_error_t err;
// Test packet loss handling with timeout
if (true) {
SrsRtcFrameBuilderAudioPacketCache cache;
std::vector<SrsRtpPacket *> ready_packets;
// Set a very short timeout for testing (1ms)
cache.set_timeout(1 * SRS_UTIME_MILLISECONDS);
// Process first packet to initialize
SrsUniquePtr<SrsRtpPacket> pkt1(mock_create_audio_rtp_packet(100, 1000));
HELPER_EXPECT_SUCCESS(cache.process_packet(pkt1.get(), ready_packets));
EXPECT_EQ(1, (int)ready_packets.size());
free_audio_packets(ready_packets);
// Process packet 103 (missing 101, 102)
SrsUniquePtr<SrsRtpPacket> pkt3(mock_create_audio_rtp_packet(103, 1060));
HELPER_EXPECT_SUCCESS(cache.process_packet(pkt3.get(), ready_packets));
// Should not process yet, waiting for missing packets
EXPECT_EQ(0, (int)ready_packets.size());
bool found_103 = false;
for (int i = 0; i < 10 && !found_103; i++) {
// Sleep for N ms to exceed the 1ms timeout
srs_usleep(3 * SRS_UTIME_MILLISECONDS);
// Process another packet to trigger timeout check
SrsUniquePtr<SrsRtpPacket> pkt4(mock_create_audio_rtp_packet(104, 1080));
HELPER_EXPECT_SUCCESS(cache.process_packet(pkt4.get(), ready_packets));
// Should process packet 103 despite missing 101, 102 due to timeout
for (size_t i = 0; i < ready_packets.size(); i++) {
if (ready_packets[i]->header_.get_sequence() == 103) {
found_103 = true;
break;
}
}
}
EXPECT_TRUE(found_103);
free_audio_packets(ready_packets);
}
}
VOID TEST(RTC3AudioCacheTest, BufferOverflowProtection)
{
srs_error_t err;
// Test buffer overflow protection
if (true) {
SrsRtcFrameBuilderAudioPacketCache cache;
std::vector<SrsRtpPacket *> ready_packets;
// Process first packet to initialize
SrsUniquePtr<SrsRtpPacket> pkt1(mock_create_audio_rtp_packet(100, 1000));
HELPER_EXPECT_SUCCESS(cache.process_packet(pkt1.get(), ready_packets));
EXPECT_EQ(1, (int)ready_packets.size());
free_audio_packets(ready_packets);
// Fill buffer with out-of-order packets to trigger overflow protection
// Add packets with large gaps to fill the buffer
for (uint16_t i = 0; i < AUDIO_JITTER_BUFFER_SIZE + 10; i++) {
uint16_t seq = 200 + i * 2; // Create gaps to avoid immediate processing
SrsUniquePtr<SrsRtpPacket> pkt(mock_create_audio_rtp_packet(seq, 2000 + i * 20));
HELPER_EXPECT_SUCCESS(cache.process_packet(pkt.get(), ready_packets));
}
// Buffer overflow protection should have kicked in and processed some packets
EXPECT_GT((int)ready_packets.size(), 0);
free_audio_packets(ready_packets);
}
}
VOID TEST(RTC3AudioCacheTest, ClearAllFunctionality)
{
srs_error_t err;
// Test clear_all functionality
if (true) {
SrsRtcFrameBuilderAudioPacketCache cache;
std::vector<SrsRtpPacket *> ready_packets;
// Process first packet to initialize
SrsUniquePtr<SrsRtpPacket> pkt1(mock_create_audio_rtp_packet(100, 1000));
HELPER_EXPECT_SUCCESS(cache.process_packet(pkt1.get(), ready_packets));
free_audio_packets(ready_packets);
// Add some out-of-order packets to buffer
SrsUniquePtr<SrsRtpPacket> pkt3(mock_create_audio_rtp_packet(103, 1060));
HELPER_EXPECT_SUCCESS(cache.process_packet(pkt3.get(), ready_packets));
SrsUniquePtr<SrsRtpPacket> pkt5(mock_create_audio_rtp_packet(105, 1100));
HELPER_EXPECT_SUCCESS(cache.process_packet(pkt5.get(), ready_packets));
// Should have some packets waiting in buffer
EXPECT_EQ(0, (int)ready_packets.size());
// Clear all cached packets
cache.clear_all();
EXPECT_EQ(0, (int)cache.audio_buffer_.size());
}
}
VOID TEST(RTC3AudioCacheTest, DuplicatePacketHandling)
{
srs_error_t err;
// Test duplicate packet handling
if (true) {
SrsRtcFrameBuilderAudioPacketCache cache;
std::vector<SrsRtpPacket *> ready_packets;
// Process first packet
SrsUniquePtr<SrsRtpPacket> pkt1(mock_create_audio_rtp_packet(100, 1000));
HELPER_EXPECT_SUCCESS(cache.process_packet(pkt1.get(), ready_packets));
EXPECT_EQ(1, (int)ready_packets.size());
free_audio_packets(ready_packets);
// Process packet 102 (out of order)
SrsUniquePtr<SrsRtpPacket> pkt3(mock_create_audio_rtp_packet(102, 1040));
HELPER_EXPECT_SUCCESS(cache.process_packet(pkt3.get(), ready_packets));
EXPECT_EQ(0, (int)ready_packets.size()); // Waiting for 101
// Process duplicate packet 102
SrsUniquePtr<SrsRtpPacket> pkt3_dup(mock_create_audio_rtp_packet(102, 1040));
HELPER_EXPECT_SUCCESS(cache.process_packet(pkt3_dup.get(), ready_packets));
EXPECT_EQ(0, (int)ready_packets.size()); // Still waiting for 101
// Process packet 101 to complete sequence
SrsUniquePtr<SrsRtpPacket> pkt2(mock_create_audio_rtp_packet(101, 1020));
HELPER_EXPECT_SUCCESS(cache.process_packet(pkt2.get(), ready_packets));
// Should process 101 and one instance of 102 (duplicate should be handled)
EXPECT_GE((int)ready_packets.size(), 2);
EXPECT_EQ(101, ready_packets[0]->header_.get_sequence());
EXPECT_EQ(102, ready_packets[1]->header_.get_sequence());
free_audio_packets(ready_packets);
}
}