Fix WHIP with transcoding bug. v7.0.92 (#4495)

This commit is contained in:
winlin 2025-09-21 08:52:18 -04:00
parent ca261fe955
commit 10c0b66c0f
12 changed files with 71 additions and 48 deletions

View File

@ -7,6 +7,7 @@ The changelog for SRS.
<a name="v7-changes"></a> <a name="v7-changes"></a>
## SRS 7.0 Changelog ## 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-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-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) * v7.0, 2025-09-15, RTC2RTMP: Fix sequence number wraparound assertion crashes. v7.0.89 (#4491)
@ -105,6 +106,7 @@ The changelog for SRS.
<a name="v6-changes"></a> <a name="v6-changes"></a>
## SRS 6.0 Changelog ## 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-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-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) * 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)

View File

@ -1869,6 +1869,9 @@ SrsRtcConnection::~SrsRtcConnection()
srs_freep(req_); srs_freep(req_);
srs_freep(pli_epp_); srs_freep(pli_epp_);
// Optional to release the publisher token.
publish_token_ = NULL;
} }
void SrsRtcConnection::on_before_dispose(ISrsResource *c) void SrsRtcConnection::on_before_dispose(ISrsResource *c)
@ -1931,6 +1934,11 @@ string SrsRtcConnection::token()
return token_; return token_;
} }
void SrsRtcConnection::set_publish_token(SrsSharedPtr<SrsStreamPublishToken> publish_token)
{
publish_token_ = publish_token;
}
ISrsKbpsDelta *SrsRtcConnection::delta() ISrsKbpsDelta *SrsRtcConnection::delta()
{ {
return networks_->delta(); return networks_->delta();

View File

@ -55,6 +55,7 @@ class SrsRtcNetworks;
class SrsRtcUdpNetwork; class SrsRtcUdpNetwork;
class ISrsRtcNetwork; class ISrsRtcNetwork;
class SrsRtcTcpNetwork; class SrsRtcTcpNetwork;
class SrsStreamPublishToken;
const uint8_t kSR = 200; const uint8_t kSR = 200;
const uint8_t kRR = 201; const uint8_t kRR = 201;
@ -529,6 +530,7 @@ private:
ISrsRequest *req_; ISrsRequest *req_;
SrsSdp remote_sdp_; SrsSdp remote_sdp_;
SrsSdp local_sdp_; SrsSdp local_sdp_;
SrsSharedPtr<SrsStreamPublishToken> publish_token_;
private: private:
// twcc handler // twcc handler
@ -561,6 +563,8 @@ public:
std::string username(); std::string username();
// Get the token for verify this session, for example, when delete session by WHIP API. // Get the token for verify this session, for example, when delete session by WHIP API.
std::string token(); std::string token();
// Set the publish token for this session if publisher.
void set_publish_token(SrsSharedPtr<SrsStreamPublishToken> publish_token);
public: public:
virtual ISrsKbpsDelta *delta(); virtual ISrsKbpsDelta *delta();

View File

@ -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) { 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"); return srs_error_wrap(err, "acquire stream publish token");
} }
SrsUniquePtr<SrsStreamPublishToken> publish_token(publish_token_raw); SrsSharedPtr<SrsStreamPublishToken> publish_token(publish_token_raw);
if (publish_token.get()) { if (publish_token.get()) {
srs_trace("stream publish token acquired, type=rtc, url=%s", req->get_stream_url().c_str()); 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"); return srs_error_wrap(err, "create session");
} }
// Update publish token for publisher.
if (ruc->publish_) {
session->set_publish_token(publish_token);
}
*psession = session; *psession = session;
return err; return err;

View File

