Skip to content

Commit 18c30dc

Browse files
authored
AI: SRT: Fix player not exiting when publisher disconnects. v7.0.130 (#4591) (#4596)
When SRT publisher disconnects, player hangs indefinitely instead of exiting after the configured peer_idle_timeout. This is because the consumer wait() never checks if the publisher is still connected. After fix, player waits for peer_idle_timeout (default 10s) then exits gracefully when no packets arrive and publisher has disconnected.
1 parent 4101900 commit 18c30dc

11 files changed

+38
-14
lines changed

trunk/doc/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ The changelog for SRS.
77
<a name="v7-changes"></a>
88

99
## SRS 7.0 Changelog
10+
* v7.0, 2025-11-28, SRT: Fix player not exiting when publisher disconnects. v7.0.130 (#4591)
1011
* v7.0, 2025-11-27, Merge [#4588](https://github.com/ossrs/srs/pull/4588): RTMP: Ignore FMLE start packet after flash publish. v7.0.129 (#4588)
1112
* v7.0, 2025-11-18, AI: API: Change pagination default count to 10, minimum 1. v7.0.128
1213
* v7.0, 2025-11-14, AI: Fix race condition causing immediate deletion of new sources. v7.0.127 (#4449)

trunk/src/app/srs_app_config.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,8 @@ class ISrsAppConfig : public ISrsConfig
371371
public:
372372
// SRT config
373373
virtual std::vector<std::string> get_srt_listens() = 0;
374+
// Get the srt SRTO_PEERIDLETIMEO, peer idle timeout, default is 10000ms.
375+
virtual srs_utime_t get_srto_peeridletimeout() = 0;
374376

375377
public:
376378
// Stream caster config

trunk/src/app/srs_app_srt_conn.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,7 @@ srs_error_t SrsMpegtsSrtConn::do_playing()
619619
}
620620

621621
int nb_packets = 0;
622+
srs_utime_t timeout = config_->get_srto_peeridletimeout();
622623

623624
while (true) {
624625
// Check recv thread error first, so we can detect the client disconnecting event.
@@ -634,8 +635,13 @@ srs_error_t SrsMpegtsSrtConn::do_playing()
634635
SrsSrtPacket *pkt_raw = NULL;
635636
consumer->dump_packet(&pkt_raw);
636637
if (!pkt_raw) {
637-
// TODO: FIXME: We should check the quit event.
638-
consumer->wait(1, 1000 * SRS_UTIME_MILLISECONDS);
638+
// Wait for peer_idle_timeout. Note that enqueue() signals the cond, so we wake up
639+
// immediately when packets arrive during normal playback. Only check publisher disconnect
640+
// when no packets available after timeout. @see https://github.com/ossrs/srs/issues/4591
641+
bool has_msgs = consumer->wait(1, timeout);
642+
if (!has_msgs && srt_source_->can_publish()) {
643+
return srs_error_new(ERROR_SRT_SOURCE_DISCONNECTED, "srt source disconnected");
644+
}
639645
continue;
640646
}
641647

trunk/src/app/srs_app_srt_source.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -293,20 +293,23 @@ srs_error_t SrsSrtConsumer::dump_packet(SrsSrtPacket **ppkt)
293293
return err;
294294
}
295295

296-
void SrsSrtConsumer::wait(int nb_msgs, srs_utime_t timeout)
296+
bool SrsSrtConsumer::wait(int nb_msgs, srs_utime_t timeout)
297297
{
298298
mw_min_msgs_ = nb_msgs;
299299

300-
// when duration ok, signal to flush.
301-
if ((int)queue_.size() > mw_min_msgs_) {
302-
return;
300+
// When duration ok, signal to flush.
301+
if ((int)queue_.size() >= mw_min_msgs_) {
302+
return true;
303303
}
304304

305-
// the enqueue will notify this cond.
305+
// The enqueue will notify this cond.
306306
mw_waiting_ = true;
307307

308-
// use cond block wait for high performance mode.
308+
// Use cond block wait for high performance mode.
309309
srs_cond_timedwait(mw_wait_, timeout);
310+
311+
// Return true if there are enough messages after wait.
312+
return (int)queue_.size() >= mw_min_msgs_;
310313
}
311314

312315
SrsSrtFrameBuilder::SrsSrtFrameBuilder(ISrsFrameTarget *target)

trunk/src/app/srs_app_srt_source.hpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,9 @@ class ISrsSrtConsumer
113113
public:
114114
virtual srs_error_t enqueue(SrsSrtPacket *packet) = 0;
115115
virtual srs_error_t dump_packet(SrsSrtPacket **ppkt) = 0;
116-
virtual void wait(int nb_msgs, srs_utime_t timeout) = 0;
116+
// Wait for at-least some messages incoming in queue.
117+
// @return true if there are enough messages, false if timeout.
118+
virtual bool wait(int nb_msgs, srs_utime_t timeout) = 0;
117119
};
118120

119121
// The SRT consumer, consume packets from SRT stream source.
@@ -146,7 +148,8 @@ class SrsSrtConsumer : public ISrsSrtConsumer
146148
// For SRT, we only got one packet, because there is not many packets in queue.
147149
virtual srs_error_t dump_packet(SrsSrtPacket **ppkt);
148150
// Wait for at-least some messages incoming in queue.
149-
virtual void wait(int nb_msgs, srs_utime_t timeout);
151+
// @return true if there are enough messages, false if timeout.
152+
virtual bool wait(int nb_msgs, srs_utime_t timeout);
150153
};
151154

152155
// The SRT format interface.
@@ -271,6 +274,8 @@ class ISrsSrtSource : public ISrsSrtTarget
271274
virtual SrsContextId source_id() = 0;
272275
virtual SrsContextId pre_source_id() = 0;
273276
virtual void on_consumer_destroy(ISrsSrtConsumer *consumer) = 0;
277+
// Whether we can publish stream to the source, return true if no publisher.
278+
virtual bool can_publish() = 0;
274279
};
275280

276281
// A SRT source is a stream, to publish and to play with.

trunk/src/core/srs_core_version7.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@
99

1010
#define VERSION_MAJOR 7
1111
#define VERSION_MINOR 0
12-
#define VERSION_REVISION 129
12+
#define VERSION_REVISION 130
1313

1414
#endif

trunk/src/kernel/srs_kernel_error.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,8 @@
397397
XX(ERROR_SRT_SOURCE_BUSY, 6007, "SrtStreamBusy", "SRT stream already exists or busy") \
398398
XX(ERROR_RTMP_TO_SRT, 6008, "SrtFromRtmp", "Covert RTMP to SRT failed") \
399399
XX(ERROR_SRT_STATS, 6009, "SrtStats", "SRT get statistic data failed") \
400-
XX(ERROR_SRT_TO_RTMP_EMPTY_SPS_PPS, 6010, "SrtToRtmpEmptySpsPps", "SRT to rtmp have empty sps or pps")
400+
XX(ERROR_SRT_TO_RTMP_EMPTY_SPS_PPS, 6010, "SrtToRtmpEmptySpsPps", "SRT to rtmp have empty sps or pps") \
401+
XX(ERROR_SRT_SOURCE_DISCONNECTED, 6011, "SrtSourceDisconnected", "SRT source publisher disconnected")
401402

402403
/**************************************************/
403404
/* For user-define error. */

trunk/src/utest/srs_utest_ai21.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1425,8 +1425,9 @@ srs_error_t MockSrtConsumer::dump_packet(SrsSrtPacket **ppkt)
14251425
return srs_success;
14261426
}
14271427

