// // Copyright (c) 2013-2025 The SRS Authors // // SPDX-License-Identifier: MIT // #include #include #include #include #include #include // 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 &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 ready_packets; // Process first packet SrsUniquePtr 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 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 ready_packets; // Process first packet 100 to initialize SrsUniquePtr 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 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 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 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 ready_packets; // Process packets 100, 101, 102 in order for (uint16_t seq = 100; seq <= 102; seq++) { SrsUniquePtr 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 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 ready_packets; // Process packets near the 16-bit boundary uint16_t seq_near_max = 65534; SrsUniquePtr 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 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 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 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 ready_packets; // Set a very short timeout for testing (1ms) cache.set_timeout(1 * SRS_UTIME_MILLISECONDS); // Process first packet to initialize SrsUniquePtr 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 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 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 ready_packets; // Process first packet to initialize SrsUniquePtr 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 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 ready_packets; // Process first packet to initialize SrsUniquePtr 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 pkt3(mock_create_audio_rtp_packet(103, 1060)); HELPER_EXPECT_SUCCESS(cache.process_packet(pkt3.get(), ready_packets)); SrsUniquePtr 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 ready_packets; // Process first packet SrsUniquePtr 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 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 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 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); } }