@ -715,9 +715,6 @@ void SrsRtcSource::on_unpublish()
srs_trace("cleanup when unpublish, created=%u, deliver=%u", is_created_, is_delivering_packets_); 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()) { if (!_source_id.empty()) {
_pre_source_id = _source_id; _pre_source_id = _source_id;
} }
@ -744,16 +741,20 @@ void SrsRtcSource::on_unpublish()
if (consumers_.empty()) { if (consumers_.empty()) {
stream_die_at_ = srs_time_now_cached(); 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()) { if (std::find(event_handlers_.begin(), event_handlers_.end(), h) == event_handlers_.end()) {
event_handlers_.push_back(h); event_handlers_.push_back(h);
} }
} }
void SrsRtcSource::unsubscribe(ISrsRtcSourceEventHandler *h) void SrsRtcSource::rtc_source_unsubscribe(ISrsRtcSourceEventHandler *h)
{ {
std::vector<ISrsRtcSourceEventHandler *>::iterator it; std::vector<ISrsRtcSourceEventHandler *>::iterator it;
it = std::find(event_handlers_.begin(), event_handlers_.end(), h); it = std::find(event_handlers_.begin(), event_handlers_.end(), h);

View File

@ -310,8 +310,8 @@ public:
public: public:
// For event handler // For event handler
virtual void subscribe(ISrsRtcSourceEventHandler *h); virtual void rtc_source_subscribe(ISrsRtcSourceEventHandler *h);
virtual void unsubscribe(ISrsRtcSourceEventHandler *h); virtual void rtc_source_unsubscribe(ISrsRtcSourceEventHandler *h);
public: public:
// Get and set the publisher, passed to consumer to process requests such as PLI. // Get and set the publisher, passed to consumer to process requests such as PLI.

View File

@ -444,9 +444,6 @@ void SrsRtspSource::on_unpublish()
srs_trace("cleanup when unpublish, created=%u, deliver=%u", is_created_, is_delivering_packets_); 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()) { if (!_source_id.empty()) {
_pre_source_id = _source_id; _pre_source_id = _source_id;
} }
@ -459,6 +456,10 @@ void SrsRtspSource::on_unpublish()
if (consumers_.empty()) { if (consumers_.empty()) {
stream_die_at_ = srs_time_now_cached(); 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) srs_error_t SrsRtspSource::on_rtp(SrsRtpPacket *pkt)

View File

@ -1085,8 +1085,6 @@ void SrsSrtSource::on_unpublish()
return; return;
} }
can_publish_ = true;
SrsStatistic *stat = SrsStatistic::instance(); SrsStatistic *stat = SrsStatistic::instance();
stat->on_stream_close(req_); stat->on_stream_close(req_);
@ -1099,6 +1097,9 @@ void SrsSrtSource::on_unpublish()
if (consumers_.empty()) { if (consumers_.empty()) {
stream_die_at_ = srs_time_now_cached(); 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) srs_error_t SrsSrtSource::on_packet(SrsSrtPacket *packet)

View File

@ -185,6 +185,7 @@ void SrsFastCoroutine::stop()
} }
disposed_ = true; disposed_ = true;
stopping_ = true; stopping_ = true;
stopping_cid_ = _srs_context->get_id();
interrupt(); interrupt();

View File

@ -9,6 +9,6 @@
#define VERSION_MAJOR 6 #define VERSION_MAJOR 6
#define VERSION_MINOR 0 #define VERSION_MINOR 0
#define VERSION_REVISION 177 #define VERSION_REVISION 179
#endif #endif

View File

@ -9,6 +9,6 @@
#define VERSION_MAJOR 7 #define VERSION_MAJOR 7
#define VERSION_MINOR 0 #define VERSION_MINOR 0
#define VERSION_REVISION 91 #define VERSION_REVISION 92
#endif #endif

View File

