From 1b6f97bd2dc29a1c70e52774b9dc505bb9bec996 Mon Sep 17 00:00:00 2001 From: Winlin Date: Sat, 23 Aug 2025 07:36:41 -0600 Subject: [PATCH] Refine source lock to fix race condition in source managers. v7.0.61 (#4449) This PR fixes a critical race condition in SRS source managers where multiple coroutines could create duplicate sources for the same stream. - **Atomic source creation**: Source lookup, creation, and pool insertion now happen atomically within lock scope - **Consistent interface**: Standardize on `ISrsRequest*` interface throughout codebase - **Handler simplification**: Remove `ISrsLiveSourceHandler*` parameter, obtain from global server instance --------- Co-authored-by: OSSRS-AI --- trunk/configure | 2 +- trunk/doc/CHANGELOG.md | 1 + trunk/src/app/srs_app_caster_flv.hpp | 2 +- trunk/src/app/srs_app_config.cpp | 2 +- trunk/src/app/srs_app_config.hpp | 5 +- trunk/src/app/srs_app_coworkers.cpp | 18 +- trunk/src/app/srs_app_coworkers.hpp | 10 +- trunk/src/app/srs_app_dash.cpp | 12 +- trunk/src/app/srs_app_dash.hpp | 16 +- trunk/src/app/srs_app_dvr.cpp | 18 +- trunk/src/app/srs_app_dvr.hpp | 28 +- trunk/src/app/srs_app_edge.cpp | 20 +- trunk/src/app/srs_app_edge.hpp | 24 +- trunk/src/app/srs_app_encoder.cpp | 8 +- trunk/src/app/srs_app_encoder.hpp | 10 +- trunk/src/app/srs_app_forward.cpp | 2 +- trunk/src/app/srs_app_forward.hpp | 6 +- trunk/src/app/srs_app_hds.cpp | 6 +- trunk/src/app/srs_app_hds.hpp | 6 +- trunk/src/app/srs_app_hls.cpp | 18 +- trunk/src/app/srs_app_hls.hpp | 34 +- trunk/src/app/srs_app_http_api.hpp | 2 +- trunk/src/app/srs_app_http_conn.cpp | 12 +- trunk/src/app/srs_app_http_conn.hpp | 11 +- trunk/src/app/srs_app_http_hooks.cpp | 20 +- trunk/src/app/srs_app_http_hooks.hpp | 42 +- trunk/src/app/srs_app_http_static.cpp | 12 +- trunk/src/app/srs_app_http_static.hpp | 12 +- trunk/src/app/srs_app_http_stream.cpp | 22 +- trunk/src/app/srs_app_http_stream.hpp | 18 +- trunk/src/app/srs_app_mpegts_udp.hpp | 2 +- trunk/src/app/srs_app_ng_exec.cpp | 6 +- trunk/src/app/srs_app_ng_exec.hpp | 8 +- trunk/src/app/srs_app_recv_thread.cpp | 2 +- trunk/src/app/srs_app_recv_thread.hpp | 6 +- trunk/src/app/srs_app_rtc_api.cpp | 4 +- trunk/src/app/srs_app_rtc_api.hpp | 6 +- trunk/src/app/srs_app_rtc_conn.cpp | 28 +- trunk/src/app/srs_app_rtc_conn.hpp | 28 +- trunk/src/app/srs_app_rtc_dtls.hpp | 2 +- trunk/src/app/srs_app_rtc_server.cpp | 4 +- trunk/src/app/srs_app_rtc_server.hpp | 4 +- trunk/src/app/srs_app_rtc_source.cpp | 70 +- trunk/src/app/srs_app_rtc_source.hpp | 18 +- trunk/src/app/srs_app_rtmp_conn.cpp | 48 +- trunk/src/app/srs_app_rtmp_conn.hpp | 4 +- trunk/src/app/srs_app_rtsp_conn.cpp | 4 +- trunk/src/app/srs_app_rtsp_conn.hpp | 10 +- trunk/src/app/srs_app_rtsp_source.cpp | 68 +- trunk/src/app/srs_app_rtsp_source.hpp | 17 +- trunk/src/app/srs_app_security.cpp | 4 +- trunk/src/app/srs_app_security.hpp | 4 +- trunk/src/app/srs_app_server.cpp | 4 +- trunk/src/app/srs_app_server.hpp | 4 +- trunk/src/app/srs_app_source.cpp | 95 +- trunk/src/app/srs_app_source.hpp | 22 +- trunk/src/app/srs_app_srt_conn.cpp | 2 +- trunk/src/app/srs_app_srt_conn.hpp | 2 +- trunk/src/app/srs_app_srt_source.cpp | 84 +- trunk/src/app/srs_app_srt_source.hpp | 18 +- trunk/src/app/srs_app_srt_utility.cpp | 2 +- trunk/src/app/srs_app_srt_utility.hpp | 4 +- trunk/src/app/srs_app_statistic.cpp | 16 +- trunk/src/app/srs_app_statistic.hpp | 20 +- trunk/src/app/srs_app_stream_bridge.cpp | 8 +- trunk/src/app/srs_app_stream_bridge.hpp | 12 +- trunk/src/core/srs_core_version7.hpp | 2 +- trunk/src/main/srs_main_ingest_hls.cpp | 2 +- trunk/src/protocol/srs_protocol_http_conn.cpp | 4 +- trunk/src/protocol/srs_protocol_http_conn.hpp | 4 +- trunk/src/protocol/srs_protocol_rtmp_conn.hpp | 4 +- .../src/protocol/srs_protocol_rtmp_stack.cpp | 28 +- .../src/protocol/srs_protocol_rtmp_stack.hpp | 78 +- trunk/src/utest/srs_utest_rtmp.cpp | 4 +- trunk/src/utest/srs_utest_service.cpp | 8 +- trunk/src/utest/srs_utest_source_lock.cpp | 817 ++++++++++++++++++ trunk/src/utest/srs_utest_source_lock.hpp | 15 + 77 files changed, 1484 insertions(+), 521 deletions(-) create mode 100644 trunk/src/utest/srs_utest_source_lock.cpp create mode 100644 trunk/src/utest/srs_utest_source_lock.hpp diff --git a/trunk/configure b/trunk/configure index 9bd530793..596d68e0e 100755 --- a/trunk/configure +++ b/trunk/configure @@ -439,7 +439,7 @@ if [[ $SRS_UTEST == YES ]]; then "srs_utest_config" "srs_utest_rtmp" "srs_utest_http" "srs_utest_avc" "srs_utest_reload" "srs_utest_mp4" "srs_utest_service" "srs_utest_app" "srs_utest_rtc" "srs_utest_config2" "srs_utest_protocol" "srs_utest_protocol2" "srs_utest_kernel2" "srs_utest_protocol3" - "srs_utest_st" "srs_utest_rtc2" "srs_utest_rtc3" "srs_utest_fmp4") + "srs_utest_st" "srs_utest_rtc2" "srs_utest_rtc3" "srs_utest_fmp4" "srs_utest_source_lock") if [[ $SRS_SRT == YES ]]; then MODULE_FILES+=("srs_utest_srt") fi diff --git a/trunk/doc/CHANGELOG.md b/trunk/doc/CHANGELOG.md index 96dc15cdf..3133325e4 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-08-22, Merge [#4449](https://github.com/ossrs/srs/pull/4449): Refine source lock. v7.0.61 (#4449) * v7.0, 2025-08-21, Merge [#4447](https://github.com/ossrs/srs/pull/4447): AI: Always enable WebRTC and enforce C++98 compatibility. v7.0.60 (#4447) * v7.0, 2025-08-20, Merge [#4445](https://github.com/ossrs/srs/pull/4445): AI: Remove multi-threading support and change to single-thread architecture. v7.0.59 (#4445) * v7.0, 2025-08-19, Merge [#4444](https://github.com/ossrs/srs/pull/4444): AI: Refine hooks from static to instance functions. v7.0.58 (#4444) diff --git a/trunk/src/app/srs_app_caster_flv.hpp b/trunk/src/app/srs_app_caster_flv.hpp index 69785009e..65621a36b 100644 --- a/trunk/src/app/srs_app_caster_flv.hpp +++ b/trunk/src/app/srs_app_caster_flv.hpp @@ -16,7 +16,7 @@ class SrsConfDirective; class SrsHttpServeMux; class SrsRtmpClient; class SrsStSocket; -class SrsRequest; +class ISrsRequest; class SrsPithyPrint; class ISrsHttpResponseReader; class SrsFlvDecoder; diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index b0ba36b52..8518045bc 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -342,7 +342,7 @@ bool srs_stream_caster_is_gb28181(string caster) return caster == "gb28181"; } -bool srs_config_apply_filter(SrsConfDirective *dvr_apply, SrsRequest *req) +bool srs_config_apply_filter(SrsConfDirective *dvr_apply, ISrsRequest *req) { static bool DEFAULT = true; diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index c9a6d5042..83de76990 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -19,14 +19,13 @@ #include #include -class SrsRequest; +class ISrsRequest; class SrsFileWriter; class SrsJsonObject; class SrsJsonArray; class SrsJsonAny; class SrsConfig; -class SrsRequest; class SrsJsonArray; class SrsConfDirective; @@ -106,7 +105,7 @@ extern bool srs_stream_caster_is_udp(std::string caster); extern bool srs_stream_caster_is_flv(std::string caster); extern bool srs_stream_caster_is_gb28181(std::string caster); // Whether the dvr_apply active the stream specified by req. -extern bool srs_config_apply_filter(SrsConfDirective *dvr_apply, SrsRequest *req); +extern bool srs_config_apply_filter(SrsConfDirective *dvr_apply, ISrsRequest *req); // Convert bool in str to on/off extern std::string srs_config_bool2switch(std::string sbool); diff --git a/trunk/src/app/srs_app_coworkers.cpp b/trunk/src/app/srs_app_coworkers.cpp index 66e19a2da..a79f7217f 100644 --- a/trunk/src/app/srs_app_coworkers.cpp +++ b/trunk/src/app/srs_app_coworkers.cpp @@ -24,9 +24,9 @@ SrsCoWorkers::SrsCoWorkers() SrsCoWorkers::~SrsCoWorkers() { - map::iterator it; + map::iterator it; for (it = streams.begin(); it != streams.end(); ++it) { - SrsRequest *r = it->second; + ISrsRequest *r = it->second; srs_freep(r); } streams.clear(); @@ -42,7 +42,7 @@ SrsCoWorkers *SrsCoWorkers::instance() SrsJsonAny *SrsCoWorkers::dumps(string vhost, string coworker, string app, string stream) { - SrsRequest *r = find_stream_info(vhost, app, stream); + ISrsRequest *r = find_stream_info(vhost, app, stream); if (!r) { // TODO: FIXME: Find stream from our origin util return to the start point. return SrsJsonAny::null(); @@ -103,7 +103,7 @@ SrsJsonAny *SrsCoWorkers::dumps(string vhost, string coworker, string app, strin ->set("routers", routers); } -SrsRequest *SrsCoWorkers::find_stream_info(string vhost, string app, string stream) +ISrsRequest *SrsCoWorkers::find_stream_info(string vhost, string app, string stream) { // First, we should parse the vhost, if not exists, try default vhost instead. SrsConfDirective *conf = _srs_config->get_vhost(vhost, true); @@ -113,7 +113,7 @@ SrsRequest *SrsCoWorkers::find_stream_info(string vhost, string app, string stre // Get stream information from local cache. string url = srs_generate_stream_url(conf->arg0(), app, stream); - map::iterator it = streams.find(url); + map::iterator it = streams.find(url); if (it == streams.end()) { return NULL; } @@ -121,14 +121,14 @@ SrsRequest *SrsCoWorkers::find_stream_info(string vhost, string app, string stre return it->second; } -srs_error_t SrsCoWorkers::on_publish(SrsRequest *r) +srs_error_t SrsCoWorkers::on_publish(ISrsRequest *r) { srs_error_t err = srs_success; string url = r->get_stream_url(); // Delete the previous stream informations. - map::iterator it = streams.find(url); + map::iterator it = streams.find(url); if (it != streams.end()) { srs_freep(it->second); } @@ -139,11 +139,11 @@ srs_error_t SrsCoWorkers::on_publish(SrsRequest *r) return err; } -void SrsCoWorkers::on_unpublish(SrsRequest *r) +void SrsCoWorkers::on_unpublish(ISrsRequest *r) { string url = r->get_stream_url(); - map::iterator it = streams.find(url); + map::iterator it = streams.find(url); if (it != streams.end()) { srs_freep(it->second); streams.erase(it); diff --git a/trunk/src/app/srs_app_coworkers.hpp b/trunk/src/app/srs_app_coworkers.hpp index 1ddc9fd55..3bc2257e6 100644 --- a/trunk/src/app/srs_app_coworkers.hpp +++ b/trunk/src/app/srs_app_coworkers.hpp @@ -13,7 +13,7 @@ #include class SrsJsonAny; -class SrsRequest; +class ISrsRequest; class SrsLiveSource; // For origin cluster. @@ -23,7 +23,7 @@ private: static SrsCoWorkers *_instance; private: - std::map streams; + std::map streams; private: SrsCoWorkers(); @@ -36,11 +36,11 @@ public: virtual SrsJsonAny *dumps(std::string vhost, std::string coworker, std::string app, std::string stream); private: - virtual SrsRequest *find_stream_info(std::string vhost, std::string app, std::string stream); + virtual ISrsRequest *find_stream_info(std::string vhost, std::string app, std::string stream); public: - virtual srs_error_t on_publish(SrsRequest *r); - virtual void on_unpublish(SrsRequest *r); + virtual srs_error_t on_publish(ISrsRequest *r); + virtual void on_unpublish(ISrsRequest *r); }; #endif diff --git a/trunk/src/app/srs_app_dash.cpp b/trunk/src/app/srs_app_dash.cpp index 74e368117..9adc4405a 100644 --- a/trunk/src/app/srs_app_dash.cpp +++ b/trunk/src/app/srs_app_dash.cpp @@ -79,7 +79,7 @@ SrsFragmentedMp4::~SrsFragmentedMp4() srs_freep(fw); } -srs_error_t SrsFragmentedMp4::initialize(SrsRequest *r, bool video, int64_t time, SrsMpdWriter *mpd, uint32_t tid) +srs_error_t SrsFragmentedMp4::initialize(ISrsRequest *r, bool video, int64_t time, SrsMpdWriter *mpd, uint32_t tid) { srs_error_t err = srs_success; @@ -185,7 +185,7 @@ void SrsMpdWriter::dispose() } } -srs_error_t SrsMpdWriter::initialize(SrsRequest *r) +srs_error_t SrsMpdWriter::initialize(ISrsRequest *r) { req = r; return srs_success; @@ -193,7 +193,7 @@ srs_error_t SrsMpdWriter::initialize(SrsRequest *r) srs_error_t SrsMpdWriter::on_publish() { - SrsRequest *r = req; + ISrsRequest *r = req; fragment = _srs_config->get_dash_fragment(r->vhost); update_period = _srs_config->get_dash_update_period(r->vhost); @@ -394,7 +394,7 @@ void SrsDashController::dispose() srs_trace("gracefully dispose dash %s", req ? req->get_stream_url().c_str() : ""); } -srs_error_t SrsDashController::initialize(SrsRequest *r) +srs_error_t SrsDashController::initialize(ISrsRequest *r) { srs_error_t err = srs_success; @@ -411,7 +411,7 @@ srs_error_t SrsDashController::on_publish() { srs_error_t err = srs_success; - SrsRequest *r = req; + ISrsRequest *r = req; fragment = _srs_config->get_dash_fragment(r->vhost); home = _srs_config->get_dash_path(r->vhost); @@ -737,7 +737,7 @@ srs_utime_t SrsDash::cleanup_delay() return _srs_config->get_dash_dispose(req->vhost) * 1.1; } -srs_error_t SrsDash::initialize(SrsOriginHub *h, SrsRequest *r) +srs_error_t SrsDash::initialize(SrsOriginHub *h, ISrsRequest *r) { srs_error_t err = srs_success; diff --git a/trunk/src/app/srs_app_dash.hpp b/trunk/src/app/srs_app_dash.hpp index e44dd6412..4bcdecfe9 100644 --- a/trunk/src/app/srs_app_dash.hpp +++ b/trunk/src/app/srs_app_dash.hpp @@ -14,7 +14,7 @@ #include -class SrsRequest; +class ISrsRequest; class SrsOriginHub; class SrsSharedPtrMessage; class SrsFormat; @@ -52,7 +52,7 @@ public: public: // Initialize the fragment, create the home dir, open the file. - virtual srs_error_t initialize(SrsRequest *r, bool video, int64_t time, SrsMpdWriter *mpd, uint32_t tid); + virtual srs_error_t initialize(ISrsRequest *r, bool video, int64_t time, SrsMpdWriter *mpd, uint32_t tid); // Write media message to fragment. virtual srs_error_t write(SrsSharedPtrMessage *shared_msg, SrsFormat *format); // Reap the fragment, close the fd and rename tmp to official file. @@ -63,7 +63,7 @@ public: class SrsMpdWriter { private: - SrsRequest *req; + ISrsRequest *req; private: // The duration of fragment in srs_utime_t. @@ -97,7 +97,7 @@ public: virtual void dispose(); public: - virtual srs_error_t initialize(SrsRequest *r); + virtual srs_error_t initialize(ISrsRequest *r); virtual srs_error_t on_publish(); virtual void on_unpublish(); // Write MPD according to parsed format of stream. @@ -116,7 +116,7 @@ public: class SrsDashController { private: - SrsRequest *req; + ISrsRequest *req; SrsFormat *format_; SrsMpdWriter *mpd; @@ -151,7 +151,7 @@ public: virtual void dispose(); public: - virtual srs_error_t initialize(SrsRequest *r); + virtual srs_error_t initialize(ISrsRequest *r); virtual srs_error_t on_publish(); virtual void on_unpublish(); virtual srs_error_t on_audio(SrsSharedPtrMessage *shared_audio, SrsFormat *format); @@ -171,7 +171,7 @@ private: srs_utime_t last_update_time_; private: - SrsRequest *req; + ISrsRequest *req; SrsOriginHub *hub; SrsDashController *controller; @@ -186,7 +186,7 @@ public: public: // Initalize the encoder. - virtual srs_error_t initialize(SrsOriginHub *h, SrsRequest *r); + virtual srs_error_t initialize(SrsOriginHub *h, ISrsRequest *r); // When stream start publishing. virtual srs_error_t on_publish(); // When got an shared audio message. diff --git a/trunk/src/app/srs_app_dvr.cpp b/trunk/src/app/srs_app_dvr.cpp index dc5c7accd..647baab9b 100644 --- a/trunk/src/app/srs_app_dvr.cpp +++ b/trunk/src/app/srs_app_dvr.cpp @@ -51,7 +51,7 @@ SrsDvrSegmenter::~SrsDvrSegmenter() srs_freep(fs); } -srs_error_t SrsDvrSegmenter::initialize(SrsDvrPlan *p, SrsRequest *r) +srs_error_t SrsDvrSegmenter::initialize(SrsDvrPlan *p, ISrsRequest *r) { req = r; plan = p; @@ -517,7 +517,7 @@ srs_error_t SrsDvrMp4Segmenter::close_encoder() return err; } -SrsDvrAsyncCallOnDvr::SrsDvrAsyncCallOnDvr(SrsContextId c, SrsRequest *r, string p) +SrsDvrAsyncCallOnDvr::SrsDvrAsyncCallOnDvr(SrsContextId c, ISrsRequest *r, string p) { cid = c; req = r->copy(); @@ -581,7 +581,7 @@ SrsDvrPlan::~SrsDvrPlan() srs_freep(req); } -srs_error_t SrsDvrPlan::initialize(SrsOriginHub *h, SrsDvrSegmenter *s, SrsRequest *r) +srs_error_t SrsDvrPlan::initialize(SrsOriginHub *h, SrsDvrSegmenter *s, ISrsRequest *r) { srs_error_t err = srs_success; @@ -596,7 +596,7 @@ srs_error_t SrsDvrPlan::initialize(SrsOriginHub *h, SrsDvrSegmenter *s, SrsReque return err; } -srs_error_t SrsDvrPlan::on_publish(SrsRequest *r) +srs_error_t SrsDvrPlan::on_publish(ISrsRequest *r) { // @see https://github.com/ossrs/srs/issues/1613#issuecomment-960623359 srs_freep(req); @@ -689,7 +689,7 @@ SrsDvrSessionPlan::~SrsDvrSessionPlan() { } -srs_error_t SrsDvrSessionPlan::on_publish(SrsRequest *r) +srs_error_t SrsDvrSessionPlan::on_publish(ISrsRequest *r) { srs_error_t err = srs_success; @@ -751,7 +751,7 @@ SrsDvrSegmentPlan::~SrsDvrSegmentPlan() { } -srs_error_t SrsDvrSegmentPlan::initialize(SrsOriginHub *h, SrsDvrSegmenter *s, SrsRequest *r) +srs_error_t SrsDvrSegmentPlan::initialize(SrsOriginHub *h, SrsDvrSegmenter *s, ISrsRequest *r) { srs_error_t err = srs_success; @@ -766,7 +766,7 @@ srs_error_t SrsDvrSegmentPlan::initialize(SrsOriginHub *h, SrsDvrSegmenter *s, S return srs_success; } -srs_error_t SrsDvrSegmentPlan::on_publish(SrsRequest *r) +srs_error_t SrsDvrSegmentPlan::on_publish(ISrsRequest *r) { srs_error_t err = srs_success; @@ -932,7 +932,7 @@ SrsDvr::~SrsDvr() srs_freep(req); } -srs_error_t SrsDvr::initialize(SrsOriginHub *h, SrsRequest *r) +srs_error_t SrsDvr::initialize(SrsOriginHub *h, ISrsRequest *r) { srs_error_t err = srs_success; @@ -962,7 +962,7 @@ srs_error_t SrsDvr::initialize(SrsOriginHub *h, SrsRequest *r) return err; } -srs_error_t SrsDvr::on_publish(SrsRequest *r) +srs_error_t SrsDvr::on_publish(ISrsRequest *r) { srs_error_t err = srs_success; diff --git a/trunk/src/app/srs_app_dvr.hpp b/trunk/src/app/srs_app_dvr.hpp index 9575ea632..69edec222 100644 --- a/trunk/src/app/srs_app_dvr.hpp +++ b/trunk/src/app/srs_app_dvr.hpp @@ -14,7 +14,7 @@ class SrsLiveSource; class SrsOriginHub; -class SrsRequest; +class ISrsRequest; class SrsBuffer; class SrsRtmpJitter; class SrsSharedPtrMessage; @@ -44,7 +44,7 @@ protected: SrsFragment *fragment; private: - SrsRequest *req; + ISrsRequest *req; SrsDvrPlan *plan; private: @@ -57,7 +57,7 @@ public: public: // Initialize the segment. - virtual srs_error_t initialize(SrsDvrPlan *p, SrsRequest *r); + virtual srs_error_t initialize(SrsDvrPlan *p, ISrsRequest *r); // Get the current framgnet. virtual SrsFragment *current(); // Open new segment file. @@ -157,10 +157,10 @@ class SrsDvrAsyncCallOnDvr : public ISrsAsyncCallTask private: SrsContextId cid; std::string path; - SrsRequest *req; + ISrsRequest *req; public: - SrsDvrAsyncCallOnDvr(SrsContextId c, SrsRequest *r, std::string p); + SrsDvrAsyncCallOnDvr(SrsContextId c, ISrsRequest *r, std::string p); virtual ~SrsDvrAsyncCallOnDvr(); public: @@ -172,7 +172,7 @@ public: class SrsDvrPlan : public ISrsReloadHandler { public: - SrsRequest *req; + ISrsRequest *req; protected: SrsOriginHub *hub; @@ -184,8 +184,8 @@ public: virtual ~SrsDvrPlan(); public: - virtual srs_error_t initialize(SrsOriginHub *h, SrsDvrSegmenter *s, SrsRequest *r); - virtual srs_error_t on_publish(SrsRequest *r); + virtual srs_error_t initialize(SrsOriginHub *h, SrsDvrSegmenter *s, ISrsRequest *r); + virtual srs_error_t on_publish(ISrsRequest *r); virtual void on_unpublish(); virtual srs_error_t on_meta_data(SrsSharedPtrMessage *shared_metadata); virtual srs_error_t on_audio(SrsSharedPtrMessage *shared_audio, SrsFormat *format); @@ -207,7 +207,7 @@ public: virtual ~SrsDvrSessionPlan(); public: - virtual srs_error_t on_publish(SrsRequest *r); + virtual srs_error_t on_publish(ISrsRequest *r); virtual void on_unpublish(); }; @@ -226,8 +226,8 @@ public: virtual ~SrsDvrSegmentPlan(); public: - virtual srs_error_t initialize(SrsOriginHub *h, SrsDvrSegmenter *s, SrsRequest *r); - virtual srs_error_t on_publish(SrsRequest *r); + virtual srs_error_t initialize(SrsOriginHub *h, SrsDvrSegmenter *s, ISrsRequest *r); + virtual srs_error_t on_publish(ISrsRequest *r); virtual void on_unpublish(); virtual srs_error_t on_audio(SrsSharedPtrMessage *shared_audio, SrsFormat *format); virtual srs_error_t on_video(SrsSharedPtrMessage *shared_video, SrsFormat *format); @@ -245,7 +245,7 @@ class SrsDvr : public ISrsReloadHandler private: SrsOriginHub *hub; SrsDvrPlan *plan; - SrsRequest *req; + ISrsRequest *req; private: // whether the dvr is actived by filter, which is specified by dvr_apply. @@ -261,11 +261,11 @@ public: // initialize dvr, create dvr plan. // when system initialize(encoder publish at first time, or reload), // initialize the dvr will reinitialize the plan, the whole dvr framework. - virtual srs_error_t initialize(SrsOriginHub *h, SrsRequest *r); + virtual srs_error_t initialize(SrsOriginHub *h, ISrsRequest *r); // publish stream event, // when encoder start to publish RTMP stream. // @param fetch_sequence_header whether fetch sequence from source. - virtual srs_error_t on_publish(SrsRequest *r); + virtual srs_error_t on_publish(ISrsRequest *r); // the unpublish event., // when encoder stop(unpublish) to publish RTMP stream. virtual void on_unpublish(); diff --git a/trunk/src/app/srs_app_edge.cpp b/trunk/src/app/srs_app_edge.cpp index f08920807..c405f01c2 100644 --- a/trunk/src/app/srs_app_edge.cpp +++ b/trunk/src/app/srs_app_edge.cpp @@ -62,11 +62,11 @@ SrsEdgeRtmpUpstream::~SrsEdgeRtmpUpstream() close(); } -srs_error_t SrsEdgeRtmpUpstream::connect(SrsRequest *r, SrsLbRoundRobin *lb) +srs_error_t SrsEdgeRtmpUpstream::connect(ISrsRequest *r, SrsLbRoundRobin *lb) { srs_error_t err = srs_success; - SrsRequest *req = r; + ISrsRequest *req = r; std::string url; if (true) { @@ -178,10 +178,10 @@ SrsEdgeFlvUpstream::~SrsEdgeFlvUpstream() close(); } -srs_error_t SrsEdgeFlvUpstream::connect(SrsRequest *r, SrsLbRoundRobin *lb) +srs_error_t SrsEdgeFlvUpstream::connect(ISrsRequest *r, SrsLbRoundRobin *lb) { // Because we might modify the r, which cause retry fail, so we must copy it. - SrsRequest *cp = r->copy(); + ISrsRequest *cp = r->copy(); // Free the request when close upstream. srs_freep(req_); @@ -190,11 +190,11 @@ srs_error_t SrsEdgeFlvUpstream::connect(SrsRequest *r, SrsLbRoundRobin *lb) return do_connect(cp, lb, 0); } -srs_error_t SrsEdgeFlvUpstream::do_connect(SrsRequest *r, SrsLbRoundRobin *lb, int redirect_depth) +srs_error_t SrsEdgeFlvUpstream::do_connect(ISrsRequest *r, SrsLbRoundRobin *lb, int redirect_depth) { srs_error_t err = srs_success; - SrsRequest *req = r; + ISrsRequest *req = r; if (redirect_depth == 0) { SrsConfDirective *conf = _srs_config->get_vhost_edge_origin(req->vhost); @@ -417,7 +417,7 @@ SrsEdgeIngester::~SrsEdgeIngester() srs_freep(trd); } -srs_error_t SrsEdgeIngester::initialize(SrsSharedPtr s, SrsPlayEdge *e, SrsRequest *r) +srs_error_t SrsEdgeIngester::initialize(SrsSharedPtr s, SrsPlayEdge *e, ISrsRequest *r) { // Because source references to this object, so we should directly use the source ptr. source_ = s.get(); @@ -750,7 +750,7 @@ void SrsEdgeForwarder::set_queue_size(srs_utime_t queue_size) return queue->set_queue_size(queue_size); } -srs_error_t SrsEdgeForwarder::initialize(SrsSharedPtr s, SrsPublishEdge *e, SrsRequest *r) +srs_error_t SrsEdgeForwarder::initialize(SrsSharedPtr s, SrsPublishEdge *e, ISrsRequest *r) { // Because source references to this object, so we should directly use the source ptr. source_ = s.get(); @@ -965,7 +965,7 @@ SrsPlayEdge::~SrsPlayEdge() srs_freep(ingester); } -srs_error_t SrsPlayEdge::initialize(SrsSharedPtr source, SrsRequest *req) +srs_error_t SrsPlayEdge::initialize(SrsSharedPtr source, ISrsRequest *req) { srs_error_t err = srs_success; @@ -1058,7 +1058,7 @@ void SrsPublishEdge::set_queue_size(srs_utime_t queue_size) return forwarder->set_queue_size(queue_size); } -srs_error_t SrsPublishEdge::initialize(SrsSharedPtr source, SrsRequest *req) +srs_error_t SrsPublishEdge::initialize(SrsSharedPtr source, ISrsRequest *req) { srs_error_t err = srs_success; diff --git a/trunk/src/app/srs_app_edge.hpp b/trunk/src/app/srs_app_edge.hpp index 0ea205a1e..2f733f4b6 100644 --- a/trunk/src/app/srs_app_edge.hpp +++ b/trunk/src/app/srs_app_edge.hpp @@ -17,7 +17,7 @@ class SrsStSocket; class SrsRtmpServer; class SrsLiveSource; -class SrsRequest; +class ISrsRequest; class SrsPlayEdge; class SrsPublishEdge; class SrsRtmpClient; @@ -65,7 +65,7 @@ public: virtual ~SrsEdgeUpstream(); public: - virtual srs_error_t connect(SrsRequest *r, SrsLbRoundRobin *lb) = 0; + virtual srs_error_t connect(ISrsRequest *r, SrsLbRoundRobin *lb) = 0; virtual srs_error_t recv_message(SrsCommonMessage **pmsg) = 0; virtual srs_error_t decode_message(SrsCommonMessage *msg, SrsPacket **ppacket) = 0; virtual void close() = 0; @@ -95,7 +95,7 @@ public: virtual ~SrsEdgeRtmpUpstream(); public: - virtual srs_error_t connect(SrsRequest *r, SrsLbRoundRobin *lb); + virtual srs_error_t connect(ISrsRequest *r, SrsLbRoundRobin *lb); virtual srs_error_t recv_message(SrsCommonMessage **pmsg); virtual srs_error_t decode_message(SrsCommonMessage *msg, SrsPacket **ppacket); virtual void close(); @@ -119,7 +119,7 @@ private: private: // We might modify the request by HTTP redirect. - SrsRequest *req_; + ISrsRequest *req_; // Current selected server, the ip:port. std::string selected_ip; int selected_port; @@ -129,10 +129,10 @@ public: virtual ~SrsEdgeFlvUpstream(); public: - virtual srs_error_t connect(SrsRequest *r, SrsLbRoundRobin *lb); + virtual srs_error_t connect(ISrsRequest *r, SrsLbRoundRobin *lb); private: - virtual srs_error_t do_connect(SrsRequest *r, SrsLbRoundRobin *lb, int redirect_depth); + virtual srs_error_t do_connect(ISrsRequest *r, SrsLbRoundRobin *lb, int redirect_depth); public: virtual srs_error_t recv_message(SrsCommonMessage **pmsg); @@ -154,7 +154,7 @@ private: private: SrsPlayEdge *edge; - SrsRequest *req; + ISrsRequest *req; SrsCoroutine *trd; SrsLbRoundRobin *lb; SrsEdgeUpstream *upstream; @@ -166,7 +166,7 @@ public: virtual ~SrsEdgeIngester(); public: - virtual srs_error_t initialize(SrsSharedPtr s, SrsPlayEdge *e, SrsRequest *r); + virtual srs_error_t initialize(SrsSharedPtr s, SrsPlayEdge *e, ISrsRequest *r); virtual srs_error_t start(); virtual void stop(); virtual std::string get_curr_origin(); @@ -195,7 +195,7 @@ private: private: SrsPublishEdge *edge; - SrsRequest *req; + ISrsRequest *req; SrsCoroutine *trd; SrsSimpleRtmpClient *sdk; SrsLbRoundRobin *lb; @@ -215,7 +215,7 @@ public: virtual void set_queue_size(srs_utime_t queue_size); public: - virtual srs_error_t initialize(SrsSharedPtr s, SrsPublishEdge *e, SrsRequest *r); + virtual srs_error_t initialize(SrsSharedPtr s, SrsPublishEdge *e, ISrsRequest *r); virtual srs_error_t start(); virtual void stop(); // Interface ISrsReusableThread2Handler @@ -244,7 +244,7 @@ public: // Always use the req of source, // For we assume all client to edge is invalid, // if auth open, edge must valid it from origin, then service it. - virtual srs_error_t initialize(SrsSharedPtr source, SrsRequest *req); + virtual srs_error_t initialize(SrsSharedPtr source, ISrsRequest *req); // When client play stream on edge. virtual srs_error_t on_client_play(); // When all client stopped play, disconnect to origin. @@ -271,7 +271,7 @@ public: virtual void set_queue_size(srs_utime_t queue_size); public: - virtual srs_error_t initialize(SrsSharedPtr source, SrsRequest *req); + virtual srs_error_t initialize(SrsSharedPtr source, ISrsRequest *req); virtual bool can_publish(); // When client publish stream on edge. virtual srs_error_t on_client_publish(); diff --git a/trunk/src/app/srs_app_encoder.cpp b/trunk/src/app/srs_app_encoder.cpp index 0ee20aeae..1cc1fa39d 100644 --- a/trunk/src/app/srs_app_encoder.cpp +++ b/trunk/src/app/srs_app_encoder.cpp @@ -35,7 +35,7 @@ SrsEncoder::~SrsEncoder() srs_freep(pprint); } -srs_error_t SrsEncoder::on_publish(SrsRequest *req) +srs_error_t SrsEncoder::on_publish(ISrsRequest *req) { srs_error_t err = srs_success; @@ -155,7 +155,7 @@ SrsFFMPEG *SrsEncoder::at(int index) return ffmpegs[index]; } -srs_error_t SrsEncoder::parse_scope_engines(SrsRequest *req) +srs_error_t SrsEncoder::parse_scope_engines(ISrsRequest *req) { srs_error_t err = srs_success; @@ -188,7 +188,7 @@ srs_error_t SrsEncoder::parse_scope_engines(SrsRequest *req) return err; } -srs_error_t SrsEncoder::parse_ffmpeg(SrsRequest *req, SrsConfDirective *conf) +srs_error_t SrsEncoder::parse_ffmpeg(ISrsRequest *req, SrsConfDirective *conf) { srs_error_t err = srs_success; @@ -234,7 +234,7 @@ srs_error_t SrsEncoder::parse_ffmpeg(SrsRequest *req, SrsConfDirective *conf) return err; } -srs_error_t SrsEncoder::initialize_ffmpeg(SrsFFMPEG *ffmpeg, SrsRequest *req, SrsConfDirective *engine) +srs_error_t SrsEncoder::initialize_ffmpeg(SrsFFMPEG *ffmpeg, ISrsRequest *req, SrsConfDirective *engine) { srs_error_t err = srs_success; diff --git a/trunk/src/app/srs_app_encoder.hpp b/trunk/src/app/srs_app_encoder.hpp index 0a4c67fb2..6bbe2d782 100644 --- a/trunk/src/app/srs_app_encoder.hpp +++ b/trunk/src/app/srs_app_encoder.hpp @@ -15,7 +15,7 @@ #include class SrsConfDirective; -class SrsRequest; +class ISrsRequest; class SrsPithyPrint; class SrsFFMPEG; @@ -36,7 +36,7 @@ public: virtual ~SrsEncoder(); public: - virtual srs_error_t on_publish(SrsRequest *req); + virtual srs_error_t on_publish(ISrsRequest *req); virtual void on_unpublish(); // Interface ISrsReusableThreadHandler. public: @@ -48,9 +48,9 @@ private: private: virtual void clear_engines(); virtual SrsFFMPEG *at(int index); - virtual srs_error_t parse_scope_engines(SrsRequest *req); - virtual srs_error_t parse_ffmpeg(SrsRequest *req, SrsConfDirective *conf); - virtual srs_error_t initialize_ffmpeg(SrsFFMPEG *ffmpeg, SrsRequest *req, SrsConfDirective *engine); + virtual srs_error_t parse_scope_engines(ISrsRequest *req); + virtual srs_error_t parse_ffmpeg(ISrsRequest *req, SrsConfDirective *conf); + virtual srs_error_t initialize_ffmpeg(SrsFFMPEG *ffmpeg, ISrsRequest *req, SrsConfDirective *engine); virtual void show_encode_log_message(); }; diff --git a/trunk/src/app/srs_app_forward.cpp b/trunk/src/app/srs_app_forward.cpp index 4f26a7daf..3bac5177a 100644 --- a/trunk/src/app/srs_app_forward.cpp +++ b/trunk/src/app/srs_app_forward.cpp @@ -56,7 +56,7 @@ SrsForwarder::~SrsForwarder() srs_freep(req); } -srs_error_t SrsForwarder::initialize(SrsRequest *r, string ep) +srs_error_t SrsForwarder::initialize(ISrsRequest *r, string ep) { srs_error_t err = srs_success; diff --git a/trunk/src/app/srs_app_forward.hpp b/trunk/src/app/srs_app_forward.hpp index 833630a16..2dce9a1db 100644 --- a/trunk/src/app/srs_app_forward.hpp +++ b/trunk/src/app/srs_app_forward.hpp @@ -19,7 +19,7 @@ class SrsOnMetaDataPacket; class SrsMessageQueue; class SrsRtmpJitter; class SrsRtmpClient; -class SrsRequest; +class ISrsRequest; class SrsLiveSource; class SrsOriginHub; class SrsKbps; @@ -31,7 +31,7 @@ class SrsForwarder : public ISrsCoroutineHandler private: // The ep to forward, server[:port]. std::string ep_forward; - SrsRequest *req; + ISrsRequest *req; private: // The source or stream context id to bind to. @@ -54,7 +54,7 @@ public: virtual ~SrsForwarder(); public: - virtual srs_error_t initialize(SrsRequest *r, std::string ep); + virtual srs_error_t initialize(ISrsRequest *r, std::string ep); virtual void set_queue_size(srs_utime_t queue_size); public: diff --git a/trunk/src/app/srs_app_hds.cpp b/trunk/src/app/srs_app_hds.cpp index efe511ff1..760f4d9ee 100644 --- a/trunk/src/app/srs_app_hds.cpp +++ b/trunk/src/app/srs_app_hds.cpp @@ -70,7 +70,7 @@ string serialFlv(SrsSharedPtrMessage *msg) class SrsHdsFragment { public: - SrsHdsFragment(SrsRequest *r) + SrsHdsFragment(ISrsRequest *r) : req(r), index(-1), start_time(0), videoSh(NULL), audioSh(NULL) { } @@ -218,7 +218,7 @@ public: } private: - SrsRequest *req; + ISrsRequest *req; list msgs; /*! @@ -241,7 +241,7 @@ SrsHds::~SrsHds() { } -srs_error_t SrsHds::on_publish(SrsRequest *req) +srs_error_t SrsHds::on_publish(ISrsRequest *req) { srs_error_t err = srs_success; diff --git a/trunk/src/app/srs_app_hds.hpp b/trunk/src/app/srs_app_hds.hpp index ba32d543c..f7037bee9 100644 --- a/trunk/src/app/srs_app_hds.hpp +++ b/trunk/src/app/srs_app_hds.hpp @@ -13,7 +13,7 @@ #include -class SrsRequest; +class ISrsRequest; class SrsSharedPtrMessage; class SrsHdsFragment; class SrsLiveSource; @@ -25,7 +25,7 @@ public: SrsHds(); virtual ~SrsHds(); - srs_error_t on_publish(SrsRequest *req); + srs_error_t on_publish(ISrsRequest *req); srs_error_t on_unpublish(); srs_error_t on_video(SrsSharedPtrMessage *msg); @@ -43,7 +43,7 @@ private: SrsSharedPtrMessage *video_sh; SrsSharedPtrMessage *audio_sh; - SrsRequest *hds_req; + ISrsRequest *hds_req; bool hds_enabled; }; diff --git a/trunk/src/app/srs_app_hls.cpp b/trunk/src/app/srs_app_hls.cpp index 995720745..d490ed07f 100644 --- a/trunk/src/app/srs_app_hls.cpp +++ b/trunk/src/app/srs_app_hls.cpp @@ -254,7 +254,7 @@ srs_error_t SrsHlsM4sSegment::reap(uint64_t dts) return err; } -SrsDvrAsyncCallOnHls::SrsDvrAsyncCallOnHls(SrsContextId c, SrsRequest *r, string p, string t, string m, string mu, int s, srs_utime_t d) +SrsDvrAsyncCallOnHls::SrsDvrAsyncCallOnHls(SrsContextId c, ISrsRequest *r, string p, string t, string m, string mu, int s, srs_utime_t d) { req = r->copy(); cid = c; @@ -309,7 +309,7 @@ string SrsDvrAsyncCallOnHls::to_string() return "on_hls: " + path; } -SrsDvrAsyncCallOnHlsNotify::SrsDvrAsyncCallOnHlsNotify(SrsContextId c, SrsRequest *r, string u) +SrsDvrAsyncCallOnHlsNotify::SrsDvrAsyncCallOnHlsNotify(SrsContextId c, ISrsRequest *r, string u) { cid = c; req = r->copy(); @@ -473,7 +473,7 @@ srs_error_t SrsHlsFmp4Muxer::initialize(int v_tid, int a_tid) return srs_success; } -srs_error_t SrsHlsFmp4Muxer::on_publish(SrsRequest *req) +srs_error_t SrsHlsFmp4Muxer::on_publish(ISrsRequest *req) { srs_error_t err = srs_success; @@ -632,7 +632,7 @@ srs_error_t SrsHlsFmp4Muxer::on_unpublish() return srs_success; } -srs_error_t SrsHlsFmp4Muxer::update_config(SrsRequest *r) +srs_error_t SrsHlsFmp4Muxer::update_config(ISrsRequest *r) { srs_error_t err = srs_success; @@ -1177,7 +1177,7 @@ srs_error_t SrsHlsMuxer::initialize() return srs_success; } -srs_error_t SrsHlsMuxer::on_publish(SrsRequest *req) +srs_error_t SrsHlsMuxer::on_publish(ISrsRequest *req) { srs_error_t err = srs_success; @@ -1194,7 +1194,7 @@ srs_error_t SrsHlsMuxer::on_unpublish() return srs_success; } -srs_error_t SrsHlsMuxer::update_config(SrsRequest *r, string entry_prefix, +srs_error_t SrsHlsMuxer::update_config(ISrsRequest *r, string entry_prefix, string path, string m3u8_file, string ts_file, srs_utime_t fragment, srs_utime_t window, bool ts_floor, double aof_ratio, bool cleanup, bool wait_keyframe, bool keys, int fragments_per_key, string key_file, string key_file_path, string key_url) @@ -1935,7 +1935,7 @@ int SrsHlsController::deviation() return muxer->deviation(); } -srs_error_t SrsHlsController::on_publish(SrsRequest *req) +srs_error_t SrsHlsController::on_publish(ISrsRequest *req) { srs_error_t err = srs_success; @@ -2239,7 +2239,7 @@ void SrsHlsMp4Controller::dispose() muxer_->dispose(); } -srs_error_t SrsHlsMp4Controller::on_publish(SrsRequest *req) +srs_error_t SrsHlsMp4Controller::on_publish(ISrsRequest *req) { srs_error_t err = srs_success; @@ -2514,7 +2514,7 @@ srs_utime_t SrsHls::cleanup_delay() return _srs_config->get_hls_dispose(req->vhost) * 1.1; } -srs_error_t SrsHls::initialize(SrsOriginHub *h, SrsRequest *r) +srs_error_t SrsHls::initialize(SrsOriginHub *h, ISrsRequest *r) { srs_error_t err = srs_success; diff --git a/trunk/src/app/srs_app_hls.hpp b/trunk/src/app/srs_app_hls.hpp index 8b26dbffa..db0258223 100644 --- a/trunk/src/app/srs_app_hls.hpp +++ b/trunk/src/app/srs_app_hls.hpp @@ -23,7 +23,7 @@ class SrsSharedPtrMessage; class SrsAmf0Object; class SrsRtmpJitter; class SrsTsContextWriter; -class SrsRequest; +class ISrsRequest; class SrsPithyPrint; class SrsLiveSource; class SrsOriginHub; @@ -132,12 +132,12 @@ private: std::string m3u8; std::string m3u8_url; int seq_no; - SrsRequest *req; + ISrsRequest *req; srs_utime_t duration; public: // TODO: FIXME: Use TBN 1000. - SrsDvrAsyncCallOnHls(SrsContextId c, SrsRequest *r, std::string p, std::string t, std::string m, std::string mu, int s, srs_utime_t d); + SrsDvrAsyncCallOnHls(SrsContextId c, ISrsRequest *r, std::string p, std::string t, std::string m, std::string mu, int s, srs_utime_t d); virtual ~SrsDvrAsyncCallOnHls(); public: @@ -151,10 +151,10 @@ class SrsDvrAsyncCallOnHlsNotify : public ISrsAsyncCallTask private: SrsContextId cid; std::string ts_url; - SrsRequest *req; + ISrsRequest *req; public: - SrsDvrAsyncCallOnHlsNotify(SrsContextId c, SrsRequest *r, std::string u); + SrsDvrAsyncCallOnHlsNotify(SrsContextId c, ISrsRequest *r, std::string u); virtual ~SrsDvrAsyncCallOnHlsNotify(); public: @@ -172,7 +172,7 @@ public: class SrsHlsMuxer { private: - SrsRequest *req; + ISrsRequest *req; private: std::string hls_entry_prefix; @@ -257,10 +257,10 @@ public: // Initialize the hls muxer. virtual srs_error_t initialize(); // When publish or unpublish stream. - virtual srs_error_t on_publish(SrsRequest *req); + virtual srs_error_t on_publish(ISrsRequest *req); virtual srs_error_t on_unpublish(); // When publish, update the config for muxer. - virtual srs_error_t update_config(SrsRequest *r, std::string entry_prefix, + virtual srs_error_t update_config(ISrsRequest *r, std::string entry_prefix, std::string path, std::string m3u8_file, std::string ts_file, srs_utime_t fragment, srs_utime_t window, bool ts_floor, double aof_ratio, bool cleanup, bool wait_keyframe, bool keys, int fragments_per_key, @@ -308,7 +308,7 @@ public: class SrsHlsFmp4Muxer { private: - SrsRequest *req_; + ISrsRequest *req_; private: std::string hls_entry_prefix_; @@ -406,7 +406,7 @@ public: // Initialize the hls muxer. virtual srs_error_t initialize(int v_tid, int a_tid); // When publish or unpublish stream. - virtual srs_error_t on_publish(SrsRequest *req); + virtual srs_error_t on_publish(ISrsRequest *req); public: virtual srs_error_t write_init_mp4(SrsFormat *format, bool has_video, bool has_audio); @@ -416,7 +416,7 @@ public: public: virtual srs_error_t on_unpublish(); // When publish, update the config for muxer. - virtual srs_error_t update_config(SrsRequest *r); + virtual srs_error_t update_config(ISrsRequest *r); // Open a new segment(a new ts file) virtual srs_error_t segment_open(srs_utime_t basetime); virtual srs_error_t on_sequence_header(); @@ -455,7 +455,7 @@ public: virtual srs_error_t initialize() = 0; virtual void dispose() = 0; // When publish or unpublish stream. - virtual srs_error_t on_publish(SrsRequest *req) = 0; + virtual srs_error_t on_publish(ISrsRequest *req) = 0; virtual srs_error_t on_unpublish() = 0; public: @@ -518,7 +518,7 @@ public: public: // When publish or unpublish stream. - virtual srs_error_t on_publish(SrsRequest *req); + virtual srs_error_t on_publish(ISrsRequest *req); virtual srs_error_t on_unpublish(); // When get sequence header, // must write a #EXT-X-DISCONTINUITY to m3u8. @@ -557,7 +557,7 @@ private: uint64_t video_dts_; private: - SrsRequest *req_; + ISrsRequest *req_; private: SrsHlsFmp4Muxer *muxer_; @@ -570,7 +570,7 @@ public: virtual srs_error_t initialize(); virtual void dispose(); // When publish or unpublish stream. - virtual srs_error_t on_publish(SrsRequest *req); + virtual srs_error_t on_publish(ISrsRequest *req); virtual srs_error_t on_unpublish(); virtual srs_error_t write_audio(SrsSharedPtrMessage *shared_audio, SrsFormat *format); virtual srs_error_t write_video(SrsSharedPtrMessage *shared_video, SrsFormat *format); @@ -591,7 +591,7 @@ private: ISrsHlsController *controller; private: - SrsRequest *req; + ISrsRequest *req; // Whether the HLS is enabled. bool enabled; // Whether the HLS stream is able to be disposed. @@ -627,7 +627,7 @@ public: public: // Initialize the hls by handler and source. - virtual srs_error_t initialize(SrsOriginHub *h, SrsRequest *r); + virtual srs_error_t initialize(SrsOriginHub *h, ISrsRequest *r); // Publish stream event, continue to write the m3u8, // for the muxer object not destroyed. // @param fetch_sequence_header whether fetch sequence from source. diff --git a/trunk/src/app/srs_app_http_api.hpp b/trunk/src/app/srs_app_http_api.hpp index 82031a3e3..ff639dd15 100644 --- a/trunk/src/app/srs_app_http_api.hpp +++ b/trunk/src/app/srs_app_http_api.hpp @@ -16,7 +16,7 @@ class SrsServer; class SrsRtcServer; class SrsJsonObject; class SrsSdp; -class SrsRequest; +class ISrsRequest; class ISrsHttpResponseWriter; class SrsHttpConn; diff --git a/trunk/src/app/srs_app_http_conn.cpp b/trunk/src/app/srs_app_http_conn.cpp index 22f7edcb1..fcf41aa59 100644 --- a/trunk/src/app/srs_app_http_conn.cpp +++ b/trunk/src/app/srs_app_http_conn.cpp @@ -154,9 +154,9 @@ srs_error_t SrsHttpConn::do_cycle() } // process all http messages. - SrsRequest *last_req_raw = NULL; + ISrsRequest *last_req_raw = NULL; err = process_requests(&last_req_raw); - SrsUniquePtr last_req(last_req_raw); + SrsUniquePtr last_req(last_req_raw); srs_error_t r0 = srs_success; if ((r0 = on_disconnect(last_req.get())) != srs_success) { @@ -167,7 +167,7 @@ srs_error_t SrsHttpConn::do_cycle() return err; } -srs_error_t SrsHttpConn::process_requests(SrsRequest **preq) +srs_error_t SrsHttpConn::process_requests(ISrsRequest **preq) { srs_error_t err = srs_success; @@ -236,7 +236,7 @@ srs_error_t SrsHttpConn::process_request(ISrsHttpResponseWriter *w, ISrsHttpMess return err; } -srs_error_t SrsHttpConn::on_disconnect(SrsRequest *req) +srs_error_t SrsHttpConn::on_disconnect(ISrsRequest *req) { // TODO: FIXME: Implements it. return srs_success; @@ -539,12 +539,12 @@ srs_error_t SrsHttpServer::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage return http_static->mux.serve_http(w, r); } -srs_error_t SrsHttpServer::http_mount(SrsRequest *r) +srs_error_t SrsHttpServer::http_mount(ISrsRequest *r) { return http_stream->http_mount(r); } -void SrsHttpServer::http_unmount(SrsRequest *r) +void SrsHttpServer::http_unmount(ISrsRequest *r) { http_stream->http_unmount(r); } diff --git a/trunk/src/app/srs_app_http_conn.hpp b/trunk/src/app/srs_app_http_conn.hpp index f27011d28..3bb3a6e3b 100644 --- a/trunk/src/app/srs_app_http_conn.hpp +++ b/trunk/src/app/srs_app_http_conn.hpp @@ -22,7 +22,7 @@ class SrsServer; class SrsLiveSource; -class SrsRequest; +class ISrsRequest; class SrsLiveConsumer; class SrsStSocket; class SrsHttpParser; @@ -30,7 +30,6 @@ class ISrsHttpMessage; class SrsHttpHandler; class SrsMessageQueue; class SrsSharedPtrMessage; -class SrsRequest; class SrsFastStream; class SrsHttpUri; class SrsHttpMessage; @@ -104,12 +103,12 @@ public: private: virtual srs_error_t do_cycle(); - virtual srs_error_t process_requests(SrsRequest **preq); + virtual srs_error_t process_requests(ISrsRequest **preq); virtual srs_error_t process_request(ISrsHttpResponseWriter *w, ISrsHttpMessage *r, int rid); // When the connection disconnect, call this method. // e.g. log msg of connection and report to other system. // @param request: request which is converted by the last http message. - virtual srs_error_t on_disconnect(SrsRequest *req); + virtual srs_error_t on_disconnect(ISrsRequest *req); public: // Get the HTTP message handler. @@ -202,8 +201,8 @@ public: virtual srs_error_t serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r); public: - virtual srs_error_t http_mount(SrsRequest *r); - virtual void http_unmount(SrsRequest *r); + virtual srs_error_t http_mount(ISrsRequest *r); + virtual void http_unmount(ISrsRequest *r); }; #endif diff --git a/trunk/src/app/srs_app_http_hooks.cpp b/trunk/src/app/srs_app_http_hooks.cpp index cad37ec60..17ebb473e 100644 --- a/trunk/src/app/srs_app_http_hooks.cpp +++ b/trunk/src/app/srs_app_http_hooks.cpp @@ -52,7 +52,7 @@ SrsHttpHooks::~SrsHttpHooks() { } -srs_error_t SrsHttpHooks::on_connect(string url, SrsRequest *req) +srs_error_t SrsHttpHooks::on_connect(string url, ISrsRequest *req) { srs_error_t err = srs_success; @@ -88,7 +88,7 @@ srs_error_t SrsHttpHooks::on_connect(string url, SrsRequest *req) return err; } -void SrsHttpHooks::on_close(string url, SrsRequest *req, int64_t send_bytes, int64_t recv_bytes) +void SrsHttpHooks::on_close(string url, ISrsRequest *req, int64_t send_bytes, int64_t recv_bytes) { srs_error_t err = srs_success; @@ -125,7 +125,7 @@ void SrsHttpHooks::on_close(string url, SrsRequest *req, int64_t send_bytes, int return; } -srs_error_t SrsHttpHooks::on_publish(string url, SrsRequest *req) +srs_error_t SrsHttpHooks::on_publish(string url, ISrsRequest *req) { srs_error_t err = srs_success; @@ -166,7 +166,7 @@ srs_error_t SrsHttpHooks::on_publish(string url, SrsRequest *req) return err; } -void SrsHttpHooks::on_unpublish(string url, SrsRequest *req) +void SrsHttpHooks::on_unpublish(string url, ISrsRequest *req) { srs_error_t err = srs_success; @@ -210,7 +210,7 @@ void SrsHttpHooks::on_unpublish(string url, SrsRequest *req) return; } -srs_error_t SrsHttpHooks::on_play(string url, SrsRequest *req) +srs_error_t SrsHttpHooks::on_play(string url, ISrsRequest *req) { srs_error_t err = srs_success; @@ -252,7 +252,7 @@ srs_error_t SrsHttpHooks::on_play(string url, SrsRequest *req) return err; } -void SrsHttpHooks::on_stop(string url, SrsRequest *req) +void SrsHttpHooks::on_stop(string url, ISrsRequest *req) { srs_error_t err = srs_success; @@ -296,7 +296,7 @@ void SrsHttpHooks::on_stop(string url, SrsRequest *req) return; } -srs_error_t SrsHttpHooks::on_dvr(SrsContextId c, string url, SrsRequest *req, string file) +srs_error_t SrsHttpHooks::on_dvr(SrsContextId c, string url, ISrsRequest *req, string file) { srs_error_t err = srs_success; @@ -341,7 +341,7 @@ srs_error_t SrsHttpHooks::on_dvr(SrsContextId c, string url, SrsRequest *req, st return err; } -srs_error_t SrsHttpHooks::on_hls(SrsContextId c, string url, SrsRequest *req, string file, string ts_url, string m3u8, string m3u8_url, int sn, srs_utime_t duration) +srs_error_t SrsHttpHooks::on_hls(SrsContextId c, string url, ISrsRequest *req, string file, string ts_url, string m3u8, string m3u8_url, int sn, srs_utime_t duration) { srs_error_t err = srs_success; @@ -396,7 +396,7 @@ srs_error_t SrsHttpHooks::on_hls(SrsContextId c, string url, SrsRequest *req, st return err; } -srs_error_t SrsHttpHooks::on_hls_notify(SrsContextId c, std::string url, SrsRequest *req, std::string ts_url, int nb_notify) +srs_error_t SrsHttpHooks::on_hls_notify(SrsContextId c, std::string url, ISrsRequest *req, std::string ts_url, int nb_notify) { srs_error_t err = srs_success; @@ -520,7 +520,7 @@ srs_error_t SrsHttpHooks::discover_co_workers(string url, string &host, int &por return err; } -srs_error_t SrsHttpHooks::on_forward_backend(string url, SrsRequest *req, std::vector &rtmp_urls) +srs_error_t SrsHttpHooks::on_forward_backend(string url, ISrsRequest *req, std::vector &rtmp_urls) { srs_error_t err = srs_success; diff --git a/trunk/src/app/srs_app_http_hooks.hpp b/trunk/src/app/srs_app_http_hooks.hpp index 78e17ee05..29ec38b40 100644 --- a/trunk/src/app/srs_app_http_hooks.hpp +++ b/trunk/src/app/srs_app_http_hooks.hpp @@ -14,7 +14,7 @@ class SrsHttpUri; class SrsStSocket; -class SrsRequest; +class ISrsRequest; class SrsHttpParser; class SrsHttpClient; @@ -41,14 +41,14 @@ public: // @param url The HTTP callback URL for publish validation. If empty, hook is ignored. // @param req The publish request information including stream details. // @return srs_success if publishing is allowed, error otherwise to reject publishing. - virtual srs_error_t on_publish(std::string url, SrsRequest *req) = 0; + virtual srs_error_t on_publish(std::string url, ISrsRequest *req) = 0; // Stream stop publishing notification hook. // Called when a client (encoder) stops publishing a stream. // This is a notification-only hook that cannot prevent the unpublishing. // @param url The HTTP callback URL for unpublish notification. If empty, hook is ignored. // @param req The unpublish request information. - virtual void on_unpublish(std::string url, SrsRequest *req) = 0; + virtual void on_unpublish(std::string url, ISrsRequest *req) = 0; // Stream start playing validation hook. // Called when a client attempts to start playing/subscribing to a stream. @@ -56,14 +56,14 @@ public: // @param url The HTTP callback URL for play validation. If empty, hook is ignored. // @param req The play request information including stream details. // @return srs_success if playing is allowed, error otherwise to reject playing. - virtual srs_error_t on_play(std::string url, SrsRequest *req) = 0; + virtual srs_error_t on_play(std::string url, ISrsRequest *req) = 0; // Stream stop playing notification hook. // Called when a client stops playing/subscribing to a stream. // This is a notification-only hook that cannot prevent the stop operation. // @param url The HTTP callback URL for stop notification. If empty, hook is ignored. // @param req The stop request information. - virtual void on_stop(std::string url, SrsRequest *req) = 0; + virtual void on_stop(std::string url, ISrsRequest *req) = 0; public: // DVR file completion notification hook. @@ -75,7 +75,7 @@ public: // @param req The original stream request information. // @param file The completed DVR file path (can be relative or absolute). // @return srs_success if processing succeeds, error otherwise (logged but doesn't affect DVR). - virtual srs_error_t on_dvr(SrsContextId cid, std::string url, SrsRequest *req, std::string file) = 0; + virtual srs_error_t on_dvr(SrsContextId cid, std::string url, ISrsRequest *req, std::string file) = 0; public: // HLS segment completion notification hook. @@ -92,7 +92,7 @@ public: // @param sn The sequence number of the TS segment in the HLS playlist. // @param duration The segment duration in microseconds (srs_utime_t). // @return srs_success if processing succeeds, error otherwise (logged but doesn't affect HLS). - virtual srs_error_t on_hls(SrsContextId cid, std::string url, SrsRequest *req, std::string file, std::string ts_url, + virtual srs_error_t on_hls(SrsContextId cid, std::string url, ISrsRequest *req, std::string file, std::string ts_url, std::string m3u8, std::string m3u8_url, int sn, srs_utime_t duration) = 0; // HLS segment notification hook with custom URL template. @@ -105,7 +105,7 @@ public: // @param ts_url The TS segment URL to replace [ts_url] variable in the callback URL. // @param nb_notify Maximum bytes to read from the notification server response. // @return srs_success if processing succeeds, error otherwise (logged but doesn't affect HLS). - virtual srs_error_t on_hls_notify(SrsContextId cid, std::string url, SrsRequest *req, std::string ts_url, int nb_notify) = 0; + virtual srs_error_t on_hls_notify(SrsContextId cid, std::string url, ISrsRequest *req, std::string ts_url, int nb_notify) = 0; public: // Origin cluster co-worker discovery hook. @@ -125,7 +125,7 @@ public: // @param req The publish request information. // @param rtmp_urls Output parameter to receive the list of RTMP URLs for forwarding. // @return srs_success if backends are discovered, error otherwise. - virtual srs_error_t on_forward_backend(std::string url, SrsRequest *req, std::vector &rtmp_urls) = 0; + virtual srs_error_t on_forward_backend(std::string url, ISrsRequest *req, std::vector &rtmp_urls) = 0; // Deprecated hooks. public: @@ -135,7 +135,7 @@ public: // @param url The HTTP callback URL for client validation. If empty, hook is ignored. // @param req The client request information including IP, vhost, app, stream, etc. // @return srs_success if connection is allowed, error otherwise to reject connection. - virtual srs_error_t on_connect(std::string url, SrsRequest *req) = 0; + virtual srs_error_t on_connect(std::string url, ISrsRequest *req) = 0; // Client disconnection notification hook. // Called when a client disconnects from the SRS server. @@ -144,7 +144,7 @@ public: // @param req The client request information. // @param send_bytes Total bytes sent to the client during the session. // @param recv_bytes Total bytes received from the client during the session. - virtual void on_close(std::string url, SrsRequest *req, int64_t send_bytes, int64_t recv_bytes) = 0; + virtual void on_close(std::string url, ISrsRequest *req, int64_t send_bytes, int64_t recv_bytes) = 0; }; class SrsHttpHooks : public ISrsHttpHooks @@ -154,18 +154,18 @@ public: virtual ~SrsHttpHooks(); public: - srs_error_t on_connect(std::string url, SrsRequest *req); - void on_close(std::string url, SrsRequest *req, int64_t send_bytes, int64_t recv_bytes); - srs_error_t on_publish(std::string url, SrsRequest *req); - void on_unpublish(std::string url, SrsRequest *req); - srs_error_t on_play(std::string url, SrsRequest *req); - void on_stop(std::string url, SrsRequest *req); - srs_error_t on_dvr(SrsContextId cid, std::string url, SrsRequest *req, std::string file); - srs_error_t on_hls(SrsContextId cid, std::string url, SrsRequest *req, std::string file, std::string ts_url, + srs_error_t on_connect(std::string url, ISrsRequest *req); + void on_close(std::string url, ISrsRequest *req, int64_t send_bytes, int64_t recv_bytes); + srs_error_t on_publish(std::string url, ISrsRequest *req); + void on_unpublish(std::string url, ISrsRequest *req); + srs_error_t on_play(std::string url, ISrsRequest *req); + void on_stop(std::string url, ISrsRequest *req); + srs_error_t on_dvr(SrsContextId cid, std::string url, ISrsRequest *req, std::string file); + srs_error_t on_hls(SrsContextId cid, std::string url, ISrsRequest *req, std::string file, std::string ts_url, std::string m3u8, std::string m3u8_url, int sn, srs_utime_t duration); - srs_error_t on_hls_notify(SrsContextId cid, std::string url, SrsRequest *req, std::string ts_url, int nb_notify); + srs_error_t on_hls_notify(SrsContextId cid, std::string url, ISrsRequest *req, std::string ts_url, int nb_notify); srs_error_t discover_co_workers(std::string url, std::string &host, int &port); - srs_error_t on_forward_backend(std::string url, SrsRequest *req, std::vector &rtmp_urls); + srs_error_t on_forward_backend(std::string url, ISrsRequest *req, std::vector &rtmp_urls); private: srs_error_t do_post(SrsHttpClient *hc, std::string url, std::string req, int &code, std::string &res); diff --git a/trunk/src/app/srs_app_http_static.cpp b/trunk/src/app/srs_app_http_static.cpp index 44c1c0794..8020080a3 100644 --- a/trunk/src/app/srs_app_http_static.cpp +++ b/trunk/src/app/srs_app_http_static.cpp @@ -78,7 +78,7 @@ SrsHlsStream::~SrsHlsStream() srs_freep(security_); } -srs_error_t SrsHlsStream::serve_m3u8_ctx(ISrsHttpResponseWriter *w, ISrsHttpMessage *r, ISrsFileReaderFactory *factory, string fullpath, SrsRequest *req, bool *served) +srs_error_t SrsHlsStream::serve_m3u8_ctx(ISrsHttpResponseWriter *w, ISrsHttpMessage *r, ISrsFileReaderFactory *factory, string fullpath, ISrsRequest *req, bool *served) { srs_error_t err = srs_success; @@ -144,7 +144,7 @@ void SrsHlsStream::on_serve_ts_ctx(ISrsHttpResponseWriter *w, ISrsHttpMessage *r SrsStatistic::instance()->kbps_add_delta(ctx, delta); } -srs_error_t SrsHlsStream::serve_new_session(ISrsHttpResponseWriter *w, ISrsHttpMessage *r, SrsRequest *req, std::string &ctx) +srs_error_t SrsHlsStream::serve_new_session(ISrsHttpResponseWriter *w, ISrsHttpMessage *r, ISrsRequest *req, std::string &ctx) { srs_error_t err = srs_success; @@ -279,7 +279,7 @@ bool SrsHlsStream::ctx_is_exist(std::string ctx) return (map_ctx_info_.find(ctx) != map_ctx_info_.end()); } -void SrsHlsStream::alive(std::string ctx, SrsRequest *req) +void SrsHlsStream::alive(std::string ctx, ISrsRequest *req) { std::map::iterator it = map_ctx_info_.find(ctx); @@ -308,7 +308,7 @@ void SrsHlsStream::alive(std::string ctx, SrsRequest *req) } } -srs_error_t SrsHlsStream::http_hooks_on_play(SrsRequest *req) +srs_error_t SrsHlsStream::http_hooks_on_play(ISrsRequest *req) { srs_error_t err = srs_success; @@ -341,7 +341,7 @@ srs_error_t SrsHlsStream::http_hooks_on_play(SrsRequest *req) return err; } -void SrsHlsStream::http_hooks_on_stop(SrsRequest *req) +void SrsHlsStream::http_hooks_on_stop(ISrsRequest *req) { if (!_srs_config->get_vhost_http_hooks_enabled(req->vhost)) { return; @@ -552,7 +552,7 @@ srs_error_t SrsVodStream::serve_m3u8_ctx(ISrsHttpResponseWriter *w, ISrsHttpMess SrsHttpMessage *hr = dynamic_cast(r); srs_assert(hr); - SrsUniquePtr req(hr->to_request(hr->host())->as_http()); + SrsUniquePtr req(hr->to_request(hr->host())->as_http()); // discovery vhost, resolve the vhost from config SrsConfDirective *parsed_vhost = _srs_config->get_vhost(req->vhost); diff --git a/trunk/src/app/srs_app_http_static.hpp b/trunk/src/app/srs_app_http_static.hpp index e5334a977..97df3d66a 100644 --- a/trunk/src/app/srs_app_http_static.hpp +++ b/trunk/src/app/srs_app_http_static.hpp @@ -18,7 +18,7 @@ class SrsHlsVirtualConn : public ISrsExpire { public: srs_utime_t request_time; - SrsRequest *req; + ISrsRequest *req; std::string ctx; bool interrupt; @@ -42,16 +42,16 @@ public: virtual ~SrsHlsStream(); public: - virtual srs_error_t serve_m3u8_ctx(ISrsHttpResponseWriter *w, ISrsHttpMessage *r, ISrsFileReaderFactory *factory, std::string fullpath, SrsRequest *req, bool *served); + virtual srs_error_t serve_m3u8_ctx(ISrsHttpResponseWriter *w, ISrsHttpMessage *r, ISrsFileReaderFactory *factory, std::string fullpath, ISrsRequest *req, bool *served); virtual void on_serve_ts_ctx(ISrsHttpResponseWriter *w, ISrsHttpMessage *r); private: - srs_error_t serve_new_session(ISrsHttpResponseWriter *w, ISrsHttpMessage *r, SrsRequest *req, std::string &ctx); + srs_error_t serve_new_session(ISrsHttpResponseWriter *w, ISrsHttpMessage *r, ISrsRequest *req, std::string &ctx); srs_error_t serve_exists_session(ISrsHttpResponseWriter *w, ISrsHttpMessage *r, ISrsFileReaderFactory *factory, std::string fullpath); bool ctx_is_exist(std::string ctx); - void alive(std::string ctx, SrsRequest *req); - srs_error_t http_hooks_on_play(SrsRequest *req); - void http_hooks_on_stop(SrsRequest *req); + void alive(std::string ctx, ISrsRequest *req); + srs_error_t http_hooks_on_play(ISrsRequest *req); + void http_hooks_on_stop(ISrsRequest *req); bool is_interrupt(std::string id); // interface ISrsFastTimer private: diff --git a/trunk/src/app/srs_app_http_stream.cpp b/trunk/src/app/srs_app_http_stream.cpp index 587ba941b..ecf5bba5e 100644 --- a/trunk/src/app/srs_app_http_stream.cpp +++ b/trunk/src/app/srs_app_http_stream.cpp @@ -40,7 +40,7 @@ using namespace std; #include #include -SrsBufferCache::SrsBufferCache(SrsServer *s, SrsRequest *r) +SrsBufferCache::SrsBufferCache(SrsServer *s, ISrsRequest *r) { req = r->copy()->as_http(); queue = new SrsMessageQueue(true); @@ -59,7 +59,7 @@ SrsBufferCache::~SrsBufferCache() srs_freep(req); } -srs_error_t SrsBufferCache::update_auth(SrsRequest *r) +srs_error_t SrsBufferCache::update_auth(ISrsRequest *r) { srs_freep(req); req = r->copy(); @@ -133,7 +133,7 @@ srs_error_t SrsBufferCache::cycle() srs_error_t err = srs_success; SrsSharedPtr live_source; - if ((err = _srs_sources->fetch_or_create(req, server_, live_source)) != srs_success) { + if ((err = _srs_sources->fetch_or_create(req, live_source)) != srs_success) { return srs_error_wrap(err, "source create"); } srs_assert(live_source.get() != NULL); @@ -596,7 +596,7 @@ srs_error_t SrsBufferWriter::writev(const iovec *iov, int iovcnt, ssize_t *pnwri return writer->writev(iov, iovcnt, pnwrite); } -SrsLiveStream::SrsLiveStream(SrsServer *s, SrsRequest *r, SrsBufferCache *c) +SrsLiveStream::SrsLiveStream(SrsServer *s, ISrsRequest *r, SrsBufferCache *c) { cache = c; req = r->copy()->as_http(); @@ -613,7 +613,7 @@ SrsLiveStream::~SrsLiveStream() srs_assert(viewers_.empty()); } -srs_error_t SrsLiveStream::update_auth(SrsRequest *r) +srs_error_t SrsLiveStream::update_auth(ISrsRequest *r) { srs_freep(req); req = r->copy()->as_http(); @@ -684,7 +684,7 @@ srs_error_t SrsLiveStream::serve_http_impl(ISrsHttpResponseWriter *w, ISrsHttpMe // Always try to create the source, because http handler won't create it. SrsSharedPtr live_source; - if ((err = _srs_sources->fetch_or_create(req, server_, live_source)) != srs_success) { + if ((err = _srs_sources->fetch_or_create(req, live_source)) != srs_success) { return srs_error_wrap(err, "source create"); } srs_assert(live_source.get() != NULL); @@ -887,7 +887,7 @@ srs_error_t SrsLiveStream::http_hooks_on_play(ISrsHttpMessage *r) // Create request to report for the specified connection. SrsHttpMessage *hr = dynamic_cast(r); - SrsUniquePtr nreq(hr->to_request(req->vhost)); + SrsUniquePtr nreq(hr->to_request(req->vhost)); // the http hooks will cause context switch, // so we must copy all hooks for the on_connect may freed. @@ -922,7 +922,7 @@ void SrsLiveStream::http_hooks_on_stop(ISrsHttpMessage *r) // Create request to report for the specified connection. SrsHttpMessage *hr = dynamic_cast(r); - SrsUniquePtr nreq(hr->to_request(req->vhost)); + SrsUniquePtr nreq(hr->to_request(req->vhost)); // the http hooks will cause context switch, // so we must copy all hooks for the on_connect may freed. @@ -1067,7 +1067,7 @@ srs_error_t SrsHttpStreamServer::initialize() } // TODO: FIXME: rename for HTTP FLV mount. -srs_error_t SrsHttpStreamServer::http_mount(SrsRequest *r) +srs_error_t SrsHttpStreamServer::http_mount(ISrsRequest *r) { srs_error_t err = srs_success; @@ -1144,7 +1144,7 @@ srs_error_t SrsHttpStreamServer::http_mount(SrsRequest *r) return err; } -void SrsHttpStreamServer::http_unmount(SrsRequest *r) +void SrsHttpStreamServer::http_unmount(ISrsRequest *r) { std::string sid = r->get_stream_url(); @@ -1245,7 +1245,7 @@ srs_error_t SrsHttpStreamServer::hijack(ISrsHttpMessage *request, ISrsHttpHandle srs_assert(hreq); // hijack for entry. - SrsUniquePtr r(hreq->to_request(vhost->arg0())); + SrsUniquePtr r(hreq->to_request(vhost->arg0())); std::string sid = r->get_stream_url(); // check whether the http remux is enabled, diff --git a/trunk/src/app/srs_app_http_stream.hpp b/trunk/src/app/srs_app_http_stream.hpp index 0d3c8f795..352ce4cfa 100644 --- a/trunk/src/app/srs_app_http_stream.hpp +++ b/trunk/src/app/srs_app_http_stream.hpp @@ -29,13 +29,13 @@ private: private: SrsMessageQueue *queue; - SrsRequest *req; + ISrsRequest *req; SrsCoroutine *trd; public: - SrsBufferCache(SrsServer *s, SrsRequest *r); + SrsBufferCache(SrsServer *s, ISrsRequest *r); virtual ~SrsBufferCache(); - virtual srs_error_t update_auth(SrsRequest *r); + virtual srs_error_t update_auth(ISrsRequest *r); public: virtual srs_error_t start(); @@ -209,7 +209,7 @@ public: class SrsLiveStream : public ISrsHttpHandler, public ISrsExpire { private: - SrsRequest *req; + ISrsRequest *req; SrsBufferCache *cache; SrsSecurity *security_; SrsServer *server_; @@ -219,9 +219,9 @@ private: std::vector viewers_; public: - SrsLiveStream(SrsServer *s, SrsRequest *r, SrsBufferCache *c); + SrsLiveStream(SrsServer *s, ISrsRequest *r, SrsBufferCache *c); virtual ~SrsLiveStream(); - virtual srs_error_t update_auth(SrsRequest *r); + virtual srs_error_t update_auth(ISrsRequest *r); public: virtual srs_error_t serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r); @@ -252,7 +252,7 @@ private: public: // We will free the request. - SrsRequest *req; + ISrsRequest *req; public: // For template, the mount contains variables. @@ -298,8 +298,8 @@ public: public: // HTTP flv/ts/mp3/aac stream - virtual srs_error_t http_mount(SrsRequest *r); - virtual void http_unmount(SrsRequest *r); + virtual srs_error_t http_mount(ISrsRequest *r); + virtual void http_unmount(ISrsRequest *r); // Interface ISrsHttpMatchHijacker public: virtual srs_error_t hijack(ISrsHttpMessage *request, ISrsHttpHandler **ph); diff --git a/trunk/src/app/srs_app_mpegts_udp.hpp b/trunk/src/app/srs_app_mpegts_udp.hpp index a868cb9bb..c8cd8faee 100644 --- a/trunk/src/app/srs_app_mpegts_udp.hpp +++ b/trunk/src/app/srs_app_mpegts_udp.hpp @@ -19,7 +19,7 @@ class SrsConfDirective; class SrsSimpleStream; class SrsRtmpClient; class SrsStSocket; -class SrsRequest; +class ISrsRequest; class SrsRawH264Stream; class SrsSharedPtrMessage; class SrsRawAacStream; diff --git a/trunk/src/app/srs_app_ng_exec.cpp b/trunk/src/app/srs_app_ng_exec.cpp index 504baf845..b79ba2bed 100644 --- a/trunk/src/app/srs_app_ng_exec.cpp +++ b/trunk/src/app/srs_app_ng_exec.cpp @@ -34,7 +34,7 @@ SrsNgExec::~SrsNgExec() srs_freep(pprint); } -srs_error_t SrsNgExec::on_publish(SrsRequest *req) +srs_error_t SrsNgExec::on_publish(ISrsRequest *req) { srs_error_t err = srs_success; @@ -120,7 +120,7 @@ srs_error_t SrsNgExec::do_cycle() return err; } -srs_error_t SrsNgExec::parse_exec_publish(SrsRequest *req) +srs_error_t SrsNgExec::parse_exec_publish(ISrsRequest *req) { srs_error_t err = srs_success; @@ -193,7 +193,7 @@ void SrsNgExec::show_exec_log_message() } } -string SrsNgExec::parse(SrsRequest *req, string tmpl) +string SrsNgExec::parse(ISrsRequest *req, string tmpl) { string output = tmpl; diff --git a/trunk/src/app/srs_app_ng_exec.hpp b/trunk/src/app/srs_app_ng_exec.hpp index a9a579008..da0579f8d 100644 --- a/trunk/src/app/srs_app_ng_exec.hpp +++ b/trunk/src/app/srs_app_ng_exec.hpp @@ -14,7 +14,7 @@ #include -class SrsRequest; +class ISrsRequest; class SrsPithyPrint; class SrsProcess; @@ -34,7 +34,7 @@ public: virtual ~SrsNgExec(); public: - virtual srs_error_t on_publish(SrsRequest *req); + virtual srs_error_t on_publish(ISrsRequest *req); virtual void on_unpublish(); // Interface ISrsReusableThreadHandler. public: @@ -44,10 +44,10 @@ private: virtual srs_error_t do_cycle(); private: - virtual srs_error_t parse_exec_publish(SrsRequest *req); + virtual srs_error_t parse_exec_publish(ISrsRequest *req); virtual void clear_exec_publish(); virtual void show_exec_log_message(); - virtual std::string parse(SrsRequest *req, std::string tmpl); + virtual std::string parse(ISrsRequest *req, std::string tmpl); }; #endif diff --git a/trunk/src/app/srs_app_recv_thread.cpp b/trunk/src/app/srs_app_recv_thread.cpp index a148ad412..8f8253000 100644 --- a/trunk/src/app/srs_app_recv_thread.cpp +++ b/trunk/src/app/srs_app_recv_thread.cpp @@ -257,7 +257,7 @@ void SrsQueueRecvThread::on_stop() rtmp->set_auto_response(true); } -SrsPublishRecvThread::SrsPublishRecvThread(SrsRtmpServer *rtmp_sdk, SrsRequest *_req, +SrsPublishRecvThread::SrsPublishRecvThread(SrsRtmpServer *rtmp_sdk, ISrsRequest *_req, int mr_sock_fd, srs_utime_t tm, SrsRtmpConn *conn, SrsSharedPtr source, SrsContextId parent_cid) : trd(this, rtmp_sdk, tm, parent_cid) { diff --git a/trunk/src/app/srs_app_recv_thread.hpp b/trunk/src/app/srs_app_recv_thread.hpp index b32ab2d2a..037aa6692 100644 --- a/trunk/src/app/srs_app_recv_thread.hpp +++ b/trunk/src/app/srs_app_recv_thread.hpp @@ -22,7 +22,7 @@ class SrsRtmpServer; class SrsCommonMessage; class SrsRtmpConn; class SrsLiveSource; -class SrsRequest; +class ISrsRequest; class SrsLiveConsumer; class SrsHttpConn; class SrsHttpxConn; @@ -141,7 +141,7 @@ private: uint32_t nn_msgs_for_yield_; SrsRecvThread trd; SrsRtmpServer *rtmp; - SrsRequest *req; + ISrsRequest *req; // The msgs already got. int64_t _nb_msgs; // The video frames we got. @@ -165,7 +165,7 @@ private: SrsContextId ncid; public: - SrsPublishRecvThread(SrsRtmpServer *rtmp_sdk, SrsRequest *_req, + SrsPublishRecvThread(SrsRtmpServer *rtmp_sdk, ISrsRequest *_req, int mr_sock_fd, srs_utime_t tm, SrsRtmpConn *conn, SrsSharedPtr source, SrsContextId parent_cid); virtual ~SrsPublishRecvThread(); diff --git a/trunk/src/app/srs_app_rtc_api.cpp b/trunk/src/app/srs_app_rtc_api.cpp index 36e681985..0c6477b8c 100644 --- a/trunk/src/app/srs_app_rtc_api.cpp +++ b/trunk/src/app/srs_app_rtc_api.cpp @@ -292,7 +292,7 @@ srs_error_t SrsGoApiRtcPlay::check_remote_sdp(const SrsSdp &remote_sdp) return err; } -srs_error_t SrsGoApiRtcPlay::http_hooks_on_play(SrsRequest *req) +srs_error_t SrsGoApiRtcPlay::http_hooks_on_play(ISrsRequest *req) { srs_error_t err = srs_success; @@ -567,7 +567,7 @@ srs_error_t SrsGoApiRtcPublish::check_remote_sdp(const SrsSdp &remote_sdp) return err; } -srs_error_t SrsGoApiRtcPublish::http_hooks_on_publish(SrsRequest *req) +srs_error_t SrsGoApiRtcPublish::http_hooks_on_publish(ISrsRequest *req) { srs_error_t err = srs_success; diff --git a/trunk/src/app/srs_app_rtc_api.hpp b/trunk/src/app/srs_app_rtc_api.hpp index 24805503c..bc9aea12e 100644 --- a/trunk/src/app/srs_app_rtc_api.hpp +++ b/trunk/src/app/srs_app_rtc_api.hpp @@ -12,7 +12,7 @@ #include class SrsRtcServer; -class SrsRequest; +class ISrsRequest; class SrsSdp; class SrsRtcUserConfig; @@ -39,7 +39,7 @@ private: srs_error_t check_remote_sdp(const SrsSdp &remote_sdp); private: - virtual srs_error_t http_hooks_on_play(SrsRequest *req); + virtual srs_error_t http_hooks_on_play(ISrsRequest *req); }; class SrsGoApiRtcPublish : public ISrsHttpHandler @@ -65,7 +65,7 @@ private: srs_error_t check_remote_sdp(const SrsSdp &remote_sdp); private: - virtual srs_error_t http_hooks_on_publish(SrsRequest *req); + virtual srs_error_t http_hooks_on_publish(ISrsRequest *req); }; // See https://datatracker.ietf.org/doc/draft-ietf-wish-whip/ diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 38ebed95b..e1ddcbe48 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -364,7 +364,7 @@ srs_error_t SrsRtcPLIWorker::cycle() return err; } -SrsRtcAsyncCallOnStop::SrsRtcAsyncCallOnStop(SrsContextId c, SrsRequest *r) +SrsRtcAsyncCallOnStop::SrsRtcAsyncCallOnStop(SrsContextId c, ISrsRequest *r) { cid = c; req = r->copy(); @@ -471,7 +471,7 @@ SrsRtcPlayStream::~SrsRtcPlayStream() stat->on_disconnect(cid_.c_str(), srs_success); } -srs_error_t SrsRtcPlayStream::initialize(SrsRequest *req, std::map sub_relations) +srs_error_t SrsRtcPlayStream::initialize(ISrsRequest *req, std::map sub_relations) { srs_error_t err = srs_success; @@ -1022,7 +1022,7 @@ srs_error_t SrsRtcPublishTwccTimer::on_timer(srs_utime_t interval) return err; } -SrsRtcAsyncCallOnUnpublish::SrsRtcAsyncCallOnUnpublish(SrsContextId c, SrsRequest *r) +SrsRtcAsyncCallOnUnpublish::SrsRtcAsyncCallOnUnpublish(SrsContextId c, ISrsRequest *r) { cid = c; req = r->copy(); @@ -1134,7 +1134,7 @@ SrsRtcPublishStream::~SrsRtcPublishStream() stat->on_disconnect(cid_.c_str(), srs_success); } -srs_error_t SrsRtcPublishStream::initialize(SrsRequest *r, SrsRtcSourceDescription *stream_desc) +srs_error_t SrsRtcPublishStream::initialize(ISrsRequest *r, SrsRtcSourceDescription *stream_desc) { srs_error_t err = srs_success; @@ -1226,7 +1226,7 @@ srs_error_t SrsRtcPublishStream::initialize(SrsRequest *r, SrsRtcSourceDescripti #if defined(SRS_FFMPEG_FIT) bool rtc_to_rtmp = _srs_config->get_rtc_to_rtmp(req_->vhost); if (rtc_to_rtmp) { - if ((err = _srs_sources->fetch_or_create(r, _srs_hybrid->srs()->instance(), live_source)) != srs_success) { + if ((err = _srs_sources->fetch_or_create(r, live_source)) != srs_success) { return srs_error_wrap(err, "create source"); } @@ -1937,7 +1937,7 @@ srs_error_t SrsRtcConnection::add_publisher(SrsRtcUserConfig *ruc, SrsSdp &local { srs_error_t err = srs_success; - SrsRequest *req = ruc->req_; + ISrsRequest *req = ruc->req_; SrsUniquePtr stream_desc(new SrsRtcSourceDescription()); @@ -1978,7 +1978,7 @@ srs_error_t SrsRtcConnection::add_player(SrsRtcUserConfig *ruc, SrsSdp &local_sd { srs_error_t err = srs_success; - SrsRequest *req = ruc->req_; + ISrsRequest *req = ruc->req_; std::map play_sub_relations; if ((err = negotiate_play_capability(ruc, play_sub_relations)) != srs_success) { @@ -2016,7 +2016,7 @@ srs_error_t SrsRtcConnection::add_player(SrsRtcUserConfig *ruc, SrsSdp &local_sd return err; } -srs_error_t SrsRtcConnection::initialize(SrsRequest *r, bool dtls, bool srtp, string username) +srs_error_t SrsRtcConnection::initialize(ISrsRequest *r, bool dtls, bool srtp, string username) { srs_error_t err = srs_success; @@ -2654,7 +2654,7 @@ srs_error_t SrsRtcConnection::negotiate_publish_capability(SrsRtcUserConfig *ruc return srs_error_new(ERROR_RTC_SDP_EXCHANGE, "stream description is NULL"); } - SrsRequest *req = ruc->req_; + ISrsRequest *req = ruc->req_; const SrsSdp &remote_sdp = ruc->remote_sdp_; bool nack_enabled = _srs_config->get_rtc_nack_enabled(req->vhost); @@ -2947,7 +2947,7 @@ srs_error_t SrsRtcConnection::negotiate_publish_capability(SrsRtcUserConfig *ruc return err; } -srs_error_t SrsRtcConnection::generate_publish_local_sdp(SrsRequest *req, SrsSdp &local_sdp, SrsRtcSourceDescription *stream_desc, bool unified_plan, bool audio_before_video) +srs_error_t SrsRtcConnection::generate_publish_local_sdp(ISrsRequest *req, SrsSdp &local_sdp, SrsRtcSourceDescription *stream_desc, bool unified_plan, bool audio_before_video) { srs_error_t err = srs_success; @@ -3086,7 +3086,7 @@ srs_error_t SrsRtcConnection::negotiate_play_capability(SrsRtcUserConfig *ruc, s { srs_error_t err = srs_success; - SrsRequest *req = ruc->req_; + ISrsRequest *req = ruc->req_; const SrsSdp &remote_sdp = ruc->remote_sdp_; bool nack_enabled = _srs_config->get_rtc_nack_enabled(req->vhost); @@ -3325,7 +3325,7 @@ void video_track_generate_play_offer(SrsRtcTrackDescription *track, string mid, } } -srs_error_t SrsRtcConnection::generate_play_local_sdp(SrsRequest *req, SrsSdp &local_sdp, SrsRtcSourceDescription *stream_desc, bool unified_plan, bool audio_before_video) +srs_error_t SrsRtcConnection::generate_play_local_sdp(ISrsRequest *req, SrsSdp &local_sdp, SrsRtcSourceDescription *stream_desc, bool unified_plan, bool audio_before_video) { srs_error_t err = srs_success; @@ -3479,7 +3479,7 @@ srs_error_t SrsRtcConnection::generate_play_local_sdp_for_video(SrsSdp &local_sd return err; } -srs_error_t SrsRtcConnection::create_player(SrsRequest *req, std::map sub_relations) +srs_error_t SrsRtcConnection::create_player(ISrsRequest *req, std::map sub_relations) { srs_error_t err = srs_success; @@ -3545,7 +3545,7 @@ srs_error_t SrsRtcConnection::create_player(SrsRequest *req, std::map source_; // key: publish_ssrc, value: send track to process rtp/rtcp std::map audio_tracks_; @@ -266,7 +266,7 @@ public: virtual ~SrsRtcPlayStream(); public: - srs_error_t initialize(SrsRequest *request, std::map sub_relations); + srs_error_t initialize(ISrsRequest *request, std::map sub_relations); // Interface ISrsRtcSourceChangeCallback public: void on_stream_change(SrsRtcSourceDescription *desc); @@ -337,10 +337,10 @@ class SrsRtcAsyncCallOnUnpublish : public ISrsAsyncCallTask { private: SrsContextId cid; - SrsRequest *req; + ISrsRequest *req; public: - SrsRtcAsyncCallOnUnpublish(SrsContextId c, SrsRequest *r); + SrsRtcAsyncCallOnUnpublish(SrsContextId c, ISrsRequest *r); virtual ~SrsRtcAsyncCallOnUnpublish(); public: @@ -376,7 +376,7 @@ private: SrsErrorPithyPrint *pli_epp; private: - SrsRequest *req_; + ISrsRequest *req_; SrsSharedPtr source_; // Simulators. int nn_simulate_nack_drop; @@ -399,7 +399,7 @@ public: virtual ~SrsRtcPublishStream(); public: - srs_error_t initialize(SrsRequest *req, SrsRtcSourceDescription *stream_desc); + srs_error_t initialize(ISrsRequest *req, SrsRtcSourceDescription *stream_desc); srs_error_t start(); // Directly set the status of track, generally for init to set the default value. void set_all_tracks_status(bool status); @@ -516,7 +516,7 @@ private: private: // For each RTC session, we use a specified cid for debugging logs. SrsContextId cid_; - SrsRequest *req_; + ISrsRequest *req_; SrsSdp remote_sdp; SrsSdp local_sdp; @@ -572,7 +572,7 @@ public: public: // Before initialize, user must set the local SDP, which is used to inititlize DTLS. - srs_error_t initialize(SrsRequest *r, bool dtls, bool srtp, std::string username); + srs_error_t initialize(ISrsRequest *r, bool dtls, bool srtp, std::string username); srs_error_t on_rtp_cipher(char *data, int nb_data); srs_error_t on_rtp_plaintext(char *data, int nb_data); @@ -623,17 +623,17 @@ public: private: // publish media capabilitiy negotiate srs_error_t negotiate_publish_capability(SrsRtcUserConfig *ruc, SrsRtcSourceDescription *stream_desc); - srs_error_t generate_publish_local_sdp(SrsRequest *req, SrsSdp &local_sdp, SrsRtcSourceDescription *stream_desc, bool unified_plan, bool audio_before_video); + srs_error_t generate_publish_local_sdp(ISrsRequest *req, SrsSdp &local_sdp, SrsRtcSourceDescription *stream_desc, bool unified_plan, bool audio_before_video); srs_error_t generate_publish_local_sdp_for_audio(SrsSdp &local_sdp, SrsRtcSourceDescription *stream_desc); srs_error_t generate_publish_local_sdp_for_video(SrsSdp &local_sdp, SrsRtcSourceDescription *stream_desc, bool unified_plan); // play media capabilitiy negotiate // TODO: Use StreamDescription to negotiate and remove first negotiate_play_capability function srs_error_t negotiate_play_capability(SrsRtcUserConfig *ruc, std::map &sub_relations); - srs_error_t generate_play_local_sdp(SrsRequest *req, SrsSdp &local_sdp, SrsRtcSourceDescription *stream_desc, bool unified_plan, bool audio_before_video); + srs_error_t generate_play_local_sdp(ISrsRequest *req, SrsSdp &local_sdp, SrsRtcSourceDescription *stream_desc, bool unified_plan, bool audio_before_video); srs_error_t generate_play_local_sdp_for_audio(SrsSdp &local_sdp, SrsRtcSourceDescription *stream_desc, std::string cname); srs_error_t generate_play_local_sdp_for_video(SrsSdp &local_sdp, SrsRtcSourceDescription *stream_desc, bool unified_plan, std::string cname); - srs_error_t create_player(SrsRequest *request, std::map sub_relations); - srs_error_t create_publisher(SrsRequest *request, SrsRtcSourceDescription *stream_desc); + srs_error_t create_player(ISrsRequest *request, std::map sub_relations); + srs_error_t create_publisher(ISrsRequest *request, SrsRtcSourceDescription *stream_desc); }; #endif diff --git a/trunk/src/app/srs_app_rtc_dtls.hpp b/trunk/src/app/srs_app_rtc_dtls.hpp index 22b249559..c0316e80e 100644 --- a/trunk/src/app/srs_app_rtc_dtls.hpp +++ b/trunk/src/app/srs_app_rtc_dtls.hpp @@ -17,7 +17,7 @@ #include -class SrsRequest; +class ISrsRequest; class SrsDtlsCertificate { diff --git a/trunk/src/app/srs_app_rtc_server.cpp b/trunk/src/app/srs_app_rtc_server.cpp index 4b7ddb9c0..d0003da97 100644 --- a/trunk/src/app/srs_app_rtc_server.cpp +++ b/trunk/src/app/srs_app_rtc_server.cpp @@ -500,7 +500,7 @@ srs_error_t SrsRtcServer::create_session(SrsRtcUserConfig *ruc, SrsSdp &local_sd SrsContextId cid = _srs_context->get_id(); - SrsRequest *req = ruc->req_; + ISrsRequest *req = ruc->req_; SrsSharedPtr source; if ((err = _srs_rtc_sources->fetch_or_create(req, source)) != srs_success) { @@ -527,7 +527,7 @@ srs_error_t SrsRtcServer::do_create_session(SrsRtcUserConfig *ruc, SrsSdp &local { srs_error_t err = srs_success; - SrsRequest *req = ruc->req_; + ISrsRequest *req = ruc->req_; // first add publisher/player for negotiate sdp media info if (ruc->publish_) { diff --git a/trunk/src/app/srs_app_rtc_server.hpp b/trunk/src/app/srs_app_rtc_server.hpp index 1eda54e14..d1eed212f 100644 --- a/trunk/src/app/srs_app_rtc_server.hpp +++ b/trunk/src/app/srs_app_rtc_server.hpp @@ -22,7 +22,7 @@ class SrsRtcServer; class SrsHourGlass; class SrsRtcConnection; -class SrsRequest; +class ISrsRequest; class SrsSdp; class SrsRtcSource; class SrsResourceManager; @@ -68,7 +68,7 @@ public: std::string token_; // Generated data. - SrsRequest *req_; + ISrsRequest *req_; bool publish_; bool dtls_; bool srtp_; diff --git a/trunk/src/app/srs_app_rtc_source.cpp b/trunk/src/app/srs_app_rtc_source.cpp index 7d3b7d5d9..8cb977127 100644 --- a/trunk/src/app/srs_app_rtc_source.cpp +++ b/trunk/src/app/srs_app_rtc_source.cpp @@ -290,43 +290,49 @@ srs_error_t SrsRtcSourceManager::notify(int event, srs_utime_t interval, srs_uti return err; } -srs_error_t SrsRtcSourceManager::fetch_or_create(SrsRequest *r, SrsSharedPtr &pps) +srs_error_t SrsRtcSourceManager::fetch_or_create(ISrsRequest *r, SrsSharedPtr &pps) { srs_error_t err = srs_success; - // Use lock to protect coroutine switch. - // @bug https://github.com/ossrs/srs/issues/1230 - SrsLocker(lock); + bool created = false; + // Should never invoke any function during the locking. + if (true) { + // Use lock to protect coroutine switch. + // @bug https://github.com/ossrs/srs/issues/1230 + SrsLocker(lock); - string stream_url = r->get_stream_url(); - std::map >::iterator it = pool.find(stream_url); + string stream_url = r->get_stream_url(); + std::map >::iterator it = pool.find(stream_url); - if (it != pool.end()) { - SrsSharedPtr source = it->second; + if (it != pool.end()) { + SrsSharedPtr source = it->second; + pps = source; + } else { + SrsSharedPtr source = SrsSharedPtr(new SrsRtcSource()); + srs_trace("new rtc source, stream_url=%s", stream_url.c_str()); + pps = source; - // we always update the request of resource, - // for origin auth is on, the token in request maybe invalid, - // and we only need to update the token of request, it's simple. - source->update_auth(r); - pps = source; - - return err; + pool[stream_url] = source; + created = true; + } } - SrsSharedPtr source = SrsSharedPtr(new SrsRtcSource()); - srs_trace("new rtc source, stream_url=%s", stream_url.c_str()); - - if ((err = source->initialize(r)) != srs_success) { + // Initialize source. + if (created && (err = pps->initialize(r)) != srs_success) { return srs_error_wrap(err, "init source %s", r->get_stream_url().c_str()); } - pool[stream_url] = source; - pps = source; + // we always update the request of resource, + // for origin auth is on, the token in request maybe invalid, + // and we only need to update the token of request, it's simple. + if (!created) { + pps->update_auth(r); + } return err; } -SrsSharedPtr SrsRtcSourceManager::fetch(SrsRequest *r) +SrsSharedPtr SrsRtcSourceManager::fetch(ISrsRequest *r) { // Use lock to protect coroutine switch. // @bug https://github.com/ossrs/srs/issues/1230 @@ -399,7 +405,19 @@ SrsRtcSource::~SrsRtcSource() srs_trace("free rtc source id=[%s]", cid.c_str()); } -srs_error_t SrsRtcSource::initialize(SrsRequest *r) +// CRITICAL: This method is called AFTER the source has been added to the source pool +// in the fetch_or_create pattern (see PR 4449). +// +// IMPORTANT: All field initialization in this method MUST NOT cause coroutine context switches +// before completing the basic field setup. +// +// If context switches occur before all fields are properly initialized, other coroutines +// accessing this source from the pool may encounter uninitialized state, leading to crashes +// or undefined behavior. +// +// This prevents the race condition where multiple coroutines could create duplicate sources +// for the same stream when context switches occurred during initialization. +srs_error_t SrsRtcSource::initialize(ISrsRequest *r) { srs_error_t err = srs_success; @@ -499,7 +517,7 @@ void SrsRtcSource::init_for_play_before_publishing() set_stream_desc(stream_desc.get()); } -void SrsRtcSource::update_auth(SrsRequest *r) +void SrsRtcSource::update_auth(ISrsRequest *r) { req->update_auth(r); } @@ -937,7 +955,7 @@ srs_error_t SrsRtcRtpBuilder::initialize_video_track(SrsVideoCodecId codec) return err; } -srs_error_t SrsRtcRtpBuilder::initialize(SrsRequest *r) +srs_error_t SrsRtcRtpBuilder::initialize(ISrsRequest *r) { srs_error_t err = srs_success; @@ -1733,7 +1751,7 @@ SrsRtcFrameBuilder::~SrsRtcFrameBuilder() srs_freep(obs_whip_pps_); } -srs_error_t SrsRtcFrameBuilder::initialize(SrsRequest *r, SrsAudioCodecId audio_codec, SrsVideoCodecId video_codec) +srs_error_t SrsRtcFrameBuilder::initialize(ISrsRequest *r, SrsAudioCodecId audio_codec, SrsVideoCodecId video_codec) { srs_error_t err = srs_success; diff --git a/trunk/src/app/srs_app_rtc_source.hpp b/trunk/src/app/srs_app_rtc_source.hpp index 83107d2f7..8c98fa5ac 100644 --- a/trunk/src/app/srs_app_rtc_source.hpp +++ b/trunk/src/app/srs_app_rtc_source.hpp @@ -22,7 +22,7 @@ #include #include -class SrsRequest; +class ISrsRequest; class SrsMetaCache; class SrsSharedPtrMessage; class SrsCommonMessage; @@ -150,11 +150,11 @@ public: // create source when fetch from cache failed. // @param r the client request. // @param pps the matched source, if success never be NULL. - virtual srs_error_t fetch_or_create(SrsRequest *r, SrsSharedPtr &pps); + virtual srs_error_t fetch_or_create(ISrsRequest *r, SrsSharedPtr &pps); public: // Get the exists source, NULL when not exists. - virtual SrsSharedPtr fetch(SrsRequest *r); + virtual SrsSharedPtr fetch(ISrsRequest *r); }; // Global singleton instance. @@ -198,7 +198,7 @@ private: SrsContextId _source_id; // previous source id. SrsContextId _pre_source_id; - SrsRequest *req; + ISrsRequest *req; ISrsRtcPublishStream *publish_stream_; // Steam description for this steam. SrsRtcSourceDescription *stream_desc_; @@ -235,7 +235,7 @@ public: virtual ~SrsRtcSource(); public: - virtual srs_error_t initialize(SrsRequest *r); + virtual srs_error_t initialize(ISrsRequest *r); public: // Whether stream is dead, which is no publisher or player. @@ -246,7 +246,7 @@ private: public: // Update the authentication information in request. - virtual void update_auth(SrsRequest *r); + virtual void update_auth(ISrsRequest *r); private: // The stream source changed. @@ -306,7 +306,7 @@ private: class SrsRtcRtpBuilder { private: - SrsRequest *req; + ISrsRequest *req; SrsFrameToRtcBridge *bridge_; // The format, codec information. SrsRtmpFormat *format; @@ -343,7 +343,7 @@ private: srs_error_t initialize_video_track(SrsVideoCodecId codec); public: - virtual srs_error_t initialize(SrsRequest *r); + virtual srs_error_t initialize(ISrsRequest *r); virtual srs_error_t on_publish(); virtual void on_unpublish(); virtual srs_error_t on_frame(SrsSharedPtrMessage *frame); @@ -490,7 +490,7 @@ public: virtual ~SrsRtcFrameBuilder(); public: - srs_error_t initialize(SrsRequest *r, SrsAudioCodecId audio_codec, SrsVideoCodecId video_codec); + srs_error_t initialize(ISrsRequest *r, SrsAudioCodecId audio_codec, SrsVideoCodecId video_codec); virtual srs_error_t on_publish(); virtual void on_unpublish(); virtual srs_error_t on_rtp(SrsRtpPacket *pkt); diff --git a/trunk/src/app/srs_app_rtmp_conn.cpp b/trunk/src/app/srs_app_rtmp_conn.cpp index d244d7e49..87a880124 100644 --- a/trunk/src/app/srs_app_rtmp_conn.cpp +++ b/trunk/src/app/srs_app_rtmp_conn.cpp @@ -300,7 +300,7 @@ srs_error_t SrsRtmpConn::do_cycle() span_connect_ = _srs_apm->span("connect")->as_child(span_main_); #endif - SrsRequest *req = info->req; + ISrsRequest *req = info->req; if ((err = rtmp->connect_app(req)) != srs_success) { return srs_error_wrap(err, "rtmp connect tcUrl"); } @@ -368,7 +368,7 @@ srs_error_t SrsRtmpConn::on_reload_vhost_removed(string vhost) { srs_error_t err = srs_success; - SrsRequest *req = info->req; + ISrsRequest *req = info->req; if (req->vhost != vhost) { return err; @@ -390,7 +390,7 @@ srs_error_t SrsRtmpConn::on_reload_vhost_play(string vhost) { srs_error_t err = srs_success; - SrsRequest *req = info->req; + ISrsRequest *req = info->req; if (req->vhost != vhost) { return err; @@ -416,7 +416,7 @@ srs_error_t SrsRtmpConn::on_reload_vhost_tcp_nodelay(string vhost) { srs_error_t err = srs_success; - SrsRequest *req = info->req; + ISrsRequest *req = info->req; if (req->vhost != vhost) { return err; @@ -431,7 +431,7 @@ srs_error_t SrsRtmpConn::on_reload_vhost_realtime(string vhost) { srs_error_t err = srs_success; - SrsRequest *req = info->req; + ISrsRequest *req = info->req; if (req->vhost != vhost) { return err; @@ -454,7 +454,7 @@ srs_error_t SrsRtmpConn::on_reload_vhost_publish(string vhost) { srs_error_t err = srs_success; - SrsRequest *req = info->req; + ISrsRequest *req = info->req; if (req->vhost != vhost) { return err; @@ -484,7 +484,7 @@ srs_error_t SrsRtmpConn::service_cycle() { srs_error_t err = srs_success; - SrsRequest *req = info->req; + ISrsRequest *req = info->req; int out_ack_size = _srs_config->get_out_ack_size(req->vhost); if (out_ack_size && (err = rtmp->set_window_ack_size(out_ack_size)) != srs_success) { @@ -579,7 +579,7 @@ srs_error_t SrsRtmpConn::stream_service_cycle() { srs_error_t err = srs_success; - SrsRequest *req = info->req; + ISrsRequest *req = info->req; if ((err = rtmp->identify_client(info->res->stream_id, info->type, req->stream, req->duration)) != srs_success) { return srs_error_wrap(err, "rtmp: identify client"); } @@ -657,7 +657,7 @@ srs_error_t SrsRtmpConn::stream_service_cycle() // find a source to serve. SrsSharedPtr live_source; - if ((err = _srs_sources->fetch_or_create(req, server, live_source)) != srs_success) { + if ((err = _srs_sources->fetch_or_create(req, live_source)) != srs_success) { return srs_error_wrap(err, "rtmp: fetch source"); } srs_assert(live_source.get() != NULL); @@ -754,7 +754,7 @@ srs_error_t SrsRtmpConn::check_vhost(bool try_default_vhost) { srs_error_t err = srs_success; - SrsRequest *req = info->req; + ISrsRequest *req = info->req; srs_assert(req != NULL); SrsConfDirective *vhost = _srs_config->get_vhost(req->vhost, try_default_vhost); @@ -789,7 +789,7 @@ srs_error_t SrsRtmpConn::playing(SrsSharedPtr source) srs_error_t err = srs_success; // Check page referer of player. - SrsRequest *req = info->req; + ISrsRequest *req = info->req; if (_srs_config->get_refer_enabled(req->vhost)) { if ((err = refer->check(req->pageUrl, _srs_config->get_refer_play(req->vhost))) != srs_success) { return srs_error_wrap(err, "rtmp: referer check"); @@ -876,7 +876,7 @@ srs_error_t SrsRtmpConn::do_playing(SrsSharedPtr source, SrsLiveC { srs_error_t err = srs_success; - SrsRequest *req = info->req; + ISrsRequest *req = info->req; srs_assert(req); srs_assert(consumer); @@ -1009,7 +1009,7 @@ srs_error_t SrsRtmpConn::publishing(SrsSharedPtr source) { srs_error_t err = srs_success; - SrsRequest *req = info->req; + ISrsRequest *req = info->req; if (_srs_config->get_refer_enabled(req->vhost)) { if ((err = refer->check(req->pageUrl, _srs_config->get_refer_publish(req->vhost))) != srs_success) { @@ -1052,7 +1052,7 @@ srs_error_t SrsRtmpConn::do_publishing(SrsSharedPtr source, SrsPu { srs_error_t err = srs_success; - SrsRequest *req = info->req; + ISrsRequest *req = info->req; SrsUniquePtr pprint(SrsPithyPrint::create_rtmp_publish()); // start isolate recv thread. @@ -1151,7 +1151,7 @@ srs_error_t SrsRtmpConn::acquire_publish(SrsSharedPtr source) { srs_error_t err = srs_success; - SrsRequest *req = info->req; + ISrsRequest *req = info->req; // Check whether RTMP stream is busy. if (!source->can_publish(info->edge)) { @@ -1404,7 +1404,7 @@ srs_error_t SrsRtmpConn::process_play_control_msg(SrsLiveConsumer *consumer, Srs void SrsRtmpConn::set_sock_options() { - SrsRequest *req = info->req; + ISrsRequest *req = info->req; bool nvalue = _srs_config->get_tcp_nodelay(req->vhost); if (nvalue != tcp_nodelay) { @@ -1422,7 +1422,7 @@ srs_error_t SrsRtmpConn::check_edge_token_traverse_auth() { srs_error_t err = srs_success; - SrsRequest *req = info->req; + ISrsRequest *req = info->req; srs_assert(req); vector args = _srs_config->get_vhost_edge_origin(req->vhost)->args; @@ -1456,7 +1456,7 @@ srs_error_t SrsRtmpConn::do_token_traverse_auth(SrsRtmpClient *client) { srs_error_t err = srs_success; - SrsRequest *req = info->req; + ISrsRequest *req = info->req; srs_assert(client); client->set_recv_timeout(SRS_CONSTS_RTMP_TIMEOUT); @@ -1491,7 +1491,7 @@ srs_error_t SrsRtmpConn::http_hooks_on_connect() { srs_error_t err = srs_success; - SrsRequest *req = info->req; + ISrsRequest *req = info->req; if (!_srs_config->get_vhost_http_hooks_enabled(req->vhost)) { return err; @@ -1524,7 +1524,7 @@ srs_error_t SrsRtmpConn::http_hooks_on_connect() void SrsRtmpConn::http_hooks_on_close() { - SrsRequest *req = info->req; + ISrsRequest *req = info->req; if (!_srs_config->get_vhost_http_hooks_enabled(req->vhost)) { return; @@ -1555,7 +1555,7 @@ srs_error_t SrsRtmpConn::http_hooks_on_publish() { srs_error_t err = srs_success; - SrsRequest *req = info->req; + ISrsRequest *req = info->req; if (!_srs_config->get_vhost_http_hooks_enabled(req->vhost)) { return err; @@ -1588,7 +1588,7 @@ srs_error_t SrsRtmpConn::http_hooks_on_publish() void SrsRtmpConn::http_hooks_on_unpublish() { - SrsRequest *req = info->req; + ISrsRequest *req = info->req; if (!_srs_config->get_vhost_http_hooks_enabled(req->vhost)) { return; @@ -1619,7 +1619,7 @@ srs_error_t SrsRtmpConn::http_hooks_on_play() { srs_error_t err = srs_success; - SrsRequest *req = info->req; + ISrsRequest *req = info->req; if (!_srs_config->get_vhost_http_hooks_enabled(req->vhost)) { return err; @@ -1652,7 +1652,7 @@ srs_error_t SrsRtmpConn::http_hooks_on_play() void SrsRtmpConn::http_hooks_on_stop() { - SrsRequest *req = info->req; + ISrsRequest *req = info->req; if (!_srs_config->get_vhost_http_hooks_enabled(req->vhost)) { return; diff --git a/trunk/src/app/srs_app_rtmp_conn.hpp b/trunk/src/app/srs_app_rtmp_conn.hpp index 5f54ffc9c..70822e5f1 100644 --- a/trunk/src/app/srs_app_rtmp_conn.hpp +++ b/trunk/src/app/srs_app_rtmp_conn.hpp @@ -20,7 +20,7 @@ class SrsServer; class SrsRtmpServer; -class SrsRequest; +class ISrsRequest; class SrsResponse; class SrsLiveSource; class SrsRefer; @@ -62,7 +62,7 @@ public: // Whether the client connected at the edge server. bool edge; // Original request object from client. - SrsRequest *req; + ISrsRequest *req; // Response object to client. SrsResponse *res; diff --git a/trunk/src/app/srs_app_rtsp_conn.cpp b/trunk/src/app/srs_app_rtsp_conn.cpp index b91c30c25..19f1fc304 100644 --- a/trunk/src/app/srs_app_rtsp_conn.cpp +++ b/trunk/src/app/srs_app_rtsp_conn.cpp @@ -80,7 +80,7 @@ SrsRtspPlayStream::~SrsRtspPlayStream() stat->on_disconnect(cid_.c_str(), srs_success); } -srs_error_t SrsRtspPlayStream::initialize(SrsRequest *req, std::map sub_relations) +srs_error_t SrsRtspPlayStream::initialize(ISrsRequest *req, std::map sub_relations) { srs_error_t err = srs_success; @@ -850,7 +850,7 @@ srs_error_t SrsRtspConnection::do_teardown() return srs_success; } -srs_error_t SrsRtspConnection::http_hooks_on_play(SrsRequest *req) +srs_error_t SrsRtspConnection::http_hooks_on_play(ISrsRequest *req) { srs_error_t err = srs_success; diff --git a/trunk/src/app/srs_app_rtsp_conn.hpp b/trunk/src/app/srs_app_rtsp_conn.hpp index 48e330921..a533f9b76 100644 --- a/trunk/src/app/srs_app_rtsp_conn.hpp +++ b/trunk/src/app/srs_app_rtsp_conn.hpp @@ -21,7 +21,7 @@ #include #include -class SrsRequest; +class ISrsRequest; class SrsRtpPacket; class SrsRtspSource; class SrsRtspAudioSendTrack; @@ -42,7 +42,7 @@ private: SrsRtspConnection *session_; private: - SrsRequest *req_; + ISrsRequest *req_; SrsSharedPtr source_; // key: publish_ssrc, value: send track to process rtp/rtcp std::map audio_tracks_; @@ -66,7 +66,7 @@ public: virtual ~SrsRtspPlayStream(); public: - srs_error_t initialize(SrsRequest *request, std::map sub_relations); + srs_error_t initialize(ISrsRequest *request, std::map sub_relations); // Interface ISrsRtcSourceChangeCallback public: void on_stream_change(SrsRtcSourceDescription *desc); @@ -101,7 +101,7 @@ private: // TODO: FIXME: Rename it. srs_utime_t last_stun_time; SrsContextId cid_; - SrsRequest *request_; + ISrsRequest *request_; // The manager object to manage the connection. ISrsResourceManager *manager_; // Each connection start a green thread, @@ -179,7 +179,7 @@ private: srs_error_t do_cycle(); private: - srs_error_t http_hooks_on_play(SrsRequest *req); + srs_error_t http_hooks_on_play(ISrsRequest *req); srs_error_t get_ssrc_by_stream_id(uint32_t stream_id, uint32_t *ssrc); }; diff --git a/trunk/src/app/srs_app_rtsp_source.cpp b/trunk/src/app/srs_app_rtsp_source.cpp index b1e16319a..42bf2f1f0 100644 --- a/trunk/src/app/srs_app_rtsp_source.cpp +++ b/trunk/src/app/srs_app_rtsp_source.cpp @@ -168,43 +168,49 @@ srs_error_t SrsRtspSourceManager::notify(int event, srs_utime_t interval, srs_ut return err; } -srs_error_t SrsRtspSourceManager::fetch_or_create(SrsRequest *r, SrsSharedPtr &pps) +srs_error_t SrsRtspSourceManager::fetch_or_create(ISrsRequest *r, SrsSharedPtr &pps) { srs_error_t err = srs_success; - // Use lock to protect coroutine switch. - // @bug https://github.com/ossrs/srs/issues/1230 - SrsLocker(lock); + bool created = false; + // Should never invoke any function during the locking. + if (true) { + // Use lock to protect coroutine switch. + // @bug https://github.com/ossrs/srs/issues/1230 + SrsLocker(lock); - string stream_url = r->get_stream_url(); - std::map >::iterator it = pool.find(stream_url); + string stream_url = r->get_stream_url(); + std::map >::iterator it = pool.find(stream_url); - if (it != pool.end()) { - SrsSharedPtr source = it->second; + if (it != pool.end()) { + SrsSharedPtr source = it->second; + pps = source; + } else { + SrsSharedPtr source = SrsSharedPtr(new SrsRtspSource()); + srs_trace("new rtsp source, stream_url=%s", stream_url.c_str()); + pps = source; - // we always update the request of resource, - // for origin auth is on, the token in request maybe invalid, - // and we only need to update the token of request, it's simple. - source->update_auth(r); - pps = source; - - return err; + pool[stream_url] = source; + created = true; + } } - SrsSharedPtr source = SrsSharedPtr(new SrsRtspSource()); - srs_trace("new rtsp source, stream_url=%s", stream_url.c_str()); - - if ((err = source->initialize(r)) != srs_success) { + // Initialize source. + if (created && (err = pps->initialize(r)) != srs_success) { return srs_error_wrap(err, "init source %s", r->get_stream_url().c_str()); } - pool[stream_url] = source; - pps = source; + // we always update the request of resource, + // for origin auth is on, the token in request maybe invalid, + // and we only need to update the token of request, it's simple. + if (!created) { + pps->update_auth(r); + } return err; } -SrsSharedPtr SrsRtspSourceManager::fetch(SrsRequest *r) +SrsSharedPtr SrsRtspSourceManager::fetch(ISrsRequest *r) { // Use lock to protect coroutine switch. // @bug https://github.com/ossrs/srs/issues/1230 @@ -255,7 +261,19 @@ SrsRtspSource::~SrsRtspSource() srs_trace("free rtc source id=[%s]", cid.c_str()); } -srs_error_t SrsRtspSource::initialize(SrsRequest *r) +// CRITICAL: This method is called AFTER the source has been added to the source pool +// in the fetch_or_create pattern (see PR 4449). +// +// IMPORTANT: All field initialization in this method MUST NOT cause coroutine context switches +// before completing the basic field setup. +// +// If context switches occur before all fields are properly initialized, other coroutines +// accessing this source from the pool may encounter uninitialized state, leading to crashes +// or undefined behavior. +// +// This prevents the race condition where multiple coroutines could create duplicate sources +// for the same stream when context switches occurred during initialization. +srs_error_t SrsRtspSource::initialize(ISrsRequest *r) { srs_error_t err = srs_success; @@ -285,7 +303,7 @@ bool SrsRtspSource::stream_is_dead() return true; } -void SrsRtspSource::update_auth(SrsRequest *r) +void SrsRtspSource::update_auth(ISrsRequest *r) { req->update_auth(r); } @@ -638,7 +656,7 @@ srs_error_t SrsRtspRtpBuilder::initialize_video_track(SrsVideoCodecId codec) return err; } -srs_error_t SrsRtspRtpBuilder::initialize(SrsRequest *r) +srs_error_t SrsRtspRtpBuilder::initialize(ISrsRequest *r) { srs_error_t err = srs_success; diff --git a/trunk/src/app/srs_app_rtsp_source.hpp b/trunk/src/app/srs_app_rtsp_source.hpp index 338499372..3bb40b209 100644 --- a/trunk/src/app/srs_app_rtsp_source.hpp +++ b/trunk/src/app/srs_app_rtsp_source.hpp @@ -17,7 +17,7 @@ #include #include -class SrsRequest; +class ISrsRequest; class SrsRtpPacket; class SrsRtspSource; class SrsRtspConsumer; @@ -26,6 +26,7 @@ class SrsRtcSourceDescription; class SrsResourceManager; class SrsRtspConnection; class SrsRtpVideoBuilder; +class SrsFrameToRtspBridge; // The RTSP stream consumer, consume packets from RTSP stream source. class SrsRtspConsumer @@ -89,11 +90,11 @@ public: // create source when fetch from cache failed. // @param r the client request. // @param pps the matched source, if success never be NULL. - virtual srs_error_t fetch_or_create(SrsRequest *r, SrsSharedPtr &pps); + virtual srs_error_t fetch_or_create(ISrsRequest *r, SrsSharedPtr &pps); public: // Get the exists source, NULL when not exists. - virtual SrsSharedPtr fetch(SrsRequest *r); + virtual SrsSharedPtr fetch(ISrsRequest *r); }; // The global RTSP source manager. @@ -112,7 +113,7 @@ private: SrsContextId _source_id; // previous source id. SrsContextId _pre_source_id; - SrsRequest *req; + ISrsRequest *req; // Steam description for this steam. SrsRtcTrackDescription *audio_desc_; SrsRtcTrackDescription *video_desc_; @@ -134,7 +135,7 @@ public: virtual ~SrsRtspSource(); public: - virtual srs_error_t initialize(SrsRequest *r); + virtual srs_error_t initialize(ISrsRequest *r); public: // Whether stream is dead, which is no publisher or player. @@ -142,7 +143,7 @@ public: public: // Update the authentication information in request. - virtual void update_auth(SrsRequest *r); + virtual void update_auth(ISrsRequest *r); private: // The stream source changed. @@ -188,7 +189,7 @@ public: class SrsRtspRtpBuilder { private: - SrsRequest *req; + ISrsRequest *req; SrsFrameToRtspBridge *bridge_; // The format, codec information. SrsRtmpFormat *format; @@ -219,7 +220,7 @@ private: srs_error_t initialize_video_track(SrsVideoCodecId codec); public: - virtual srs_error_t initialize(SrsRequest *r); + virtual srs_error_t initialize(ISrsRequest *r); virtual srs_error_t on_publish(); virtual void on_unpublish(); virtual srs_error_t on_frame(SrsSharedPtrMessage *frame); diff --git a/trunk/src/app/srs_app_security.cpp b/trunk/src/app/srs_app_security.cpp index ec6c69e7e..2827f1cb2 100644 --- a/trunk/src/app/srs_app_security.cpp +++ b/trunk/src/app/srs_app_security.cpp @@ -19,7 +19,7 @@ SrsSecurity::~SrsSecurity() { } -srs_error_t SrsSecurity::check(SrsRtmpConnType type, string ip, SrsRequest *req) +srs_error_t SrsSecurity::check(SrsRtmpConnType type, string ip, ISrsRequest *req) { srs_error_t err = srs_success; @@ -33,7 +33,7 @@ srs_error_t SrsSecurity::check(SrsRtmpConnType type, string ip, SrsRequest *req) return do_check(rules, type, ip, req); } -srs_error_t SrsSecurity::do_check(SrsConfDirective *rules, SrsRtmpConnType type, string ip, SrsRequest *req) +srs_error_t SrsSecurity::do_check(SrsConfDirective *rules, SrsRtmpConnType type, string ip, ISrsRequest *req) { srs_error_t err = srs_success; diff --git a/trunk/src/app/srs_app_security.hpp b/trunk/src/app/srs_app_security.hpp index f2ecea11d..010f39ea7 100644 --- a/trunk/src/app/srs_app_security.hpp +++ b/trunk/src/app/srs_app_security.hpp @@ -28,10 +28,10 @@ public: // @param type the client type, publish or play. // @param ip the ip address of client. // @param req the request object of client. - virtual srs_error_t check(SrsRtmpConnType type, std::string ip, SrsRequest *req); + virtual srs_error_t check(SrsRtmpConnType type, std::string ip, ISrsRequest *req); private: - virtual srs_error_t do_check(SrsConfDirective *rules, SrsRtmpConnType type, std::string ip, SrsRequest *req); + virtual srs_error_t do_check(SrsConfDirective *rules, SrsRtmpConnType type, std::string ip, ISrsRequest *req); virtual srs_error_t allow_check(SrsConfDirective *rules, SrsRtmpConnType type, std::string ip); virtual srs_error_t deny_check(SrsConfDirective *rules, SrsRtmpConnType type, std::string ip); }; diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp index bd528d297..c5a39115b 100644 --- a/trunk/src/app/srs_app_server.cpp +++ b/trunk/src/app/srs_app_server.cpp @@ -1396,7 +1396,7 @@ srs_error_t SrsServer::on_reload_listen() return err; } -srs_error_t SrsServer::on_publish(SrsRequest *r) +srs_error_t SrsServer::on_publish(ISrsRequest *r) { srs_error_t err = srs_success; @@ -1412,7 +1412,7 @@ srs_error_t SrsServer::on_publish(SrsRequest *r) return err; } -void SrsServer::on_unpublish(SrsRequest *r) +void SrsServer::on_unpublish(ISrsRequest *r) { http_server->http_unmount(r); diff --git a/trunk/src/app/srs_app_server.hpp b/trunk/src/app/srs_app_server.hpp index 415e2fd1f..960f7c321 100644 --- a/trunk/src/app/srs_app_server.hpp +++ b/trunk/src/app/srs_app_server.hpp @@ -256,8 +256,8 @@ public: virtual srs_error_t on_reload_listen(); // Interface ISrsLiveSourceHandler public: - virtual srs_error_t on_publish(SrsRequest *r); - virtual void on_unpublish(SrsRequest *r); + virtual srs_error_t on_publish(ISrsRequest *r); + virtual void on_unpublish(ISrsRequest *r); }; // The SRS server adapter, the master server. diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp index cea23b938..da6da16da 100644 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_source.cpp @@ -19,8 +19,10 @@ using namespace std; #include #include #include +#include #include #include +#include #include #include #include @@ -857,7 +859,7 @@ SrsOriginHub::~SrsOriginHub() #endif } -srs_error_t SrsOriginHub::initialize(SrsSharedPtr s, SrsRequest *r) +srs_error_t SrsOriginHub::initialize(SrsSharedPtr s, ISrsRequest *r) { srs_error_t err = srs_success; @@ -1524,7 +1526,7 @@ srs_error_t SrsOriginHub::create_backend_forwarders(bool &applied) std::string url = *it; // create temp Request by url - SrsUniquePtr req(new SrsRequest()); + SrsUniquePtr req(new SrsRequest()); srs_parse_rtmp_url(url, req->tcUrl, req->stream); srs_discovery_tc_url(req->tcUrl, req->schema, req->host, req->vhost, req->app, req->stream, req->port, req->param); @@ -1760,42 +1762,53 @@ srs_error_t SrsLiveSourceManager::initialize() return setup_ticks(); } -srs_error_t SrsLiveSourceManager::fetch_or_create(SrsRequest *r, ISrsLiveSourceHandler *h, SrsSharedPtr &pps) +srs_error_t SrsLiveSourceManager::fetch_or_create(ISrsRequest *r, SrsSharedPtr &pps) { srs_error_t err = srs_success; - // Use lock to protect coroutine switch. - // @bug https://github.com/ossrs/srs/issues/1230 - // TODO: FIXME: Use smaller scope lock. - SrsLocker(lock); + bool created = false; + // Should never invoke any function during the locking. + if (true) { + // Use lock to protect coroutine switch. + // @bug https://github.com/ossrs/srs/issues/1230 + // TODO: FIXME: Use smaller scope lock. + SrsLocker(lock); - string stream_url = r->get_stream_url(); - std::map >::iterator it = pool.find(stream_url); + string stream_url = r->get_stream_url(); + std::map >::iterator it = pool.find(stream_url); - if (it != pool.end()) { - SrsSharedPtr &source = it->second; + if (it != pool.end()) { + SrsSharedPtr &source = it->second; + pps = source; + } else { + SrsSharedPtr source = new SrsLiveSource(); + srs_trace("new live source, stream_url=%s", stream_url.c_str()); + pps = source; - // we always update the request of resource, - // for origin auth is on, the token in request maybe invalid, - // and we only need to update the token of request, it's simple. - source->update_auth(r); - pps = source; - return err; + // Callback to notify request of source creation + r->on_source_created(); + + pool[stream_url] = source; + created = true; + } } - SrsSharedPtr source = new SrsLiveSource(); - srs_trace("new live source, stream_url=%s", stream_url.c_str()); - - if ((err = source->initialize(source, r, h)) != srs_success) { + // Initialize source with the wrapper of itself. + if (created && (err = pps->initialize(pps, r)) != srs_success) { return srs_error_wrap(err, "init source %s", r->get_stream_url().c_str()); } - pool[stream_url] = source; - pps = source; + // we always update the request of resource, + // for origin auth is on, the token in request maybe invalid, + // and we only need to update the token of request, it's simple. + if (!created) { + pps->update_auth(r); + } + return err; } -SrsSharedPtr SrsLiveSourceManager::fetch(SrsRequest *r) +SrsSharedPtr SrsLiveSourceManager::fetch(ISrsRequest *r) { // Use lock to protect coroutine switch. // @bug https://github.com/ossrs/srs/issues/1230 @@ -1886,7 +1899,6 @@ SrsLiveSource::SrsLiveSource() stream_die_at_ = 0; publisher_idle_at_ = 0; - handler = NULL; bridge_ = NULL; play_edge = new SrsPlayEdge(); @@ -1985,17 +1997,30 @@ bool SrsLiveSource::publisher_is_idle_for(srs_utime_t timeout) return false; } -srs_error_t SrsLiveSource::initialize(SrsSharedPtr wrapper, SrsRequest *r, ISrsLiveSourceHandler *h) +// CRITICAL: This method is called AFTER the source has been added to the source pool +// in the fetch_or_create pattern (see PR 4449). +// +// IMPORTANT: All field initialization in this method MUST NOT cause coroutine context switches +// before completing the basic field setup. +// +// If context switches occur before all fields are properly initialized, other coroutines +// accessing this source from the pool may encounter uninitialized state, leading to crashes +// or undefined behavior. +// +// This prevents the race condition where multiple coroutines could create duplicate sources +// for the same stream when context switches occurred during initialization. +srs_error_t SrsLiveSource::initialize(SrsSharedPtr wrapper, ISrsRequest *r) { srs_error_t err = srs_success; - srs_assert(h); srs_assert(!req); - handler = h; req = r->copy(); atc = _srs_config->get_atc(req->vhost); + jitter_algorithm = (SrsRtmpJitterAlgorithm)_srs_config->get_time_jitter(req->vhost); + mix_correct = _srs_config->get_mix_correct(req->vhost); + if ((err = format_->initialize()) != srs_success) { return srs_error_wrap(err, "format initialize"); } @@ -2003,10 +2028,6 @@ srs_error_t SrsLiveSource::initialize(SrsSharedPtr wrapper, SrsRe // Setup the SPS/PPS parsing strategy. format_->try_annexb_first = _srs_config->try_annexb_first(r->vhost); - if ((err = hub->initialize(wrapper, req)) != srs_success) { - return srs_error_wrap(err, "hub"); - } - if ((err = play_edge->initialize(wrapper, req)) != srs_success) { return srs_error_wrap(err, "edge(play)"); } @@ -2017,8 +2038,9 @@ srs_error_t SrsLiveSource::initialize(SrsSharedPtr wrapper, SrsRe srs_utime_t queue_size = _srs_config->get_queue_length(req->vhost); publish_edge->set_queue_size(queue_size); - jitter_algorithm = (SrsRtmpJitterAlgorithm)_srs_config->get_time_jitter(req->vhost); - mix_correct = _srs_config->get_mix_correct(req->vhost); + if ((err = hub->initialize(wrapper, req)) != srs_success) { + return srs_error_wrap(err, "hub"); + } return err; } @@ -2151,7 +2173,7 @@ bool SrsLiveSource::inactive() return can_publish_; } -void SrsLiveSource::update_auth(SrsRequest *r) +void SrsLiveSource::update_auth(ISrsRequest *r) { req->update_auth(r); } @@ -2588,6 +2610,7 @@ srs_error_t SrsLiveSource::on_publish() } // notify the handler. + ISrsLiveSourceHandler *handler = _srs_hybrid->srs()->instance(); srs_assert(handler); if ((err = handler->on_publish(req)) != srs_success) { return srs_error_wrap(err, "handle publish"); @@ -2636,7 +2659,9 @@ void SrsLiveSource::on_unpublish() _source_id = SrsContextId(); // notify the handler. + ISrsLiveSourceHandler *handler = _srs_hybrid->srs()->instance(); srs_assert(handler); + SrsStatistic *stat = SrsStatistic::instance(); stat->on_stream_close(req); diff --git a/trunk/src/app/srs_app_source.hpp b/trunk/src/app/srs_app_source.hpp index 7fa54b923..11ab13210 100644 --- a/trunk/src/app/srs_app_source.hpp +++ b/trunk/src/app/srs_app_source.hpp @@ -31,7 +31,7 @@ class SrsCommonMessage; class SrsOnMetaDataPacket; class SrsSharedPtrMessage; class SrsForwarder; -class SrsRequest; +class ISrsRequest; class SrsStSocket; class SrsRtmpServer; class SrsEdgeProxyContext; @@ -306,9 +306,9 @@ public: public: // when stream start publish, mount stream. - virtual srs_error_t on_publish(SrsRequest *r) = 0; + virtual srs_error_t on_publish(ISrsRequest *r) = 0; // when stream stop publish, unmount stream. - virtual void on_unpublish(SrsRequest *r) = 0; + virtual void on_unpublish(ISrsRequest *r) = 0; }; // The mix queue to correct the timestamp for mix_correct algorithm. @@ -339,7 +339,7 @@ private: SrsLiveSource *source_; private: - SrsRequest *req_; + ISrsRequest *req_; bool is_active; private: @@ -367,7 +367,7 @@ public: public: // Initialize the hub with source and request. // @param r The request object, managed by source. - virtual srs_error_t initialize(SrsSharedPtr s, SrsRequest *r); + virtual srs_error_t initialize(SrsSharedPtr s, ISrsRequest *r); // Dispose the hub, release utilities resource, // For example, delete all HLS pieces. virtual void dispose(); @@ -492,11 +492,11 @@ public: // @param r the client request. // @param h the event handler for source. // @param pps the matched source, if success never be NULL. - virtual srs_error_t fetch_or_create(SrsRequest *r, ISrsLiveSourceHandler *h, SrsSharedPtr &pps); + virtual srs_error_t fetch_or_create(ISrsRequest *r, SrsSharedPtr &pps); public: // Get the exists source, NULL when not exists. - virtual SrsSharedPtr fetch(SrsRequest *r); + virtual SrsSharedPtr fetch(ISrsRequest *r); public: // dispose and cycle all sources. @@ -529,7 +529,7 @@ private: // previous source id. SrsContextId _pre_source_id; // deep copy of client request. - SrsRequest *req; + ISrsRequest *req; // To delivery stream to clients. std::vector consumers; // The time jitter algorithm for vhost. @@ -547,8 +547,6 @@ private: bool is_monotonically_increase; // The time of the packet we just got. int64_t last_packet_time; - // The event handler. - ISrsLiveSourceHandler *handler; // The source bridge for other source. ISrsStreamBridge *bridge_; // The edge control service @@ -585,7 +583,7 @@ public: public: // Initialize the hls with handlers. - virtual srs_error_t initialize(SrsSharedPtr wrapper, SrsRequest *r, ISrsLiveSourceHandler *h); + virtual srs_error_t initialize(SrsSharedPtr wrapper, ISrsRequest *r); // Bridge to other source, forward packets to it. void set_bridge(ISrsStreamBridge *v); // Interface ISrsReloadHandler @@ -602,7 +600,7 @@ public: // @remark For edge, it's inactive util stream has been pulled from origin. virtual bool inactive(); // Update the authentication information in request. - virtual void update_auth(SrsRequest *r); + virtual void update_auth(ISrsRequest *r); public: virtual bool can_publish(bool is_edge); diff --git a/trunk/src/app/srs_app_srt_conn.cpp b/trunk/src/app/srs_app_srt_conn.cpp index 15173f2fa..9ac18dd4d 100644 --- a/trunk/src/app/srs_app_srt_conn.cpp +++ b/trunk/src/app/srs_app_srt_conn.cpp @@ -372,7 +372,7 @@ srs_error_t SrsMpegtsSrtConn::acquire_publish() return srs_error_new(ERROR_SYSTEM_STREAM_BUSY, "live_source stream %s busy", req_->get_stream_url().c_str()); } - if ((err = _srs_sources->fetch_or_create(req_, _srs_hybrid->srs()->instance(), live_source)) != srs_success) { + if ((err = _srs_sources->fetch_or_create(req_, live_source)) != srs_success) { return srs_error_wrap(err, "create source"); } diff --git a/trunk/src/app/srs_app_srt_conn.hpp b/trunk/src/app/srs_app_srt_conn.hpp index 8dff7d9c6..4d21bf154 100644 --- a/trunk/src/app/srs_app_srt_conn.hpp +++ b/trunk/src/app/srs_app_srt_conn.hpp @@ -134,7 +134,7 @@ private: int port_; SrsCoroutine *trd_; - SrsRequest *req_; + ISrsRequest *req_; SrsSharedPtr srt_source_; SrsSecurity *security_; }; diff --git a/trunk/src/app/srs_app_srt_source.cpp b/trunk/src/app/srs_app_srt_source.cpp index 8976cc59d..2ddfa4a18 100644 --- a/trunk/src/app/srs_app_srt_source.cpp +++ b/trunk/src/app/srs_app_srt_source.cpp @@ -151,39 +151,63 @@ srs_error_t SrsSrtSourceManager::notify(int event, srs_utime_t interval, srs_uti return err; } -srs_error_t SrsSrtSourceManager::fetch_or_create(SrsRequest *r, SrsSharedPtr &pps) +srs_error_t SrsSrtSourceManager::fetch_or_create(ISrsRequest *r, SrsSharedPtr &pps) { srs_error_t err = srs_success; + bool created = false; + // Should never invoke any function during the locking. + if (true) { + // Use lock to protect coroutine switch. + // @bug https://github.com/ossrs/srs/issues/1230 + SrsLocker(lock); + + string stream_url = r->get_stream_url(); + std::map >::iterator it = pool.find(stream_url); + if (it != pool.end()) { + SrsSharedPtr source = it->second; + pps = source; + } else { + SrsSharedPtr source(new SrsSrtSource()); + srs_trace("new srt source, stream_url=%s", stream_url.c_str()); + pps = source; + + pool[stream_url] = source; + created = true; + } + } + + // Initialize source. + if (created && (err = pps->initialize(r)) != srs_success) { + return srs_error_wrap(err, "init source %s", r->get_stream_url().c_str()); + } + + // we always update the request of resource, + // for origin auth is on, the token in request maybe invalid, + // and we only need to update the token of request, it's simple. + if (!created) { + pps->update_auth(r); + } + + return err; +} + +SrsSharedPtr SrsSrtSourceManager::fetch(ISrsRequest *r) +{ // Use lock to protect coroutine switch. // @bug https://github.com/ossrs/srs/issues/1230 SrsLocker(lock); string stream_url = r->get_stream_url(); std::map >::iterator it = pool.find(stream_url); - if (it != pool.end()) { - SrsSharedPtr source = it->second; - // we always update the request of resource, - // for origin auth is on, the token in request maybe invalid, - // and we only need to update the token of request, it's simple. - source->update_auth(r); - pps = source; - - return err; + SrsSharedPtr source; + if (it == pool.end()) { + return source; } - SrsSharedPtr source(new SrsSrtSource()); - srs_trace("new srt source, stream_url=%s", stream_url.c_str()); - - if ((err = source->initialize(r)) != srs_success) { - return srs_error_wrap(err, "init source %s", r->get_stream_url().c_str()); - } - - pool[stream_url] = source; - pps = source; - - return err; + source = it->second; + return source; } SrsSrtSourceManager *_srs_srt_sources = NULL; @@ -326,7 +350,7 @@ void SrsSrtFrameBuilder::on_unpublish() { } -srs_error_t SrsSrtFrameBuilder::initialize(SrsRequest *req) +srs_error_t SrsSrtFrameBuilder::initialize(ISrsRequest *req) { srs_error_t err = srs_success; @@ -927,7 +951,19 @@ SrsSrtSource::~SrsSrtSource() srs_trace("free srt source id=[%s]", cid.c_str()); } -srs_error_t SrsSrtSource::initialize(SrsRequest *r) +// CRITICAL: This method is called AFTER the source has been added to the source pool +// in the fetch_or_create pattern (see PR 4449). +// +// IMPORTANT: All field initialization in this method MUST NOT cause coroutine context switches +// before completing the basic field setup. +// +// If context switches occur before all fields are properly initialized, other coroutines +// accessing this source from the pool may encounter uninitialized state, leading to crashes +// or undefined behavior. +// +// This prevents the race condition where multiple coroutines could create duplicate sources +// for the same stream when context switches occurred during initialization. +srs_error_t SrsSrtSource::initialize(ISrsRequest *r) { srs_error_t err = srs_success; @@ -990,7 +1026,7 @@ SrsContextId SrsSrtSource::pre_source_id() return _pre_source_id; } -void SrsSrtSource::update_auth(SrsRequest *r) +void SrsSrtSource::update_auth(ISrsRequest *r) { req->update_auth(r); } diff --git a/trunk/src/app/srs_app_srt_source.hpp b/trunk/src/app/srs_app_srt_source.hpp index a501d38a7..25c4b5ee1 100644 --- a/trunk/src/app/srs_app_srt_source.hpp +++ b/trunk/src/app/srs_app_srt_source.hpp @@ -19,7 +19,7 @@ #include class SrsSharedPtrMessage; -class SrsRequest; +class ISrsRequest; class SrsLiveSource; class SrsSrtSource; class SrsAlonePithyPrint; @@ -73,7 +73,11 @@ public: // create source when fetch from cache failed. // @param r the client request. // @param pps the matched source, if success never be NULL. - virtual srs_error_t fetch_or_create(SrsRequest *r, SrsSharedPtr &pps); + virtual srs_error_t fetch_or_create(ISrsRequest *r, SrsSharedPtr &pps); + +public: + // Get the exists source, NULL when not exists. + virtual SrsSharedPtr fetch(ISrsRequest *r); }; // Global singleton instance. @@ -117,7 +121,7 @@ public: virtual ~SrsSrtFrameBuilder(); public: - srs_error_t initialize(SrsRequest *r); + srs_error_t initialize(ISrsRequest *r); public: virtual srs_error_t on_publish(); @@ -156,7 +160,7 @@ private: std::string audio_sh_; private: - SrsRequest *req_; + ISrsRequest *req_; private: // SRT to rtmp, video stream id. @@ -174,7 +178,7 @@ public: virtual ~SrsSrtSource(); public: - virtual srs_error_t initialize(SrsRequest *r); + virtual srs_error_t initialize(ISrsRequest *r); public: // Whether stream is dead, which is no publisher or player. @@ -187,7 +191,7 @@ public: virtual SrsContextId source_id(); virtual SrsContextId pre_source_id(); // Update the authentication information in request. - virtual void update_auth(SrsRequest *r); + virtual void update_auth(ISrsRequest *r); public: void set_bridge(ISrsStreamBridge *bridge); @@ -214,7 +218,7 @@ private: SrsContextId _source_id; // previous source id. SrsContextId _pre_source_id; - SrsRequest *req; + ISrsRequest *req; // To delivery packets to clients. std::vector consumers; bool can_publish_; diff --git a/trunk/src/app/srs_app_srt_utility.cpp b/trunk/src/app/srs_app_srt_utility.cpp index 0fed815c1..f50ed67a6 100644 --- a/trunk/src/app/srs_app_srt_utility.cpp +++ b/trunk/src/app/srs_app_srt_utility.cpp @@ -112,7 +112,7 @@ bool srs_srt_streamid_info(const std::string &streamid, SrtMode &mode, std::stri return true; } -bool srs_srt_streamid_to_request(const std::string &streamid, SrtMode &mode, SrsRequest *request) +bool srs_srt_streamid_to_request(const std::string &streamid, SrtMode &mode, ISrsRequest *request) { string url_subpath = ""; bool ret = srs_srt_streamid_info(streamid, mode, request->vhost, url_subpath); diff --git a/trunk/src/app/srs_app_srt_utility.hpp b/trunk/src/app/srs_app_srt_utility.hpp index ccd601364..f320805f0 100644 --- a/trunk/src/app/srs_app_srt_utility.hpp +++ b/trunk/src/app/srs_app_srt_utility.hpp @@ -14,7 +14,7 @@ #include #include -class SrsRequest; +class ISrsRequest; enum SrtMode { SrtModePull = 1, @@ -25,6 +25,6 @@ enum SrtMode { extern bool srs_srt_streamid_info(const std::string &streamid, SrtMode &mode, std::string &vhost, std::string &url_subpath); // SRT streamid to request. -extern bool srs_srt_streamid_to_request(const std::string &streamid, SrtMode &mode, SrsRequest *request); +extern bool srs_srt_streamid_to_request(const std::string &streamid, SrtMode &mode, ISrsRequest *request); #endif diff --git a/trunk/src/app/srs_app_statistic.cpp b/trunk/src/app/srs_app_statistic.cpp index 38a142cb2..ad8c635b6 100644 --- a/trunk/src/app/srs_app_statistic.cpp +++ b/trunk/src/app/srs_app_statistic.cpp @@ -345,7 +345,7 @@ SrsStatisticClient *SrsStatistic::find_client(string client_id) return NULL; } -srs_error_t SrsStatistic::on_video_info(SrsRequest *req, SrsVideoCodecId vcodec, int profile, int level, int width, int height) +srs_error_t SrsStatistic::on_video_info(ISrsRequest *req, SrsVideoCodecId vcodec, int profile, int level, int width, int height) { srs_error_t err = srs_success; @@ -372,7 +372,7 @@ srs_error_t SrsStatistic::on_video_info(SrsRequest *req, SrsVideoCodecId vcodec, return err; } -srs_error_t SrsStatistic::on_audio_info(SrsRequest *req, SrsAudioCodecId acodec, SrsAudioSampleRate asample_rate, SrsAudioChannels asound_type, SrsAacObjectType aac_object) +srs_error_t SrsStatistic::on_audio_info(ISrsRequest *req, SrsAudioCodecId acodec, SrsAudioSampleRate asample_rate, SrsAudioChannels asound_type, SrsAacObjectType aac_object) { srs_error_t err = srs_success; @@ -388,7 +388,7 @@ srs_error_t SrsStatistic::on_audio_info(SrsRequest *req, SrsAudioCodecId acodec, return err; } -srs_error_t SrsStatistic::on_video_frames(SrsRequest *req, int nb_frames) +srs_error_t SrsStatistic::on_video_frames(ISrsRequest *req, int nb_frames) { srs_error_t err = srs_success; @@ -400,7 +400,7 @@ srs_error_t SrsStatistic::on_video_frames(SrsRequest *req, int nb_frames) return err; } -void SrsStatistic::on_stream_publish(SrsRequest *req, std::string publisher_id) +void SrsStatistic::on_stream_publish(ISrsRequest *req, std::string publisher_id) { SrsStatisticVhost *vhost = create_vhost(req); SrsStatisticStream *stream = create_stream(vhost, req); @@ -408,14 +408,14 @@ void SrsStatistic::on_stream_publish(SrsRequest *req, std::string publisher_id) stream->publish(publisher_id); } -void SrsStatistic::on_stream_close(SrsRequest *req) +void SrsStatistic::on_stream_close(ISrsRequest *req) { SrsStatisticVhost *vhost = create_vhost(req); SrsStatisticStream *stream = create_stream(vhost, req); stream->close(); } -srs_error_t SrsStatistic::on_client(std::string id, SrsRequest *req, ISrsExpire *conn, SrsRtmpConnType type) +srs_error_t SrsStatistic::on_client(std::string id, ISrsRequest *req, ISrsExpire *conn, SrsRtmpConnType type) { srs_error_t err = srs_success; @@ -734,7 +734,7 @@ void SrsStatistic::dumps_cls_streams(SrsClsSugars *sugars) } #endif -SrsStatisticVhost *SrsStatistic::create_vhost(SrsRequest *req) +SrsStatisticVhost *SrsStatistic::create_vhost(ISrsRequest *req) { SrsStatisticVhost *vhost = NULL; @@ -752,7 +752,7 @@ SrsStatisticVhost *SrsStatistic::create_vhost(SrsRequest *req) return vhost; } -SrsStatisticStream *SrsStatistic::create_stream(SrsStatisticVhost *vhost, SrsRequest *req) +SrsStatisticStream *SrsStatistic::create_stream(SrsStatisticVhost *vhost, ISrsRequest *req) { // To identify a stream, use url without extension, for example, the bellow are the same stream: // ossrs.io/live/livestream diff --git a/trunk/src/app/srs_app_statistic.hpp b/trunk/src/app/srs_app_statistic.hpp index 974ceef7f..f4be0c829 100644 --- a/trunk/src/app/srs_app_statistic.hpp +++ b/trunk/src/app/srs_app_statistic.hpp @@ -19,7 +19,7 @@ class SrsKbps; class SrsWallClock; -class SrsRequest; +class ISrsRequest; class ISrsExpire; class SrsJsonObject; class SrsJsonArray; @@ -113,7 +113,7 @@ public: public: SrsStatisticStream *stream; - SrsRequest *req; + ISrsRequest *req; SrsRtmpConnType type; std::string id; srs_utime_t create; @@ -183,19 +183,19 @@ public: public: // When got video info for stream. - virtual srs_error_t on_video_info(SrsRequest *req, SrsVideoCodecId vcodec, int avc_profile, int avc_level, int width, int height); + virtual srs_error_t on_video_info(ISrsRequest *req, SrsVideoCodecId vcodec, int avc_profile, int avc_level, int width, int height); // When got audio info for stream. - virtual srs_error_t on_audio_info(SrsRequest *req, SrsAudioCodecId acodec, SrsAudioSampleRate asample_rate, + virtual srs_error_t on_audio_info(ISrsRequest *req, SrsAudioCodecId acodec, SrsAudioSampleRate asample_rate, SrsAudioChannels asound_type, SrsAacObjectType aac_object); // When got videos, update the frames. // We only stat the total number of video frames. - virtual srs_error_t on_video_frames(SrsRequest *req, int nb_frames); + virtual srs_error_t on_video_frames(ISrsRequest *req, int nb_frames); // When publish stream. // @param req the request object of publish connection. // @param publisher_id The id of publish connection. - virtual void on_stream_publish(SrsRequest *req, std::string publisher_id); + virtual void on_stream_publish(ISrsRequest *req, std::string publisher_id); // When close stream. - virtual void on_stream_close(SrsRequest *req); + virtual void on_stream_close(ISrsRequest *req); public: // When got a client to publish/play stream, @@ -203,7 +203,7 @@ public: // @param req, the client request object. // @param conn, the physical absract connection object. // @param type, the type of connection. - virtual srs_error_t on_client(std::string id, SrsRequest *req, ISrsExpire *conn, SrsRtmpConnType type); + virtual srs_error_t on_client(std::string id, ISrsRequest *req, ISrsExpire *conn, SrsRtmpConnType type); // Client disconnect // @remark the on_disconnect always call, while the on_client is call when // only got the request object, so the client specified by id maybe not @@ -248,8 +248,8 @@ public: void dumps_cls_streams(SrsClsSugars *sugars); #endif private: - virtual SrsStatisticVhost *create_vhost(SrsRequest *req); - virtual SrsStatisticStream *create_stream(SrsStatisticVhost *vhost, SrsRequest *req); + virtual SrsStatisticVhost *create_vhost(ISrsRequest *req); + virtual SrsStatisticStream *create_stream(SrsStatisticVhost *vhost, ISrsRequest *req); public: // Dumps exporter metrics. diff --git a/trunk/src/app/srs_app_stream_bridge.cpp b/trunk/src/app/srs_app_stream_bridge.cpp index a100f55ea..0b4d39ebd 100644 --- a/trunk/src/app/srs_app_stream_bridge.cpp +++ b/trunk/src/app/srs_app_stream_bridge.cpp @@ -37,7 +37,7 @@ SrsFrameToRtmpBridge::~SrsFrameToRtmpBridge() { } -srs_error_t SrsFrameToRtmpBridge::initialize(SrsRequest *r) +srs_error_t SrsFrameToRtmpBridge::initialize(ISrsRequest *r) { return srs_success; } @@ -82,7 +82,7 @@ SrsFrameToRtcBridge::~SrsFrameToRtcBridge() #endif } -srs_error_t SrsFrameToRtcBridge::initialize(SrsRequest *r) +srs_error_t SrsFrameToRtcBridge::initialize(ISrsRequest *r) { #ifdef SRS_FFMPEG_FIT return rtp_builder_->initialize(r); @@ -148,7 +148,7 @@ SrsFrameToRtspBridge::~SrsFrameToRtspBridge() srs_freep(rtp_builder_); } -srs_error_t SrsFrameToRtspBridge::initialize(SrsRequest *r) +srs_error_t SrsFrameToRtspBridge::initialize(ISrsRequest *r) { return rtp_builder_->initialize(r); } @@ -201,7 +201,7 @@ SrsCompositeBridge::~SrsCompositeBridge() } } -srs_error_t SrsCompositeBridge::initialize(SrsRequest *r) +srs_error_t SrsCompositeBridge::initialize(ISrsRequest *r) { srs_error_t err = srs_success; diff --git a/trunk/src/app/srs_app_stream_bridge.hpp b/trunk/src/app/srs_app_stream_bridge.hpp index 9f0589c4f..143a08566 100644 --- a/trunk/src/app/srs_app_stream_bridge.hpp +++ b/trunk/src/app/srs_app_stream_bridge.hpp @@ -14,7 +14,7 @@ #include -class SrsRequest; +class ISrsRequest; class SrsSharedPtrMessage; class SrsLiveSource; class SrsRtcSource; @@ -35,7 +35,7 @@ public: virtual ~ISrsStreamBridge(); public: - virtual srs_error_t initialize(SrsRequest *r) = 0; + virtual srs_error_t initialize(ISrsRequest *r) = 0; virtual srs_error_t on_publish() = 0; virtual srs_error_t on_frame(SrsSharedPtrMessage *frame) = 0; virtual void on_unpublish() = 0; @@ -52,7 +52,7 @@ public: virtual ~SrsFrameToRtmpBridge(); public: - srs_error_t initialize(SrsRequest *r); + srs_error_t initialize(ISrsRequest *r); public: virtual srs_error_t on_publish(); @@ -77,7 +77,7 @@ public: virtual ~SrsFrameToRtcBridge(); public: - virtual srs_error_t initialize(SrsRequest *r); + virtual srs_error_t initialize(ISrsRequest *r); virtual srs_error_t on_publish(); virtual void on_unpublish(); virtual srs_error_t on_frame(SrsSharedPtrMessage *frame); @@ -99,7 +99,7 @@ public: virtual ~SrsFrameToRtspBridge(); public: - virtual srs_error_t initialize(SrsRequest *r); + virtual srs_error_t initialize(ISrsRequest *r); virtual srs_error_t on_publish(); virtual void on_unpublish(); virtual srs_error_t on_frame(SrsSharedPtrMessage *frame); @@ -117,7 +117,7 @@ public: public: bool empty() { return bridges_.empty(); } // SrsCompositeBridge::empty() public: - srs_error_t initialize(SrsRequest *r); + srs_error_t initialize(ISrsRequest *r); public: virtual srs_error_t on_publish(); diff --git a/trunk/src/core/srs_core_version7.hpp b/trunk/src/core/srs_core_version7.hpp index 36992b251..56b0e01d5 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 60 +#define VERSION_REVISION 61 #endif \ No newline at end of file diff --git a/trunk/src/main/srs_main_ingest_hls.cpp b/trunk/src/main/srs_main_ingest_hls.cpp index bdc1237e6..540702098 100644 --- a/trunk/src/main/srs_main_ingest_hls.cpp +++ b/trunk/src/main/srs_main_ingest_hls.cpp @@ -661,7 +661,7 @@ private: int64_t raw_aac_dts; private: - SrsRequest *req; + ISrsRequest *req; SrsBasicRtmpClient *sdk; private: diff --git a/trunk/src/protocol/srs_protocol_http_conn.cpp b/trunk/src/protocol/srs_protocol_http_conn.cpp index 23fc7df5f..bf63c9b3d 100644 --- a/trunk/src/protocol/srs_protocol_http_conn.cpp +++ b/trunk/src/protocol/srs_protocol_http_conn.cpp @@ -593,9 +593,9 @@ SrsHttpHeader *SrsHttpMessage::header() return &_header; } -SrsRequest *SrsHttpMessage::to_request(string vhost) +ISrsRequest *SrsHttpMessage::to_request(string vhost) { - SrsRequest *req = new SrsRequest(); + ISrsRequest *req = new SrsRequest(); // http path, for instance, /live/livestream.flv, parse to // app: /live diff --git a/trunk/src/protocol/srs_protocol_http_conn.hpp b/trunk/src/protocol/srs_protocol_http_conn.hpp index 45d26633f..3f5ade3f2 100644 --- a/trunk/src/protocol/srs_protocol_http_conn.hpp +++ b/trunk/src/protocol/srs_protocol_http_conn.hpp @@ -16,7 +16,7 @@ class ISrsConnection; class SrsFastStream; -class SrsRequest; +class ISrsRequest; class ISrsReader; class SrsHttpResponseReader; class ISrsProtocolReadWriter; @@ -192,7 +192,7 @@ public: public: // Convert the http message to a request. // @remark user must free the return request. - virtual SrsRequest *to_request(std::string vhost); + virtual ISrsRequest *to_request(std::string vhost); public: virtual bool is_jsonp(); diff --git a/trunk/src/protocol/srs_protocol_rtmp_conn.hpp b/trunk/src/protocol/srs_protocol_rtmp_conn.hpp index 9643f4820..981114a92 100644 --- a/trunk/src/protocol/srs_protocol_rtmp_conn.hpp +++ b/trunk/src/protocol/srs_protocol_rtmp_conn.hpp @@ -11,7 +11,7 @@ #include -class SrsRequest; +class ISrsRequest; class SrsTcpClient; class SrsRtmpClient; class SrsCommonMessage; @@ -36,7 +36,7 @@ private: srs_utime_t stream_timeout; protected: - SrsRequest *req; + ISrsRequest *req; private: SrsTcpClient *transport; diff --git a/trunk/src/protocol/srs_protocol_rtmp_stack.cpp b/trunk/src/protocol/srs_protocol_rtmp_stack.cpp index 899490b39..3b9f8f292 100644 --- a/trunk/src/protocol/srs_protocol_rtmp_stack.cpp +++ b/trunk/src/protocol/srs_protocol_rtmp_stack.cpp @@ -1459,6 +1459,18 @@ SrsChunkStream::~SrsChunkStream() srs_freep(msg); } +ISrsRequest::ISrsRequest() +{ +} + +ISrsRequest::~ISrsRequest() +{ +} + +void ISrsRequest::on_source_created() +{ +} + SrsRequest::SrsRequest() { objectEncoding = RTMP_SIG_AMF0_VER; @@ -1474,7 +1486,7 @@ SrsRequest::~SrsRequest() srs_freep(args); } -SrsRequest *SrsRequest::copy() +ISrsRequest *SrsRequest::copy() { SrsRequest *cp = new SrsRequest(); @@ -1500,7 +1512,7 @@ SrsRequest *SrsRequest::copy() return cp; } -void SrsRequest::update_auth(SrsRequest *req) +void SrsRequest::update_auth(ISrsRequest *req) { pageUrl = req->pageUrl; swfUrl = req->swfUrl; @@ -1551,7 +1563,7 @@ void SrsRequest::strip() stream = srs_string_trim_start(stream, "/"); } -SrsRequest *SrsRequest::as_http() +ISrsRequest *SrsRequest::as_http() { schema = "http"; tcUrl = srs_generate_tc_url(schema, host, vhost, app, port); @@ -1883,7 +1895,7 @@ srs_error_t SrsRtmpClient::complex_handshake() return err; } -srs_error_t SrsRtmpClient::connect_app(string app, string tcUrl, SrsRequest *r, bool dsu, SrsServerInfo *si) +srs_error_t SrsRtmpClient::connect_app(string app, string tcUrl, ISrsRequest *r, bool dsu, SrsServerInfo *si) { srs_error_t err = srs_success; @@ -2256,7 +2268,7 @@ srs_error_t SrsRtmpServer::handshake() return err; } -srs_error_t SrsRtmpServer::connect_app(SrsRequest *req) +srs_error_t SrsRtmpServer::connect_app(ISrsRequest *req) { srs_error_t err = srs_success; @@ -2331,7 +2343,7 @@ srs_error_t SrsRtmpServer::set_peer_bandwidth(int bandwidth, int type) return err; } -srs_error_t SrsRtmpServer::response_connect_app(SrsRequest *req, const char *server_ip) +srs_error_t SrsRtmpServer::response_connect_app(ISrsRequest *req, const char *server_ip) { srs_error_t err = srs_success; @@ -2372,7 +2384,7 @@ srs_error_t SrsRtmpServer::response_connect_app(SrsRequest *req, const char *ser } #define SRS_RTMP_REDIRECT_TIMEOUT (3 * SRS_UTIME_SECONDS) -srs_error_t SrsRtmpServer::redirect(SrsRequest *r, string url, bool &accepted) +srs_error_t SrsRtmpServer::redirect(ISrsRequest *r, string url, bool &accepted) { srs_error_t err = srs_success; @@ -2423,7 +2435,7 @@ srs_error_t SrsRtmpServer::redirect(SrsRequest *r, string url, bool &accepted) return err; } -void SrsRtmpServer::response_connect_reject(SrsRequest * /*req*/, const char *desc) +void SrsRtmpServer::response_connect_reject(ISrsRequest * /*req*/, const char *desc) { srs_error_t err = srs_success; diff --git a/trunk/src/protocol/srs_protocol_rtmp_stack.hpp b/trunk/src/protocol/srs_protocol_rtmp_stack.hpp index c129130f0..bff00f86f 100644 --- a/trunk/src/protocol/srs_protocol_rtmp_stack.hpp +++ b/trunk/src/protocol/srs_protocol_rtmp_stack.hpp @@ -408,8 +408,7 @@ public: virtual ~SrsChunkStream(); }; -// The original request from client. -class SrsRequest +class ISrsRequest { public: // The client ip. @@ -457,34 +456,55 @@ public: // @see https://github.com/ossrs/srs/issues/104 SrsAmf0Object *args; -public: - SrsRequest(); - virtual ~SrsRequest(); - -public: - // Deep copy the request, for source to use it to support reload, - // For when initialize the source, the request is valid, - // When reload it, the request maybe invalid, so need to copy it. - virtual SrsRequest *copy(); - // update the auth info of request, - // To keep the current request ptr is ok, - // For many components use the ptr of request. - virtual void update_auth(SrsRequest *req); - // Get the stream identify, vhost/app/stream. - virtual std::string get_stream_url(); - // To strip url, user must strip when update the url. - virtual void strip(); - -public: - // Transform it as HTTP request. - virtual SrsRequest *as_http(); - public: // The protocol of client: // rtmp, Adobe RTMP protocol. // flv, HTTP-FLV protocol. // flvs, HTTPS-FLV protocol. std::string protocol; + +public: + ISrsRequest(); + virtual ~ISrsRequest(); + +public: + // Deep copy the request, for source to use it to support reload, + // For when initialize the source, the request is valid, + // When reload it, the request maybe invalid, so need to copy it. + virtual ISrsRequest *copy() = 0; + // update the auth info of request, + // To keep the current request ptr is ok, + // For many components use the ptr of request. + virtual void update_auth(ISrsRequest *req) = 0; + // Get the stream identify, vhost/app/stream. + virtual std::string get_stream_url() = 0; + // To strip url, user must strip when update the url. + virtual void strip() = 0; + +public: + // Transform it as HTTP request. + virtual ISrsRequest *as_http() = 0; + +public: + // Callback when source is created. + virtual void on_source_created(); +}; + +// The original request from client. +class SrsRequest : public ISrsRequest +{ +public: + SrsRequest(); + virtual ~SrsRequest(); + +public: + virtual ISrsRequest *copy(); + virtual void update_auth(ISrsRequest *req); + virtual std::string get_stream_url(); + virtual void strip(); + +public: + virtual ISrsRequest *as_http(); }; // The response to client. @@ -601,7 +621,7 @@ public: // @param req, the optional req object, use the swfUrl/pageUrl if specified. NULL to ignore. // @param dsu, Whether debug SRS upnode. For edge, set to true to send its info to upnode. // @param si, The server information, retrieve from response of connect app request. NULL to ignore. - virtual srs_error_t connect_app(std::string app, std::string tcUrl, SrsRequest *r, bool dsu, SrsServerInfo *si); + virtual srs_error_t connect_app(std::string app, std::string tcUrl, ISrsRequest *r, bool dsu, SrsServerInfo *si); // Create a stream, then play/publish data over this stream. virtual srs_error_t create_stream(int &stream_id); // start play stream. @@ -722,7 +742,7 @@ public: // Do handshake with client, try complex then simple. virtual srs_error_t handshake(); // Do connect app with client, to discovery tcUrl. - virtual srs_error_t connect_app(SrsRequest *req); + virtual srs_error_t connect_app(ISrsRequest *req); // Set output ack size to client, client will send ack-size for each ack window virtual srs_error_t set_window_ack_size(int ack_size); // Set the default input ack size value. @@ -731,13 +751,13 @@ public: // using the Limit type field. virtual srs_error_t set_peer_bandwidth(int bandwidth, int type); // @param server_ip the ip of server. - virtual srs_error_t response_connect_app(SrsRequest *req, const char *server_ip = NULL); + virtual srs_error_t response_connect_app(ISrsRequest *req, const char *server_ip = NULL); // Redirect the connection to another rtmp server. // @param a RTMP url to redirect to. // @param whether the client accept the redirect. - virtual srs_error_t redirect(SrsRequest *r, std::string url, bool &accepted); + virtual srs_error_t redirect(ISrsRequest *r, std::string url, bool &accepted); // Reject the connect app request. - virtual void response_connect_reject(SrsRequest *req, const char *desc); + virtual void response_connect_reject(ISrsRequest *req, const char *desc); // Response client the onBWDone message. virtual srs_error_t on_bw_done(); // Recv some message to identify the client. diff --git a/trunk/src/utest/srs_utest_rtmp.cpp b/trunk/src/utest/srs_utest_rtmp.cpp index 5b27baba0..19ca21e7e 100644 --- a/trunk/src/utest/srs_utest_rtmp.cpp +++ b/trunk/src/utest/srs_utest_rtmp.cpp @@ -976,7 +976,7 @@ VOID TEST(ProtocolRTMPTest, RecvMessage3) SrsRequest req; req.ip = "10.11.12.13"; - SrsRequest *cp = req.copy(); + ISrsRequest *cp = req.copy(); EXPECT_STREQ("10.11.12.13", cp->ip.c_str()); srs_freep(cp); } @@ -989,7 +989,7 @@ VOID TEST(ProtocolRTMPTest, RecvMessage3) obj->set("id", SrsAmf0Any::str("srs")); req.args = obj; - SrsRequest *cp = req.copy(); + ISrsRequest *cp = req.copy(); EXPECT_STREQ("10.11.12.13", cp->ip.c_str()); SrsAmf0Object *cpa = dynamic_cast(cp->args); diff --git a/trunk/src/utest/srs_utest_service.cpp b/trunk/src/utest/srs_utest_service.cpp index d4898b687..bcf78e433 100644 --- a/trunk/src/utest/srs_utest_service.cpp +++ b/trunk/src/utest/srs_utest_service.cpp @@ -636,7 +636,7 @@ VOID TEST(HTTPServerTest, MessageTurnRequest) if (true) { SrsHttpMessage m; HELPER_ASSERT_SUCCESS(m.set_url("http://127.0.0.1/live/livestream.flv", false)); - SrsRequest *r = m.to_request("ossrs.net"); + ISrsRequest *r = m.to_request("ossrs.net"); EXPECT_STREQ("live", r->app.c_str()); EXPECT_STREQ("livestream", r->stream.c_str()); EXPECT_STREQ("rtmp://ossrs.net/live", r->tcUrl.c_str()); @@ -646,7 +646,7 @@ VOID TEST(HTTPServerTest, MessageTurnRequest) if (true) { SrsHttpMessage m; HELPER_ASSERT_SUCCESS(m.set_url("http://127.0.0.1/live/livestream.flv?token=key", false)); - SrsRequest *r = m.to_request("ossrs.net"); + ISrsRequest *r = m.to_request("ossrs.net"); EXPECT_STREQ("rtmp://ossrs.net/live", r->tcUrl.c_str()); EXPECT_STREQ("?token=key", r->param.c_str()); srs_freep(r); @@ -657,7 +657,7 @@ VOID TEST(HTTPServerTest, MessageTurnRequest) SrsHttpMessage m; m.set_connection(&conn); - SrsRequest *r = m.to_request("ossrs.net"); + ISrsRequest *r = m.to_request("ossrs.net"); EXPECT_STREQ("127.0.0.1", r->ip.c_str()); srs_freep(r); } @@ -671,7 +671,7 @@ VOID TEST(HTTPServerTest, MessageTurnRequest) hdr.set("X-Real-IP", "10.11.12.13"); m.set_header(&hdr, false); - SrsRequest *r = m.to_request("ossrs.net"); + ISrsRequest *r = m.to_request("ossrs.net"); EXPECT_STREQ("10.11.12.13", r->ip.c_str()); srs_freep(r); } diff --git a/trunk/src/utest/srs_utest_source_lock.cpp b/trunk/src/utest/srs_utest_source_lock.cpp new file mode 100644 index 000000000..9c315b1d8 --- /dev/null +++ b/trunk/src/utest/srs_utest_source_lock.cpp @@ -0,0 +1,817 @@ +// +// Copyright (c) 2013-2025 The SRS Authors +// +// SPDX-License-Identifier: MIT +// +#include + +using namespace std; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef SRS_RTSP +#include +#endif + +/** + * Unit tests for source lock refinement (PR #4449) + * + * This file tests the race condition fixes in source managers where multiple + * coroutines could create duplicate sources for the same stream. The fix ensures + * atomic source creation and pool insertion. + * + * Template Design: + * - MockOtherSourceAsyncCreator: Template for RTC, SRT, RTSP + * - MockLiveSourceAsyncCreator: Separate class for Live sources (needs handler parameter) + * - Type aliases provide backward compatibility with original class names + */ + +// This mock request always cause context switch in get_stream_url(). +class MockAsyncSrsRequest : public ISrsRequest +{ +public: + string mock_stream_url; + bool enable_context_switch; + + MockAsyncSrsRequest(const string &url = "/live/livestream", bool context_switch = false) + { + mock_stream_url = url; + enable_context_switch = context_switch; + + // Initialize all ISrsRequest members to safe defaults + objectEncoding = RTMP_SIG_AMF0_VER; + duration = -1; + port = SRS_CONSTS_RTMP_DEFAULT_PORT; + args = NULL; // Initialize to NULL to prevent crashes + protocol = "rtmp"; + + // Parse the URL to set vhost, app, stream + size_t app_pos = url.find('/', 1); // Find second slash + if (app_pos != string::npos) { + size_t stream_pos = url.find('/', app_pos + 1); // Find third slash + if (stream_pos != string::npos) { + app = url.substr(app_pos + 1, stream_pos - app_pos - 1); + stream = url.substr(stream_pos + 1); + } else { + app = url.substr(app_pos + 1); + stream = "livestream"; + } + } else { + app = "live"; + stream = "livestream"; + } + + vhost = "localhost"; + } + + virtual string get_stream_url() + { + on_source_created(); + return mock_stream_url; + } + + virtual void on_source_created() + { + // Simulate context switch that could happen during source initialization + if (enable_context_switch) { + // Force a context switch by yielding to other coroutines + // This simulates the original race condition scenario + st_usleep(1 * SRS_UTIME_MILLISECONDS); // 1ms sleep to trigger context switch + } + } + + virtual ISrsRequest *copy() + { + MockAsyncSrsRequest *cp = new MockAsyncSrsRequest(mock_stream_url, enable_context_switch); + + *cp = *this; + if (args) { + cp->args = args->copy()->to_object(); + } + + return cp; + } + + virtual void update_auth(ISrsRequest *req) + { + } + + virtual void strip() + { + } + + virtual ISrsRequest *as_http() + { + return this; + } +}; + +// Template for non-live source async creators (RTC, SRT, RTSP) +// Since SRS uses C++98, we use a simple template approach +// Note: MockLiveSourceAsyncCreator is kept separate because it requires an additional +// ISrsLiveSourceHandler parameter that the other source managers don't need +template +class MockOtherSourceAsyncCreator : public ISrsCoroutineHandler +{ +public: + SrsWaitGroup *wg_; + ManagerType *manager_; + MockAsyncSrsRequest *req_; + SrsSharedPtr source_; + + MockOtherSourceAsyncCreator(SrsWaitGroup *w, ManagerType *m, MockAsyncSrsRequest *r) + { + wg_ = w; + manager_ = m; + req_ = r; + } + + virtual ~MockOtherSourceAsyncCreator() + { + } + + virtual srs_error_t cycle() + { + srs_error_t err = do_cycle(); + wg_->done(); + return err; + } + + srs_error_t do_cycle() + { + srs_error_t err = srs_success; + + // Test fetch_or_create - should create new source + if ((err = manager_->fetch_or_create(req_, source_)) != srs_success) { + return srs_error_wrap(err, "fetch or create"); + } + + return err; + } +}; + +// Type aliases for convenience (C++98 compatible) +typedef MockOtherSourceAsyncCreator MockLiveSourceAsyncCreator; + +// Test race condition of source managers +VOID TEST(SourceLockTest, LiveSourceManager_RaceCondition) +{ + srs_error_t err; + + SrsLiveSourceManager manager; + HELPER_EXPECT_SUCCESS(manager.initialize()); + + MockAsyncSrsRequest req("/live/test1", true); // Enable context switch + SrsSharedPtr source; + + // Create a coroutine to create source2. + SrsWaitGroup wg; + MockLiveSourceAsyncCreator creator(&wg, &manager, &req); + SrsSTCoroutine trd("test", &creator); + + wg.add(1); + HELPER_EXPECT_SUCCESS(trd.start()); + + // Test fetch_or_create - should create new source + HELPER_EXPECT_SUCCESS(manager.fetch_or_create(&req, source)); + EXPECT_TRUE(source.get() != NULL); + + // Wait for coroutine to finish. + wg.wait(); + + // The created two sources should be the same instance (no duplicates created) + EXPECT_EQ(source.get(), creator.source_.get()); + + // Test fetch - should return the same source + SrsSharedPtr fetched = manager.fetch(&req); + EXPECT_TRUE(fetched.get() != NULL); + EXPECT_EQ(source.get(), fetched.get()); + + // Test fetch_or_create again - should return existing source + SrsSharedPtr source2; + HELPER_EXPECT_SUCCESS(manager.fetch_or_create(&req, source2)); + EXPECT_EQ(source.get(), source2.get()); +} + +// Type aliases for convenience (C++98 compatible) +typedef MockOtherSourceAsyncCreator MockRtcSourceAsyncCreator; + +// Test race condition of source managers +VOID TEST(SourceLockTest, RtcSourceManager_RaceCondition) +{ + srs_error_t err; + + SrsRtcSourceManager manager; + HELPER_EXPECT_SUCCESS(manager.initialize()); + + MockAsyncSrsRequest req("/live/test1", true); // Enable context switch + SrsSharedPtr source; + + // Create a coroutine to create source2. + SrsWaitGroup wg; + MockRtcSourceAsyncCreator creator(&wg, &manager, &req); + SrsSTCoroutine trd("test", &creator); + + wg.add(1); + HELPER_EXPECT_SUCCESS(trd.start()); + + // Test fetch_or_create - should create new source + HELPER_EXPECT_SUCCESS(manager.fetch_or_create(&req, source)); + EXPECT_TRUE(source.get() != NULL); + + // Wait for coroutine to finish. + wg.wait(); + + // The created two sources should be the same instance (no duplicates created) + EXPECT_EQ(source.get(), creator.source_.get()); + + // Test fetch - should return the same source + SrsSharedPtr fetched = manager.fetch(&req); + EXPECT_TRUE(fetched.get() != NULL); + EXPECT_EQ(source.get(), fetched.get()); + + // Test fetch_or_create again - should return existing source + SrsSharedPtr source2; + HELPER_EXPECT_SUCCESS(manager.fetch_or_create(&req, source2)); + EXPECT_EQ(source.get(), source2.get()); +} + +typedef MockOtherSourceAsyncCreator MockSrtSourceAsyncCreator; + +// Test race condition of source managers +VOID TEST(SourceLockTest, SrtSourceManager_RaceCondition) +{ + srs_error_t err; + + SrsSrtSourceManager manager; + HELPER_EXPECT_SUCCESS(manager.initialize()); + + MockAsyncSrsRequest req("/live/test1", true); // Enable context switch + SrsSharedPtr source; + + // Create a coroutine to create source2. + SrsWaitGroup wg; + MockSrtSourceAsyncCreator creator(&wg, &manager, &req); + SrsSTCoroutine trd("test", &creator); + + wg.add(1); + HELPER_EXPECT_SUCCESS(trd.start()); + + // Test fetch_or_create - should create new source + HELPER_EXPECT_SUCCESS(manager.fetch_or_create(&req, source)); + EXPECT_TRUE(source.get() != NULL); + + // Wait for coroutine to finish. + wg.wait(); + + // The created two sources should be the same instance (no duplicates created) + EXPECT_EQ(source.get(), creator.source_.get()); + + // Test fetch - should return the same source + SrsSharedPtr fetched = manager.fetch(&req); + EXPECT_TRUE(fetched.get() != NULL); + EXPECT_EQ(source.get(), fetched.get()); + + // Test fetch_or_create again - should return existing source + SrsSharedPtr source2; + HELPER_EXPECT_SUCCESS(manager.fetch_or_create(&req, source2)); + EXPECT_EQ(source.get(), source2.get()); +} + +// Test basic functionality of source managers +VOID TEST(SourceLockTest, LiveSourceManager_BasicFunctionality) +{ + srs_error_t err; + + SrsLiveSourceManager manager; + HELPER_EXPECT_SUCCESS(manager.initialize()); + + MockAsyncSrsRequest req("/live/test1"); + SrsSharedPtr source; + + // Test fetch_or_create - should create new source + HELPER_EXPECT_SUCCESS(manager.fetch_or_create(&req, source)); + EXPECT_TRUE(source.get() != NULL); + + // Test fetch - should return the same source + SrsSharedPtr fetched = manager.fetch(&req); + EXPECT_TRUE(fetched.get() != NULL); + EXPECT_EQ(source.get(), fetched.get()); + + // Test fetch_or_create again - should return existing source + SrsSharedPtr source2; + HELPER_EXPECT_SUCCESS(manager.fetch_or_create(&req, source2)); + EXPECT_EQ(source.get(), source2.get()); +} + +// Test concurrent access scenarios to verify race condition fixes +VOID TEST(SourceLockTest, LiveSourceManager_ConcurrentAccess) +{ + srs_error_t err; + + SrsLiveSourceManager manager; + HELPER_EXPECT_SUCCESS(manager.initialize()); + + MockAsyncSrsRequest req("/live/concurrent_test", true); // Enable context switch + + // Simulate multiple concurrent requests for the same stream + vector > sources; + const int concurrent_requests = 10; + + for (int i = 0; i < concurrent_requests; i++) { + SrsSharedPtr source; + HELPER_EXPECT_SUCCESS(manager.fetch_or_create(&req, source)); + sources.push_back(source); + EXPECT_TRUE(source.get() != NULL); + } + + // All sources should be the same instance (no duplicates created) + for (int i = 1; i < concurrent_requests; i++) { + EXPECT_EQ(sources[0].get(), sources[i].get()); + } +} + +// Test different stream URLs create different sources +VOID TEST(SourceLockTest, LiveSourceManager_DifferentStreams) +{ + srs_error_t err; + + SrsLiveSourceManager manager; + HELPER_EXPECT_SUCCESS(manager.initialize()); + + // Create sources for different streams + MockAsyncSrsRequest req1("/live/stream1"); + MockAsyncSrsRequest req2("/live/stream2"); + MockAsyncSrsRequest req3("/live/stream3"); + + SrsSharedPtr source1, source2, source3; + + HELPER_EXPECT_SUCCESS(manager.fetch_or_create(&req1, source1)); + HELPER_EXPECT_SUCCESS(manager.fetch_or_create(&req2, source2)); + HELPER_EXPECT_SUCCESS(manager.fetch_or_create(&req3, source3)); + + // All sources should be different instances + EXPECT_TRUE(source1.get() != NULL); + EXPECT_TRUE(source2.get() != NULL); + EXPECT_TRUE(source3.get() != NULL); + EXPECT_NE(source1.get(), source2.get()); + EXPECT_NE(source1.get(), source3.get()); + EXPECT_NE(source2.get(), source3.get()); + + // Fetch should return the same sources + SrsSharedPtr fetched1 = manager.fetch(&req1); + SrsSharedPtr fetched2 = manager.fetch(&req2); + SrsSharedPtr fetched3 = manager.fetch(&req3); + + EXPECT_EQ(source1.get(), fetched1.get()); + EXPECT_EQ(source2.get(), fetched2.get()); + EXPECT_EQ(source3.get(), fetched3.get()); +} + +// Test fetch for non-existent stream returns NULL +VOID TEST(SourceLockTest, LiveSourceManager_FetchNonExistent) +{ + srs_error_t err; + + SrsLiveSourceManager manager; + HELPER_EXPECT_SUCCESS(manager.initialize()); + + MockAsyncSrsRequest req("/live/nonexistent"); + + // Fetch non-existent source should return NULL + SrsSharedPtr source = manager.fetch(&req); + EXPECT_TRUE(source.get() == NULL); +} + +// Test that created flag works correctly for initialization +VOID TEST(SourceLockTest, LiveSourceManager_CreatedFlagLogic) +{ + srs_error_t err; + + SrsLiveSourceManager manager; + HELPER_EXPECT_SUCCESS(manager.initialize()); + + MockAsyncSrsRequest req("/live/created_flag_test"); + + // First call should create and initialize + SrsSharedPtr source1; + HELPER_EXPECT_SUCCESS(manager.fetch_or_create(&req, source1)); + EXPECT_TRUE(source1.get() != NULL); + + // Second call should find existing and only update auth (not initialize again) + SrsSharedPtr source2; + HELPER_EXPECT_SUCCESS(manager.fetch_or_create(&req, source2)); + EXPECT_EQ(source1.get(), source2.get()); +} + +// Test lock protection during source creation +VOID TEST(SourceLockTest, LiveSourceManager_LockProtection) +{ + srs_error_t err; + + // Test that the lock scope is properly limited + // This test verifies that no functions are called during locking + + SrsLiveSourceManager live_manager; + HELPER_EXPECT_SUCCESS(live_manager.initialize()); + + SrsRtcSourceManager rtc_manager; + HELPER_EXPECT_SUCCESS(rtc_manager.initialize()); + + SrsSrtSourceManager srt_manager; + HELPER_EXPECT_SUCCESS(srt_manager.initialize()); + + // Test that managers can handle rapid successive calls + MockAsyncSrsRequest req("/live/lock_test"); + + for (int i = 0; i < 5; i++) { + SrsSharedPtr live_source; + HELPER_EXPECT_SUCCESS(live_manager.fetch_or_create(&req, live_source)); + EXPECT_TRUE(live_source.get() != NULL); + + SrsSharedPtr rtc_source; + HELPER_EXPECT_SUCCESS(rtc_manager.fetch_or_create(&req, rtc_source)); + EXPECT_TRUE(rtc_source.get() != NULL); + + SrsSharedPtr srt_source; + HELPER_EXPECT_SUCCESS(srt_manager.fetch_or_create(&req, srt_source)); + EXPECT_TRUE(srt_source.get() != NULL); + } +} + +// Test that simulates the original race condition scenario from issue #1230 +// This test verifies that the fix prevents multiple sources for the same stream +VOID TEST(SourceLockTest, LiveSourceManager_RaceConditionPrevention_Issue1230) +{ + srs_error_t err; + + SrsLiveSourceManager manager; + HELPER_EXPECT_SUCCESS(manager.initialize()); + + MockAsyncSrsRequest req("/live/race_condition_test", true); // Enable context switch + + // Simulate the scenario where multiple coroutines try to create + // sources for the same stream simultaneously + vector > sources; + const int num_attempts = 20; + + // This simulates what would happen if multiple coroutines + // called fetch_or_create simultaneously before the fix + for (int i = 0; i < num_attempts; i++) { + SrsSharedPtr source; + HELPER_EXPECT_SUCCESS(manager.fetch_or_create(&req, source)); + sources.push_back(source); + + // Verify source is valid + EXPECT_TRUE(source.get() != NULL); + + // Verify it's the same source every time (no duplicates) + if (i > 0) { + EXPECT_EQ(sources[0].get(), source.get()) + << "Race condition detected: different source instances created for same stream"; + } + } + + // Double-check that all sources are identical + for (int i = 1; i < num_attempts; i++) { + EXPECT_EQ(sources[0].get(), sources[i].get()) + << "Source " << i << " differs from source 0"; + } + + // Verify fetch also returns the same source + SrsSharedPtr fetched = manager.fetch(&req); + EXPECT_EQ(sources[0].get(), fetched.get()); +} + +// Test the atomic nature of source creation and pool insertion +VOID TEST(SourceLockTest, LiveSourceManager_AtomicSourceCreation) +{ + srs_error_t err; + + // Test all source manager types + SrsRtcSourceManager rtc_manager; + HELPER_EXPECT_SUCCESS(rtc_manager.initialize()); + + SrsSrtSourceManager srt_manager; + HELPER_EXPECT_SUCCESS(srt_manager.initialize()); + + MockAsyncSrsRequest req("/live/atomic_test", true); // Enable context switch + + // Test RTC source manager + vector > rtc_sources; + for (int i = 0; i < 10; i++) { + SrsSharedPtr source; + HELPER_EXPECT_SUCCESS(rtc_manager.fetch_or_create(&req, source)); + rtc_sources.push_back(source); + EXPECT_TRUE(source.get() != NULL); + if (i > 0) { + EXPECT_EQ(rtc_sources[0].get(), source.get()); + } + } + + // Test SRT source manager + vector > srt_sources; + for (int i = 0; i < 10; i++) { + SrsSharedPtr source; + HELPER_EXPECT_SUCCESS(srt_manager.fetch_or_create(&req, source)); + srt_sources.push_back(source); + EXPECT_TRUE(source.get() != NULL); + if (i > 0) { + EXPECT_EQ(srt_sources[0].get(), source.get()); + } + } +} + +// Test that verifies the fix addresses the specific issue mentioned in #1230 +// where DVR and HLS module initialization could cause coroutine switches +VOID TEST(SourceLockTest, LiveSourceManager_CoroutineSwitchProtection) +{ + srs_error_t err; + + SrsLiveSourceManager manager; + HELPER_EXPECT_SUCCESS(manager.initialize()); + + // Test multiple streams to ensure each gets its own source + vector stream_urls; + stream_urls.push_back("/live/dvr_test1"); + stream_urls.push_back("/live/dvr_test2"); + stream_urls.push_back("/live/hls_test1"); + stream_urls.push_back("/live/hls_test2"); + stream_urls.push_back("/live/mixed_test"); + + map > created_sources; + + // Create sources for each stream + for (size_t idx = 0; idx < stream_urls.size(); idx++) { + const string &url = stream_urls[idx]; + MockAsyncSrsRequest req(url, true); // Enable context switch + SrsSharedPtr source; + + HELPER_EXPECT_SUCCESS(manager.fetch_or_create(&req, source)); + EXPECT_TRUE(source.get() != NULL); + + created_sources[url] = source; + + // Verify subsequent calls return the same source + for (int i = 0; i < 3; i++) { + SrsSharedPtr same_source; + HELPER_EXPECT_SUCCESS(manager.fetch_or_create(&req, same_source)); + EXPECT_EQ(source.get(), same_source.get()) + << "Source changed for stream " << url << " on attempt " << i; + } + } + + // Verify all sources are different from each other + vector source_ptrs; + for (map >::iterator it = created_sources.begin(); + it != created_sources.end(); ++it) { + source_ptrs.push_back(it->second.get()); + } + + for (size_t i = 0; i < source_ptrs.size(); i++) { + for (size_t j = i + 1; j < source_ptrs.size(); j++) { + EXPECT_NE(source_ptrs[i], source_ptrs[j]) + << "Sources for different streams should be different instances"; + } + } +} + +// Test edge case with empty or invalid stream URLs +VOID TEST(SourceLockTest, LiveSourceManager_EdgeCases_InvalidUrls) +{ + srs_error_t err; + + SrsLiveSourceManager manager; + HELPER_EXPECT_SUCCESS(manager.initialize()); + + // Test with various edge case URLs + vector edge_case_urls; + edge_case_urls.push_back(""); // Empty URL + edge_case_urls.push_back("/"); // Root only + edge_case_urls.push_back("/live/"); // Trailing slash + edge_case_urls.push_back("/live//"); // Double slash + edge_case_urls.push_back("/live/test?param=value"); // With parameters + + for (size_t idx = 0; idx < edge_case_urls.size(); idx++) { + const string &url = edge_case_urls[idx]; + MockAsyncSrsRequest req(url); + SrsSharedPtr source; + + // Should handle edge cases gracefully + HELPER_EXPECT_SUCCESS(manager.fetch_or_create(&req, source)); + EXPECT_TRUE(source.get() != NULL); + + // Verify consistency + SrsSharedPtr source2; + HELPER_EXPECT_SUCCESS(manager.fetch_or_create(&req, source2)); + EXPECT_EQ(source.get(), source2.get()); + } +} + +VOID TEST(SourceLockTest, RtcSourceManager_BasicFunctionality) +{ + srs_error_t err; + + SrsRtcSourceManager manager; + HELPER_EXPECT_SUCCESS(manager.initialize()); + + MockAsyncSrsRequest req("/live/test2"); + SrsSharedPtr source; + + // Test fetch_or_create - should create new source + HELPER_EXPECT_SUCCESS(manager.fetch_or_create(&req, source)); + EXPECT_TRUE(source.get() != NULL); + + // Test fetch - should return the same source + SrsSharedPtr fetched = manager.fetch(&req); + EXPECT_TRUE(fetched.get() != NULL); + EXPECT_EQ(source.get(), fetched.get()); + + // Test fetch_or_create again - should return existing source + SrsSharedPtr source2; + HELPER_EXPECT_SUCCESS(manager.fetch_or_create(&req, source2)); + EXPECT_EQ(source.get(), source2.get()); +} + +VOID TEST(SourceLockTest, SrtSourceManager_BasicFunctionality) +{ + srs_error_t err; + + SrsSrtSourceManager manager; + HELPER_EXPECT_SUCCESS(manager.initialize()); + + MockAsyncSrsRequest req("/live/test4"); + SrsSharedPtr source; + + // Test fetch_or_create - should create new source + HELPER_EXPECT_SUCCESS(manager.fetch_or_create(&req, source)); + EXPECT_TRUE(source.get() != NULL); + + // Note: SrsSrtSourceManager doesn't have a fetch method, only fetch_or_create + // Test fetch_or_create again - should return existing source + SrsSharedPtr source2; + HELPER_EXPECT_SUCCESS(manager.fetch_or_create(&req, source2)); + EXPECT_EQ(source.get(), source2.get()); +} + +VOID TEST(SourceLockTest, RtcSourceManager_ConcurrentAccess) +{ + srs_error_t err; + + SrsRtcSourceManager manager; + HELPER_EXPECT_SUCCESS(manager.initialize()); + + MockAsyncSrsRequest req("/live/rtc_concurrent_test", true); // Enable context switch + + // Simulate multiple concurrent requests for the same stream + vector > sources; + const int concurrent_requests = 10; + + for (int i = 0; i < concurrent_requests; i++) { + SrsSharedPtr source; + HELPER_EXPECT_SUCCESS(manager.fetch_or_create(&req, source)); + sources.push_back(source); + EXPECT_TRUE(source.get() != NULL); + } + + // All sources should be the same instance (no duplicates created) + for (int i = 1; i < concurrent_requests; i++) { + EXPECT_EQ(sources[0].get(), sources[i].get()); + } +} + +VOID TEST(SourceLockTest, RtcSourceManager_FetchNonExistent) +{ + srs_error_t err; + + SrsRtcSourceManager manager; + HELPER_EXPECT_SUCCESS(manager.initialize()); + + MockAsyncSrsRequest req("/live/nonexistent"); + + // Fetch non-existent source should return NULL + SrsSharedPtr source = manager.fetch(&req); + EXPECT_TRUE(source.get() == NULL); +} + +#ifdef SRS_RTSP +typedef MockOtherSourceAsyncCreator MockRtspSourceAsyncCreator; + +// Test race condition of source managers +VOID TEST(SourceLockTest, RtspSourceManager_RaceCondition) +{ + srs_error_t err; + + SrsRtspSourceManager manager; + HELPER_EXPECT_SUCCESS(manager.initialize()); + + MockAsyncSrsRequest req("/live/test1", true); // Enable context switch + SrsSharedPtr source; + + // Create a coroutine to create source2. + SrsWaitGroup wg; + MockRtspSourceAsyncCreator creator(&wg, &manager, &req); + SrsSTCoroutine trd("test", &creator); + + wg.add(1); + HELPER_EXPECT_SUCCESS(trd.start()); + + // Test fetch_or_create - should create new source + HELPER_EXPECT_SUCCESS(manager.fetch_or_create(&req, source)); + EXPECT_TRUE(source.get() != NULL); + + // Wait for coroutine to finish. + wg.wait(); + + // The created two sources should be the same instance (no duplicates created) + EXPECT_EQ(source.get(), creator.source_.get()); + + // Test fetch - should return the same source + SrsSharedPtr fetched = manager.fetch(&req); + EXPECT_TRUE(fetched.get() != NULL); + EXPECT_EQ(source.get(), fetched.get()); + + // Test fetch_or_create again - should return existing source + SrsSharedPtr source2; + HELPER_EXPECT_SUCCESS(manager.fetch_or_create(&req, source2)); + EXPECT_EQ(source.get(), source2.get()); +} + +// Test lock protection during source creation +VOID TEST(SourceLockTest, LiveSourceManager_LockProtection2) +{ + srs_error_t err; + + // Test that the lock scope is properly limited + // This test verifies that no functions are called during locking + + SrsRtspSourceManager rtsp_manager; + HELPER_EXPECT_SUCCESS(rtsp_manager.initialize()); + + // Test that managers can handle rapid successive calls + MockAsyncSrsRequest req("/live/lock_test"); + + for (int i = 0; i < 5; i++) { + SrsSharedPtr rtsp_source; + HELPER_EXPECT_SUCCESS(rtsp_manager.fetch_or_create(&req, rtsp_source)); + EXPECT_TRUE(rtsp_source.get() != NULL); + } +} + +// Test the atomic nature of source creation and pool insertion +VOID TEST(SourceLockTest, LiveSourceManager_AtomicSourceCreation2) +{ + srs_error_t err; + + // Test all source manager types + SrsRtspSourceManager rtsp_manager; + HELPER_EXPECT_SUCCESS(rtsp_manager.initialize()); + + MockAsyncSrsRequest req("/live/atomic_test", true); // Enable context switch + + // Test RTSP source manager + vector > rtsp_sources; + for (int i = 0; i < 10; i++) { + SrsSharedPtr source; + HELPER_EXPECT_SUCCESS(rtsp_manager.fetch_or_create(&req, source)); + rtsp_sources.push_back(source); + EXPECT_TRUE(source.get() != NULL); + if (i > 0) { + EXPECT_EQ(rtsp_sources[0].get(), source.get()); + } + } +} + +VOID TEST(SourceLockTest, RtspSourceManager_BasicFunctionality) +{ + srs_error_t err; + + SrsRtspSourceManager manager; + HELPER_EXPECT_SUCCESS(manager.initialize()); + + MockAsyncSrsRequest req("/live/test3"); + SrsSharedPtr source; + + // Test fetch_or_create - should create new source + HELPER_EXPECT_SUCCESS(manager.fetch_or_create(&req, source)); + EXPECT_TRUE(source.get() != NULL); + + // Test fetch - should return the same source + SrsSharedPtr fetched = manager.fetch(&req); + EXPECT_TRUE(fetched.get() != NULL); + EXPECT_EQ(source.get(), fetched.get()); + + // Test fetch_or_create again - should return existing source + SrsSharedPtr source2; + HELPER_EXPECT_SUCCESS(manager.fetch_or_create(&req, source2)); + EXPECT_EQ(source.get(), source2.get()); +} +#endif diff --git a/trunk/src/utest/srs_utest_source_lock.hpp b/trunk/src/utest/srs_utest_source_lock.hpp new file mode 100644 index 000000000..57dd2d296 --- /dev/null +++ b/trunk/src/utest/srs_utest_source_lock.hpp @@ -0,0 +1,15 @@ +// +// Copyright (c) 2013-2025 The SRS Authors +// +// SPDX-License-Identifier: MIT +// + +#ifndef SRS_UTEST_SOURCE_LOCK_HPP +#define SRS_UTEST_SOURCE_LOCK_HPP + +/* +#include +*/ +#include + +#endif