improve blackbox test for rtsp. v7.0.93 (#4505)

Co-authored-by: winlin <winlinvip@gmail.com>
This commit is contained in:
Haibo Chen(陈海博) 2025-09-22 11:36:49 +08:00 committed by GitHub
parent a1dd73545a
commit 2dfa54e21b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 489 additions and 169 deletions

View File

@ -109,7 +109,8 @@ func TestFast_RtmpPublish_RtspPlay_Basic(t *testing.T) {
r3 = errors.Errorf("invalid streams=%v, %v, %v", len(m.Streams), m.String(), str)
}
if ts := 90; m.Format.ProbeScore < ts {
// Note that RTSP score might be lower than RTMP, so we use a lower threshold
if ts := 80; m.Format.ProbeScore < ts {
r4 = errors.Errorf("low score=%v < %v, %v, %v", m.Format.ProbeScore, ts, m.String(), str)
}
if dv := m.Duration(); dv < duration {
@ -117,3 +118,296 @@ func TestFast_RtmpPublish_RtspPlay_Basic(t *testing.T) {
}
}
}
func TestFast_RtmpPublish_RtspPlay_MultipleClients(t *testing.T) {
// This case is run in parallel.
t.Parallel()
// Setup the max timeout for this case.
ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond)
defer cancel()
// Check a set of errors.
var r0, r1, r2, r3, r4, r5, r6, r7, r8, r9 error
defer func(ctx context.Context) {
if err := filterTestError(ctx.Err(), r0, r1, r2, r3, r4, r5, r6, r7, r8, r9); err != nil {
t.Errorf("Fail for err %+v", err)
} else {
logger.Tf(ctx, "test done with err %+v", err)
}
}(ctx)
var wg sync.WaitGroup
defer wg.Wait()
// Start SRS server and wait for it to be ready.
svr := NewSRSServer(func(v *srsServer) {
v.envs = []string{
"SRS_RTSP_SERVER_ENABLED=on",
"SRS_VHOST_RTSP_ENABLED=on",
"SRS_VHOST_RTSP_RTMP_TO_RTSP=on",
}
})
wg.Add(1)
go func() {
defer wg.Done()
r0 = svr.Run(ctx, cancel)
}()
// Start FFmpeg to publish stream.
streamID := fmt.Sprintf("stream-%v-%v", os.Getpid(), rand.Int())
streamURL := fmt.Sprintf("rtmp://localhost:%v/live/%v", svr.RTMPPort(), streamID)
ffmpeg := NewFFmpeg(func(v *ffmpegClient) {
v.args = []string{
"-stream_loop", "-1", "-re", "-i", *srsPublishAvatar, "-c", "copy", "-f", "flv", streamURL,
}
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r1 = ffmpeg.Run(ctx, cancel)
}()
// Start multiple FFprobe clients to test concurrent RTSP playback.
duration := time.Duration(*srsFFprobeDuration) * time.Millisecond
rtspURL := fmt.Sprintf("rtsp://localhost:%v/live/%v", svr.RTSPPort(), streamID)
// First RTSP client
ffprobe1 := NewFFprobe(func(v *ffprobeClient) {
v.dvrFile = path.Join(svr.WorkDir(), "objs", fmt.Sprintf("srs-ffprobe1-%v.mp4", streamID))
v.streamURL = rtspURL
v.duration, v.timeout = duration, time.Duration(*srsFFprobeTimeout)*time.Millisecond
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r2 = ffprobe1.Run(ctx, cancel)
}()
// Second RTSP client
ffprobe2 := NewFFprobe(func(v *ffprobeClient) {
v.dvrFile = path.Join(svr.WorkDir(), "objs", fmt.Sprintf("srs-ffprobe2-%v.mp4", streamID))
v.streamURL = rtspURL
v.duration, v.timeout = duration, time.Duration(*srsFFprobeTimeout)*time.Millisecond
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r3 = ffprobe2.Run(ctx, cancel)
}()
// Wait for both probes to complete and verify results.
var probe1Done, probe2Done bool
for !probe1Done || !probe2Done {
select {
case <-ctx.Done():
return
case <-ffprobe1.ProbeDoneCtx().Done():
if !probe1Done {
probe1Done = true
str, m := ffprobe1.Result()
if len(m.Streams) != 2 {
r4 = errors.Errorf("client1: invalid streams=%v, %v, %v", len(m.Streams), m.String(), str)
}
if ts := 80; m.Format.ProbeScore < ts {
r5 = errors.Errorf("client1: low score=%v < %v, %v, %v", m.Format.ProbeScore, ts, m.String(), str)
}
if dv := m.Duration(); dv < duration {
r6 = errors.Errorf("client1: short duration=%v < %v, %v, %v", dv, duration, m.String(), str)
}
}
case <-ffprobe2.ProbeDoneCtx().Done():
if !probe2Done {
probe2Done = true
str, m := ffprobe2.Result()
if len(m.Streams) != 2 {
r7 = errors.Errorf("client2: invalid streams=%v, %v, %v", len(m.Streams), m.String(), str)
}
if ts := 80; m.Format.ProbeScore < ts {
r8 = errors.Errorf("client2: low score=%v < %v, %v, %v", m.Format.ProbeScore, ts, m.String(), str)
}
if dv := m.Duration(); dv < duration {
r9 = errors.Errorf("client2: short duration=%v < %v, %v, %v", dv, duration, m.String(), str)
}
}
}
}
defer cancel()
}
func TestFast_RtmpPublish_RtspPlay_CustomPort(t *testing.T) {
// This case is run in parallel.
t.Parallel()
// Setup the max timeout for this case.
ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond)
defer cancel()
// Check a set of errors.
var r0, r1, r2, r3, r4, r5 error
defer func(ctx context.Context) {
if err := filterTestError(ctx.Err(), r0, r1, r2, r3, r4, r5); err != nil {
t.Errorf("Fail for err %+v", err)
} else {
logger.Tf(ctx, "test done with err %+v", err)
}
}(ctx)
var wg sync.WaitGroup
defer wg.Wait()
// Start SRS server with custom RTSP port.
customRTSPPort := 15540 + rand.Intn(1000)
svr := NewSRSServer(func(v *srsServer) {
v.envs = []string{
"SRS_RTSP_SERVER_ENABLED=on",
"SRS_VHOST_RTSP_ENABLED=on",
"SRS_VHOST_RTSP_RTMP_TO_RTSP=on",
fmt.Sprintf("SRS_RTSP_SERVER_LISTEN=%d", customRTSPPort),
}
})
wg.Add(1)
go func() {
defer wg.Done()
r0 = svr.Run(ctx, cancel)
}()
// Start FFmpeg to publish stream.
streamID := fmt.Sprintf("stream-%v-%v", os.Getpid(), rand.Int())
streamURL := fmt.Sprintf("rtmp://localhost:%v/live/%v", svr.RTMPPort(), streamID)
ffmpeg := NewFFmpeg(func(v *ffmpegClient) {
v.args = []string{
"-stream_loop", "-1", "-re", "-i", *srsPublishAvatar, "-c", "copy", "-f", "flv", streamURL,
}
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r1 = ffmpeg.Run(ctx, cancel)
}()
// Start FFprobe to detect and verify stream on custom port.
duration := time.Duration(*srsFFprobeDuration) * time.Millisecond
ffprobe := NewFFprobe(func(v *ffprobeClient) {
v.dvrFile = path.Join(svr.WorkDir(), "objs", fmt.Sprintf("srs-ffprobe-%v.mp4", streamID))
v.streamURL = fmt.Sprintf("rtsp://localhost:%v/live/%v", customRTSPPort, streamID)
v.duration, v.timeout = duration, time.Duration(*srsFFprobeTimeout)*time.Millisecond
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r2 = ffprobe.Run(ctx, cancel)
}()
// Fast quit for probe done.
select {
case <-ctx.Done():
case <-ffprobe.ProbeDoneCtx().Done():
defer cancel()
str, m := ffprobe.Result()
if len(m.Streams) != 2 {
r3 = errors.Errorf("invalid streams=%v, %v, %v", len(m.Streams), m.String(), str)
}
// Note that RTSP score might be lower than RTMP, so we use a lower threshold
if ts := 80; m.Format.ProbeScore < ts {
r4 = errors.Errorf("low score=%v < %v, %v, %v", m.Format.ProbeScore, ts, m.String(), str)
}
if dv := m.Duration(); dv < duration {
r5 = errors.Errorf("short duration=%v < %v, %v, %v", dv, duration, m.String(), str)
}
}
}
func TestFast_RtmpPublish_RtspPlay_AudioOnly(t *testing.T) {
// This case is run in parallel.
t.Parallel()
// Setup the max timeout for this case.
ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond)
defer cancel()
// Check a set of errors.
var r0, r1, r2, r3, r4, r5 error
defer func(ctx context.Context) {
if err := filterTestError(ctx.Err(), r0, r1, r2, r3, r4, r5); err != nil {
t.Errorf("Fail for err %+v", err)
} else {
logger.Tf(ctx, "test done with err %+v", err)
}
}(ctx)
var wg sync.WaitGroup
defer wg.Wait()
// Start SRS server and wait for it to be ready.
svr := NewSRSServer(func(v *srsServer) {
v.envs = []string{
"SRS_RTSP_SERVER_ENABLED=on",
"SRS_VHOST_RTSP_ENABLED=on",
"SRS_VHOST_RTSP_RTMP_TO_RTSP=on",
}
})
wg.Add(1)
go func() {
defer wg.Done()
r0 = svr.Run(ctx, cancel)
}()
// Start FFmpeg to publish audio-only stream.
streamID := fmt.Sprintf("stream-%v-%v", os.Getpid(), rand.Int())
streamURL := fmt.Sprintf("rtmp://localhost:%v/live/%v", svr.RTMPPort(), streamID)
ffmpeg := NewFFmpeg(func(v *ffmpegClient) {
v.args = []string{
"-stream_loop", "-1", "-re", "-i", *srsPublishAvatar, "-vn", "-c:a", "copy", "-f", "flv", streamURL,
}
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r1 = ffmpeg.Run(ctx, cancel)
}()
// Start FFprobe to detect and verify audio-only stream.
duration := time.Duration(*srsFFprobeDuration) * time.Millisecond
ffprobe := NewFFprobe(func(v *ffprobeClient) {
v.dvrFile = path.Join(svr.WorkDir(), "objs", fmt.Sprintf("srs-ffprobe-%v.mp4", streamID))
v.streamURL = fmt.Sprintf("rtsp://localhost:%v/live/%v", svr.RTSPPort(), streamID)
v.duration, v.timeout = duration, time.Duration(*srsFFprobeTimeout)*time.Millisecond
})
wg.Add(1)
go func() {
defer wg.Done()
<-svr.ReadyCtx().Done()
r2 = ffprobe.Run(ctx, cancel)
}()
// Fast quit for probe done.
select {
case <-ctx.Done():
case <-ffprobe.ProbeDoneCtx().Done():
defer cancel()
str, m := ffprobe.Result()
// Audio-only stream should have 1 stream
if len(m.Streams) != 1 {
r3 = errors.Errorf("invalid streams=%v, expected 1 for audio-only, %v, %v", len(m.Streams), m.String(), str)
}
// Check if it's audio stream
if len(m.Streams) > 0 && m.Streams[0].CodecType != "audio" {
r4 = errors.Errorf("expected audio stream, got %v, %v, %v", m.Streams[0].CodecType, m.String(), str)
}
if dv := m.Duration(); dv < duration {
r5 = errors.Errorf("short duration=%v < %v, %v, %v", dv, duration, m.String(), str)
}
}
}

View File

@ -7,6 +7,7 @@ The changelog for SRS.
<a name="v7-changes"></a>
## SRS 7.0 Changelog
* v7.0, 2025-09-21, Merge [#4505](https://github.com/ossrs/srs/pull/4505): improve blackbox test for rtsp. v7.0.93 (#4505)
* v7.0, 2025-09-21, Fix WHIP with transcoding bug. v7.0.92 (#4495)
* v7.0, 2025-09-20, Merge [#4504](https://github.com/ossrs/srs/pull/4504): fix rtsp compiling warning. v7.0.91 (#4504)
* v7.0, 2025-09-19, Merge [#4503](https://github.com/ossrs/srs/pull/4503): AI: Refine RTMP/SRT/RTC bridge. v7.0.90 (#4503)

View File

@ -9,6 +9,6 @@
#define VERSION_MAJOR 7
#define VERSION_MINOR 0
#define VERSION_REVISION 92
#define VERSION_REVISION 93
#endif

View File

@ -1287,13 +1287,13 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterSEIFiltering)
// Create SEI NALU sample
uint8_t sei_data[] = {0x06, 0x01, 0x02, 0x03}; // SEI NALU type (6)
SrsNaluSample sei_sample((char*)sei_data, sizeof(sei_data));
SrsNaluSample sei_sample((char *)sei_data, sizeof(sei_data));
format.video_->samples_[0] = sei_sample;
format.video_->nb_samples_ = 1;
SrsMediaPacket msg;
bool has_idr = false;
std::vector<SrsNaluSample*> samples;
std::vector<SrsNaluSample *> samples;
// When keep_avc_nalu_sei_ = true, SEI should be kept
HELPER_EXPECT_SUCCESS(builder.filter(&msg, &format, has_idr, samples));
@ -1309,7 +1309,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterSEIFiltering)
// Test 3: Non-SEI NALU with SEI filtering enabled
uint8_t idr_data[] = {0x05, 0x01, 0x02, 0x03}; // IDR NALU type (5)
SrsNaluSample idr_sample((char*)idr_data, sizeof(idr_data));
SrsNaluSample idr_sample((char *)idr_data, sizeof(idr_data));
format.video_->samples_[0] = idr_sample;
samples.clear();
@ -1319,9 +1319,9 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterSEIFiltering)
// Test 4: Mixed SEI and non-SEI NALUs
SrsNaluSample mixed_samples[3];
mixed_samples[0] = sei_sample; // SEI (should be filtered)
mixed_samples[1] = idr_sample; // IDR (should be kept)
mixed_samples[2] = sei_sample; // SEI (should be filtered)
mixed_samples[0] = sei_sample; // SEI (should be filtered)
mixed_samples[1] = idr_sample; // IDR (should be kept)
mixed_samples[2] = sei_sample; // SEI (should be filtered)
format.video_->samples_[0] = mixed_samples[0];
format.video_->samples_[1] = mixed_samples[1];
@ -1365,14 +1365,14 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterBFrameFilteringAVC)
SrsMediaPacket msg;
bool has_idr = false;
std::vector<SrsNaluSample*> samples;
std::vector<SrsNaluSample *> samples;
// Test 1: B-frame filtering disabled (keep_bframe_ = true)
builder.keep_bframe_ = true;
// Create B-frame NALU sample (NonIDR with B-frame slice type)
uint8_t bframe_data[] = {0x01, 0xA8, 0x00, 0x00}; // NonIDR NALU type (1), slice_type=1 (B)
SrsNaluSample bframe_sample((char*)bframe_data, sizeof(bframe_data));
SrsNaluSample bframe_sample((char *)bframe_data, sizeof(bframe_data));
format.video_->samples_[0] = bframe_sample;
format.video_->nb_samples_ = 1;
@ -1390,7 +1390,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterBFrameFilteringAVC)
// Test 3: Non-B-frame NALU with B-frame filtering enabled
uint8_t pframe_data[] = {0x01, 0x88, 0x00, 0x00}; // NonIDR NALU type (1), slice_type=0 (P)
SrsNaluSample pframe_sample((char*)pframe_data, sizeof(pframe_data));
SrsNaluSample pframe_sample((char *)pframe_data, sizeof(pframe_data));
format.video_->samples_[0] = pframe_sample;
samples.clear();
@ -1446,14 +1446,14 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterBFrameFilteringHEVC)
SrsMediaPacket msg;
bool has_idr = false;
std::vector<SrsNaluSample*> samples;
std::vector<SrsNaluSample *> samples;
// Test 1: B-frame filtering disabled (keep_bframe_ = true)
builder.keep_bframe_ = true;
// Create HEVC B-frame NALU sample
uint8_t hevc_bframe_data[] = {0x02, 0x01, 0xE0, 0x44}; // HEVC NALU with B-frame slice type
SrsNaluSample hevc_bframe_sample((char*)hevc_bframe_data, sizeof(hevc_bframe_data));
SrsNaluSample hevc_bframe_sample((char *)hevc_bframe_data, sizeof(hevc_bframe_data));
format.video_->samples_[0] = hevc_bframe_sample;
format.video_->nb_samples_ = 1;
@ -1471,7 +1471,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterBFrameFilteringHEVC)
// Test 3: Non-B-frame HEVC NALU with B-frame filtering enabled
uint8_t hevc_pframe_data[] = {0x02, 0x01, 0xD0, 0x30}; // HEVC NALU with P-frame slice type
SrsNaluSample hevc_pframe_sample((char*)hevc_pframe_data, sizeof(hevc_pframe_data));
SrsNaluSample hevc_pframe_sample((char *)hevc_pframe_data, sizeof(hevc_pframe_data));
format.video_->samples_[0] = hevc_pframe_sample;
samples.clear();
@ -1481,7 +1481,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterBFrameFilteringHEVC)
// Test 4: HEVC VPS/SPS/PPS NALUs (should not be filtered as B-frames)
uint8_t hevc_vps_data[] = {0x40, 0x01, 0xE0, 0x44}; // VPS NALU
SrsNaluSample hevc_vps_sample((char*)hevc_vps_data, sizeof(hevc_vps_data));
SrsNaluSample hevc_vps_sample((char *)hevc_vps_data, sizeof(hevc_vps_data));
format.video_->samples_[0] = hevc_vps_sample;
samples.clear();
@ -1522,33 +1522,33 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterCombinedSEIAndBFrameFiltering
SrsMediaPacket msg;
bool has_idr = false;
std::vector<SrsNaluSample*> samples;
std::vector<SrsNaluSample *> samples;
// Test complex scenario with multiple NALU types
SrsNaluSample test_samples[6];
// SEI NALU (should be filtered by SEI filter)
uint8_t sei_data[] = {0x06, 0x01, 0x02, 0x03};
test_samples[0] = SrsNaluSample((char*)sei_data, sizeof(sei_data));
test_samples[0] = SrsNaluSample((char *)sei_data, sizeof(sei_data));
// B-frame NALU (should be filtered by B-frame filter)
uint8_t bframe_data[] = {0x01, 0xA8, 0x00, 0x00};
test_samples[1] = SrsNaluSample((char*)bframe_data, sizeof(bframe_data));
test_samples[1] = SrsNaluSample((char *)bframe_data, sizeof(bframe_data));
// P-frame NALU (should be kept)
uint8_t pframe_data[] = {0x01, 0x88, 0x00, 0x00};
test_samples[2] = SrsNaluSample((char*)pframe_data, sizeof(pframe_data));
test_samples[2] = SrsNaluSample((char *)pframe_data, sizeof(pframe_data));
// IDR NALU (should be kept)
uint8_t idr_data[] = {0x05, 0x01, 0x02, 0x03};
test_samples[3] = SrsNaluSample((char*)idr_data, sizeof(idr_data));
test_samples[3] = SrsNaluSample((char *)idr_data, sizeof(idr_data));
// Another SEI NALU (should be filtered by SEI filter)
test_samples[4] = SrsNaluSample((char*)sei_data, sizeof(sei_data));
test_samples[4] = SrsNaluSample((char *)sei_data, sizeof(sei_data));
// SPS NALU (should be kept)
uint8_t sps_data[] = {0x07, 0x01, 0x02, 0x03};
test_samples[5] = SrsNaluSample((char*)sps_data, sizeof(sps_data));
test_samples[5] = SrsNaluSample((char *)sps_data, sizeof(sps_data));
// Set up format with all samples
for (int i = 0; i < 6; i++) {
@ -1564,9 +1564,12 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterCombinedSEIAndBFrameFiltering
bool found_pframe = false, found_idr = false, found_sps = false;
for (size_t i = 0; i < samples.size(); i++) {
uint8_t nalu_type = samples[i]->bytes_[0] & 0x1F;
if (nalu_type == 0x01) found_pframe = true; // P-frame
if (nalu_type == 0x05) found_idr = true; // IDR
if (nalu_type == 0x07) found_sps = true; // SPS
if (nalu_type == 0x01)
found_pframe = true; // P-frame
if (nalu_type == 0x05)
found_idr = true; // IDR
if (nalu_type == 0x07)
found_sps = true; // SPS
}
EXPECT_TRUE(found_pframe);
EXPECT_TRUE(found_idr);
@ -1606,12 +1609,12 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterIDRDetection)
SrsMediaPacket msg;
bool has_idr = false;
std::vector<SrsNaluSample*> samples;
std::vector<SrsNaluSample *> samples;
// Test 1: No IDR frame
format.video_->has_idr_ = false;
uint8_t pframe_data[] = {0x01, 0x88, 0x00, 0x00};
SrsNaluSample pframe_sample((char*)pframe_data, sizeof(pframe_data));
SrsNaluSample pframe_sample((char *)pframe_data, sizeof(pframe_data));
format.video_->samples_[0] = pframe_sample;
format.video_->nb_samples_ = 1;
@ -1660,7 +1663,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterErrorHandling)
SrsMediaPacket msg;
bool has_idr = false;
std::vector<SrsNaluSample*> samples;
std::vector<SrsNaluSample *> samples;
// Test with empty NALU sample (should cause parse error)
SrsNaluSample empty_sample(NULL, 0);
@ -1706,13 +1709,13 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterNonAVCCodecSkipsSEIFiltering)
// Create a sample that would be SEI in AVC (0x06), but should be kept for HEVC
uint8_t hevc_data[] = {0x06, 0x01, 0x02, 0x03};
SrsNaluSample hevc_sample((char*)hevc_data, sizeof(hevc_data));
SrsNaluSample hevc_sample((char *)hevc_data, sizeof(hevc_data));
hevc_format.video_->samples_[0] = hevc_sample;
hevc_format.video_->nb_samples_ = 1;
SrsMediaPacket msg;
bool has_idr = false;
std::vector<SrsNaluSample*> samples;
std::vector<SrsNaluSample *> samples;
// For HEVC, SEI filtering should be skipped, so sample should be kept
HELPER_EXPECT_SUCCESS(builder.filter(&msg, &hevc_format, has_idr, samples));
@ -1729,7 +1732,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterNonAVCCodecSkipsSEIFiltering)
unknown_format.video_ = new SrsParsedVideoPacket();
uint8_t unknown_data[] = {0x06, 0x01, 0x02, 0x03};
SrsNaluSample unknown_sample((char*)unknown_data, sizeof(unknown_data));
SrsNaluSample unknown_sample((char *)unknown_data, sizeof(unknown_data));
unknown_format.video_->samples_[0] = unknown_sample;
unknown_format.video_->nb_samples_ = 1;
@ -1775,7 +1778,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterZeroSamples)
SrsMediaPacket msg;
bool has_idr = false;
std::vector<SrsNaluSample*> samples;
std::vector<SrsNaluSample *> samples;
// Should handle zero samples gracefully
HELPER_EXPECT_SUCCESS(builder.filter(&msg, &format, has_idr, samples));
@ -1811,8 +1814,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoMergeNalusMultipleSamples)
0x17, // keyframe + AVC codec
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20,
0xac, 0xd9, 0x40, 0xc0, 0x29, 0xb0, 0x11, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00,
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c
};
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c};
char *h264_data = new char[sizeof(h264_seq_raw)];
memcpy(h264_data, h264_seq_raw, sizeof(h264_seq_raw));
@ -1831,10 +1833,10 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoMergeNalusMultipleSamples)
// Create H.264 frame with single NALU (known working pattern)
uint8_t h264_frame_raw[] = {
0x17, // keyframe + AVC codec
0x01, // AVC NALU (not sequence header)
0x00, 0x00, 0x00, // composition time
0x00, 0x00, 0x00, 0x05, // NALU length (5 bytes)
0x17, // keyframe + AVC codec
0x01, // AVC NALU (not sequence header)
0x00, 0x00, 0x00, // composition time
0x00, 0x00, 0x00, 0x05, // NALU length (5 bytes)
0x65, 0x88, 0x84, 0x00, (uint8_t)(0x10 + i) // IDR slice data (vary last byte)
};
@ -1885,8 +1887,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoLargeNaluPackageFuA)
0x17, // keyframe + AVC codec
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20,
0xac, 0xd9, 0x40, 0xc0, 0x29, 0xb0, 0x11, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00,
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c
};
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c};
char *h264_data = new char[sizeof(h264_seq_raw)];
memcpy(h264_data, h264_seq_raw, sizeof(h264_seq_raw));
@ -1971,8 +1972,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoExtremelyLargeNaluPackageFuA
0x17, // keyframe + AVC codec
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20,
0xac, 0xd9, 0x40, 0xc0, 0x29, 0xb0, 0x11, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00,
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c
};
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c};
char *h264_data = new char[sizeof(h264_seq_raw)];
memcpy(h264_data, h264_seq_raw, sizeof(h264_seq_raw));
@ -2052,8 +2052,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoMergeNalusWithMultipleNalus)
0x17, // keyframe + AVC codec
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20,
0xac, 0xd9, 0x40, 0xc0, 0x29, 0xb0, 0x11, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00,
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c
};
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c};
char *h264_data = new char[sizeof(h264_seq_raw)];
memcpy(h264_data, h264_seq_raw, sizeof(h264_seq_raw));
@ -2070,17 +2069,17 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoMergeNalusWithMultipleNalus)
// Create frame with multiple small NALUs - use minimal valid NALU structure
// Total frame: 5 (header) + 4+3 (first NALU) + 4+3 (second NALU) = 19 bytes
uint8_t h264_idr_raw[] = {
0x17, // keyframe + AVC codec
0x01, // AVC NALU (not sequence header)
0x17, // keyframe + AVC codec
0x01, // AVC NALU (not sequence header)
0x00, 0x00, 0x00, // composition time
// First NALU: 3 bytes of data
0x00, 0x00, 0x00, 0x03, // NALU length (3 bytes)
0x65, 0x88, 0x84, // Minimal IDR slice
0x65, 0x88, 0x84, // Minimal IDR slice
// Second NALU: 3 bytes of data
0x00, 0x00, 0x00, 0x03, // NALU length (3 bytes)
0x65, 0x88, 0x85 // Minimal IDR slice (slightly different)
0x65, 0x88, 0x85 // Minimal IDR slice (slightly different)
};
char *idr_data = new char[sizeof(h264_idr_raw)];
@ -2136,8 +2135,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoMultipleLargeNalusPackageFuA
0x17, // keyframe + AVC codec
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20,
0xac, 0xd9, 0x40, 0xc0, 0x29, 0xb0, 0x11, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00,
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c
};
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c};
char *h264_data = new char[sizeof(h264_seq_raw)];
memcpy(h264_data, h264_seq_raw, sizeof(h264_seq_raw));
@ -2217,8 +2215,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoMergeNalusLargePayload)
0x17, // keyframe + AVC codec
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20,
0xac, 0xd9, 0x40, 0xc0, 0x29, 0xb0, 0x11, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00,
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c
};
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c};
char *h264_data = new char[sizeof(h264_seq_raw)];
memcpy(h264_data, h264_seq_raw, sizeof(h264_seq_raw));
@ -2244,7 +2241,9 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoMergeNalusLargePayload)
// AVC header
large_data[pos++] = 0x17; // keyframe + AVC codec
large_data[pos++] = 0x01; // AVC NALU
large_data[pos++] = 0x00; large_data[pos++] = 0x00; large_data[pos++] = 0x00; // composition time
large_data[pos++] = 0x00;
large_data[pos++] = 0x00;
large_data[pos++] = 0x00; // composition time
// First large NALU
large_data[pos++] = (first_nalu_size >> 24) & 0xFF;
@ -2318,7 +2317,9 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnAudioRealAacFrames)
frame_data[0] = 0xAF; // AAC, 44kHz, 16-bit, stereo
frame_data[1] = 0x01; // AAC raw data (not sequence header)
// Add minimal AAC raw data - transcoding may fail but we'll reach the target lines
frame_data[2] = 0x21; frame_data[3] = 0x10; frame_data[4] = 0x05;
frame_data[2] = 0x21;
frame_data[3] = 0x10;
frame_data[4] = 0x05;
aac_frame->wrap(frame_data, 5);
aac_frame->timestamp_ = 2000;
@ -2379,7 +2380,9 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnAudioAddSampleFailure)
char *frame_data = new char[5];
frame_data[0] = 0xAF; // AAC, 44kHz, 16-bit, stereo
frame_data[1] = 0x01; // AAC raw data
frame_data[2] = 0x21; frame_data[3] = 0x10; frame_data[4] = 0x05;
frame_data[2] = 0x21;
frame_data[3] = 0x10;
frame_data[4] = 0x05;
aac_frame->wrap(frame_data, 5);
aac_frame->timestamp_ = 2000;
@ -2433,7 +2436,8 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnAudioTranscodeFailure)
frame_data[0] = 0xAF; // AAC, 44kHz, 16-bit, stereo
frame_data[1] = 0x01; // AAC raw data
// Add minimal AAC data - will likely cause transcoding to fail
frame_data[2] = 0x00; frame_data[3] = 0x00;
frame_data[2] = 0x00;
frame_data[3] = 0x00;
aac_frame->wrap(frame_data, 4);
aac_frame->timestamp_ = 2000;
@ -2486,7 +2490,9 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnAudioMemoryCleanup)
char *frame_data = new char[5];
frame_data[0] = 0xAF; // AAC, 44kHz, 16-bit, stereo
frame_data[1] = 0x01; // AAC raw data
frame_data[2] = 0x21 + i; frame_data[3] = 0x10; frame_data[4] = 0x05;
frame_data[2] = 0x21 + i;
frame_data[3] = 0x10;
frame_data[4] = 0x05;
aac_frame->wrap(frame_data, 5);
aac_frame->timestamp_ = 2000 + i * 1000;
@ -2531,8 +2537,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoComprehensiveCoverage)
0x17, // keyframe + AVC codec
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20,
0xac, 0xd9, 0x40, 0xc0, 0x29, 0xb0, 0x11, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00,
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c
};
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c};
char *h264_data = new char[sizeof(h264_seq_raw)];
memcpy(h264_data, h264_seq_raw, sizeof(h264_seq_raw));
@ -2548,10 +2553,10 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoComprehensiveCoverage)
h264_frame->message_type_ = SrsFrameTypeVideo;
uint8_t h264_frame_raw[] = {
0x17, // keyframe + AVC codec
0x01, // AVC NALU (not sequence header)
0x00, 0x00, 0x00, // composition time
0x00, 0x00, 0x00, 0x05, // NALU length
0x17, // keyframe + AVC codec
0x01, // AVC NALU (not sequence header)
0x00, 0x00, 0x00, // composition time
0x00, 0x00, 0x00, 0x05, // NALU length
0x65, 0x88, 0x84, 0x00, 0x10 // IDR slice data
};
@ -2592,9 +2597,9 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoUnsupportedCodec)
h263_frame->message_type_ = SrsFrameTypeVideo;
uint8_t h263_raw[] = {
0x22, // keyframe + H.263 codec (codec ID 2)
0x00, // packet type
0x00, 0x00, 0x00, // composition time
0x22, // keyframe + H.263 codec (codec ID 2)
0x00, // packet type
0x00, 0x00, 0x00, // composition time
0x01, 0x02, 0x03, 0x04, 0x05 // dummy H.263 data
};
@ -2633,7 +2638,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoNoVcodecParsed)
// Create invalid video data that format_->on_video() can process but won't set vcodec_
uint8_t invalid_raw[] = {
0x00, // invalid frame type and codec combination
0x00, // invalid frame type and codec combination
0x00, 0x00, 0x00, 0x00 // minimal data
};
@ -2675,8 +2680,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoInitializeTrackError)
0x17, // keyframe + AVC codec
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20,
0xac, 0xd9, 0x40, 0xc0, 0x29, 0xb0, 0x11, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00,
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c
};
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c};
char *h264_data = new char[sizeof(h264_seq_raw)];
memcpy(h264_data, h264_seq_raw, sizeof(h264_seq_raw));
@ -2696,10 +2700,10 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoInitializeTrackError)
h264_frame2->message_type_ = SrsFrameTypeVideo;
uint8_t h264_frame_raw[] = {
0x17, // keyframe + AVC codec
0x01, // AVC NALU (not sequence header)
0x00, 0x00, 0x00, // composition time
0x00, 0x00, 0x00, 0x05, // NALU length
0x17, // keyframe + AVC codec
0x01, // AVC NALU (not sequence header)
0x00, 0x00, 0x00, // composition time
0x00, 0x00, 0x00, 0x05, // NALU length
0x65, 0x88, 0x84, 0x00, 0x10 // IDR slice data
};
@ -2739,8 +2743,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoFilterMethod)
0x17, // keyframe + AVC codec
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20,
0xac, 0xd9, 0x40, 0xc0, 0x29, 0xb0, 0x11, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00,
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c
};
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c};
char *h264_data = new char[sizeof(h264_seq_raw)];
memcpy(h264_data, h264_seq_raw, sizeof(h264_seq_raw));
@ -2755,17 +2758,17 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoFilterMethod)
// Create IDR frame with multiple NALUs to test filter method thoroughly
uint8_t idr_raw[] = {
0x17, // keyframe + AVC codec
0x01, // AVC NALU (not sequence header)
0x17, // keyframe + AVC codec
0x01, // AVC NALU (not sequence header)
0x00, 0x00, 0x00, // composition time
// First NALU (SPS)
0x00, 0x00, 0x00, 0x08, // NALU length
0x00, 0x00, 0x00, 0x08, // NALU length
0x67, 0x64, 0x00, 0x20, 0xac, 0xd9, 0x40, 0xc0, // SPS data
// Second NALU (PPS)
0x00, 0x00, 0x00, 0x04, // NALU length
0x68, 0xeb, 0xec, 0xb2, // PPS data
// Third NALU (IDR slice)
0x00, 0x00, 0x00, 0x06, // NALU length
0x00, 0x00, 0x00, 0x06, // NALU length
0x65, 0x88, 0x84, 0x00, 0x10, 0x20 // IDR slice data
};
@ -2782,10 +2785,10 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoFilterMethod)
p_frame->message_type_ = SrsFrameTypeVideo;
uint8_t p_raw[] = {
0x27, // inter frame + AVC codec
0x01, // AVC NALU
0x00, 0x00, 0x00, // composition time
0x00, 0x00, 0x00, 0x05, // NALU length
0x27, // inter frame + AVC codec
0x01, // AVC NALU
0x00, 0x00, 0x00, // composition time
0x00, 0x00, 0x00, 0x05, // NALU length
0x41, 0x88, 0x84, 0x00, 0x10 // P slice data
};
@ -2843,8 +2846,8 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoFormatError)
// Create malformed data with valid codec ID but invalid structure
uint8_t malformed_raw[] = {
0x17, // keyframe + AVC codec
0x00, // sequence header indicator
0x17, // keyframe + AVC codec
0x00, // sequence header indicator
0xFF, 0xFF, 0xFF // invalid composition time and truncated data
};
@ -2888,8 +2891,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoCodecSwitching)
0x17, // keyframe + AVC codec
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20,
0xac, 0xd9, 0x40, 0xc0, 0x29, 0xb0, 0x11, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00,
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c
};
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c};
char *h264_data = new char[sizeof(h264_seq_raw)];
memcpy(h264_data, h264_seq_raw, sizeof(h264_seq_raw));
@ -2903,10 +2905,10 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoCodecSwitching)
h264_frame->message_type_ = SrsFrameTypeVideo;
uint8_t h264_frame_raw[] = {
0x17, // keyframe + AVC codec
0x01, // AVC NALU
0x00, 0x00, 0x00, // composition time
0x00, 0x00, 0x00, 0x05, // NALU length
0x17, // keyframe + AVC codec
0x01, // AVC NALU
0x00, 0x00, 0x00, // composition time
0x00, 0x00, 0x00, 0x05, // NALU length
0x65, 0x88, 0x84, 0x00, 0x10 // IDR slice data
};
@ -2927,8 +2929,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoCodecSwitching)
0x17, // keyframe + AVC codec
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20,
0xac, 0xd9, 0x40, 0xc0, 0x29, 0xb0, 0x11, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00,
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c
};
0x32, 0x0f, 0x18, 0x31, 0x96, 0x01, 0x00, 0x05, 0x68, 0xeb, 0xec, 0xb2, 0x2c};
char *h264_data2 = new char[sizeof(h264_seq_raw2)];
memcpy(h264_data2, h264_seq_raw2, sizeof(h264_seq_raw2));
@ -4256,8 +4257,6 @@ VOID TEST(RtcFrameBuilderTest, TranscodeAudio_ErrorInTranscoderLoop)
EXPECT_EQ(1, target.on_frame_count_); // Failed on first transcoded frame
}
// Test SrsRtcFrameBuilder::packet_video with complete frame detection and packet_video_rtmp error
VOID TEST(RtcFrameBuilderTest, PacketVideo_CompleteFrameDetectionWithPacketVideoRtmpError)
{

View File

@ -8,15 +8,15 @@
using namespace std;
#include <srs_app_rtc_codec.hpp>
#include <srs_app_rtc_source.hpp>
#include <srs_app_rtmp_source.hpp>
#include <srs_core_autofree.hpp>
#include <srs_kernel_error.hpp>
#include <srs_kernel_packet.hpp>
#include <srs_kernel_rtc_rtp.hpp>
#include <srs_protocol_format.hpp>
#include <srs_protocol_rtmp_stack.hpp>
#include <srs_app_rtmp_source.hpp>
#include <srs_app_rtc_codec.hpp>
#include <srs_kernel_packet.hpp>
MockRtcFrameTarget::MockRtcFrameTarget()
{
@ -33,13 +33,13 @@ MockRtcFrameTarget::~MockRtcFrameTarget()
srs_error_t MockRtcFrameTarget::on_frame(SrsMediaPacket *frame)
{
on_frame_count_++;
// Store a copy of the frame for verification
srs_freep(last_frame_);
if (frame) {
last_frame_ = frame->copy();
}
return srs_error_copy(frame_error_);
}
@ -360,21 +360,21 @@ SrsRtpPacket *create_hevc_stap_packet_with_vps_sps_pps()
VOID TEST(RtcFrameBuilderTest, OnRtp_NoPayload)
{
srs_error_t err;
MockRtcFrameTarget target;
SrsRtcFrameBuilder builder(&target);
// Initialize the builder
SrsUniquePtr<MockRtcRequest> req(new MockRtcRequest());
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
// Create RTP packet with no payload
SrsUniquePtr<SrsRtpPacket> pkt(new SrsRtpPacket());
pkt->set_avsync_time(1000);
// Should return success but do nothing
HELPER_EXPECT_SUCCESS(builder.on_rtp(pkt.get()));
// No frames should be generated
EXPECT_EQ(0, target.on_frame_count_);
}
@ -383,20 +383,20 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_NoPayload)
VOID TEST(RtcFrameBuilderTest, OnRtp_NoAvsyncTime_InitialState)
{
srs_error_t err;
MockRtcFrameTarget target;
SrsRtcFrameBuilder builder(&target);
// Initialize the builder
SrsUniquePtr<MockRtcRequest> req(new MockRtcRequest());
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
// Create RTP packet with no avsync_time (initial sync_state_ is -1)
SrsUniquePtr<SrsRtpPacket> pkt(create_mock_rtp_packet(true, 0)); // avsync_time = 0
// Should return success but discard packet and change sync_state_ from -1 to 0
HELPER_EXPECT_SUCCESS(builder.on_rtp(pkt.get()));
// No frames should be generated
EXPECT_EQ(0, target.on_frame_count_);
}
@ -405,22 +405,22 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_NoAvsyncTime_InitialState)
VOID TEST(RtcFrameBuilderTest, OnRtp_NoAvsyncTime_StateZero)
{
srs_error_t err;
MockRtcFrameTarget target;
SrsRtcFrameBuilder builder(&target);
// Initialize the builder
SrsUniquePtr<MockRtcRequest> req(new MockRtcRequest());
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
// First packet with no avsync_time to set sync_state_ to 0
SrsUniquePtr<SrsRtpPacket> pkt1(create_mock_rtp_packet(true, 0));
HELPER_EXPECT_SUCCESS(builder.on_rtp(pkt1.get()));
// Second packet with no avsync_time (sync_state_ is now 0, should not trace)
SrsUniquePtr<SrsRtpPacket> pkt2(create_mock_rtp_packet(false, -1)); // avsync_time = -1
HELPER_EXPECT_SUCCESS(builder.on_rtp(pkt2.get()));
// No frames should be generated
EXPECT_EQ(0, target.on_frame_count_);
}
@ -1789,8 +1789,6 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_ComprehensiveCodePathCoverage)
HELPER_EXPECT_SUCCESS(builder.on_rtp(video_process.get()));
}
// Helper function to create a mock RTP packet with STAP-A payload containing SPS and PPS
SrsRtpPacket *create_stap_a_packet_with_sps_pps()
{
@ -1844,10 +1842,6 @@ SrsRtpPacket *create_raw_payload_packet(SrsAvcNaluType nalu_type, const uint8_t
return pkt;
}
// Test SrsRtcFrameBuilder::packet_sequence_header_avc with STAP-A payload containing SPS and PPS
VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderAvc_STAPAPayload_WithSPSAndPPS)
{
@ -3332,7 +3326,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_OutOfOrderPackets)
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
// Helper function to create audio packet
auto create_audio_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket* {
auto create_audio_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket * {
SrsRtpPacket *pkt = new SrsRtpPacket();
pkt->header_.set_ssrc(12345);
pkt->header_.set_sequence(seq);
@ -3354,23 +3348,28 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_OutOfOrderPackets)
// Send packets out of order: 100, 102, 101, 104, 103
SrsUniquePtr<SrsRtpPacket> pkt1(create_audio_packet(100, 48000, 1000));
srs_error_t result1 = builder.packet_audio(pkt1.get());
if (result1 != srs_success) srs_freep(result1);
if (result1 != srs_success)
srs_freep(result1);
SrsUniquePtr<SrsRtpPacket> pkt3(create_audio_packet(102, 48000 + 2 * 960, 1040));
srs_error_t result3 = builder.packet_audio(pkt3.get());
if (result3 != srs_success) srs_freep(result3);
if (result3 != srs_success)
srs_freep(result3);
SrsUniquePtr<SrsRtpPacket> pkt2(create_audio_packet(101, 48000 + 960, 1020));
srs_error_t result2 = builder.packet_audio(pkt2.get());
if (result2 != srs_success) srs_freep(result2);
if (result2 != srs_success)
srs_freep(result2);
SrsUniquePtr<SrsRtpPacket> pkt5(create_audio_packet(104, 48000 + 4 * 960, 1080));
srs_error_t result5 = builder.packet_audio(pkt5.get());
if (result5 != srs_success) srs_freep(result5);
if (result5 != srs_success)
srs_freep(result5);
SrsUniquePtr<SrsRtpPacket> pkt4(create_audio_packet(103, 48000 + 3 * 960, 1060));
srs_error_t result4 = builder.packet_audio(pkt4.get());
if (result4 != srs_success) srs_freep(result4);
if (result4 != srs_success)
srs_freep(result4);
// Audio cache should handle out-of-order packets and deliver them in sequence
}
@ -3388,7 +3387,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_DuplicatePackets)
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
// Helper function to create audio packet
auto create_audio_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket* {
auto create_audio_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket * {
SrsRtpPacket *pkt = new SrsRtpPacket();
pkt->header_.set_ssrc(12345);
pkt->header_.set_sequence(seq);
@ -3410,17 +3409,20 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_DuplicatePackets)
// Send original packet
SrsUniquePtr<SrsRtpPacket> pkt1(create_audio_packet(100, 48000, 1000));
srs_error_t result1 = builder.packet_audio(pkt1.get());
if (result1 != srs_success) srs_freep(result1);
if (result1 != srs_success)
srs_freep(result1);
// Send duplicate packet with same sequence number
SrsUniquePtr<SrsRtpPacket> pkt1_dup(create_audio_packet(100, 48000, 1000));
srs_error_t result1_dup = builder.packet_audio(pkt1_dup.get());
if (result1_dup != srs_success) srs_freep(result1_dup);
if (result1_dup != srs_success)
srs_freep(result1_dup);
// Send next packet
SrsUniquePtr<SrsRtpPacket> pkt2(create_audio_packet(101, 48000 + 960, 1020));
srs_error_t result2 = builder.packet_audio(pkt2.get());
if (result2 != srs_success) srs_freep(result2);
if (result2 != srs_success)
srs_freep(result2);
// Audio cache should handle duplicate packets gracefully
}
@ -3438,7 +3440,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_LatePackets)
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
// Helper function to create audio packet
auto create_audio_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket* {
auto create_audio_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket * {
SrsRtpPacket *pkt = new SrsRtpPacket();
pkt->header_.set_ssrc(12345);
pkt->header_.set_sequence(seq);
@ -3460,20 +3462,24 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_LatePackets)
// Send packets in order: 100, 101, 102
SrsUniquePtr<SrsRtpPacket> pkt1(create_audio_packet(100, 48000, 1000));
srs_error_t result1 = builder.packet_audio(pkt1.get());
if (result1 != srs_success) srs_freep(result1);
if (result1 != srs_success)
srs_freep(result1);
SrsUniquePtr<SrsRtpPacket> pkt2(create_audio_packet(101, 48000 + 960, 1020));
srs_error_t result2 = builder.packet_audio(pkt2.get());
if (result2 != srs_success) srs_freep(result2);
if (result2 != srs_success)
srs_freep(result2);
SrsUniquePtr<SrsRtpPacket> pkt3(create_audio_packet(102, 48000 + 2 * 960, 1040));
srs_error_t result3 = builder.packet_audio(pkt3.get());
if (result3 != srs_success) srs_freep(result3);
if (result3 != srs_success)
srs_freep(result3);
// Now send a late packet with sequence number 99 (before already processed 100)
SrsUniquePtr<SrsRtpPacket> late_pkt(create_audio_packet(99, 48000 - 960, 980));
srs_error_t late_result = builder.packet_audio(late_pkt.get());
if (late_result != srs_success) srs_freep(late_result);
if (late_result != srs_success)
srs_freep(late_result);
// Audio cache should discard late packets gracefully
}
@ -3662,7 +3668,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_SequenceWrapAround)
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
// Helper function to create audio packet
auto create_audio_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket* {
auto create_audio_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket * {
SrsRtpPacket *pkt = new SrsRtpPacket();
pkt->header_.set_ssrc(12345);
pkt->header_.set_sequence(seq);
@ -3684,19 +3690,23 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_SequenceWrapAround)
// Test sequence number wrap-around: 65534, 65535, 0, 1
SrsUniquePtr<SrsRtpPacket> pkt1(create_audio_packet(65534, 48000, 1000));
srs_error_t result1 = builder.packet_audio(pkt1.get());
if (result1 != srs_success) srs_freep(result1);
if (result1 != srs_success)
srs_freep(result1);
SrsUniquePtr<SrsRtpPacket> pkt2(create_audio_packet(65535, 48000 + 960, 1020));
srs_error_t result2 = builder.packet_audio(pkt2.get());
if (result2 != srs_success) srs_freep(result2);
if (result2 != srs_success)
srs_freep(result2);
SrsUniquePtr<SrsRtpPacket> pkt3(create_audio_packet(0, 48000 + 2 * 960, 1040));
srs_error_t result3 = builder.packet_audio(pkt3.get());
if (result3 != srs_success) srs_freep(result3);
if (result3 != srs_success)
srs_freep(result3);
SrsUniquePtr<SrsRtpPacket> pkt4(create_audio_packet(1, 48000 + 3 * 960, 1060));
srs_error_t result4 = builder.packet_audio(pkt4.get());
if (result4 != srs_success) srs_freep(result4);
if (result4 != srs_success)
srs_freep(result4);
// Audio cache should handle sequence number wrap-around correctly
}
@ -3714,7 +3724,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_TimestampWrapAround)
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
// Helper function to create audio packet
auto create_audio_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket* {
auto create_audio_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket * {
SrsRtpPacket *pkt = new SrsRtpPacket();
pkt->header_.set_ssrc(12345);
pkt->header_.set_sequence(seq);
@ -3736,19 +3746,23 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_TimestampWrapAround)
// Test timestamp wrap-around: near UINT32_MAX, then wrap to 0
SrsUniquePtr<SrsRtpPacket> pkt1(create_audio_packet(100, UINT32_MAX - 960, 1000));
srs_error_t result1 = builder.packet_audio(pkt1.get());
if (result1 != srs_success) srs_freep(result1);
if (result1 != srs_success)
srs_freep(result1);
SrsUniquePtr<SrsRtpPacket> pkt2(create_audio_packet(101, UINT32_MAX, 1020));
srs_error_t result2 = builder.packet_audio(pkt2.get());
if (result2 != srs_success) srs_freep(result2);
if (result2 != srs_success)
srs_freep(result2);
SrsUniquePtr<SrsRtpPacket> pkt3(create_audio_packet(102, 0, 1040));
srs_error_t result3 = builder.packet_audio(pkt3.get());
if (result3 != srs_success) srs_freep(result3);
if (result3 != srs_success)
srs_freep(result3);
SrsUniquePtr<SrsRtpPacket> pkt4(create_audio_packet(103, 960, 1060));
srs_error_t result4 = builder.packet_audio(pkt4.get());
if (result4 != srs_success) srs_freep(result4);
if (result4 != srs_success)
srs_freep(result4);
// Should handle timestamp wrap-around correctly
}
@ -3766,7 +3780,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_DifferentSSRC)
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
// Helper function to create audio packet
auto create_audio_packet = [](uint16_t seq, uint32_t ssrc, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket* {
auto create_audio_packet = [](uint16_t seq, uint32_t ssrc, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket * {
SrsRtpPacket *pkt = new SrsRtpPacket();
pkt->header_.set_ssrc(ssrc);
pkt->header_.set_sequence(seq);
@ -3788,15 +3802,18 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_DifferentSSRC)
// Send packets with different SSRC values
SrsUniquePtr<SrsRtpPacket> pkt1(create_audio_packet(100, 11111, 48000, 1000));
srs_error_t result1 = builder.packet_audio(pkt1.get());
if (result1 != srs_success) srs_freep(result1);
if (result1 != srs_success)
srs_freep(result1);
SrsUniquePtr<SrsRtpPacket> pkt2(create_audio_packet(101, 22222, 48000 + 960, 1020));
srs_error_t result2 = builder.packet_audio(pkt2.get());
if (result2 != srs_success) srs_freep(result2);
if (result2 != srs_success)
srs_freep(result2);
SrsUniquePtr<SrsRtpPacket> pkt3(create_audio_packet(102, 33333, 48000 + 2 * 960, 1040));
srs_error_t result3 = builder.packet_audio(pkt3.get());
if (result3 != srs_success) srs_freep(result3);
if (result3 != srs_success)
srs_freep(result3);
// Should handle packets with different SSRC values
}
@ -3814,7 +3831,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_RapidSequence)
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
// Helper function to create audio packet
auto create_audio_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket* {
auto create_audio_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket * {
SrsRtpPacket *pkt = new SrsRtpPacket();
pkt->header_.set_ssrc(12345);
pkt->header_.set_sequence(seq);
@ -3837,7 +3854,8 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_RapidSequence)
for (int i = 0; i < 50; ++i) {
SrsUniquePtr<SrsRtpPacket> pkt(create_audio_packet(100 + i, 48000 + i * 960, 1000 + i * 20));
srs_error_t result = builder.packet_audio(pkt.get());
if (result != srs_success) srs_freep(result);
if (result != srs_success)
srs_freep(result);
}
// All packets should be processed through audio cache (transcoding may fail)
@ -4185,7 +4203,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_SequenceWrapAround)
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
// Helper function to create video packet
auto create_video_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket* {
auto create_video_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket * {
SrsRtpPacket *pkt = new SrsRtpPacket();
pkt->header_.set_ssrc(12345);
pkt->header_.set_sequence(seq);
@ -4234,7 +4252,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_TimestampWrapAround)
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
// Helper function to create video packet
auto create_video_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket* {
auto create_video_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket * {
SrsRtpPacket *pkt = new SrsRtpPacket();
pkt->header_.set_ssrc(12345);
pkt->header_.set_sequence(seq);
@ -4283,7 +4301,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_DifferentSSRC)
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
// Helper function to create video packet
auto create_video_packet = [](uint16_t seq, uint32_t ssrc, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket* {
auto create_video_packet = [](uint16_t seq, uint32_t ssrc, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket * {
SrsRtpPacket *pkt = new SrsRtpPacket();
pkt->header_.set_ssrc(ssrc);
pkt->header_.set_sequence(seq);
@ -4371,7 +4389,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_RapidSequence)
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
// Helper function to create video packet
auto create_video_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time, bool is_keyframe = false) -> SrsRtpPacket* {
auto create_video_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time, bool is_keyframe = false) -> SrsRtpPacket * {
SrsRtpPacket *pkt = new SrsRtpPacket();
pkt->header_.set_ssrc(12345);
pkt->header_.set_sequence(seq);
@ -4414,7 +4432,7 @@ VOID TEST(RtcFrameBuilderTest, PacketVideo_MixedKeyframeSequence)
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
// Helper function to create video packet
auto create_video_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time, SrsAvcNaluType nalu_type) -> SrsRtpPacket* {
auto create_video_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time, SrsAvcNaluType nalu_type) -> SrsRtpPacket * {
SrsRtpPacket *pkt = new SrsRtpPacket();
pkt->header_.set_ssrc(12345);
pkt->header_.set_sequence(seq);
@ -4653,7 +4671,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_MixedPayloadSizes)
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
// Helper function to create audio packet with specific payload size
auto create_audio_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time, int payload_size) -> SrsRtpPacket* {
auto create_audio_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time, int payload_size) -> SrsRtpPacket * {
SrsRtpPacket *pkt = new SrsRtpPacket();
pkt->header_.set_ssrc(12345);
pkt->header_.set_sequence(seq);
@ -4675,7 +4693,8 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_MixedPayloadSizes)
for (int i = 0; i < 8; ++i) {
SrsUniquePtr<SrsRtpPacket> pkt(create_audio_packet(100 + i, 48000 + i * 960, 1000 + i * 20, payload_sizes[i]));
srs_error_t result = builder.packet_audio(pkt.get());
if (result != srs_success) srs_freep(result);
if (result != srs_success)
srs_freep(result);
}
// Should handle packets with different payload sizes
@ -4694,7 +4713,7 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_ComprehensiveScenario)
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
// Helper function to create audio packet
auto create_audio_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket* {
auto create_audio_packet = [](uint16_t seq, uint32_t ts, uint32_t avsync_time) -> SrsRtpPacket * {
SrsRtpPacket *pkt = new SrsRtpPacket();
pkt->header_.set_ssrc(12345);
pkt->header_.set_sequence(seq);
@ -4717,36 +4736,43 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_ComprehensiveScenario)
// 1. Normal sequential packets
SrsUniquePtr<SrsRtpPacket> pkt1(create_audio_packet(100, 48000, 1000));
srs_error_t result1 = builder.packet_audio(pkt1.get());
if (result1 != srs_success) srs_freep(result1);
if (result1 != srs_success)
srs_freep(result1);
SrsUniquePtr<SrsRtpPacket> pkt2(create_audio_packet(101, 48000 + 960, 1020));
srs_error_t result2 = builder.packet_audio(pkt2.get());
if (result2 != srs_success) srs_freep(result2);
if (result2 != srs_success)
srs_freep(result2);
// 2. Out-of-order packet
SrsUniquePtr<SrsRtpPacket> pkt4(create_audio_packet(103, 48000 + 3 * 960, 1060));
srs_error_t result4 = builder.packet_audio(pkt4.get());
if (result4 != srs_success) srs_freep(result4);
if (result4 != srs_success)
srs_freep(result4);
// 3. Fill the gap
SrsUniquePtr<SrsRtpPacket> pkt3(create_audio_packet(102, 48000 + 2 * 960, 1040));
srs_error_t result3 = builder.packet_audio(pkt3.get());
if (result3 != srs_success) srs_freep(result3);
if (result3 != srs_success)
srs_freep(result3);
// 4. Duplicate packet
SrsUniquePtr<SrsRtpPacket> pkt3_dup(create_audio_packet(102, 48000 + 2 * 960, 1040));
srs_error_t result3_dup = builder.packet_audio(pkt3_dup.get());
if (result3_dup != srs_success) srs_freep(result3_dup);
if (result3_dup != srs_success)
srs_freep(result3_dup);
// 5. Late packet (should be discarded)
SrsUniquePtr<SrsRtpPacket> late_pkt(create_audio_packet(99, 48000 - 960, 980));
srs_error_t late_result = builder.packet_audio(late_pkt.get());
if (late_result != srs_success) srs_freep(late_result);
if (late_result != srs_success)
srs_freep(late_result);
// 6. Continue with normal sequence
SrsUniquePtr<SrsRtpPacket> pkt5(create_audio_packet(104, 48000 + 4 * 960, 1080));
srs_error_t result5 = builder.packet_audio(pkt5.get());
if (result5 != srs_success) srs_freep(result5);
if (result5 != srs_success)
srs_freep(result5);
// All scenarios should be handled correctly by the audio cache (transcoding may fail)
}

View File

@ -12,12 +12,12 @@
*/
#include <srs_utest.hpp>
#include <srs_app_rtc_codec.hpp>
#include <srs_app_rtc_source.hpp>
#include <srs_kernel_rtc_rtp.hpp>
#include <srs_protocol_amf0.hpp>
#include <srs_protocol_format.hpp>
#include <srs_protocol_rtmp_stack.hpp>
#include <srs_protocol_amf0.hpp>
#include <srs_app_rtc_codec.hpp>
// Forward declarations
class SrsMediaPacket;