Refine utest by AI.

This commit is contained in:
OSSRS-AI 2025-10-27 11:42:25 -04:00 committed by winlin
parent 19ac413101
commit ace8bea84f
9 changed files with 149 additions and 125 deletions

View File

@ -372,6 +372,7 @@ SrsRtcBridge::~SrsRtcBridge()
srs_freep(frame_builder_);
#endif
rtmp_target_ = NULL;
initialized_ = false;
}
void SrsRtcBridge::enable_rtc2rtmp(SrsSharedPtr<SrsLiveSource> rtmp_target)
@ -388,6 +389,11 @@ srs_error_t SrsRtcBridge::initialize(ISrsRequest *r)
{
srs_error_t err = srs_success;
if (initialized_) {
return err;
}
initialized_ = true;
srs_freep(req_);
req_ = r->copy();

View File

@ -195,6 +195,8 @@ SRS_DECLARE_PRIVATE: // clang-format on
#endif
// The Source bridge, bridge stream to other source.
SrsSharedPtr<SrsLiveSource> rtmp_target_;
// To avoid initialize multiple times, we use this flag.
bool initialized_;
public:
SrsRtcBridge();

View File

@ -3833,7 +3833,7 @@ VOID TEST(RtcFrameBuilderTest, TranscodeAudio_Success)
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
// Replace the audio transcoder with our mock
MockAudioTranscoder *mock_transcoder = new MockAudioTranscoder();
MockAudioTranscoderForUtest *mock_transcoder = new MockAudioTranscoderForUtest();
mock_transcoder->set_output_packets(2); // Mock transcoder will output 2 packets
// Access private member through friendship (utests have access to private members)
@ -3880,7 +3880,7 @@ VOID TEST(RtcFrameBuilderTest, TranscodeAudio_TranscoderError)
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
// Replace the audio transcoder with our mock
MockAudioTranscoder *mock_transcoder = new MockAudioTranscoder();
MockAudioTranscoderForUtest *mock_transcoder = new MockAudioTranscoderForUtest();
srs_error_t mock_error = srs_error_new(ERROR_RTC_RTP_MUXER, "mock transcoder error");
mock_transcoder->set_transcode_error(mock_error);
@ -3925,7 +3925,7 @@ VOID TEST(RtcFrameBuilderTest, TranscodeAudio_FrameTargetError)
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
// Replace the audio transcoder with our mock
MockAudioTranscoder *mock_transcoder = new MockAudioTranscoder();
MockAudioTranscoderForUtest *mock_transcoder = new MockAudioTranscoderForUtest();
mock_transcoder->set_output_packets(1); // Mock transcoder will output 1 packet
builder.audio_transcoder_ = mock_transcoder;
@ -3972,7 +3972,7 @@ VOID TEST(RtcFrameBuilderTest, TranscodeAudio_MultipleOutputPackets)
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
// Replace the audio transcoder with our mock
MockAudioTranscoder *mock_transcoder = new MockAudioTranscoder();
MockAudioTranscoderForUtest *mock_transcoder = new MockAudioTranscoderForUtest();
mock_transcoder->set_output_packets(5); // Mock transcoder will output 5 packets
builder.audio_transcoder_ = mock_transcoder;
@ -4018,7 +4018,7 @@ VOID TEST(RtcFrameBuilderTest, TranscodeAudio_NoOutputPackets)
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
// Replace the audio transcoder with our mock
MockAudioTranscoder *mock_transcoder = new MockAudioTranscoder();
MockAudioTranscoderForUtest *mock_transcoder = new MockAudioTranscoderForUtest();
mock_transcoder->set_output_packets(0); // Mock transcoder will output 0 packets
builder.audio_transcoder_ = mock_transcoder;
@ -4062,7 +4062,7 @@ VOID TEST(RtcFrameBuilderTest, TranscodeAudio_FrameTargetErrorOnTranscodedFrame)
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
// Replace the audio transcoder with our mock
MockAudioTranscoder *mock_transcoder = new MockAudioTranscoder();
MockAudioTranscoderForUtest *mock_transcoder = new MockAudioTranscoderForUtest();
mock_transcoder->set_output_packets(3); // Mock transcoder will output 3 packets
builder.audio_transcoder_ = mock_transcoder;
@ -4133,7 +4133,7 @@ VOID TEST(RtcFrameBuilderTest, TranscodeAudio_SpecificCodePath)
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
// Replace the audio transcoder with our mock
MockAudioTranscoder *mock_transcoder = new MockAudioTranscoder();
MockAudioTranscoderForUtest *mock_transcoder = new MockAudioTranscoderForUtest();
// Set up mock transcoder to output packets with specific timestamps and sample data
const char sample_data[] = {0x21, 0x10, 0x04, 0x60, (char)0x8C}; // Mock AAC data
@ -4194,7 +4194,7 @@ VOID TEST(RtcFrameBuilderTest, TranscodeAudio_ErrorInTranscoderLoop)
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdAAC, SrsVideoCodecIdAVC));
// Replace the audio transcoder with our mock
MockAudioTranscoder *mock_transcoder = new MockAudioTranscoder();
MockAudioTranscoderForUtest *mock_transcoder = new MockAudioTranscoderForUtest();
mock_transcoder->set_output_packets(3); // Mock transcoder will output 3 packets
builder.audio_transcoder_ = mock_transcoder;

