diff --git a/trunk/doc/CHANGELOG.md b/trunk/doc/CHANGELOG.md index d7d03da73..a1d216280 100644 --- a/trunk/doc/CHANGELOG.md +++ b/trunk/doc/CHANGELOG.md @@ -7,6 +7,7 @@ The changelog for SRS. ## SRS 7.0 Changelog +* 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-19, Merge [#4503](https://github.com/ossrs/srs/pull/4503): AI: Refine RTMP/SRT/RTC bridge. v7.0.90 (#4503) * v7.0, 2025-09-15, RTC2RTMP: Fix sequence number wraparound assertion crashes. v7.0.89 (#4491) @@ -105,6 +106,7 @@ The changelog for SRS. ## SRS 6.0 Changelog +* v6.0, 2025-09-21, Fix WHIP with transcoding bug. v6.0.179 (#4495) * v6.0, 2025-09-15, RTC2RTMP: Fix sequence number wraparound assertion crashes. v6.0.177 (#4491) * v6.0, 2025-09-05, RTX: Fix race condition for timer. v6.0.176 (#4470) (#4474) * v6.0, 2025-08-26, Merge [#4451](https://github.com/ossrs/srs/pull/4451): RTC: Fix null pointer crash in RTC2RTMP when start packet is missing. v6.0.175 (#4451) diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 50e361cb8..5e9cd561a 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -1869,6 +1869,9 @@ SrsRtcConnection::~SrsRtcConnection() srs_freep(req_); srs_freep(pli_epp_); + + // Optional to release the publisher token. + publish_token_ = NULL; } void SrsRtcConnection::on_before_dispose(ISrsResource *c) @@ -1931,6 +1934,11 @@ string SrsRtcConnection::token() return token_; } +void SrsRtcConnection::set_publish_token(SrsSharedPtr publish_token) +{ + publish_token_ = publish_token; +} + ISrsKbpsDelta *SrsRtcConnection::delta() { return networks_->delta(); diff --git a/trunk/src/app/srs_app_rtc_conn.hpp b/trunk/src/app/srs_app_rtc_conn.hpp index 1423fa625..e30ac76fa 100644 --- a/trunk/src/app/srs_app_rtc_conn.hpp +++ b/trunk/src/app/srs_app_rtc_conn.hpp @@ -55,6 +55,7 @@ class SrsRtcNetworks; class SrsRtcUdpNetwork; class ISrsRtcNetwork; class SrsRtcTcpNetwork; +class SrsStreamPublishToken; const uint8_t kSR = 200; const uint8_t kRR = 201; @@ -529,6 +530,7 @@ private: ISrsRequest *req_; SrsSdp remote_sdp_; SrsSdp local_sdp_; + SrsSharedPtr publish_token_; private: // twcc handler @@ -561,6 +563,8 @@ public: std::string username(); // Get the token for verify this session, for example, when delete session by WHIP API. std::string token(); + // Set the publish token for this session if publisher. + void set_publish_token(SrsSharedPtr publish_token); public: virtual ISrsKbpsDelta *delta(); diff --git a/trunk/src/app/srs_app_rtc_server.cpp b/trunk/src/app/srs_app_rtc_server.cpp index 6937d1fd7..f998f41e5 100644 --- a/trunk/src/app/srs_app_rtc_server.cpp +++ b/trunk/src/app/srs_app_rtc_server.cpp @@ -348,7 +348,7 @@ srs_error_t SrsRtcSessionManager::create_rtc_session(SrsRtcUserConfig *ruc, SrsS if (ruc->publish_ && (err = _srs_stream_publish_tokens->acquire_token(req, publish_token_raw)) != srs_success) { return srs_error_wrap(err, "acquire stream publish token"); } - SrsUniquePtr publish_token(publish_token_raw); + SrsSharedPtr publish_token(publish_token_raw); if (publish_token.get()) { srs_trace("stream publish token acquired, type=rtc, url=%s", req->get_stream_url().c_str()); } @@ -370,6 +370,11 @@ srs_error_t SrsRtcSessionManager::create_rtc_session(SrsRtcUserConfig *ruc, SrsS return srs_error_wrap(err, "create session"); } + // Update publish token for publisher. + if (ruc->publish_) { + session->set_publish_token(publish_token); + } + *psession = session; return err; diff --git a/trunk/src/app/srs_app_rtc_source.cpp b/trunk/src/app/srs_app_rtc_source.cpp index b84fee9e8..b89064db4 100644 --- a/trunk/src/app/srs_app_rtc_source.cpp +++ b/trunk/src/app/srs_app_rtc_source.cpp @@ -715,9 +715,6 @@ void SrsRtcSource::on_unpublish() srs_trace("cleanup when unpublish, created=%u, deliver=%u", is_created_, is_delivering_packets_); - is_created_ = false; - is_delivering_packets_ = false; - if (!_source_id.empty()) { _pre_source_id = _source_id; } @@ -744,16 +741,20 @@ void SrsRtcSource::on_unpublish() if (consumers_.empty()) { stream_die_at_ = srs_time_now_cached(); } + + // Should never change the final state before all cleanup is done. + is_created_ = false; + is_delivering_packets_ = false; } -void SrsRtcSource::subscribe(ISrsRtcSourceEventHandler *h) +void SrsRtcSource::rtc_source_subscribe(ISrsRtcSourceEventHandler *h) { if (std::find(event_handlers_.begin(), event_handlers_.end(), h) == event_handlers_.end()) { event_handlers_.push_back(h); } } -void SrsRtcSource::unsubscribe(ISrsRtcSourceEventHandler *h) +void SrsRtcSource::rtc_source_unsubscribe(ISrsRtcSourceEventHandler *h) { std::vector::iterator it; it = std::find(event_handlers_.begin(), event_handlers_.end(), h); diff --git a/trunk/src/app/srs_app_rtc_source.hpp b/trunk/src/app/srs_app_rtc_source.hpp index 1adcc5b18..609ce17c8 100644 --- a/trunk/src/app/srs_app_rtc_source.hpp +++ b/trunk/src/app/srs_app_rtc_source.hpp @@ -310,8 +310,8 @@ public: public: // For event handler - virtual void subscribe(ISrsRtcSourceEventHandler *h); - virtual void unsubscribe(ISrsRtcSourceEventHandler *h); + virtual void rtc_source_subscribe(ISrsRtcSourceEventHandler *h); + virtual void rtc_source_unsubscribe(ISrsRtcSourceEventHandler *h); public: // Get and set the publisher, passed to consumer to process requests such as PLI. diff --git a/trunk/src/app/srs_app_rtsp_source.cpp b/trunk/src/app/srs_app_rtsp_source.cpp index 01bf75578..8aee27514 100644 --- a/trunk/src/app/srs_app_rtsp_source.cpp +++ b/trunk/src/app/srs_app_rtsp_source.cpp @@ -444,9 +444,6 @@ void SrsRtspSource::on_unpublish() srs_trace("cleanup when unpublish, created=%u, deliver=%u", is_created_, is_delivering_packets_); - is_created_ = false; - is_delivering_packets_ = false; - if (!_source_id.empty()) { _pre_source_id = _source_id; } @@ -459,6 +456,10 @@ void SrsRtspSource::on_unpublish() if (consumers_.empty()) { stream_die_at_ = srs_time_now_cached(); } + + // Should never change the final state before all cleanup is done. + is_created_ = false; + is_delivering_packets_ = false; } srs_error_t SrsRtspSource::on_rtp(SrsRtpPacket *pkt) diff --git a/trunk/src/app/srs_app_srt_source.cpp b/trunk/src/app/srs_app_srt_source.cpp index 5a8e2f00e..2e5dd2b86 100644 --- a/trunk/src/app/srs_app_srt_source.cpp +++ b/trunk/src/app/srs_app_srt_source.cpp @@ -1085,8 +1085,6 @@ void SrsSrtSource::on_unpublish() return; } - can_publish_ = true; - SrsStatistic *stat = SrsStatistic::instance(); stat->on_stream_close(req_); @@ -1099,6 +1097,9 @@ void SrsSrtSource::on_unpublish() if (consumers_.empty()) { stream_die_at_ = srs_time_now_cached(); } + + // Should never change the final state before all cleanup is done. + can_publish_ = true; } srs_error_t SrsSrtSource::on_packet(SrsSrtPacket *packet) diff --git a/trunk/src/app/srs_app_st.cpp b/trunk/src/app/srs_app_st.cpp index bc9695fb5..2fa3a8f3c 100644 --- a/trunk/src/app/srs_app_st.cpp +++ b/trunk/src/app/srs_app_st.cpp @@ -185,6 +185,7 @@ void SrsFastCoroutine::stop() } disposed_ = true; stopping_ = true; + stopping_cid_ = _srs_context->get_id(); interrupt(); diff --git a/trunk/src/core/srs_core_version6.hpp b/trunk/src/core/srs_core_version6.hpp index a47cbcd67..2152ad512 100644 --- a/trunk/src/core/srs_core_version6.hpp +++ b/trunk/src/core/srs_core_version6.hpp @@ -9,6 +9,6 @@ #define VERSION_MAJOR 6 #define VERSION_MINOR 0 -#define VERSION_REVISION 177 +#define VERSION_REVISION 179 #endif diff --git a/trunk/src/core/srs_core_version7.hpp b/trunk/src/core/srs_core_version7.hpp index 13c13f3d6..1ad45ef8e 100644 --- a/trunk/src/core/srs_core_version7.hpp +++ b/trunk/src/core/srs_core_version7.hpp @@ -9,6 +9,6 @@ #define VERSION_MAJOR 7 #define VERSION_MINOR 0 -#define VERSION_REVISION 91 +#define VERSION_REVISION 92 #endif \ No newline at end of file diff --git a/trunk/src/utest/srs_utest_app2.cpp b/trunk/src/utest/srs_utest_app2.cpp index 661120778..41bcef5bf 100644 --- a/trunk/src/utest/srs_utest_app2.cpp +++ b/trunk/src/utest/srs_utest_app2.cpp @@ -1575,8 +1575,8 @@ VOID TEST(AppTest2, RtcSourceOnConsumerDestroyNotifyEventHandlers) // Set up source with publish stream and event handlers source->set_publish_stream(publish_stream); - source->subscribe(handler1); - source->subscribe(handler2); + source->rtc_source_subscribe(handler1); + source->rtc_source_subscribe(handler2); // Create mock consumers MockRtcConsumer *consumer1 = new MockRtcConsumer(); @@ -1625,7 +1625,7 @@ VOID TEST(AppTest2, RtcSourceOnConsumerDestroyNoPublishStream) // Create mock event handler MockRtcSourceEventHandler *handler = new MockRtcSourceEventHandler(); - source->subscribe(handler); + source->rtc_source_subscribe(handler); // Create mock consumer MockRtcConsumer *consumer = new MockRtcConsumer(); @@ -1961,12 +1961,12 @@ VOID TEST(AppTest2, RtcSourceSubscribeBasic) EXPECT_EQ(0, (int)source->event_handlers_.size()); // Subscribe first handler - source->subscribe(handler1.get()); + source->rtc_source_subscribe(handler1.get()); EXPECT_EQ(1, (int)source->event_handlers_.size()); EXPECT_EQ(handler1.get(), source->event_handlers_[0]); // Subscribe second handler - source->subscribe(handler2.get()); + source->rtc_source_subscribe(handler2.get()); EXPECT_EQ(2, (int)source->event_handlers_.size()); EXPECT_EQ(handler1.get(), source->event_handlers_[0]); EXPECT_EQ(handler2.get(), source->event_handlers_[1]); @@ -1991,18 +1991,18 @@ VOID TEST(AppTest2, RtcSourceSubscribeDuplicateHandler) SrsUniquePtr handler(new MockRtcSourceEventHandler()); // Subscribe handler first time - source->subscribe(handler.get()); + source->rtc_source_subscribe(handler.get()); EXPECT_EQ(1, (int)source->event_handlers_.size()); EXPECT_EQ(handler.get(), source->event_handlers_[0]); // Subscribe same handler again - should not add duplicate - source->subscribe(handler.get()); + source->rtc_source_subscribe(handler.get()); EXPECT_EQ(1, (int)source->event_handlers_.size()); EXPECT_EQ(handler.get(), source->event_handlers_[0]); // Subscribe same handler multiple times - should still be only one - source->subscribe(handler.get()); - source->subscribe(handler.get()); + source->rtc_source_subscribe(handler.get()); + source->rtc_source_subscribe(handler.get()); EXPECT_EQ(1, (int)source->event_handlers_.size()); EXPECT_EQ(handler.get(), source->event_handlers_[0]); } @@ -2026,12 +2026,12 @@ VOID TEST(AppTest2, RtcSourceSubscribeNullHandler) EXPECT_EQ(0, (int)source->event_handlers_.size()); // Subscribe null handler - should add it (implementation allows null) - source->subscribe(NULL); + source->rtc_source_subscribe(NULL); EXPECT_EQ(1, (int)source->event_handlers_.size()); EXPECT_EQ(NULL, source->event_handlers_[0]); // Subscribe null handler again - should not add duplicate - source->subscribe(NULL); + source->rtc_source_subscribe(NULL); EXPECT_EQ(1, (int)source->event_handlers_.size()); EXPECT_EQ(NULL, source->event_handlers_[0]); } @@ -2060,9 +2060,9 @@ VOID TEST(AppTest2, RtcSourceSubscribeMultipleHandlers) EXPECT_EQ(0, (int)source->event_handlers_.size()); // Subscribe handlers in order - source->subscribe(handler1.get()); - source->subscribe(handler2.get()); - source->subscribe(handler3.get()); + source->rtc_source_subscribe(handler1.get()); + source->rtc_source_subscribe(handler2.get()); + source->rtc_source_subscribe(handler3.get()); // Verify all handlers are subscribed in correct order EXPECT_EQ(3, (int)source->event_handlers_.size()); @@ -2071,8 +2071,8 @@ VOID TEST(AppTest2, RtcSourceSubscribeMultipleHandlers) EXPECT_EQ(handler3.get(), source->event_handlers_[2]); // Try to subscribe duplicates - should not change the list - source->subscribe(handler2.get()); - source->subscribe(handler1.get()); + source->rtc_source_subscribe(handler2.get()); + source->rtc_source_subscribe(handler1.get()); EXPECT_EQ(3, (int)source->event_handlers_.size()); EXPECT_EQ(handler1.get(), source->event_handlers_[0]); EXPECT_EQ(handler2.get(), source->event_handlers_[1]); @@ -2099,29 +2099,29 @@ VOID TEST(AppTest2, RtcSourceSubscribeUnsubscribeInteraction) SrsUniquePtr handler2(new MockRtcSourceEventHandler()); // Subscribe both handlers - source->subscribe(handler1.get()); - source->subscribe(handler2.get()); + source->rtc_source_subscribe(handler1.get()); + source->rtc_source_subscribe(handler2.get()); EXPECT_EQ(2, (int)source->event_handlers_.size()); // Unsubscribe first handler - source->unsubscribe(handler1.get()); + source->rtc_source_unsubscribe(handler1.get()); EXPECT_EQ(1, (int)source->event_handlers_.size()); EXPECT_EQ(handler2.get(), source->event_handlers_[0]); // Re-subscribe first handler - should be added back - source->subscribe(handler1.get()); + source->rtc_source_subscribe(handler1.get()); EXPECT_EQ(2, (int)source->event_handlers_.size()); EXPECT_EQ(handler2.get(), source->event_handlers_[0]); EXPECT_EQ(handler1.get(), source->event_handlers_[1]); // Unsubscribe all handlers - source->unsubscribe(handler1.get()); - source->unsubscribe(handler2.get()); + source->rtc_source_unsubscribe(handler1.get()); + source->rtc_source_unsubscribe(handler2.get()); EXPECT_EQ(0, (int)source->event_handlers_.size()); // Re-subscribe in different order - source->subscribe(handler2.get()); - source->subscribe(handler1.get()); + source->rtc_source_subscribe(handler2.get()); + source->rtc_source_subscribe(handler1.get()); EXPECT_EQ(2, (int)source->event_handlers_.size()); EXPECT_EQ(handler2.get(), source->event_handlers_[0]); EXPECT_EQ(handler1.get(), source->event_handlers_[1]); @@ -2147,8 +2147,8 @@ VOID TEST(AppTest2, RtcSourceSubscribeEventNotification) SrsUniquePtr handler2(new MockRtcSourceEventHandler()); // Subscribe handlers - source->subscribe(handler1.get()); - source->subscribe(handler2.get()); + source->rtc_source_subscribe(handler1.get()); + source->rtc_source_subscribe(handler2.get()); // Verify initial state EXPECT_EQ(0, handler1->on_unpublish_count_); @@ -2174,11 +2174,11 @@ VOID TEST(AppTest2, RtcSourceSubscribeEventNotification) handler2->on_unpublish_count_ = 0; // Subscribe both handlers to the new source - source2->subscribe(handler1.get()); - source2->subscribe(handler2.get()); + source2->rtc_source_subscribe(handler1.get()); + source2->rtc_source_subscribe(handler2.get()); // Unsubscribe handler1 - source2->unsubscribe(handler1.get()); + source2->rtc_source_unsubscribe(handler1.get()); // Verify only handler2 is subscribed now EXPECT_EQ(1, (int)source2->event_handlers_.size()); @@ -2255,7 +2255,7 @@ VOID TEST(AppTest2, RtcSourcePublishStreamWithConsumerDestroy) // Create a mock event handler SrsUniquePtr handler(new MockRtcSourceEventHandler()); - source->subscribe(handler.get()); + source->rtc_source_subscribe(handler.get()); // Create consumers ISrsRtcConsumer *consumer1 = NULL; @@ -3204,8 +3204,8 @@ VOID TEST(AppTest2, RtcSourceSetStreamCreatedWithEventHandlers) // Create and subscribe event handlers SrsUniquePtr handler1(new MockRtcSourceEventHandler()); SrsUniquePtr handler2(new MockRtcSourceEventHandler()); - source->subscribe(handler1.get()); - source->subscribe(handler2.get()); + source->rtc_source_subscribe(handler1.get()); + source->rtc_source_subscribe(handler2.get()); // Verify initial state EXPECT_FALSE(source->is_created_); @@ -3242,7 +3242,7 @@ VOID TEST(AppTest2, RtcSourcePublishStreamWithoutConsumerDestroy) // Create a mock event handler SrsUniquePtr handler(new MockRtcSourceEventHandler()); - source->subscribe(handler.get()); + source->rtc_source_subscribe(handler.get()); // Create and destroy consumer ISrsRtcConsumer *consumer = NULL;