1428-
void MockSrtConsumer::wait(int nb_msgs, srs_utime_t timeout)
1428+
bool MockSrtConsumer::wait(int nb_msgs, srs_utime_t timeout)
14291429
{
1430+
return true;
14301431
}
14311432

14321433
void MockSrtConsumer::set_enqueue_error(srs_error_t err)

trunk/src/utest/srs_utest_ai21.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ class MockSrtConsumer : public ISrsSrtConsumer
107107
virtual ~MockSrtConsumer();
108108
virtual srs_error_t enqueue(SrsSrtPacket *packet);
109109
virtual srs_error_t dump_packet(SrsSrtPacket **ppkt);
110-
virtual void wait(int nb_msgs, srs_utime_t timeout);
110+
virtual bool wait(int nb_msgs, srs_utime_t timeout);
111111
void set_enqueue_error(srs_error_t err);
112112
void reset();
113113
};

trunk/src/utest/srs_utest_manual_mock.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,7 @@ class MockAppConfig : public ISrsAppConfig
534534
virtual bool get_srt_enabled(std::string vhost) { return srt_enabled_; }
535535
virtual std::string get_srt_default_streamid() { return "#!::r=live/livestream,m=request"; }
536536
virtual bool get_srt_to_rtmp(std::string vhost) { return srt_to_rtmp_; }
537+
virtual srs_utime_t get_srto_peeridletimeout() { return 10 * SRS_UTIME_SECONDS; }
537538
virtual bool get_rtc_to_rtmp(std::string vhost) { return rtc_to_rtmp_; }
538539
virtual srs_utime_t get_rtc_stun_timeout(std::string vhost) { return 30 * SRS_UTIME_SECONDS; }
539540
virtual bool get_rtc_stun_strict_check(std::string vhost) { return false; }

0 commit comments

Comments
 (0)