View File

@ -50,7 +50,7 @@ void MockRtcFrameTarget::reset()
srs_freep(frame_error_);
}
MockAudioTranscoder::MockAudioTranscoder()
MockAudioTranscoderForUtest::MockAudioTranscoderForUtest()
{
transcode_error_ = srs_success;
should_output_packets_ = false;
@ -58,13 +58,13 @@ MockAudioTranscoder::MockAudioTranscoder()
aac_header_len_ = 0;
}
MockAudioTranscoder::~MockAudioTranscoder()
MockAudioTranscoderForUtest::~MockAudioTranscoderForUtest()
{
reset();
srs_freepa(aac_header_data_);
}
srs_error_t MockAudioTranscoder::initialize(SrsAudioCodecId from, SrsAudioCodecId to, int channels, int sample_rate, int bit_rate)
srs_error_t MockAudioTranscoderForUtest::initialize(SrsAudioCodecId from, SrsAudioCodecId to, int channels, int sample_rate, int bit_rate)
{
// Create default AAC header for testing
if (!aac_header_data_) {
@ -76,7 +76,7 @@ srs_error_t MockAudioTranscoder::initialize(SrsAudioCodecId from, SrsAudioCodecI
return srs_success;
}
srs_error_t MockAudioTranscoder::transcode(SrsParsedAudioPacket *in, std::vector<SrsParsedAudioPacket *> &outs)
srs_error_t MockAudioTranscoderForUtest::transcode(SrsParsedAudioPacket *in, std::vector<SrsParsedAudioPacket *> &outs)
{
if (transcode_error_ != srs_success) {
return srs_error_copy(transcode_error_);
@ -105,7 +105,7 @@ srs_error_t MockAudioTranscoder::transcode(SrsParsedAudioPacket *in, std::vector
return srs_success;
}
void MockAudioTranscoder::free_frames(std::vector<SrsParsedAudioPacket *> &frames)
void MockAudioTranscoderForUtest::free_frames(std::vector<SrsParsedAudioPacket *> &frames)
{
for (std::vector<SrsParsedAudioPacket *>::iterator it = frames.begin(); it != frames.end(); ++it) {
SrsParsedAudioPacket *p = *it;
@ -119,13 +119,13 @@ void MockAudioTranscoder::free_frames(std::vector<SrsParsedAudioPacket *> &frame
}
}
void MockAudioTranscoder::aac_codec_header(uint8_t **data, int *len)
void MockAudioTranscoderForUtest::aac_codec_header(uint8_t **data, int *len)
{
*data = aac_header_data_;
*len = aac_header_len_;
}
void MockAudioTranscoder::reset()
void MockAudioTranscoderForUtest::reset()
{
srs_freep(transcode_error_);
@ -141,7 +141,7 @@ void MockAudioTranscoder::reset()
should_output_packets_ = false;
}
void MockAudioTranscoder::set_output_packets(int count, const char *sample_data, int sample_size)
void MockAudioTranscoderForUtest::set_output_packets(int count, const char *sample_data, int sample_size)
{
reset();
should_output_packets_ = true;
@ -167,7 +167,7 @@ void MockAudioTranscoder::set_output_packets(int count, const char *sample_data,
}
}
void MockAudioTranscoder::set_transcode_error(srs_error_t err)
void MockAudioTranscoderForUtest::set_transcode_error(srs_error_t err)
{
srs_freep(transcode_error_);
transcode_error_ = srs_error_copy(err);

View File

@ -39,7 +39,7 @@ public:
};
// Mock audio transcoder for testing SrsRtcFrameBuilder::transcode_audio
class MockAudioTranscoder : public ISrsAudioTranscoder
class MockAudioTranscoderForUtest : public ISrsAudioTranscoder
{
public:
// Control behavior
@ -50,8 +50,8 @@ public:
int aac_header_len_;
public:
MockAudioTranscoder();
virtual ~MockAudioTranscoder();
MockAudioTranscoderForUtest();
virtual ~MockAudioTranscoderForUtest();
public:
// ISrsAudioTranscoder interface

View File

@ -1409,7 +1409,7 @@ VOID TEST(Rtc2RtmpConvertTest, PacketAudio_ThreeAudioPackets)
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdOpus, SrsVideoCodecIdAVC));
// Replace the audio transcoder with our mock to avoid FFmpeg issues
MockAudioTranscoder *mock_transcoder = new MockAudioTranscoder();
MockAudioTranscoderForUtest *mock_transcoder = new MockAudioTranscoderForUtest();
mock_transcoder->set_output_packets(1); // Each input packet produces 1 output packet
// Access private member through friendship (utests have access to private members)
@ -1459,7 +1459,7 @@ VOID TEST(Rtc2RtmpConvertTest, PacketAudio_ReorderingAudioPackets)
HELPER_EXPECT_SUCCESS(builder.initialize(req.get(), SrsAudioCodecIdOpus, SrsVideoCodecIdAVC));
// Replace the audio transcoder with our mock to avoid FFmpeg issues
MockAudioTranscoder *mock_transcoder = new MockAudioTranscoder();
MockAudioTranscoderForUtest *mock_transcoder = new MockAudioTranscoderForUtest();
mock_transcoder->set_output_packets(1); // Each input packet produces 1 output packet
// Access private member through friendship (utests have access to private members)

View File

@ -2483,6 +2483,31 @@ void MockOriginHub::set_on_forwarder_start_error(srs_error_t err)
on_forwarder_start_error_ = srs_error_copy(err);
}
// MockAudioCache implementation
MockAudioCache::MockAudioCache()
{
process_packet_count_ = 0;
}
MockAudioCache::~MockAudioCache()
{
}
srs_error_t MockAudioCache::process_packet(SrsRtpPacket *src, std::vector<SrsRtpPacket *> &ready_packets)
{
process_packet_count_++;
// Copy the packet.
SrsRtpPacket *copy = src->copy();
ready_packets.push_back(copy);
return srs_success;
}
void MockAudioCache::clear_all()
{
}
// Mock ISrsBasicRtmpClient implementation
MockRtmpClient::MockRtmpClient()
{
@ -2644,3 +2669,45 @@ void MockRtmpClient::set_url(std::string url)
{
url_ = url;
}
MockAudioTranscoder::MockAudioTranscoder()
{
transcode_count_ = 0;
}
MockAudioTranscoder::~MockAudioTranscoder()
{
}
srs_error_t MockAudioTranscoder::initialize(SrsAudioCodecId from, SrsAudioCodecId to, int channels, int sample_rate, int bit_rate)
{
return srs_success;
}
srs_error_t MockAudioTranscoder::transcode(SrsParsedAudioPacket *in, std::vector<SrsParsedAudioPacket *> &outs)
{
transcode_count_++;
SrsParsedAudioPacket *out = in->copy();
output_packets_.push_back(out);
outs.push_back(out);
return srs_success;
}
void MockAudioTranscoder::free_frames(std::vector<SrsParsedAudioPacket *> &frames)
{
for (std::vector<SrsParsedAudioPacket *>::iterator it = frames.begin(); it != frames.end(); ++it) {
SrsParsedAudioPacket *p = *it;
srs_freep(p);
}
}
void MockAudioTranscoder::aac_codec_header(uint8_t **data, int *len)
{
int size = aac_header_.size();
uint8_t *copy = new uint8_t[size];
memcpy(copy, aac_header_.data(), size);
*data = copy;
*len = size;
}

View File

@ -17,6 +17,7 @@
#include <srs_app_config.hpp>
#include <srs_app_factory.hpp>
#include <srs_app_ffmpeg.hpp>
#include <srs_app_rtc_codec.hpp>
#include <srs_app_rtc_conn.hpp>
#include <srs_app_rtc_dtls.hpp>
#include <srs_app_rtc_source.hpp>
@ -1111,6 +1112,21 @@ public:
void set_on_dvr_request_sh_error(srs_error_t err);
};
// Mock audio cache for ISrsRtcFrameBuilderAudioPacketCache
class MockAudioCache : public ISrsRtcFrameBuilderAudioPacketCache
{
public:
int process_packet_count_;
public:
MockAudioCache();
virtual ~MockAudioCache();
public:
virtual srs_error_t process_packet(SrsRtpPacket *src, std::vector<SrsRtpPacket *> &ready_packets);
virtual void clear_all();
};
// Mock ISrsBasicRtmpClient for testing SrsForwarder
class MockRtmpClient : public ISrsBasicRtmpClient
{
@ -1164,4 +1180,23 @@ public:
virtual void set_url(std::string url);
};
// Mock the audio transcoder ISrsAudioTranscoder.
class MockAudioTranscoder : public ISrsAudioTranscoder
{
public:
int transcode_count_;
std::vector<SrsParsedAudioPacket *> output_packets_;
std::string aac_header_;
public:
MockAudioTranscoder();
virtual ~MockAudioTranscoder();
public:
virtual srs_error_t initialize(SrsAudioCodecId from, SrsAudioCodecId to, int channels, int sample_rate, int bit_rate);
virtual srs_error_t transcode(SrsParsedAudioPacket *in, std::vector<SrsParsedAudioPacket *> &outs);
virtual void free_frames(std::vector<SrsParsedAudioPacket *> &frames);
virtual void aac_codec_header(uint8_t **data, int *len);
};
#endif

View File

@ -36,102 +36,6 @@
#include <srs_utest_manual_service.hpp>
#include <srs_utest_workflow_rtc_conn.hpp>
// Create a mock audio cache ISrsRtcFrameBuilderAudioPacketCache
class MockAudioCache : public ISrsRtcFrameBuilderAudioPacketCache
{
public:
int process_packet_count_;
public:
MockAudioCache();
virtual ~MockAudioCache();
public:
virtual srs_error_t process_packet(SrsRtpPacket *src, std::vector<SrsRtpPacket *> &ready_packets);
virtual void clear_all();
};
MockAudioCache::MockAudioCache()
{
process_packet_count_ = 0;
}
MockAudioCache::~MockAudioCache()
{
}
srs_error_t MockAudioCache::process_packet(SrsRtpPacket *src, std::vector<SrsRtpPacket *> &ready_packets)
{
process_packet_count_++;
// Copy the packet.
SrsRtpPacket *copy = src->copy();
ready_packets.push_back(copy);
return srs_success;
}
void MockAudioCache::clear_all()
{
}
// Mock the audio transcoder ISrsAudioTranscoder.
class MockAudioTranscoderForRtc2Rtmp : public ISrsAudioTranscoder
{
public:
int transcode_count_;
std::vector<SrsParsedAudioPacket *> output_packets_;
std::string aac_header_;
public:
MockAudioTranscoderForRtc2Rtmp();
virtual ~MockAudioTranscoderForRtc2Rtmp();
public:
virtual srs_error_t initialize(SrsAudioCodecId from, SrsAudioCodecId to, int channels, int sample_rate, int bit_rate);
virtual srs_error_t transcode(SrsParsedAudioPacket *in, std::vector<SrsParsedAudioPacket *> &outs);
virtual void free_frames(std::vector<SrsParsedAudioPacket *> &frames);
virtual void aac_codec_header(uint8_t **data, int *len);
};
MockAudioTranscoderForRtc2Rtmp::MockAudioTranscoderForRtc2Rtmp()
{
transcode_count_ = 0;
}
MockAudioTranscoderForRtc2Rtmp::~MockAudioTranscoderForRtc2Rtmp()
{
}
srs_error_t MockAudioTranscoderForRtc2Rtmp::initialize(SrsAudioCodecId from, SrsAudioCodecId to, int channels, int sample_rate, int bit_rate)
{
return srs_success;
}
srs_error_t MockAudioTranscoderForRtc2Rtmp::transcode(SrsParsedAudioPacket *in, std::vector<SrsParsedAudioPacket *> &outs)
{
transcode_count_++;
SrsParsedAudioPacket *out = in->copy();
output_packets_.push_back(out);
outs.push_back(out);
return srs_success;
}
void MockAudioTranscoderForRtc2Rtmp::free_frames(std::vector<SrsParsedAudioPacket *> &frames)
{
}
void MockAudioTranscoderForRtc2Rtmp::aac_codec_header(uint8_t **data, int *len)
{
int size = aac_header_.size();
uint8_t *copy = new uint8_t[size];
memcpy(copy, aac_header_.data(), size);
*data = copy;
*len = size;
}
// This test is used to verify the basic workflow of the RTC connection.
// It's finished with the help of AI, but each step is manually designed
// and verified. So this is not dominated by AI, but by humanbeing.
@ -150,7 +54,7 @@ VOID TEST(BasicWorkflowRtc2RtmpTest, ManuallyVerifyTypicalScenario)
SrsUniquePtr<MockRtcTrackDescriptionFactory> track_factory(new MockRtcTrackDescriptionFactory());
SrsUniquePtr<MockLiveSourceManager> mock_sources(new MockLiveSourceManager());
MockAudioCache *mock_audio_cache = new MockAudioCache();
MockAudioTranscoderForRtc2Rtmp *mock_audio_transcoder = new MockAudioTranscoderForRtc2Rtmp();
MockAudioTranscoder *mock_audio_transcoder = new MockAudioTranscoder();
mock_audio_transcoder->aac_header_ = std::string("\xAF\x00\x12\x10", 4); // AAC sequence header.
mock_config->rtc_to_rtmp_ = true;
@ -193,6 +97,10 @@ VOID TEST(BasicWorkflowRtc2RtmpTest, ManuallyVerifyTypicalScenario)
frame_builder = bridge->frame_builder_;
EXPECT_TRUE(frame_builder != NULL);
// Mock the frame builder object
srs_freep(frame_builder->audio_cache_);
frame_builder->audio_cache_ = mock_audio_cache;
}
// Start the publish stream.
@ -200,17 +108,17 @@ VOID TEST(BasicWorkflowRtc2RtmpTest, ManuallyVerifyTypicalScenario)
// Test: First call to start() should succeed
HELPER_EXPECT_SUCCESS(publish_stream->start());
// Wait for coroutine to start.
srs_usleep(1 * SRS_UTIME_MILLISECONDS);
// Verify is_sender_started_ flag is set
EXPECT_TRUE(publish_stream->is_sender_started_);
// When starting the publish stream, the frame builder should be recreated
EXPECT_TRUE(frame_builder != bridge->frame_builder_);
frame_builder = bridge->frame_builder_;
// When starting the publish stream, the frame builder should not be recreated
EXPECT_TRUE(frame_builder == bridge->frame_builder_);
EXPECT_TRUE(frame_builder != NULL);
// Mock the frame builder object
srs_freep(frame_builder->audio_cache_);
frame_builder->audio_cache_ = mock_audio_cache;
// Mock the frame builder object. When publish, the transcoder will be recreated.
srs_freep(frame_builder->audio_transcoder_);
frame_builder->audio_transcoder_ = mock_audio_transcoder;
}
@ -224,6 +132,12 @@ VOID TEST(BasicWorkflowRtc2RtmpTest, ManuallyVerifyTypicalScenario)
pkt.header_.set_timestamp(1000);
pkt.header_.set_payload_type(track_factory->audio_pt_);
// Create fake audio payload.
SrsRtpRawPayload *raw = new SrsRtpRawPayload();
pkt.set_payload(raw, SrsRtpPacketPayloadTypeRaw);
raw->payload_ = pkt.wrap(100);
raw->nn_payload_ = 100;
SrsUniquePtr<char[]> data(new char[1500]);
SrsBuffer buf(data.get(), 1500);
HELPER_EXPECT_SUCCESS(pkt.encode(&buf));