AI: Add utest to manually verify rtc play workflow
This commit is contained in:
parent
abaffdd4b9
commit
ed120ba88b
|
|
@ -454,7 +454,6 @@ SrsRtcPlayStream::SrsRtcPlayStream(ISrsExecRtcAsyncTask *exec, ISrsExpire *expir
|
|||
nack_enabled_ = false;
|
||||
nack_no_copy_ = false;
|
||||
|
||||
_srs_config->subscribe(this);
|
||||
nack_epp_ = new SrsErrorPithyPrint();
|
||||
pli_worker_ = new SrsRtcPliWorker(this);
|
||||
|
||||
|
|
@ -473,8 +472,6 @@ SrsRtcPlayStream::~SrsRtcPlayStream()
|
|||
exec_->exec_rtc_async_work(new SrsRtcAsyncCallOnStop(cid_, req_));
|
||||
}
|
||||
|
||||
_srs_config->unsubscribe(this);
|
||||
|
||||
srs_freep(nack_epp_);
|
||||
srs_freep(pli_worker_);
|
||||
srs_freep(trd_);
|
||||
|
|
@ -496,7 +493,9 @@ SrsRtcPlayStream::~SrsRtcPlayStream()
|
|||
|
||||
// update the statistic when client coveried.
|
||||
// TODO: FIXME: Should finger out the err.
|
||||
stat_->on_disconnect(cid_.c_str(), srs_success);
|
||||
if (stat_) {
|
||||
stat_->on_disconnect(cid_.c_str(), srs_success);
|
||||
}
|
||||
|
||||
config_ = NULL;
|
||||
rtc_sources_ = NULL;
|
||||
|
|
|
|||
|
|
@ -254,7 +254,7 @@ public:
|
|||
};
|
||||
|
||||
// A RTC play stream, client pull and play stream from SRS.
|
||||
class SrsRtcPlayStream : public ISrsCoroutineHandler, public ISrsReloadHandler, public ISrsRtcPliWorkerHandler, public ISrsRtcSourceChangeCallback
|
||||
class SrsRtcPlayStream : public ISrsCoroutineHandler, public ISrsRtcPliWorkerHandler, public ISrsRtcSourceChangeCallback
|
||||
{
|
||||
// clang-format off
|
||||
SRS_DECLARE_PRIVATE: // clang-format on
|
||||
|
|
|
|||
|
|
@ -1874,7 +1874,7 @@ VOID TEST(SrsUtilityTest, UpdateDiskStat)
|
|||
SrsDiskStat first_sample = *srs_get_disk_stat();
|
||||
|
||||
// Wait a bit to ensure time difference
|
||||
srs_usleep(100 * SRS_UTIME_MILLISECONDS);
|
||||
srs_usleep(1 * SRS_UTIME_MILLISECONDS);
|
||||
|
||||
// Call srs_update_disk_stat() again to calculate deltas
|
||||
srs_update_disk_stat();
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ VOID TEST(UdpListenerTest, ListenAndReceivePacket)
|
|||
}
|
||||
|
||||
// Wait a bit for the listener to receive and process the packet
|
||||
srs_usleep(50 * SRS_UTIME_MILLISECONDS);
|
||||
srs_usleep(30 * SRS_UTIME_MILLISECONDS);
|
||||
|
||||
// Verify that the mock handler received the packet
|
||||
EXPECT_TRUE(mock_handler->on_udp_packet_called_);
|
||||
|
|
|
|||
|
|
@ -1412,7 +1412,7 @@ VOID TEST(AppCasterFlvTest, ResourceManagerDelegation)
|
|||
// Verify subscription by checking that handler is notified when a resource is removed
|
||||
caster->remove(resource2);
|
||||
// Give time for async disposal (manager runs in coroutine)
|
||||
srs_usleep(10 * SRS_UTIME_MILLISECONDS);
|
||||
srs_usleep(1 * SRS_UTIME_MILLISECONDS);
|
||||
// Handler should have been called (but we can't easily verify this without more complex setup)
|
||||
|
||||
// Test 14: unsubscribe() - should delegate to manager_->unsubscribe()
|
||||
|
|
@ -1424,7 +1424,7 @@ VOID TEST(AppCasterFlvTest, ResourceManagerDelegation)
|
|||
caster->remove(resource4);
|
||||
|
||||
// Give time for async disposal
|
||||
srs_usleep(10 * SRS_UTIME_MILLISECONDS);
|
||||
srs_usleep(1 * SRS_UTIME_MILLISECONDS);
|
||||
|
||||
// Clean up - set to NULL to avoid double-free
|
||||
caster->config_ = NULL;
|
||||
|
|
|
|||
|
|
@ -2381,6 +2381,7 @@ MockAppConfig::MockAppConfig()
|
|||
api_as_candidates_ = true;
|
||||
resolve_api_domain_ = true;
|
||||
keep_api_domain_ = false;
|
||||
mw_msgs_ = 8;
|
||||
}
|
||||
|
||||
MockAppConfig::~MockAppConfig()
|
||||
|
|
@ -2446,7 +2447,7 @@ bool MockAppConfig::get_realtime_enabled(std::string vhost, bool is_rtc)
|
|||
|
||||
int MockAppConfig::get_mw_msgs(std::string vhost, bool is_realtime, bool is_rtc)
|
||||
{
|
||||
return 8;
|
||||
return mw_msgs_;
|
||||
}
|
||||
|
||||
int MockAppConfig::get_rtc_drop_for_pt(std::string vhost)
|
||||
|
|
|
|||
|
|
@ -326,6 +326,7 @@ public:
|
|||
bool api_as_candidates_;
|
||||
bool resolve_api_domain_;
|
||||
bool keep_api_domain_;
|
||||
int mw_msgs_;
|
||||
|
||||
public:
|
||||
MockAppConfig();
|
||||
|
|
|
|||
|
|
@ -2335,7 +2335,7 @@ VOID TEST(AppOriginHubTest, CreateForwardersTypicalScenario)
|
|||
}
|
||||
|
||||
// Give coroutines time to stop
|
||||
srs_usleep(10 * 1000); // 10ms
|
||||
srs_usleep(1 * SRS_UTIME_MILLISECONDS);
|
||||
}
|
||||
// Hub is destroyed here, before mock_config
|
||||
|
||||
|
|
@ -2881,7 +2881,7 @@ VOID TEST(AppOriginHubTest, CreateBackendForwardersTypicalScenario)
|
|||
}
|
||||
|
||||
// Give coroutines time to stop
|
||||
srs_usleep(10 * 1000); // 10ms
|
||||
srs_usleep(1 * SRS_UTIME_MILLISECONDS);
|
||||
}
|
||||
// Hub is destroyed here, before mock objects
|
||||
|
||||
|
|
|
|||
|
|
@ -7,354 +7,177 @@
|
|||
#include <srs_utest_rtc_playstream.hpp>
|
||||
|
||||
#include <srs_app_rtc_conn.hpp>
|
||||
#include <srs_app_rtc_source.hpp>
|
||||
#include <srs_kernel_error.hpp>
|
||||
#include <srs_utest_app.hpp>
|
||||
#include <srs_utest_app6.hpp>
|
||||
|
||||
// Mock ISrsCoroutine implementation
|
||||
MockCoroutineForPlayStream::MockCoroutineForPlayStream()
|
||||
// MockRtcTrackDescriptionFactory implementation
|
||||
MockRtcTrackDescriptionFactory::MockRtcTrackDescriptionFactory()
|
||||
{
|
||||
start_error_ = srs_success;
|
||||
start_count_ = 0;
|
||||
stop_count_ = 0;
|
||||
interrupt_count_ = 0;
|
||||
audio_ssrc_ = 12345;
|
||||
video_ssrc_ = 67890;
|
||||
}
|
||||
|
||||
MockCoroutineForPlayStream::~MockCoroutineForPlayStream()
|
||||
MockRtcTrackDescriptionFactory::~MockRtcTrackDescriptionFactory()
|
||||
{
|
||||
srs_freep(start_error_);
|
||||
}
|
||||
|
||||
srs_error_t MockCoroutineForPlayStream::start()
|
||||
std::map<uint32_t, SrsRtcTrackDescription *> MockRtcTrackDescriptionFactory::create_audio_video_tracks()
|
||||
{
|
||||
start_count_++;
|
||||
if (start_error_ != srs_success) {
|
||||
return srs_error_copy(start_error_);
|
||||
}
|
||||
return srs_success;
|
||||
std::map<uint32_t, SrsRtcTrackDescription *> sub_relations;
|
||||
|
||||
// Create audio track
|
||||
SrsRtcTrackDescription *audio_desc = create_audio_track(audio_ssrc_, "audio-track-1");
|
||||
sub_relations[audio_desc->ssrc_] = audio_desc;
|
||||
|
||||
// Create video track
|
||||
SrsRtcTrackDescription *video_desc = create_video_track(video_ssrc_, "video-track-1");
|
||||
sub_relations[video_desc->ssrc_] = video_desc;
|
||||
|
||||
return sub_relations;
|
||||
}
|
||||
|
||||
void MockCoroutineForPlayStream::stop()
|
||||
SrsRtcTrackDescription *MockRtcTrackDescriptionFactory::create_audio_track(uint32_t ssrc, std::string id)
|
||||
{
|
||||
stop_count_++;
|
||||
SrsRtcTrackDescription *audio_desc = new SrsRtcTrackDescription();
|
||||
audio_desc->type_ = "audio";
|
||||
audio_desc->ssrc_ = ssrc;
|
||||
audio_desc->id_ = id;
|
||||
audio_desc->is_active_ = true;
|
||||
audio_desc->direction_ = "sendrecv";
|
||||
audio_desc->mid_ = "0";
|
||||
audio_desc->media_ = new SrsAudioPayload(111, "opus", 48000, 2);
|
||||
return audio_desc;
|
||||
}
|
||||
|
||||
void MockCoroutineForPlayStream::interrupt()
|
||||
SrsRtcTrackDescription *MockRtcTrackDescriptionFactory::create_video_track(uint32_t ssrc, std::string id)
|
||||
{
|
||||
interrupt_count_++;
|
||||
}
|
||||
|
||||
srs_error_t MockCoroutineForPlayStream::pull()
|
||||
{
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
const SrsContextId &MockCoroutineForPlayStream::cid()
|
||||
{
|
||||
return cid_;
|
||||
}
|
||||
|
||||
void MockCoroutineForPlayStream::set_cid(const SrsContextId &cid)
|
||||
{
|
||||
cid_ = cid;
|
||||
}
|
||||
|
||||
void MockCoroutineForPlayStream::reset()
|
||||
{
|
||||
srs_freep(start_error_);
|
||||
start_count_ = 0;
|
||||
stop_count_ = 0;
|
||||
interrupt_count_ = 0;
|
||||
}
|
||||
|
||||
void MockCoroutineForPlayStream::set_start_error(srs_error_t err)
|
||||
{
|
||||
srs_freep(start_error_);
|
||||
start_error_ = srs_error_copy(err);
|
||||
}
|
||||
|
||||
// Mock ISrsAppFactory implementation
|
||||
MockAppFactoryForPlayStream::MockAppFactoryForPlayStream()
|
||||
{
|
||||
mock_coroutine_ = new MockCoroutineForPlayStream();
|
||||
create_coroutine_error_ = srs_success;
|
||||
create_coroutine_count_ = 0;
|
||||
last_coroutine_handler_ = NULL;
|
||||
}
|
||||
|
||||
MockAppFactoryForPlayStream::~MockAppFactoryForPlayStream()
|
||||
{
|
||||
srs_freep(mock_coroutine_);
|
||||
srs_freep(create_coroutine_error_);
|
||||
}
|
||||
|
||||
ISrsFileWriter *MockAppFactoryForPlayStream::create_file_writer()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ISrsFileWriter *MockAppFactoryForPlayStream::create_enc_file_writer()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ISrsFileReader *MockAppFactoryForPlayStream::create_file_reader()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SrsPath *MockAppFactoryForPlayStream::create_path()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SrsLiveSource *MockAppFactoryForPlayStream::create_live_source()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ISrsOriginHub *MockAppFactoryForPlayStream::create_origin_hub()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ISrsHourGlass *MockAppFactoryForPlayStream::create_hourglass(const std::string &name, ISrsHourGlassHandler *handler, srs_utime_t interval)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ISrsBasicRtmpClient *MockAppFactoryForPlayStream::create_rtmp_client(std::string url, srs_utime_t cto, srs_utime_t sto)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ISrsHttpClient *MockAppFactoryForPlayStream::create_http_client()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ISrsFileReader *MockAppFactoryForPlayStream::create_http_file_reader(ISrsHttpResponseReader *r)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ISrsFlvDecoder *MockAppFactoryForPlayStream::create_flv_decoder()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef SRS_RTSP
|
||||
ISrsRtspSendTrack *MockAppFactoryForPlayStream::create_rtsp_audio_send_track(ISrsRtspConnection *session, SrsRtcTrackDescription *track_desc)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ISrsRtspSendTrack *MockAppFactoryForPlayStream::create_rtsp_video_send_track(ISrsRtspConnection *session, SrsRtcTrackDescription *track_desc)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
ISrsFlvTransmuxer *MockAppFactoryForPlayStream::create_flv_transmuxer()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ISrsMp4Encoder *MockAppFactoryForPlayStream::create_mp4_encoder()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ISrsDvrSegmenter *MockAppFactoryForPlayStream::create_dvr_flv_segmenter()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ISrsDvrSegmenter *MockAppFactoryForPlayStream::create_dvr_mp4_segmenter()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef SRS_GB28181
|
||||
ISrsGbMediaTcpConn *MockAppFactoryForPlayStream::create_gb_media_tcp_conn()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ISrsGbSession *MockAppFactoryForPlayStream::create_gb_session()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
ISrsInitMp4 *MockAppFactoryForPlayStream::create_init_mp4()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ISrsFragmentWindow *MockAppFactoryForPlayStream::create_fragment_window()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ISrsFragmentedMp4 *MockAppFactoryForPlayStream::create_fragmented_mp4()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ISrsIpListener *MockAppFactoryForPlayStream::create_tcp_listener(ISrsTcpHandler *handler)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ISrsRtcConnection *MockAppFactoryForPlayStream::create_rtc_connection(ISrsExecRtcAsyncTask *exec, const SrsContextId &cid)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ISrsFFMPEG *MockAppFactoryForPlayStream::create_ffmpeg(std::string ffmpeg_bin)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ISrsIngesterFFMPEG *MockAppFactoryForPlayStream::create_ingester_ffmpeg()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ISrsCoroutine *MockAppFactoryForPlayStream::create_coroutine(const std::string &name, ISrsCoroutineHandler *handler, SrsContextId cid)
|
||||
{
|
||||
create_coroutine_count_++;
|
||||
last_coroutine_name_ = name;
|
||||
last_coroutine_handler_ = handler;
|
||||
last_coroutine_cid_ = cid;
|
||||
|
||||
if (create_coroutine_error_ != srs_success) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return mock_coroutine_;
|
||||
}
|
||||
|
||||
ISrsTime *MockAppFactoryForPlayStream::create_time()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ISrsConfig *MockAppFactoryForPlayStream::create_config()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ISrsCond *MockAppFactoryForPlayStream::create_cond()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void MockAppFactoryForPlayStream::reset()
|
||||
{
|
||||
mock_coroutine_->reset();
|
||||
srs_freep(create_coroutine_error_);
|
||||
create_coroutine_count_ = 0;
|
||||
last_coroutine_name_ = "";
|
||||
last_coroutine_handler_ = NULL;
|
||||
}
|
||||
|
||||
void MockAppFactoryForPlayStream::set_create_coroutine_error(srs_error_t err)
|
||||
{
|
||||
srs_freep(create_coroutine_error_);
|
||||
create_coroutine_error_ = srs_error_copy(err);
|
||||
}
|
||||
|
||||
// Mock ISrsRtcPliWorker implementation
|
||||
MockRtcPliWorkerForPlayStream::MockRtcPliWorkerForPlayStream()
|
||||
{
|
||||
start_error_ = srs_success;
|
||||
start_count_ = 0;
|
||||
request_keyframe_count_ = 0;
|
||||
}
|
||||
|
||||
MockRtcPliWorkerForPlayStream::~MockRtcPliWorkerForPlayStream()
|
||||
{
|
||||
srs_freep(start_error_);
|
||||
}
|
||||
|
||||
srs_error_t MockRtcPliWorkerForPlayStream::start()
|
||||
{
|
||||
start_count_++;
|
||||
if (start_error_ != srs_success) {
|
||||
return srs_error_copy(start_error_);
|
||||
}
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
void MockRtcPliWorkerForPlayStream::request_keyframe(uint32_t ssrc, SrsContextId cid)
|
||||
{
|
||||
request_keyframe_count_++;
|
||||
}
|
||||
|
||||
srs_error_t MockRtcPliWorkerForPlayStream::cycle()
|
||||
{
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
void MockRtcPliWorkerForPlayStream::reset()
|
||||
{
|
||||
srs_freep(start_error_);
|
||||
start_count_ = 0;
|
||||
request_keyframe_count_ = 0;
|
||||
}
|
||||
|
||||
void MockRtcPliWorkerForPlayStream::set_start_error(srs_error_t err)
|
||||
{
|
||||
srs_freep(start_error_);
|
||||
start_error_ = srs_error_copy(err);
|
||||
SrsRtcTrackDescription *video_desc = new SrsRtcTrackDescription();
|
||||
video_desc->type_ = "video";
|
||||
video_desc->ssrc_ = ssrc;
|
||||
video_desc->id_ = id;
|
||||
video_desc->is_active_ = true;
|
||||
video_desc->direction_ = "sendrecv";
|
||||
video_desc->mid_ = "1";
|
||||
video_desc->media_ = new SrsVideoPayload(96, "H264", 90000);
|
||||
return video_desc;
|
||||
}
|
||||
|
||||
// Test SrsRtcPlayStream::start() - Basic success scenario
|
||||
VOID TEST(RtcPlayStreamStartTest, StartSuccess)
|
||||
VOID TEST(RtcPlayStreamTest, ManuallyVerifyBasicWorkflow)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
// Create mock objects
|
||||
// Create mock objects for dependencies
|
||||
MockAppConfig mock_config;
|
||||
MockRtcSourceManager mock_rtc_sources;
|
||||
MockRtcStatistic mock_stat;
|
||||
MockRtcAsyncCallRequest mock_request("test.vhost", "live", "stream1");
|
||||
MockRtcAsyncTaskExecutor mock_exec;
|
||||
MockExpire mock_expire;
|
||||
MockRtcPacketSender mock_sender;
|
||||
MockRtcTrackDescriptionFactory track_factory;
|
||||
SrsContextId cid;
|
||||
cid.set_value("test-play-stream-start-cid");
|
||||
|
||||
// Create RTC play stream
|
||||
// Create RTC play stream - uses real app_factory_ and real pli_worker_
|
||||
SrsUniquePtr<SrsRtcPlayStream> play_stream(new SrsRtcPlayStream(&mock_exec, &mock_expire, &mock_sender, cid));
|
||||
|
||||
// Create and inject mock app factory
|
||||
MockAppFactoryForPlayStream mock_factory;
|
||||
play_stream->app_factory_ = &mock_factory;
|
||||
// Mock the play stream object.
|
||||
if (true) {
|
||||
// Inject mock dependencies
|
||||
play_stream->config_ = &mock_config;
|
||||
play_stream->rtc_sources_ = &mock_rtc_sources;
|
||||
play_stream->stat_ = &mock_stat;
|
||||
|
||||
// Create and inject mock PLI worker
|
||||
MockRtcPliWorkerForPlayStream *mock_pli_worker = new MockRtcPliWorkerForPlayStream();
|
||||
play_stream->pli_worker_ = mock_pli_worker;
|
||||
// Set mw_msgs to 0 to make the consumer block until we push a packet
|
||||
mock_config.mw_msgs_ = 0;
|
||||
}
|
||||
|
||||
// Test: First call to start() should succeed
|
||||
HELPER_EXPECT_SUCCESS(play_stream->start());
|
||||
// Create track descriptions using factory
|
||||
if (true) {
|
||||
std::map<uint32_t, SrsRtcTrackDescription *> sub_relations = track_factory.create_audio_video_tracks();
|
||||
|
||||
// Verify coroutine was created with correct parameters
|
||||
EXPECT_EQ(1, mock_factory.create_coroutine_count_);
|
||||
EXPECT_STREQ("rtc_sender", mock_factory.last_coroutine_name_.c_str());
|
||||
EXPECT_TRUE(mock_factory.last_coroutine_handler_ == play_stream.get());
|
||||
EXPECT_EQ(0, cid.compare(mock_factory.last_coroutine_cid_));
|
||||
// Initialize the play stream (it will take ownership of track descriptions)
|
||||
HELPER_EXPECT_SUCCESS(play_stream->initialize(&mock_request, sub_relations));
|
||||
|
||||
// Verify coroutine start was called
|
||||
EXPECT_EQ(1, mock_factory.mock_coroutine_->start_count_);
|
||||
// Test: First call to start() should succeed
|
||||
HELPER_EXPECT_SUCCESS(play_stream->start());
|
||||
|
||||
// Verify PLI worker start was called
|
||||
EXPECT_EQ(1, mock_pli_worker->start_count_);
|
||||
// Verify is_started_ flag is set
|
||||
EXPECT_TRUE(play_stream->is_started_);
|
||||
|
||||
// Verify is_started_ flag is set
|
||||
EXPECT_TRUE(play_stream->is_started_);
|
||||
// Wait for coroutine to start and create consumer. Normally it should be ready
|
||||
// and stopped at wait for RTP packets from consumer.
|
||||
srs_usleep(1 * SRS_UTIME_MILLISECONDS);
|
||||
}
|
||||
|
||||
// Push a video packet to the source to feed the consumer.
|
||||
if (true) {
|
||||
SrsUniquePtr<SrsRtpPacket> test_pkt(new SrsRtpPacket());
|
||||
test_pkt->frame_type_ = SrsFrameTypeVideo;
|
||||
test_pkt->header_.set_sequence(1000);
|
||||
test_pkt->header_.set_timestamp(5000);
|
||||
test_pkt->header_.set_ssrc(track_factory.video_ssrc_);
|
||||
|
||||
// Push packet to source - this will feed all consumers including the play stream's consumer
|
||||
HELPER_EXPECT_SUCCESS(play_stream->source_->on_rtp(test_pkt.get()));
|
||||
}
|
||||
|
||||
// Verify the video packet is sent out
|
||||
if (true) {
|
||||
// Wait for coroutine to process the packet
|
||||
srs_usleep(1 * SRS_UTIME_MILLISECONDS);
|
||||
|
||||
// Check sender should have received the packet
|
||||
EXPECT_EQ(mock_sender.send_packet_count_, 1);
|
||||
// Check the tracks, should be a video track.
|
||||
EXPECT_EQ(play_stream->video_tracks_.size(), 1);
|
||||
// The packet should create a cached track for this ssrc.
|
||||
EXPECT_EQ(play_stream->cache_ssrc0_, track_factory.video_ssrc_);
|
||||
EXPECT_TRUE(play_stream->cache_track0_ != NULL);
|
||||
// The packet should be in the nack ring buffer.
|
||||
SrsRtpPacket *pkt = play_stream->cache_track0_->rtp_queue_->at(1000);
|
||||
EXPECT_TRUE(pkt != NULL);
|
||||
EXPECT_EQ(pkt->header_.get_ssrc(), track_factory.video_ssrc_);
|
||||
}
|
||||
|
||||
// Push a audio packet to the source to feed the consumer.
|
||||
if (true) {
|
||||
SrsUniquePtr<SrsRtpPacket> test_pkt(new SrsRtpPacket());
|
||||
test_pkt->frame_type_ = SrsFrameTypeAudio;
|
||||
test_pkt->header_.set_sequence(1000);
|
||||
test_pkt->header_.set_timestamp(5000);
|
||||
test_pkt->header_.set_ssrc(track_factory.audio_ssrc_);
|
||||
|
||||
// Push packet to source - this will feed all consumers including the play stream's consumer
|
||||
HELPER_EXPECT_SUCCESS(play_stream->source_->on_rtp(test_pkt.get()));
|
||||
}
|
||||
|
||||
// Verify the audio packet is sent out
|
||||
if (true) {
|
||||
// Wait for coroutine to process the packet
|
||||
srs_usleep(1 * SRS_UTIME_MILLISECONDS);
|
||||
|
||||
// Check sender should have received the packet
|
||||
EXPECT_EQ(mock_sender.send_packet_count_, 2);
|
||||
// Check the tracks, should be a video track.
|
||||
EXPECT_EQ(play_stream->audio_tracks_.size(), 1);
|
||||
// The packet should create a cached track for this ssrc.
|
||||
EXPECT_EQ(play_stream->cache_ssrc1_, track_factory.audio_ssrc_);
|
||||
EXPECT_TRUE(play_stream->cache_track1_ != NULL);
|
||||
// The packet should be in the nack ring buffer.
|
||||
SrsRtpPacket *pkt = play_stream->cache_track1_->rtp_queue_->at(1000);
|
||||
EXPECT_TRUE(pkt != NULL);
|
||||
EXPECT_EQ(pkt->header_.get_ssrc(), track_factory.audio_ssrc_);
|
||||
}
|
||||
|
||||
// Stop the play stream
|
||||
play_stream->stop();
|
||||
|
||||
// Clean up - set to NULL to avoid double-free
|
||||
play_stream->trd_ = NULL; // Set to NULL before mock_factory is destroyed
|
||||
play_stream->app_factory_ = NULL;
|
||||
play_stream->pli_worker_ = NULL;
|
||||
srs_freep(mock_pli_worker);
|
||||
play_stream->config_ = NULL;
|
||||
play_stream->rtc_sources_ = NULL;
|
||||
play_stream->stat_ = NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,121 +7,32 @@
|
|||
#ifndef SRS_UTEST_RTC_PLAYSTREAM_HPP
|
||||
#define SRS_UTEST_RTC_PLAYSTREAM_HPP
|
||||
|
||||
/*
|
||||
#include <srs_utest_rtc_playstream.hpp>
|
||||
*/
|
||||
#include <srs_utest.hpp>
|
||||
#include <map>
|
||||
|
||||
#include <srs_app_factory.hpp>
|
||||
#include <srs_app_rtc_conn.hpp>
|
||||
#include <srs_kernel_factory.hpp>
|
||||
class SrsRtcTrackDescription;
|
||||
|
||||
// Mock ISrsCoroutine for testing SrsRtcPlayStream::start()
|
||||
class MockCoroutineForPlayStream : public ISrsCoroutine
|
||||
// Helper class to create mock track descriptions for testing
|
||||
class MockRtcTrackDescriptionFactory
|
||||
{
|
||||
public:
|
||||
srs_error_t start_error_;
|
||||
int start_count_;
|
||||
int stop_count_;
|
||||
int interrupt_count_;
|
||||
SrsContextId cid_;
|
||||
MockRtcTrackDescriptionFactory();
|
||||
virtual ~MockRtcTrackDescriptionFactory();
|
||||
|
||||
public:
|
||||
MockCoroutineForPlayStream();
|
||||
virtual ~MockCoroutineForPlayStream();
|
||||
// Default SSRCs for audio and video tracks
|
||||
uint32_t audio_ssrc_;
|
||||
uint32_t video_ssrc_;
|
||||
|
||||
public:
|
||||
virtual srs_error_t start();
|
||||
virtual void stop();
|
||||
virtual void interrupt();
|
||||
virtual srs_error_t pull();
|
||||
virtual const SrsContextId &cid();
|
||||
virtual void set_cid(const SrsContextId &cid);
|
||||
// Create a map of track descriptions with audio and video tracks
|
||||
std::map<uint32_t, SrsRtcTrackDescription *> create_audio_video_tracks();
|
||||
|
||||
public:
|
||||
void reset();
|
||||
void set_start_error(srs_error_t err);
|
||||
};
|
||||
// Create a single audio track description
|
||||
SrsRtcTrackDescription *create_audio_track(uint32_t ssrc, std::string id);
|
||||
|
||||
// Mock ISrsAppFactory for testing SrsRtcPlayStream::start()
|
||||
class MockAppFactoryForPlayStream : public ISrsAppFactory
|
||||
{
|
||||
public:
|
||||
MockCoroutineForPlayStream *mock_coroutine_;
|
||||
srs_error_t create_coroutine_error_;
|
||||
int create_coroutine_count_;
|
||||
std::string last_coroutine_name_;
|
||||
ISrsCoroutineHandler *last_coroutine_handler_;
|
||||
SrsContextId last_coroutine_cid_;
|
||||
|
||||
public:
|
||||
MockAppFactoryForPlayStream();
|
||||
virtual ~MockAppFactoryForPlayStream();
|
||||
|
||||
public:
|
||||
// ISrsAppFactory interface methods
|
||||
virtual ISrsFileWriter *create_file_writer();
|
||||
virtual ISrsFileWriter *create_enc_file_writer();
|
||||
virtual ISrsFileReader *create_file_reader();
|
||||
virtual SrsPath *create_path();
|
||||
virtual SrsLiveSource *create_live_source();
|
||||
virtual ISrsOriginHub *create_origin_hub();
|
||||
virtual ISrsHourGlass *create_hourglass(const std::string &name, ISrsHourGlassHandler *handler, srs_utime_t interval);
|
||||
virtual ISrsBasicRtmpClient *create_rtmp_client(std::string url, srs_utime_t cto, srs_utime_t sto);
|
||||
virtual ISrsHttpClient *create_http_client();
|
||||
virtual ISrsFileReader *create_http_file_reader(ISrsHttpResponseReader *r);
|
||||
virtual ISrsFlvDecoder *create_flv_decoder();
|
||||
#ifdef SRS_RTSP
|
||||
virtual ISrsRtspSendTrack *create_rtsp_audio_send_track(ISrsRtspConnection *session, SrsRtcTrackDescription *track_desc);
|
||||
virtual ISrsRtspSendTrack *create_rtsp_video_send_track(ISrsRtspConnection *session, SrsRtcTrackDescription *track_desc);
|
||||
#endif
|
||||
virtual ISrsFlvTransmuxer *create_flv_transmuxer();
|
||||
virtual ISrsMp4Encoder *create_mp4_encoder();
|
||||
virtual ISrsDvrSegmenter *create_dvr_flv_segmenter();
|
||||
virtual ISrsDvrSegmenter *create_dvr_mp4_segmenter();
|
||||
#ifdef SRS_GB28181
|
||||
virtual ISrsGbMediaTcpConn *create_gb_media_tcp_conn();
|
||||
virtual ISrsGbSession *create_gb_session();
|
||||
#endif
|
||||
virtual ISrsInitMp4 *create_init_mp4();
|
||||
virtual ISrsFragmentWindow *create_fragment_window();
|
||||
virtual ISrsFragmentedMp4 *create_fragmented_mp4();
|
||||
virtual ISrsIpListener *create_tcp_listener(ISrsTcpHandler *handler);
|
||||
virtual ISrsRtcConnection *create_rtc_connection(ISrsExecRtcAsyncTask *exec, const SrsContextId &cid);
|
||||
virtual ISrsFFMPEG *create_ffmpeg(std::string ffmpeg_bin);
|
||||
virtual ISrsIngesterFFMPEG *create_ingester_ffmpeg();
|
||||
|
||||
// ISrsKernelFactory interface methods
|
||||
virtual ISrsCoroutine *create_coroutine(const std::string &name, ISrsCoroutineHandler *handler, SrsContextId cid);
|
||||
virtual ISrsTime *create_time();
|
||||
virtual ISrsConfig *create_config();
|
||||
virtual ISrsCond *create_cond();
|
||||
|
||||
public:
|
||||
void reset();
|
||||
void set_create_coroutine_error(srs_error_t err);
|
||||
};
|
||||
|
||||
// Mock ISrsRtcPliWorker for testing SrsRtcPlayStream::start()
|
||||
class MockRtcPliWorkerForPlayStream : public ISrsRtcPliWorker
|
||||
{
|
||||
public:
|
||||
srs_error_t start_error_;
|
||||
int start_count_;
|
||||
int request_keyframe_count_;
|
||||
|
||||
public:
|
||||
MockRtcPliWorkerForPlayStream();
|
||||
virtual ~MockRtcPliWorkerForPlayStream();
|
||||
|
||||
public:
|
||||
virtual srs_error_t start();
|
||||
virtual void request_keyframe(uint32_t ssrc, SrsContextId cid);
|
||||
virtual srs_error_t cycle();
|
||||
|
||||
public:
|
||||
void reset();
|
||||
void set_start_error(srs_error_t err);
|
||||
// Create a single video track description
|
||||
SrsRtcTrackDescription *create_video_track(uint32_t ssrc, std::string id);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ VOID TEST(TCPServerTest, PingPong)
|
|||
SrsTcpClient c(_srs_tmp_host, _srs_tmp_port, _srs_tmp_timeout);
|
||||
HELPER_EXPECT_SUCCESS(c.connect());
|
||||
|
||||
srs_usleep(30 * SRS_UTIME_MILLISECONDS);
|
||||
srs_usleep(1 * SRS_UTIME_MILLISECONDS);
|
||||
EXPECT_TRUE(h.fd != NULL);
|
||||
}
|
||||
|
||||
|
|
@ -117,7 +117,7 @@ VOID TEST(TCPServerTest, PingPong)
|
|||
SrsTcpClient c(_srs_tmp_host, _srs_tmp_port, _srs_tmp_timeout);
|
||||
HELPER_EXPECT_SUCCESS(c.connect());
|
||||
|
||||
srs_usleep(30 * SRS_UTIME_MILLISECONDS);
|
||||
srs_usleep(1 * SRS_UTIME_MILLISECONDS);
|
||||
#ifdef SRS_OSX
|
||||
ASSERT_TRUE(h.fd != NULL);
|
||||
#endif
|
||||
|
|
@ -139,7 +139,7 @@ VOID TEST(TCPServerTest, PingPong)
|
|||
SrsTcpClient c(_srs_tmp_host, _srs_tmp_port, _srs_tmp_timeout);
|
||||
HELPER_EXPECT_SUCCESS(c.connect());
|
||||
|
||||
srs_usleep(30 * SRS_UTIME_MILLISECONDS);
|
||||
srs_usleep(1 * SRS_UTIME_MILLISECONDS);
|
||||
#ifdef SRS_OSX
|
||||
ASSERT_TRUE(h.fd != NULL);
|
||||
#endif
|
||||
|
|
@ -163,7 +163,7 @@ VOID TEST(TCPServerTest, PingPong)
|
|||
SrsTcpClient c(_srs_tmp_host, _srs_tmp_port, _srs_tmp_timeout);
|
||||
HELPER_EXPECT_SUCCESS(c.connect());
|
||||
|
||||
srs_usleep(30 * SRS_UTIME_MILLISECONDS);
|
||||
srs_usleep(1 * SRS_UTIME_MILLISECONDS);
|
||||
#ifdef SRS_OSX
|
||||
ASSERT_TRUE(h.fd != NULL);
|
||||
#endif
|
||||
|
|
@ -198,7 +198,7 @@ VOID TEST(TCPServerTest, PingPongWithTimeout)
|
|||
SrsTcpClient c(_srs_tmp_host, _srs_tmp_port, _srs_tmp_timeout);
|
||||
HELPER_EXPECT_SUCCESS(c.connect());
|
||||
|
||||
srs_usleep(30 * SRS_UTIME_MILLISECONDS);
|
||||
srs_usleep(1 * SRS_UTIME_MILLISECONDS);
|
||||
#ifdef SRS_OSX
|
||||
ASSERT_TRUE(h.fd != NULL);
|
||||
#endif
|
||||
|
|
@ -220,7 +220,7 @@ VOID TEST(TCPServerTest, PingPongWithTimeout)
|
|||
SrsTcpClient c(_srs_tmp_host, _srs_tmp_port, _srs_tmp_timeout);
|
||||
HELPER_EXPECT_SUCCESS(c.connect());
|
||||
|
||||
srs_usleep(30 * SRS_UTIME_MILLISECONDS);
|
||||
srs_usleep(1 * SRS_UTIME_MILLISECONDS);
|
||||
#ifdef SRS_OSX
|
||||
ASSERT_TRUE(h.fd != NULL);
|
||||
#endif
|
||||
|
|
@ -242,7 +242,7 @@ VOID TEST(TCPServerTest, PingPongWithTimeout)
|
|||
SrsTcpClient c(_srs_tmp_host, _srs_tmp_port, _srs_tmp_timeout);
|
||||
HELPER_EXPECT_SUCCESS(c.connect());
|
||||
|
||||
srs_usleep(30 * SRS_UTIME_MILLISECONDS);
|
||||
srs_usleep(1 * SRS_UTIME_MILLISECONDS);
|
||||
#ifdef SRS_OSX
|
||||
ASSERT_TRUE(h.fd != NULL);
|
||||
#endif
|
||||
|
|
@ -437,7 +437,7 @@ VOID TEST(TCPServerTest, WritevIOVC)
|
|||
SrsTcpClient c(_srs_tmp_host, _srs_tmp_port, _srs_tmp_timeout);
|
||||
HELPER_EXPECT_SUCCESS(c.connect());
|
||||
|
||||
srs_usleep(30 * SRS_UTIME_MILLISECONDS);
|
||||
srs_usleep(1 * SRS_UTIME_MILLISECONDS);
|
||||
#ifdef SRS_OSX
|
||||
ASSERT_TRUE(h.fd != NULL);
|
||||
#endif
|
||||
|
|
@ -467,7 +467,7 @@ VOID TEST(TCPServerTest, WritevIOVC)
|
|||
SrsTcpClient c(_srs_tmp_host, _srs_tmp_port, _srs_tmp_timeout);
|
||||
HELPER_EXPECT_SUCCESS(c.connect());
|
||||
|
||||
srs_usleep(30 * SRS_UTIME_MILLISECONDS);
|
||||
srs_usleep(1 * SRS_UTIME_MILLISECONDS);
|
||||
#ifdef SRS_OSX
|
||||
ASSERT_TRUE(h.fd != NULL);
|
||||
#endif
|
||||
|
|
@ -1000,7 +1000,7 @@ srs_error_t MockOnCycleThread::cycle()
|
|||
srs_error_t err = srs_success;
|
||||
|
||||
for (;;) {
|
||||
srs_usleep(10 * SRS_UTIME_MILLISECONDS);
|
||||
srs_usleep(1 * SRS_UTIME_MILLISECONDS);
|
||||
srs_cond_signal(cond);
|
||||
// If no one waiting on the cond, directly return event signal more than one time.
|
||||
// If someone waiting, signal them more than one time.
|
||||
|
|
@ -1029,7 +1029,7 @@ VOID TEST(TCPServerTest, ThreadCondWait)
|
|||
MockOnCycleThread trd;
|
||||
trd.trd.start();
|
||||
|
||||
srs_usleep(20 * SRS_UTIME_MILLISECONDS);
|
||||
srs_usleep(1 * SRS_UTIME_MILLISECONDS);
|
||||
srs_cond_wait(trd.cond);
|
||||
trd.trd.stop();
|
||||
}
|
||||
|
|
@ -1050,7 +1050,7 @@ srs_error_t MockOnCycleThread2::cycle()
|
|||
|
||||
for (;;) {
|
||||
srs_mutex_lock(lock);
|
||||
srs_usleep(10 * SRS_UTIME_MILLISECONDS);
|
||||
srs_usleep(1 * SRS_UTIME_MILLISECONDS);
|
||||
srs_mutex_unlock(lock);
|
||||
|
||||
srs_error_t err = trd.pull();
|
||||
|
|
@ -1077,7 +1077,7 @@ VOID TEST(TCPServerTest, ThreadMutexWait)
|
|||
MockOnCycleThread2 trd;
|
||||
trd.trd.start();
|
||||
|
||||
srs_usleep(20 * SRS_UTIME_MILLISECONDS);
|
||||
srs_usleep(1 * SRS_UTIME_MILLISECONDS);
|
||||
|
||||
srs_mutex_lock(trd.lock);
|
||||
trd.trd.stop();
|
||||
|
|
@ -1579,7 +1579,7 @@ VOID TEST(ThreadCriticalTest, FailIfCloseActiveFD)
|
|||
SrsTcpClient c0(_srs_tmp_host, _srs_tmp_port, _srs_tmp_timeout);
|
||||
HELPER_EXPECT_SUCCESS(c0.connect());
|
||||
|
||||
srs_usleep(30 * SRS_UTIME_MILLISECONDS);
|
||||
srs_usleep(1 * SRS_UTIME_MILLISECONDS);
|
||||
EXPECT_TRUE(h.fd != NULL);
|
||||
|
||||
MockAsyncReaderThread trd0(h.fd);
|
||||
|
|
@ -1589,7 +1589,7 @@ VOID TEST(ThreadCriticalTest, FailIfCloseActiveFD)
|
|||
HELPER_EXPECT_SUCCESS(trd1.start());
|
||||
|
||||
// Wait for all threads to run.
|
||||
srs_usleep(10 * SRS_UTIME_MILLISECONDS);
|
||||
srs_usleep(1 * SRS_UTIME_MILLISECONDS);
|
||||
|
||||
// Should fail when close, because there is 2 threads reading fd.
|
||||
int r0 = st_netfd_close((st_netfd_t)h.fd);
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ VOID TEST(StTest, AnonymouseSingleCoroutine)
|
|||
|
||||
// Wait for coroutine to terminate. Otherwise, it will be stopped
|
||||
// and terminated, which cause some of the code not executed.
|
||||
srs_usleep(50 * SRS_UTIME_MILLISECONDS);
|
||||
srs_usleep(1 * SRS_UTIME_MILLISECONDS);
|
||||
}
|
||||
|
||||
VOID TEST(StTest, AnonymouseMultipleCoroutines)
|
||||
|
|
@ -42,7 +42,7 @@ VOID TEST(StTest, AnonymouseMultipleCoroutines)
|
|||
|
||||
// Wait for coroutine to terminate. Otherwise, it will be stopped
|
||||
// and terminated, which cause some of the code not executed.
|
||||
srs_usleep(50 * SRS_UTIME_MILLISECONDS);
|
||||
srs_usleep(1 * SRS_UTIME_MILLISECONDS);
|
||||
}
|
||||
|
||||
VOID TEST(StTest, AnonymouseCoroutinePull)
|
||||
|
|
@ -67,7 +67,7 @@ VOID TEST(StTest, AnonymouseCoroutinePull)
|
|||
|
||||
// Wait for coroutine to run and terminated, or it will crash
|
||||
// because the ctx.pop is called after coroutine terminated.
|
||||
srs_usleep(50 * SRS_UTIME_MILLISECONDS);
|
||||
srs_usleep(1 * SRS_UTIME_MILLISECONDS);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(counter == 1);
|
||||
|
|
@ -90,12 +90,12 @@ VOID TEST(StTest, AnonymouseCoroutineWithContext)
|
|||
|
||||
// Wait for coroutine to run and terminated, or it will crash
|
||||
// because the ctx.pop is called after coroutine terminated.
|
||||
srs_usleep(50 * SRS_UTIME_MILLISECONDS);
|
||||
srs_usleep(1 * SRS_UTIME_MILLISECONDS);
|
||||
EXPECT_TRUE(counter == 1);
|
||||
|
||||
// Wait for coroutine to terminate. Otherwise, it will be stopped
|
||||
// and terminated, which cause some of the code not executed.
|
||||
srs_usleep(50 * SRS_UTIME_MILLISECONDS);
|
||||
srs_usleep(1 * SRS_UTIME_MILLISECONDS);
|
||||
}
|
||||
|
||||
VOID TEST(StTest, AnonymouseCoroutineWithSync)
|
||||
|
|
@ -272,7 +272,7 @@ VOID TEST(StTest, AnonymouseBadcase2)
|
|||
|
||||
// Wait for coroutine to terminate. Otherwise, it will crash, for the
|
||||
// coroutine is terminated while ctx.pop(), the lock is invalid.
|
||||
srs_usleep(100 * SRS_UTIME_MILLISECONDS);
|
||||
srs_usleep(1 * SRS_UTIME_MILLISECONDS);
|
||||
}
|
||||
|
||||
// Coroutine terminated, so the counter is increased.
|
||||
|
|
|
|||
|
|
@ -414,7 +414,7 @@ VOID TEST(StreamTokenTest, RaceConditionPrevention)
|
|||
}
|
||||
|
||||
// Wait a bit for completion
|
||||
srs_usleep(10 * SRS_UTIME_MILLISECONDS);
|
||||
srs_usleep(1 * SRS_UTIME_MILLISECONDS);
|
||||
|
||||
// Wait for all coroutines to complete
|
||||
for (size_t i = 0; i < threads.size(); i++) {
|
||||
|
|
@ -423,7 +423,7 @@ VOID TEST(StreamTokenTest, RaceConditionPrevention)
|
|||
}
|
||||
|
||||
// Wait a bit for completion
|
||||
srs_usleep(10 * SRS_UTIME_MILLISECONDS);
|
||||
srs_usleep(1 * SRS_UTIME_MILLISECONDS);
|
||||
|
||||
// Check results - exactly one should succeed, others should fail
|
||||
int success_count = 0;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user