Skip to content

Commit bf8a5a2

Browse files
ossrs-aiwinlinvip
authored andcommitted
AI: Fix the disposing new created source issue.
1 parent f9700d6 commit bf8a5a2

File tree

5 files changed

+177
-17
lines changed

5 files changed

+177
-17
lines changed

trunk/src/app/srs_app_rtc_source.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ srs_error_t SrsRtcSourceManager::fetch_or_create(ISrsRequest *r, SrsSharedPtr<Sr
335335
pps = source;
336336
} else {
337337
SrsSharedPtr<SrsRtcSource> source = SrsSharedPtr<SrsRtcSource>(new SrsRtcSource());
338-
srs_trace("new rtc source, stream_url=%s", stream_url.c_str());
338+
srs_trace("new rtc source, stream_url=%s, dead=%d", stream_url.c_str(), source->stream_is_dead());
339339
pps = source;
340340

341341
pool_[stream_url] = source;
@@ -399,7 +399,10 @@ SrsRtcSource::SrsRtcSource()
399399
circuit_breaker_ = _srs_circuit_breaker;
400400

401401
pli_for_rtmp_ = pli_elapsed_ = 0;
402-
stream_die_at_ = 0;
402+
// Initialize stream_die_at_ to current time to prevent newly created sources
403+
// from being immediately considered dead by stream_is_dead() check.
404+
// @see https://github.com/ossrs/srs/issues/4449
405+
stream_die_at_ = srs_time_now_cached();
403406

404407
app_factory_ = _srs_app_factory;
405408
}

