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) 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) r4 = errors.Errorf("low score=%v < %v, %v, %v", m.Format.ProbeScore, ts, m.String(), str)
} }
if dv := m.Duration(); dv < duration { 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> <a name="v7-changes"></a>
## SRS 7.0 Changelog ## 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-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-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) * 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_MAJOR 7
#define VERSION_MINOR 0 #define VERSION_MINOR 0
#define VERSION_REVISION 92 #define VERSION_REVISION 93
#endif #endif

View File

@ -1564,9 +1564,12 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_FilterCombinedSEIAndBFrameFiltering
bool found_pframe = false, found_idr = false, found_sps = false; bool found_pframe = false, found_idr = false, found_sps = false;
for (size_t i = 0; i < samples.size(); i++) { for (size_t i = 0; i < samples.size(); i++) {
uint8_t nalu_type = samples[i]->bytes_[0] & 0x1F; uint8_t nalu_type = samples[i]->bytes_[0] & 0x1F;
if (nalu_type == 0x01) found_pframe = true; // P-frame if (nalu_type == 0x01)
if (nalu_type == 0x05) found_idr = true; // IDR found_pframe = true; // P-frame
if (nalu_type == 0x07) found_sps = true; // SPS if (nalu_type == 0x05)
found_idr = true; // IDR
if (nalu_type == 0x07)
found_sps = true; // SPS
} }
EXPECT_TRUE(found_pframe); EXPECT_TRUE(found_pframe);
EXPECT_TRUE(found_idr); EXPECT_TRUE(found_idr);
@ -1811,8 +1814,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoMergeNalusMultipleSamples)
0x17, // keyframe + AVC codec 0x17, // keyframe + AVC codec
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20, 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, 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)]; char *h264_data = new char[sizeof(h264_seq_raw)];
memcpy(h264_data, h264_seq_raw, sizeof(h264_seq_raw)); memcpy(h264_data, h264_seq_raw, sizeof(h264_seq_raw));
@ -1885,8 +1887,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoLargeNaluPackageFuA)
0x17, // keyframe + AVC codec 0x17, // keyframe + AVC codec
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20, 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, 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)]; char *h264_data = new char[sizeof(h264_seq_raw)];
memcpy(h264_data, h264_seq_raw, 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 0x17, // keyframe + AVC codec
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20, 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, 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)]; char *h264_data = new char[sizeof(h264_seq_raw)];
memcpy(h264_data, h264_seq_raw, 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 0x17, // keyframe + AVC codec
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20, 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, 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)]; char *h264_data = new char[sizeof(h264_seq_raw)];
memcpy(h264_data, h264_seq_raw, sizeof(h264_seq_raw)); memcpy(h264_data, h264_seq_raw, sizeof(h264_seq_raw));
@ -2136,8 +2135,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoMultipleLargeNalusPackageFuA
0x17, // keyframe + AVC codec 0x17, // keyframe + AVC codec
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20, 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, 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)]; char *h264_data = new char[sizeof(h264_seq_raw)];
memcpy(h264_data, h264_seq_raw, 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 0x17, // keyframe + AVC codec
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20, 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, 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)]; char *h264_data = new char[sizeof(h264_seq_raw)];
memcpy(h264_data, h264_seq_raw, 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 // AVC header
large_data[pos++] = 0x17; // keyframe + AVC codec large_data[pos++] = 0x17; // keyframe + AVC codec
large_data[pos++] = 0x01; // AVC NALU 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 // First large NALU
large_data[pos++] = (first_nalu_size >> 24) & 0xFF; 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[0] = 0xAF; // AAC, 44kHz, 16-bit, stereo
frame_data[1] = 0x01; // AAC raw data (not sequence header) 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 // 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->wrap(frame_data, 5);
aac_frame->timestamp_ = 2000; aac_frame->timestamp_ = 2000;
@ -2379,7 +2380,9 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnAudioAddSampleFailure)
char *frame_data = new char[5]; char *frame_data = new char[5];
frame_data[0] = 0xAF; // AAC, 44kHz, 16-bit, stereo frame_data[0] = 0xAF; // AAC, 44kHz, 16-bit, stereo
frame_data[1] = 0x01; // AAC raw data 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->wrap(frame_data, 5);
aac_frame->timestamp_ = 2000; aac_frame->timestamp_ = 2000;
@ -2433,7 +2436,8 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnAudioTranscodeFailure)
frame_data[0] = 0xAF; // AAC, 44kHz, 16-bit, stereo frame_data[0] = 0xAF; // AAC, 44kHz, 16-bit, stereo
frame_data[1] = 0x01; // AAC raw data frame_data[1] = 0x01; // AAC raw data
// Add minimal AAC data - will likely cause transcoding to fail // 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->wrap(frame_data, 4);
aac_frame->timestamp_ = 2000; aac_frame->timestamp_ = 2000;
@ -2486,7 +2490,9 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnAudioMemoryCleanup)
char *frame_data = new char[5]; char *frame_data = new char[5];
frame_data[0] = 0xAF; // AAC, 44kHz, 16-bit, stereo frame_data[0] = 0xAF; // AAC, 44kHz, 16-bit, stereo
frame_data[1] = 0x01; // AAC raw data 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->wrap(frame_data, 5);
aac_frame->timestamp_ = 2000 + i * 1000; aac_frame->timestamp_ = 2000 + i * 1000;
@ -2531,8 +2537,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoComprehensiveCoverage)
0x17, // keyframe + AVC codec 0x17, // keyframe + AVC codec
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20, 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, 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)]; char *h264_data = new char[sizeof(h264_seq_raw)];
memcpy(h264_data, h264_seq_raw, sizeof(h264_seq_raw)); memcpy(h264_data, h264_seq_raw, sizeof(h264_seq_raw));
@ -2675,8 +2680,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoInitializeTrackError)
0x17, // keyframe + AVC codec 0x17, // keyframe + AVC codec
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20, 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, 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)]; char *h264_data = new char[sizeof(h264_seq_raw)];
memcpy(h264_data, h264_seq_raw, sizeof(h264_seq_raw)); memcpy(h264_data, h264_seq_raw, sizeof(h264_seq_raw));
@ -2739,8 +2743,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoFilterMethod)
0x17, // keyframe + AVC codec 0x17, // keyframe + AVC codec
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20, 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, 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)]; char *h264_data = new char[sizeof(h264_seq_raw)];
memcpy(h264_data, h264_seq_raw, sizeof(h264_seq_raw)); memcpy(h264_data, h264_seq_raw, sizeof(h264_seq_raw));
@ -2888,8 +2891,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoCodecSwitching)
0x17, // keyframe + AVC codec 0x17, // keyframe + AVC codec
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20, 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, 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)]; char *h264_data = new char[sizeof(h264_seq_raw)];
memcpy(h264_data, h264_seq_raw, sizeof(h264_seq_raw)); memcpy(h264_data, h264_seq_raw, sizeof(h264_seq_raw));
@ -2927,8 +2929,7 @@ VOID TEST(StreamBridgeTest, SrsRtcRtpBuilder_OnVideoCodecSwitching)
0x17, // keyframe + AVC codec 0x17, // keyframe + AVC codec
0x00, 0x00, 0x00, 0x00, 0x01, 0x64, 0x00, 0x20, 0xff, 0xe1, 0x00, 0x19, 0x67, 0x64, 0x00, 0x20, 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, 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)]; char *h264_data2 = new char[sizeof(h264_seq_raw2)];
memcpy(h264_data2, h264_seq_raw2, 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 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 // Test SrsRtcFrameBuilder::packet_video with complete frame detection and packet_video_rtmp error
VOID TEST(RtcFrameBuilderTest, PacketVideo_CompleteFrameDetectionWithPacketVideoRtmpError) VOID TEST(RtcFrameBuilderTest, PacketVideo_CompleteFrameDetectionWithPacketVideoRtmpError)
{ {

View File

@ -8,15 +8,15 @@
using namespace std; using namespace std;
#include <srs_app_rtc_codec.hpp>
#include <srs_app_rtc_source.hpp> #include <srs_app_rtc_source.hpp>
#include <srs_app_rtmp_source.hpp>
#include <srs_core_autofree.hpp> #include <srs_core_autofree.hpp>
#include <srs_kernel_error.hpp> #include <srs_kernel_error.hpp>
#include <srs_kernel_packet.hpp>
#include <srs_kernel_rtc_rtp.hpp> #include <srs_kernel_rtc_rtp.hpp>
#include <srs_protocol_format.hpp> #include <srs_protocol_format.hpp>
#include <srs_protocol_rtmp_stack.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() MockRtcFrameTarget::MockRtcFrameTarget()
{ {
@ -1789,8 +1789,6 @@ VOID TEST(RtcFrameBuilderTest, OnRtp_ComprehensiveCodePathCoverage)
HELPER_EXPECT_SUCCESS(builder.on_rtp(video_process.get())); 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 // Helper function to create a mock RTP packet with STAP-A payload containing SPS and PPS
SrsRtpPacket *create_stap_a_packet_with_sps_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; return pkt;
} }
// Test SrsRtcFrameBuilder::packet_sequence_header_avc with STAP-A payload containing SPS and PPS // Test SrsRtcFrameBuilder::packet_sequence_header_avc with STAP-A payload containing SPS and PPS
VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderAvc_STAPAPayload_WithSPSAndPPS) VOID TEST(RtcFrameBuilderTest, PacketSequenceHeaderAvc_STAPAPayload_WithSPSAndPPS)
{ {
@ -3354,23 +3348,28 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_OutOfOrderPackets)
// Send packets out of order: 100, 102, 101, 104, 103 // Send packets out of order: 100, 102, 101, 104, 103
SrsUniquePtr<SrsRtpPacket> pkt1(create_audio_packet(100, 48000, 1000)); SrsUniquePtr<SrsRtpPacket> pkt1(create_audio_packet(100, 48000, 1000));
srs_error_t result1 = builder.packet_audio(pkt1.get()); 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)); SrsUniquePtr<SrsRtpPacket> pkt3(create_audio_packet(102, 48000 + 2 * 960, 1040));
srs_error_t result3 = builder.packet_audio(pkt3.get()); 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)); SrsUniquePtr<SrsRtpPacket> pkt2(create_audio_packet(101, 48000 + 960, 1020));
srs_error_t result2 = builder.packet_audio(pkt2.get()); 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)); SrsUniquePtr<SrsRtpPacket> pkt5(create_audio_packet(104, 48000 + 4 * 960, 1080));
srs_error_t result5 = builder.packet_audio(pkt5.get()); 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)); SrsUniquePtr<SrsRtpPacket> pkt4(create_audio_packet(103, 48000 + 3 * 960, 1060));
srs_error_t result4 = builder.packet_audio(pkt4.get()); 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 // Audio cache should handle out-of-order packets and deliver them in sequence
} }
@ -3410,17 +3409,20 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_DuplicatePackets)
// Send original packet // Send original packet
SrsUniquePtr<SrsRtpPacket> pkt1(create_audio_packet(100, 48000, 1000)); SrsUniquePtr<SrsRtpPacket> pkt1(create_audio_packet(100, 48000, 1000));
srs_error_t result1 = builder.packet_audio(pkt1.get()); 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 // Send duplicate packet with same sequence number
SrsUniquePtr<SrsRtpPacket> pkt1_dup(create_audio_packet(100, 48000, 1000)); SrsUniquePtr<SrsRtpPacket> pkt1_dup(create_audio_packet(100, 48000, 1000));
srs_error_t result1_dup = builder.packet_audio(pkt1_dup.get()); 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 // Send next packet
SrsUniquePtr<SrsRtpPacket> pkt2(create_audio_packet(101, 48000 + 960, 1020)); SrsUniquePtr<SrsRtpPacket> pkt2(create_audio_packet(101, 48000 + 960, 1020));
srs_error_t result2 = builder.packet_audio(pkt2.get()); 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 // Audio cache should handle duplicate packets gracefully
} }
@ -3460,20 +3462,24 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_LatePackets)
// Send packets in order: 100, 101, 102 // Send packets in order: 100, 101, 102
SrsUniquePtr<SrsRtpPacket> pkt1(create_audio_packet(100, 48000, 1000)); SrsUniquePtr<SrsRtpPacket> pkt1(create_audio_packet(100, 48000, 1000));
srs_error_t result1 = builder.packet_audio(pkt1.get()); 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)); SrsUniquePtr<SrsRtpPacket> pkt2(create_audio_packet(101, 48000 + 960, 1020));
srs_error_t result2 = builder.packet_audio(pkt2.get()); 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)); SrsUniquePtr<SrsRtpPacket> pkt3(create_audio_packet(102, 48000 + 2 * 960, 1040));
srs_error_t result3 = builder.packet_audio(pkt3.get()); 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) // Now send a late packet with sequence number 99 (before already processed 100)
SrsUniquePtr<SrsRtpPacket> late_pkt(create_audio_packet(99, 48000 - 960, 980)); SrsUniquePtr<SrsRtpPacket> late_pkt(create_audio_packet(99, 48000 - 960, 980));
srs_error_t late_result = builder.packet_audio(late_pkt.get()); 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 // Audio cache should discard late packets gracefully
} }
@ -3684,19 +3690,23 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_SequenceWrapAround)
// Test sequence number wrap-around: 65534, 65535, 0, 1 // Test sequence number wrap-around: 65534, 65535, 0, 1
SrsUniquePtr<SrsRtpPacket> pkt1(create_audio_packet(65534, 48000, 1000)); SrsUniquePtr<SrsRtpPacket> pkt1(create_audio_packet(65534, 48000, 1000));
srs_error_t result1 = builder.packet_audio(pkt1.get()); 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)); SrsUniquePtr<SrsRtpPacket> pkt2(create_audio_packet(65535, 48000 + 960, 1020));
srs_error_t result2 = builder.packet_audio(pkt2.get()); 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)); SrsUniquePtr<SrsRtpPacket> pkt3(create_audio_packet(0, 48000 + 2 * 960, 1040));
srs_error_t result3 = builder.packet_audio(pkt3.get()); 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)); SrsUniquePtr<SrsRtpPacket> pkt4(create_audio_packet(1, 48000 + 3 * 960, 1060));
srs_error_t result4 = builder.packet_audio(pkt4.get()); 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 // Audio cache should handle sequence number wrap-around correctly
} }
@ -3736,19 +3746,23 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_TimestampWrapAround)
// Test timestamp wrap-around: near UINT32_MAX, then wrap to 0 // Test timestamp wrap-around: near UINT32_MAX, then wrap to 0
SrsUniquePtr<SrsRtpPacket> pkt1(create_audio_packet(100, UINT32_MAX - 960, 1000)); SrsUniquePtr<SrsRtpPacket> pkt1(create_audio_packet(100, UINT32_MAX - 960, 1000));
srs_error_t result1 = builder.packet_audio(pkt1.get()); 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)); SrsUniquePtr<SrsRtpPacket> pkt2(create_audio_packet(101, UINT32_MAX, 1020));
srs_error_t result2 = builder.packet_audio(pkt2.get()); 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)); SrsUniquePtr<SrsRtpPacket> pkt3(create_audio_packet(102, 0, 1040));
srs_error_t result3 = builder.packet_audio(pkt3.get()); 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)); SrsUniquePtr<SrsRtpPacket> pkt4(create_audio_packet(103, 960, 1060));
srs_error_t result4 = builder.packet_audio(pkt4.get()); 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 // Should handle timestamp wrap-around correctly
} }
@ -3788,15 +3802,18 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_DifferentSSRC)
// Send packets with different SSRC values // Send packets with different SSRC values
SrsUniquePtr<SrsRtpPacket> pkt1(create_audio_packet(100, 11111, 48000, 1000)); SrsUniquePtr<SrsRtpPacket> pkt1(create_audio_packet(100, 11111, 48000, 1000));
srs_error_t result1 = builder.packet_audio(pkt1.get()); 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)); SrsUniquePtr<SrsRtpPacket> pkt2(create_audio_packet(101, 22222, 48000 + 960, 1020));
srs_error_t result2 = builder.packet_audio(pkt2.get()); 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)); SrsUniquePtr<SrsRtpPacket> pkt3(create_audio_packet(102, 33333, 48000 + 2 * 960, 1040));
srs_error_t result3 = builder.packet_audio(pkt3.get()); 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 // Should handle packets with different SSRC values
} }
@ -3837,7 +3854,8 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_RapidSequence)
for (int i = 0; i < 50; ++i) { for (int i = 0; i < 50; ++i) {
SrsUniquePtr<SrsRtpPacket> pkt(create_audio_packet(100 + i, 48000 + i * 960, 1000 + i * 20)); SrsUniquePtr<SrsRtpPacket> pkt(create_audio_packet(100 + i, 48000 + i * 960, 1000 + i * 20));
srs_error_t result = builder.packet_audio(pkt.get()); 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) // All packets should be processed through audio cache (transcoding may fail)
@ -4675,7 +4693,8 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_MixedPayloadSizes)
for (int i = 0; i < 8; ++i) { for (int i = 0; i < 8; ++i) {
SrsUniquePtr<SrsRtpPacket> pkt(create_audio_packet(100 + i, 48000 + i * 960, 1000 + i * 20, payload_sizes[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()); 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 // Should handle packets with different payload sizes
@ -4717,36 +4736,43 @@ VOID TEST(RtcFrameBuilderTest, PacketAudio_ComprehensiveScenario)
// 1. Normal sequential packets // 1. Normal sequential packets
SrsUniquePtr<SrsRtpPacket> pkt1(create_audio_packet(100, 48000, 1000)); SrsUniquePtr<SrsRtpPacket> pkt1(create_audio_packet(100, 48000, 1000));
srs_error_t result1 = builder.packet_audio(pkt1.get()); 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)); SrsUniquePtr<SrsRtpPacket> pkt2(create_audio_packet(101, 48000 + 960, 1020));
srs_error_t result2 = builder.packet_audio(pkt2.get()); 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 // 2. Out-of-order packet
SrsUniquePtr<SrsRtpPacket> pkt4(create_audio_packet(103, 48000 + 3 * 960, 1060)); SrsUniquePtr<SrsRtpPacket> pkt4(create_audio_packet(103, 48000 + 3 * 960, 1060));
srs_error_t result4 = builder.packet_audio(pkt4.get()); 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 // 3. Fill the gap
SrsUniquePtr<SrsRtpPacket> pkt3(create_audio_packet(102, 48000 + 2 * 960, 1040)); SrsUniquePtr<SrsRtpPacket> pkt3(create_audio_packet(102, 48000 + 2 * 960, 1040));
srs_error_t result3 = builder.packet_audio(pkt3.get()); 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 // 4. Duplicate packet
SrsUniquePtr<SrsRtpPacket> pkt3_dup(create_audio_packet(102, 48000 + 2 * 960, 1040)); SrsUniquePtr<SrsRtpPacket> pkt3_dup(create_audio_packet(102, 48000 + 2 * 960, 1040));
srs_error_t result3_dup = builder.packet_audio(pkt3_dup.get()); 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) // 5. Late packet (should be discarded)
SrsUniquePtr<SrsRtpPacket> late_pkt(create_audio_packet(99, 48000 - 960, 980)); SrsUniquePtr<SrsRtpPacket> late_pkt(create_audio_packet(99, 48000 - 960, 980));
srs_error_t late_result = builder.packet_audio(late_pkt.get()); 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 // 6. Continue with normal sequence
SrsUniquePtr<SrsRtpPacket> pkt5(create_audio_packet(104, 48000 + 4 * 960, 1080)); SrsUniquePtr<SrsRtpPacket> pkt5(create_audio_packet(104, 48000 + 4 * 960, 1080));
srs_error_t result5 = builder.packet_audio(pkt5.get()); 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) // 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_utest.hpp>
#include <srs_app_rtc_codec.hpp>
#include <srs_app_rtc_source.hpp> #include <srs_app_rtc_source.hpp>
#include <srs_kernel_rtc_rtp.hpp> #include <srs_kernel_rtc_rtp.hpp>
#include <srs_protocol_amf0.hpp>
#include <srs_protocol_format.hpp> #include <srs_protocol_format.hpp>
#include <srs_protocol_rtmp_stack.hpp> #include <srs_protocol_rtmp_stack.hpp>
#include <srs_protocol_amf0.hpp>
#include <srs_app_rtc_codec.hpp>
// Forward declarations // Forward declarations
class SrsMediaPacket; class SrsMediaPacket;