@ -1575,8 +1575,8 @@ VOID TEST(AppTest2, RtcSourceOnConsumerDestroyNotifyEventHandlers)
// Set up source with publish stream and event handlers // Set up source with publish stream and event handlers
source->set_publish_stream(publish_stream); source->set_publish_stream(publish_stream);
source->subscribe(handler1); source->rtc_source_subscribe(handler1);
source->subscribe(handler2); source->rtc_source_subscribe(handler2);
// Create mock consumers // Create mock consumers
MockRtcConsumer *consumer1 = new MockRtcConsumer(); MockRtcConsumer *consumer1 = new MockRtcConsumer();
@ -1625,7 +1625,7 @@ VOID TEST(AppTest2, RtcSourceOnConsumerDestroyNoPublishStream)
// Create mock event handler // Create mock event handler
MockRtcSourceEventHandler *handler = new MockRtcSourceEventHandler(); MockRtcSourceEventHandler *handler = new MockRtcSourceEventHandler();
source->subscribe(handler); source->rtc_source_subscribe(handler);
// Create mock consumer // Create mock consumer
MockRtcConsumer *consumer = new MockRtcConsumer(); MockRtcConsumer *consumer = new MockRtcConsumer();
@ -1961,12 +1961,12 @@ VOID TEST(AppTest2, RtcSourceSubscribeBasic)
EXPECT_EQ(0, (int)source->event_handlers_.size()); EXPECT_EQ(0, (int)source->event_handlers_.size());
// Subscribe first handler // Subscribe first handler
source->subscribe(handler1.get()); source->rtc_source_subscribe(handler1.get());
EXPECT_EQ(1, (int)source->event_handlers_.size()); EXPECT_EQ(1, (int)source->event_handlers_.size());
EXPECT_EQ(handler1.get(), source->event_handlers_[0]); EXPECT_EQ(handler1.get(), source->event_handlers_[0]);
// Subscribe second handler // Subscribe second handler
source->subscribe(handler2.get()); source->rtc_source_subscribe(handler2.get());
EXPECT_EQ(2, (int)source->event_handlers_.size()); EXPECT_EQ(2, (int)source->event_handlers_.size());
EXPECT_EQ(handler1.get(), source->event_handlers_[0]); EXPECT_EQ(handler1.get(), source->event_handlers_[0]);
EXPECT_EQ(handler2.get(), source->event_handlers_[1]); EXPECT_EQ(handler2.get(), source->event_handlers_[1]);
@ -1991,18 +1991,18 @@ VOID TEST(AppTest2, RtcSourceSubscribeDuplicateHandler)
SrsUniquePtr<MockRtcSourceEventHandler> handler(new MockRtcSourceEventHandler()); SrsUniquePtr<MockRtcSourceEventHandler> handler(new MockRtcSourceEventHandler());
// Subscribe handler first time // Subscribe handler first time
source->subscribe(handler.get()); source->rtc_source_subscribe(handler.get());
EXPECT_EQ(1, (int)source->event_handlers_.size()); EXPECT_EQ(1, (int)source->event_handlers_.size());
EXPECT_EQ(handler.get(), source->event_handlers_[0]); EXPECT_EQ(handler.get(), source->event_handlers_[0]);
// Subscribe same handler again - should not add duplicate // 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(1, (int)source->event_handlers_.size());
EXPECT_EQ(handler.get(), source->event_handlers_[0]); EXPECT_EQ(handler.get(), source->event_handlers_[0]);
// Subscribe same handler multiple times - should still be only one // Subscribe same handler multiple times - should still be only one
source->subscribe(handler.get()); source->rtc_source_subscribe(handler.get());
source->subscribe(handler.get()); source->rtc_source_subscribe(handler.get());
EXPECT_EQ(1, (int)source->event_handlers_.size()); EXPECT_EQ(1, (int)source->event_handlers_.size());
EXPECT_EQ(handler.get(), source->event_handlers_[0]); EXPECT_EQ(handler.get(), source->event_handlers_[0]);
} }
@ -2026,12 +2026,12 @@ VOID TEST(AppTest2, RtcSourceSubscribeNullHandler)
EXPECT_EQ(0, (int)source->event_handlers_.size()); EXPECT_EQ(0, (int)source->event_handlers_.size());
// Subscribe null handler - should add it (implementation allows null) // 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(1, (int)source->event_handlers_.size());
EXPECT_EQ(NULL, source->event_handlers_[0]); EXPECT_EQ(NULL, source->event_handlers_[0]);
// Subscribe null handler again - should not add duplicate // 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(1, (int)source->event_handlers_.size());
EXPECT_EQ(NULL, source->event_handlers_[0]); EXPECT_EQ(NULL, source->event_handlers_[0]);
} }
@ -2060,9 +2060,9 @@ VOID TEST(AppTest2, RtcSourceSubscribeMultipleHandlers)
EXPECT_EQ(0, (int)source->event_handlers_.size()); EXPECT_EQ(0, (int)source->event_handlers_.size());
// Subscribe handlers in order // Subscribe handlers in order
source->subscribe(handler1.get()); source->rtc_source_subscribe(handler1.get());
source->subscribe(handler2.get()); source->rtc_source_subscribe(handler2.get());
source->subscribe(handler3.get()); source->rtc_source_subscribe(handler3.get());
// Verify all handlers are subscribed in correct order // Verify all handlers are subscribed in correct order
EXPECT_EQ(3, (int)source->event_handlers_.size()); EXPECT_EQ(3, (int)source->event_handlers_.size());
@ -2071,8 +2071,8 @@ VOID TEST(AppTest2, RtcSourceSubscribeMultipleHandlers)
EXPECT_EQ(handler3.get(), source->event_handlers_[2]); EXPECT_EQ(handler3.get(), source->event_handlers_[2]);
// Try to subscribe duplicates - should not change the list // Try to subscribe duplicates - should not change the list
source->subscribe(handler2.get()); source->rtc_source_subscribe(handler2.get());
source->subscribe(handler1.get()); source->rtc_source_subscribe(handler1.get());
EXPECT_EQ(3, (int)source->event_handlers_.size()); EXPECT_EQ(3, (int)source->event_handlers_.size());
EXPECT_EQ(handler1.get(), source->event_handlers_[0]); EXPECT_EQ(handler1.get(), source->event_handlers_[0]);
EXPECT_EQ(handler2.get(), source->event_handlers_[1]); EXPECT_EQ(handler2.get(), source->event_handlers_[1]);
@ -2099,29 +2099,29 @@ VOID TEST(AppTest2, RtcSourceSubscribeUnsubscribeInteraction)
SrsUniquePtr<MockRtcSourceEventHandler> handler2(new MockRtcSourceEventHandler()); SrsUniquePtr<MockRtcSourceEventHandler> handler2(new MockRtcSourceEventHandler());
// Subscribe both handlers // Subscribe both handlers
source->subscribe(handler1.get()); source->rtc_source_subscribe(handler1.get());
source->subscribe(handler2.get()); source->rtc_source_subscribe(handler2.get());
EXPECT_EQ(2, (int)source->event_handlers_.size()); EXPECT_EQ(2, (int)source->event_handlers_.size());
// Unsubscribe first handler // Unsubscribe first handler
source->unsubscribe(handler1.get()); source->rtc_source_unsubscribe(handler1.get());
EXPECT_EQ(1, (int)source->event_handlers_.size()); EXPECT_EQ(1, (int)source->event_handlers_.size());
EXPECT_EQ(handler2.get(), source->event_handlers_[0]); EXPECT_EQ(handler2.get(), source->event_handlers_[0]);
// Re-subscribe first handler - should be added back // 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(2, (int)source->event_handlers_.size());
EXPECT_EQ(handler2.get(), source->event_handlers_[0]); EXPECT_EQ(handler2.get(), source->event_handlers_[0]);
EXPECT_EQ(handler1.get(), source->event_handlers_[1]); EXPECT_EQ(handler1.get(), source->event_handlers_[1]);
// Unsubscribe all handlers // Unsubscribe all handlers
source->unsubscribe(handler1.get()); source->rtc_source_unsubscribe(handler1.get());
source->unsubscribe(handler2.get()); source->rtc_source_unsubscribe(handler2.get());
EXPECT_EQ(0, (int)source->event_handlers_.size()); EXPECT_EQ(0, (int)source->event_handlers_.size());
// Re-subscribe in different order // Re-subscribe in different order
source->subscribe(handler2.get()); source->rtc_source_subscribe(handler2.get());
source->subscribe(handler1.get()); source->rtc_source_subscribe(handler1.get());
EXPECT_EQ(2, (int)source->event_handlers_.size()); EXPECT_EQ(2, (int)source->event_handlers_.size());
EXPECT_EQ(handler2.get(), source->event_handlers_[0]); EXPECT_EQ(handler2.get(), source->event_handlers_[0]);
EXPECT_EQ(handler1.get(), source->event_handlers_[1]); EXPECT_EQ(handler1.get(), source->event_handlers_[1]);
@ -2147,8 +2147,8 @@ VOID TEST(AppTest2, RtcSourceSubscribeEventNotification)
SrsUniquePtr<MockRtcSourceEventHandler> handler2(new MockRtcSourceEventHandler()); SrsUniquePtr<MockRtcSourceEventHandler> handler2(new MockRtcSourceEventHandler());
// Subscribe handlers // Subscribe handlers
source->subscribe(handler1.get()); source->rtc_source_subscribe(handler1.get());
source->subscribe(handler2.get()); source->rtc_source_subscribe(handler2.get());
// Verify initial state // Verify initial state
EXPECT_EQ(0, handler1->on_unpublish_count_); EXPECT_EQ(0, handler1->on_unpublish_count_);
@ -2174,11 +2174,11 @@ VOID TEST(AppTest2, RtcSourceSubscribeEventNotification)
handler2->on_unpublish_count_ = 0; handler2->on_unpublish_count_ = 0;
// Subscribe both handlers to the new source // Subscribe both handlers to the new source
source2->subscribe(handler1.get()); source2->rtc_source_subscribe(handler1.get());
source2->subscribe(handler2.get()); source2->rtc_source_subscribe(handler2.get());
// Unsubscribe handler1 // Unsubscribe handler1
source2->unsubscribe(handler1.get()); source2->rtc_source_unsubscribe(handler1.get());
// Verify only handler2 is subscribed now // Verify only handler2 is subscribed now
EXPECT_EQ(1, (int)source2->event_handlers_.size()); EXPECT_EQ(1, (int)source2->event_handlers_.size());
@ -2255,7 +2255,7 @@ VOID TEST(AppTest2, RtcSourcePublishStreamWithConsumerDestroy)
// Create a mock event handler // Create a mock event handler
SrsUniquePtr<MockRtcSourceEventHandler> handler(new MockRtcSourceEventHandler()); SrsUniquePtr<MockRtcSourceEventHandler> handler(new MockRtcSourceEventHandler());
source->subscribe(handler.get()); source->rtc_source_subscribe(handler.get());
// Create consumers // Create consumers
ISrsRtcConsumer *consumer1 = NULL; ISrsRtcConsumer *consumer1 = NULL;
@ -3204,8 +3204,8 @@ VOID TEST(AppTest2, RtcSourceSetStreamCreatedWithEventHandlers)
// Create and subscribe event handlers // Create and subscribe event handlers
SrsUniquePtr<MockRtcSourceEventHandler> handler1(new MockRtcSourceEventHandler()); SrsUniquePtr<MockRtcSourceEventHandler> handler1(new MockRtcSourceEventHandler());
SrsUniquePtr<MockRtcSourceEventHandler> handler2(new MockRtcSourceEventHandler()); SrsUniquePtr<MockRtcSourceEventHandler> handler2(new MockRtcSourceEventHandler());
source->subscribe(handler1.get()); source->rtc_source_subscribe(handler1.get());
source->subscribe(handler2.get()); source->rtc_source_subscribe(handler2.get());
// Verify initial state // Verify initial state
EXPECT_FALSE(source->is_created_); EXPECT_FALSE(source->is_created_);
@ -3242,7 +3242,7 @@ VOID TEST(AppTest2, RtcSourcePublishStreamWithoutConsumerDestroy)
// Create a mock event handler // Create a mock event handler
SrsUniquePtr<MockRtcSourceEventHandler> handler(new MockRtcSourceEventHandler()); SrsUniquePtr<MockRtcSourceEventHandler> handler(new MockRtcSourceEventHandler());
source->subscribe(handler.get()); source->rtc_source_subscribe(handler.get());
// Create and destroy consumer // Create and destroy consumer
ISrsRtcConsumer *consumer = NULL; ISrsRtcConsumer *consumer = NULL;