trunk/src/app/srs_app_rtmp_source.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1659,7 +1659,7 @@ srs_error_t SrsLiveSourceManager::fetch_or_create(ISrsRequest *r, SrsSharedPtr<S
16591659
pps = source;
16601660
} else {
16611661
SrsSharedPtr<SrsLiveSource> source = app_factory_->create_live_source();
1662-
srs_trace("new live source, stream_url=%s", stream_url.c_str());
1662+
srs_trace("new live source, stream_url=%s, dead=%d", stream_url.c_str(), source->stream_is_dead());
16631663
pps = source;
16641664

16651665
// Callback to notify request of source creation
@@ -1781,7 +1781,10 @@ SrsLiveSource::SrsLiveSource()
17811781
mix_queue_ = new SrsMixQueue();
17821782

17831783
can_publish_ = true;
1784-
stream_die_at_ = 0;
1784+
// Initialize stream_die_at_ to current time to prevent newly created sources
1785+
// from being immediately considered dead by stream_is_dead() check.
1786+
// @see https://github.com/ossrs/srs/issues/4449
1787+
stream_die_at_ = srs_time_now_cached();
17851788
publisher_idle_at_ = 0;
17861789

17871790
rtmp_bridge_ = NULL;

trunk/src/app/srs_app_rtsp_source.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ srs_error_t SrsRtspSourceManager::fetch_or_create(ISrsRequest *r, SrsSharedPtr<S
194194
pps = source;
195195
} else {
196196
SrsSharedPtr<SrsRtspSource> source = SrsSharedPtr<SrsRtspSource>(new SrsRtspSource());
197-
srs_trace("new rtsp source, stream_url=%s", stream_url.c_str());
197+
srs_trace("new rtsp source, stream_url=%s, dead=%d", stream_url.c_str(), source->stream_is_dead());
198198
pps = source;
199199

200200
pool_[stream_url] = source;
@@ -249,7 +249,10 @@ SrsRtspSource::SrsRtspSource()
249249

250250
req_ = NULL;
251251

252-
stream_die_at_ = 0;
252+
// Initialize stream_die_at_ to current time to prevent newly created sources
253+
// from being immediately considered dead by stream_is_dead() check.
254+
// @see https://github.com/ossrs/srs/issues/4449
255+
stream_die_at_ = srs_time_now_cached();
253256

254257
stat_ = _srs_stat;
255258
circuit_breaker_ = _srs_circuit_breaker;

trunk/src/app/srs_app_srt_source.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ srs_error_t SrsSrtSourceManager::fetch_or_create(ISrsRequest *r, SrsSharedPtr<Sr
179179
pps = source;
180180
} else {
181181
SrsSharedPtr<SrsSrtSource> source(new SrsSrtSource());
182-
srs_trace("new srt source, stream_url=%s", stream_url.c_str());
182+
srs_trace("new srt source, stream_url=%s, dead=%d", stream_url.c_str(), source->stream_is_dead());
183183
pps = source;
184184

185185
pool_[stream_url] = source;
@@ -1230,7 +1230,10 @@ SrsSrtSource::SrsSrtSource()
12301230
req_ = NULL;
12311231
can_publish_ = true;
12321232
srt_bridge_ = NULL;
1233-
stream_die_at_ = 0;
1233+
// Initialize stream_die_at_ to current time to prevent newly created sources
1234+
// from being immediately considered dead by stream_is_dead() check.
1235+
// @see https://github.com/ossrs/srs/issues/4449
1236+
stream_die_at_ = srs_time_now_cached();
12341237

12351238
stat_ = _srs_stat;
12361239
format_ = new SrsSrtFormat();

trunk/src/utest/srs_utest_ai07.cpp

Lines changed: 157 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@
88

99
#include <srs_app_circuit_breaker.hpp>
1010
#include <srs_app_rtc_source.hpp>
11+
#include <srs_app_rtmp_source.hpp>
12+
#include <srs_app_srt_source.hpp>
13+
#ifdef SRS_RTSP
14+
#include <srs_app_rtsp_source.hpp>
15+
#endif
1116
#include <srs_core_autofree.hpp>
1217
#include <srs_kernel_buffer.hpp>
1318
#include <srs_kernel_codec.hpp>
@@ -1790,7 +1795,6 @@ VOID TEST(AppTest2, RtcSourceManagerFetchOrCreateInitializeFailure)
17901795
mock_source->set_initialize_error(initialize_error_);
17911796
}
17921797
SrsSharedPtr<SrsRtcSource> source = SrsSharedPtr<SrsRtcSource>(mock_source);
1793-
srs_trace("new rtc source, stream_url=%s", stream_url.c_str());
17941798
pps = source;
17951799

17961800
pool_[stream_url] = source;
@@ -1870,7 +1874,6 @@ VOID TEST(AppTest2, RtcSourceManagerFetchOrCreateErrorWrapping)
18701874
srs_freep(init_error);
18711875

18721876
SrsSharedPtr<SrsRtcSource> source = SrsSharedPtr<SrsRtcSource>(mock_source);
1873-
srs_trace("new rtc source, stream_url=%s", stream_url.c_str());
18741877
pps = source;
18751878

18761879
pool_[stream_url] = source;
@@ -2176,14 +2179,16 @@ VOID TEST(AppTest2, RtcSourceOnConsumerDestroyStreamDeath)
21762179

21772180
// Verify initial state - stream is not created (no publisher)
21782181
EXPECT_FALSE(source->is_created_);
2179-
EXPECT_EQ(0, source->stream_die_at_);
2182+
// After fix #4449: stream_die_at_ is initialized to current time, not 0
2183+
srs_utime_t initial_die_at = source->stream_die_at_;
2184+
EXPECT_GT(initial_die_at, 0);
21802185

2181-
// Remove consumer when stream is not created - should set stream_die_at_
2186+
// Remove consumer when stream is not created - should update stream_die_at_
21822187
srs_utime_t before_time = srs_time_now_cached();
21832188
source->on_consumer_destroy(consumer);
21842189
srs_utime_t after_time = srs_time_now_cached();
21852190

2186-
// Verify stream death time was set
2191+
// Verify stream death time was updated to current time
21872192
EXPECT_TRUE(source->stream_die_at_ >= before_time);
21882193
EXPECT_TRUE(source->stream_die_at_ <= after_time);
21892194

@@ -2215,13 +2220,15 @@ VOID TEST(AppTest2, RtcSourceOnConsumerDestroyStreamAlive)
22152220

22162221
// Verify initial state
22172222
EXPECT_TRUE(source->is_created_);
2218-
EXPECT_EQ(0, source->stream_die_at_);
2223+
// After fix #4449: stream_die_at_ is initialized to current time, not 0
2224+
srs_utime_t initial_die_at = source->stream_die_at_;
2225+
EXPECT_GT(initial_die_at, 0);
22192226

2220-
// Remove consumer when stream is created - should NOT set stream_die_at_
2227+
// Remove consumer when stream is created - should NOT update stream_die_at_
22212228
source->on_consumer_destroy(consumer);
22222229

2223-
// Verify stream death time was NOT set
2224-
EXPECT_EQ(0, source->stream_die_at_);
2230+
// Verify stream death time was NOT changed (still has initial value)
2231+
EXPECT_EQ(initial_die_at, source->stream_die_at_);
22252232

22262233
// Clean up
22272234
srs_freep(consumer);
@@ -4598,3 +4605,144 @@ VOID TEST(AppTest2, RtcSourceGetTrackDescMultipleMatchingVideoTracks)
45984605
EXPECT_EQ("video-h264-track-2", all_video_tracks[1]->id_);
45994606
EXPECT_EQ("video-h265-track", all_video_tracks[2]->id_);
46004607
}
4608+
4609+
// Reproduce issue 4449: Newly created source is immediately considered dead
4610+
// When a new source is created with stream_die_at_=0, if notify() timer fires
4611+
// before a publisher connects, the source gets deleted because stream_is_dead()
4612+
// returns true. This causes "new live source, dead=1" in logs.
4613+
VOID TEST(ReproduceIssue4449, RtmpLiveSourceNotifyDeletesNewlyCreatedSource)
4614+
{
4615+
srs_error_t err;
4616+
4617+
// Create a source manager
4618+
SrsUniquePtr<SrsLiveSourceManager> manager(new SrsLiveSourceManager());
4619+
HELPER_EXPECT_SUCCESS(manager->initialize());
4620+
4621+
// Create a mock request
4622+
SrsUniquePtr<SrsRequest> req(new SrsRequest());
4623+
req->host_ = "localhost";
4624+
req->vhost_ = "test.vhost";
4625+
req->app_ = "live";
4626+
req->stream_ = "thegobot";
4627+
4628+
// Fetch or create source (this creates a new source)
4629+
SrsSharedPtr<SrsLiveSource> source;
4630+
HELPER_EXPECT_SUCCESS(manager->fetch_or_create(req.get(), source));
4631+
4632+
// After fix: newly created source should NOT be dead
4633+
EXPECT_FALSE(source->stream_is_dead());
4634+
EXPECT_EQ(1, (int)manager->pool_.size());
4635+
4636+
// Simulate timer firing - call notify()
4637+
int pool_size_before = (int)manager->pool_.size();
4638+
HELPER_EXPECT_SUCCESS(manager->notify(0, 0, 0));
4639+
int pool_size_after = (int)manager->pool_.size();
4640+
4641+
// After fix: the newly created source should NOT be deleted by notify
4642+
EXPECT_EQ(pool_size_before, pool_size_after);
4643+
EXPECT_EQ(1, pool_size_after);
4644+
}
4645+
4646+
// Test SRT source for the same issue
4647+
VOID TEST(ReproduceIssue4449, SrtSourceNotifyDeletesNewlyCreatedSource)
4648+
{
4649+
srs_error_t err;
4650+
4651+
// Create a SRT source manager
4652+
SrsUniquePtr<SrsSrtSourceManager> manager(new SrsSrtSourceManager());
4653+
HELPER_EXPECT_SUCCESS(manager->initialize());
4654+
4655+
// Create a mock request
4656+
SrsUniquePtr<SrsRequest> req(new SrsRequest());
4657+
req->host_ = "localhost";
4658+
req->vhost_ = "test.vhost";
4659+
req->app_ = "live";
4660+
req->stream_ = "thegobot";
4661+
4662+
// Fetch or create source (this creates a new source)
4663+
SrsSharedPtr<SrsSrtSource> source;
4664+
HELPER_EXPECT_SUCCESS(manager->fetch_or_create(req.get(), source));
4665+
4666+
// After fix: newly created source should NOT be dead
4667+
EXPECT_FALSE(source->stream_is_dead());
4668+
EXPECT_EQ(1, (int)manager->pool_.size());
4669+
4670+
// Simulate timer firing - call notify()
4671+
int pool_size_before = (int)manager->pool_.size();
4672+
HELPER_EXPECT_SUCCESS(manager->notify(0, 0, 0));
4673+
int pool_size_after = (int)manager->pool_.size();
4674+
4675+
// After fix: the newly created source should NOT be deleted by notify
4676+
EXPECT_EQ(pool_size_before, pool_size_after);
4677+
EXPECT_EQ(1, pool_size_after);
4678+
}
4679+
4680+
// Test RTC source for the same issue
4681+
VOID TEST(ReproduceIssue4449, RtcSourceNotifyDeletesNewlyCreatedSource)
4682+
{
4683+
srs_error_t err;
4684+
4685+
// Create a RTC source manager
4686+
SrsUniquePtr<SrsRtcSourceManager> manager(new SrsRtcSourceManager());
4687+
HELPER_EXPECT_SUCCESS(manager->initialize());
4688+
4689+
// Create a mock request
4690+
SrsUniquePtr<SrsRequest> req(new SrsRequest());
4691+
req->host_ = "localhost";
4692+
req->vhost_ = "test.vhost";
4693+
req->app_ = "live";
4694+
req->stream_ = "thegobot";
4695+
4696+
// Fetch or create source (this creates a new source)
4697+
SrsSharedPtr<SrsRtcSource> source;
4698+
HELPER_EXPECT_SUCCESS(manager->fetch_or_create(req.get(), source));
4699+
4700+
// After fix: newly created source should NOT be dead
4701+
EXPECT_FALSE(source->stream_is_dead());
4702+
EXPECT_EQ(1, (int)manager->pool_.size());
4703+
4704+
// Simulate timer firing - call notify()
4705+
int pool_size_before = (int)manager->pool_.size();
4706+
HELPER_EXPECT_SUCCESS(manager->notify(0, 0, 0));
4707+
int pool_size_after = (int)manager->pool_.size();
4708+
4709+
// After fix: the newly created source should NOT be deleted by notify
4710+
EXPECT_EQ(pool_size_before, pool_size_after);
4711+
EXPECT_EQ(1, pool_size_after);
4712+
}
4713+
4714+
#ifdef SRS_RTSP
4715+
// Test RTSP source for the same issue
4716+
VOID TEST(ReproduceIssue4449, RtspSourceNotifyDeletesNewlyCreatedSource)
4717+
{
4718+
srs_error_t err;
4719+
4720+
// Create a RTSP source manager
4721+
SrsUniquePtr<SrsRtspSourceManager> manager(new SrsRtspSourceManager());
4722+
HELPER_EXPECT_SUCCESS(manager->initialize());
4723+
4724+
// Create a mock request
4725+
SrsUniquePtr<SrsRequest> req(new SrsRequest());
4726+
req->host_ = "localhost";
4727+
req->vhost_ = "test.vhost";
4728+
req->app_ = "live";
4729+
req->stream_ = "thegobot";
4730+
4731+
// Fetch or create source (this creates a new source)
4732+
SrsSharedPtr<SrsRtspSource> source;
4733+
HELPER_EXPECT_SUCCESS(manager->fetch_or_create(req.get(), source));
4734+
4735+
// After fix: newly created source should NOT be dead
4736+
EXPECT_FALSE(source->stream_is_dead());
4737+
EXPECT_EQ(1, (int)manager->pool_.size());
4738+
4739+
// Simulate timer firing - call notify()
4740+
int pool_size_before = (int)manager->pool_.size();
4741+
HELPER_EXPECT_SUCCESS(manager->notify(0, 0, 0));
4742+
int pool_size_after = (int)manager->pool_.size();
4743+
4744+
// After fix: the newly created source should NOT be deleted by notify
4745+
EXPECT_EQ(pool_size_before, pool_size_after);
4746+
EXPECT_EQ(1, pool_size_after);
4747+
}
4748+
#endif

0 commit comments

Comments
 (0)