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 <winlinam@gmail.com>
This commit is contained in:
Winlin 2025-08-23 07:36:41 -06:00 committed by GitHub
parent 6ec97067de
commit 1b6f97bd2d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
77 changed files with 1484 additions and 521 deletions

2
trunk/configure vendored
View File

@ -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

View File

@ -7,6 +7,7 @@ The changelog for SRS.
<a name="v7-changes"></a>
## 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)

View File

@ -16,7 +16,7 @@ class SrsConfDirective;
class SrsHttpServeMux;
class SrsRtmpClient;
class SrsStSocket;
class SrsRequest;
class ISrsRequest;
class SrsPithyPrint;
class ISrsHttpResponseReader;
class SrsFlvDecoder;

View File

@ -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;

View File

@ -19,14 +19,13 @@
#include <srs_app_reload.hpp>
#include <srs_app_st.hpp>
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);

View File

@ -24,9 +24,9 @@ SrsCoWorkers::SrsCoWorkers()
SrsCoWorkers::~SrsCoWorkers()
{
map<string, SrsRequest *>::iterator it;
map<string, ISrsRequest *>::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<string, SrsRequest *>::iterator it = streams.find(url);
map<string, ISrsRequest *>::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<string, SrsRequest *>::iterator it = streams.find(url);
map<string, ISrsRequest *>::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<string, SrsRequest *>::iterator it = streams.find(url);
map<string, ISrsRequest *>::iterator it = streams.find(url);
if (it != streams.end()) {
srs_freep(it->second);
streams.erase(it);

View File

@ -13,7 +13,7 @@
#include <string>
class SrsJsonAny;
class SrsRequest;
class ISrsRequest;
class SrsLiveSource;
// For origin cluster.
@ -23,7 +23,7 @@ private:
static SrsCoWorkers *_instance;
private:
std::map<std::string, SrsRequest *> streams;
std::map<std::string, ISrsRequest *> 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

View File

@ -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;

View File

@ -14,7 +14,7 @@
#include <srs_app_fragment.hpp>
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.

View File

@ -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;

View File

@ -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();

View File

@ -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<SrsLiveSource> s, SrsPlayEdge *e, SrsRequest *r)
srs_error_t SrsEdgeIngester::initialize(SrsSharedPtr<SrsLiveSource> 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<SrsLiveSource> s, SrsPublishEdge *e, SrsRequest *r)
srs_error_t SrsEdgeForwarder::initialize(SrsSharedPtr<SrsLiveSource> 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<SrsLiveSource> source, SrsRequest *req)
srs_error_t SrsPlayEdge::initialize(SrsSharedPtr<SrsLiveSource> 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<SrsLiveSource> source, SrsRequest *req)
srs_error_t SrsPublishEdge::initialize(SrsSharedPtr<SrsLiveSource> source, ISrsRequest *req)
{
srs_error_t err = srs_success;

View File

@ -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<SrsLiveSource> s, SrsPlayEdge *e, SrsRequest *r);
virtual srs_error_t initialize(SrsSharedPtr<SrsLiveSource> 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<SrsLiveSource> s, SrsPublishEdge *e, SrsRequest *r);
virtual srs_error_t initialize(SrsSharedPtr<SrsLiveSource> 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<SrsLiveSource> source, SrsRequest *req);
virtual srs_error_t initialize(SrsSharedPtr<SrsLiveSource> 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<SrsLiveSource> source, SrsRequest *req);
virtual srs_error_t initialize(SrsSharedPtr<SrsLiveSource> source, ISrsRequest *req);
virtual bool can_publish();
// When client publish stream on edge.
virtual srs_error_t on_client_publish();

View File

@ -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;

View File

@ -15,7 +15,7 @@
#include <srs_app_st.hpp>
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();
};

View File

@ -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;

View File

@ -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:

View File

@ -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<SrsSharedPtrMessage *> 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;

View File

@ -13,7 +13,7 @@
#include <list>
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;
};

View File

@ -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;

View File

@ -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.

View File

@ -16,7 +16,7 @@ class SrsServer;
class SrsRtcServer;
class SrsJsonObject;
class SrsSdp;
class SrsRequest;
class ISrsRequest;
class ISrsHttpResponseWriter;
class SrsHttpConn;

View File

@ -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<SrsRequest> last_req(last_req_raw);
SrsUniquePtr<ISrsRequest> 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);
}

View File

@ -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

View File

@ -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<std::string> &rtmp_urls)
srs_error_t SrsHttpHooks::on_forward_backend(string url, ISrsRequest *req, std::vector<std::string> &rtmp_urls)
{
srs_error_t err = srs_success;

View File

@ -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<std::string> &rtmp_urls) = 0;
virtual srs_error_t on_forward_backend(std::string url, ISrsRequest *req, std::vector<std::string> &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<std::string> &rtmp_urls);
srs_error_t on_forward_backend(std::string url, ISrsRequest *req, std::vector<std::string> &rtmp_urls);
private:
srs_error_t do_post(SrsHttpClient *hc, std::string url, std::string req, int &code, std::string &res);

View File

@ -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<std::string, SrsHlsVirtualConn *>::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<SrsHttpMessage *>(r);
srs_assert(hr);
SrsUniquePtr<SrsRequest> req(hr->to_request(hr->host())->as_http());
SrsUniquePtr<ISrsRequest> req(hr->to_request(hr->host())->as_http());
// discovery vhost, resolve the vhost from config
SrsConfDirective *parsed_vhost = _srs_config->get_vhost(req->vhost);

View File

@ -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:

View File

@ -40,7 +40,7 @@ using namespace std;
#include <srs_protocol_stream.hpp>
#include <srs_protocol_utility.hpp>
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<SrsLiveSource> 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<SrsLiveSource> 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<SrsHttpMessage *>(r);
SrsUniquePtr<SrsRequest> nreq(hr->to_request(req->vhost));
SrsUniquePtr<ISrsRequest> 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<SrsHttpMessage *>(r);
SrsUniquePtr<SrsRequest> nreq(hr->to_request(req->vhost));
SrsUniquePtr<ISrsRequest> 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<SrsRequest> r(hreq->to_request(vhost->arg0()));
SrsUniquePtr<ISrsRequest> r(hreq->to_request(vhost->arg0()));
std::string sid = r->get_stream_url();
// check whether the http remux is enabled,

View File

@ -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<ISrsExpire *> 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);

View File

@ -19,7 +19,7 @@ class SrsConfDirective;
class SrsSimpleStream;
class SrsRtmpClient;
class SrsStSocket;
class SrsRequest;
class ISrsRequest;
class SrsRawH264Stream;
class SrsSharedPtrMessage;
class SrsRawAacStream;

View File

@ -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;

View File

@ -14,7 +14,7 @@
#include <srs_app_st.hpp>
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

View File

@ -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<SrsLiveSource> source, SrsContextId parent_cid)
: trd(this, rtmp_sdk, tm, parent_cid)
{

View File

@ -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<SrsLiveSource> source, SrsContextId parent_cid);
virtual ~SrsPublishRecvThread();

View File

@ -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;

View File

@ -12,7 +12,7 @@
#include <srs_protocol_http_stack.hpp>
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/

View File

@ -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<uint32_t, SrsRtcTrackDescription *> sub_relations)
srs_error_t SrsRtcPlayStream::initialize(ISrsRequest *req, std::map<uint32_t, SrsRtcTrackDescription *> 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<SrsRtcSourceDescription> 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<uint32_t, SrsRtcTrackDescription *> 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<uint32_t, SrsRtcTrackDescription *> sub_relations)
srs_error_t SrsRtcConnection::create_player(ISrsRequest *req, std::map<uint32_t, SrsRtcTrackDescription *> sub_relations)
{
srs_error_t err = srs_success;
@ -3545,7 +3545,7 @@ srs_error_t SrsRtcConnection::create_player(SrsRequest *req, std::map<uint32_t,
return err;
}
srs_error_t SrsRtcConnection::create_publisher(SrsRequest *req, SrsRtcSourceDescription *stream_desc)
srs_error_t SrsRtcConnection::create_publisher(ISrsRequest *req, SrsRtcSourceDescription *stream_desc)
{
srs_error_t err = srs_success;

View File

@ -211,10 +211,10 @@ class SrsRtcAsyncCallOnStop : public ISrsAsyncCallTask
{
private:
SrsContextId cid;
SrsRequest *req;
ISrsRequest *req;
public:
SrsRtcAsyncCallOnStop(SrsContextId c, SrsRequest *r);
SrsRtcAsyncCallOnStop(SrsContextId c, ISrsRequest *r);
virtual ~SrsRtcAsyncCallOnStop();
public:
@ -232,7 +232,7 @@ private:
SrsRtcPLIWorker *pli_worker_;
private:
SrsRequest *req_;
ISrsRequest *req_;
SrsSharedPtr<SrsRtcSource> source_;
// key: publish_ssrc, value: send track to process rtp/rtcp
std::map<uint32_t, SrsRtcAudioSendTrack *> audio_tracks_;
@ -266,7 +266,7 @@ public:
virtual ~SrsRtcPlayStream();
public:
srs_error_t initialize(SrsRequest *request, std::map<uint32_t, SrsRtcTrackDescription *> sub_relations);
srs_error_t initialize(ISrsRequest *request, std::map<uint32_t, SrsRtcTrackDescription *> 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<SrsRtcSource> 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<uint32_t, SrsRtcTrackDescription *> &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<uint32_t, SrsRtcTrackDescription *> sub_relations);
srs_error_t create_publisher(SrsRequest *request, SrsRtcSourceDescription *stream_desc);
srs_error_t create_player(ISrsRequest *request, std::map<uint32_t, SrsRtcTrackDescription *> sub_relations);
srs_error_t create_publisher(ISrsRequest *request, SrsRtcSourceDescription *stream_desc);
};
#endif

View File

@ -17,7 +17,7 @@
#include <srs_app_st.hpp>
class SrsRequest;
class ISrsRequest;
class SrsDtlsCertificate
{

View File

@ -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<SrsRtcSource> 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_) {

View File

@ -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_;

View File

@ -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<SrsRtcSource> &pps)
srs_error_t SrsRtcSourceManager::fetch_or_create(ISrsRequest *r, SrsSharedPtr<SrsRtcSource> &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<std::string, SrsSharedPtr<SrsRtcSource> >::iterator it = pool.find(stream_url);
string stream_url = r->get_stream_url();
std::map<std::string, SrsSharedPtr<SrsRtcSource> >::iterator it = pool.find(stream_url);
if (it != pool.end()) {
SrsSharedPtr<SrsRtcSource> source = it->second;
if (it != pool.end()) {
SrsSharedPtr<SrsRtcSource> source = it->second;
pps = source;
} else {
SrsSharedPtr<SrsRtcSource> source = SrsSharedPtr<SrsRtcSource>(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<SrsRtcSource> source = SrsSharedPtr<SrsRtcSource>(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<SrsRtcSource> SrsRtcSourceManager::fetch(SrsRequest *r)
SrsSharedPtr<SrsRtcSource> 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;

View File

@ -22,7 +22,7 @@
#include <srs_protocol_format.hpp>
#include <srs_protocol_st.hpp>
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<SrsRtcSource> &pps);
virtual srs_error_t fetch_or_create(ISrsRequest *r, SrsSharedPtr<SrsRtcSource> &pps);
public:
// Get the exists source, NULL when not exists.
virtual SrsSharedPtr<SrsRtcSource> fetch(SrsRequest *r);
virtual SrsSharedPtr<SrsRtcSource> 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);

View File

@ -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<SrsLiveSource> 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<SrsLiveSource> 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<SrsLiveSource> 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<SrsLiveSource> 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<SrsLiveSource> source, SrsPu
{
srs_error_t err = srs_success;
SrsRequest *req = info->req;
ISrsRequest *req = info->req;
SrsUniquePtr<SrsPithyPrint> pprint(SrsPithyPrint::create_rtmp_publish());
// start isolate recv thread.
@ -1151,7 +1151,7 @@ srs_error_t SrsRtmpConn::acquire_publish(SrsSharedPtr<SrsLiveSource> 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<string> 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;

View File

@ -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;

View File

@ -80,7 +80,7 @@ SrsRtspPlayStream::~SrsRtspPlayStream()
stat->on_disconnect(cid_.c_str(), srs_success);
}
srs_error_t SrsRtspPlayStream::initialize(SrsRequest *req, std::map<uint32_t, SrsRtcTrackDescription *> sub_relations)
srs_error_t SrsRtspPlayStream::initialize(ISrsRequest *req, std::map<uint32_t, SrsRtcTrackDescription *> 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;

View File

@ -21,7 +21,7 @@
#include <sys/socket.h>
#include <vector>
class SrsRequest;
class ISrsRequest;
class SrsRtpPacket;
class SrsRtspSource;
class SrsRtspAudioSendTrack;
@ -42,7 +42,7 @@ private:
SrsRtspConnection *session_;
private:
SrsRequest *req_;
ISrsRequest *req_;
SrsSharedPtr<SrsRtspSource> source_;
// key: publish_ssrc, value: send track to process rtp/rtcp
std::map<uint32_t, SrsRtspAudioSendTrack *> audio_tracks_;
@ -66,7 +66,7 @@ public:
virtual ~SrsRtspPlayStream();
public:
srs_error_t initialize(SrsRequest *request, std::map<uint32_t, SrsRtcTrackDescription *> sub_relations);
srs_error_t initialize(ISrsRequest *request, std::map<uint32_t, SrsRtcTrackDescription *> 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);
};

View File

@ -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<SrsRtspSource> &pps)
srs_error_t SrsRtspSourceManager::fetch_or_create(ISrsRequest *r, SrsSharedPtr<SrsRtspSource> &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<std::string, SrsSharedPtr<SrsRtspSource> >::iterator it = pool.find(stream_url);
string stream_url = r->get_stream_url();
std::map<std::string, SrsSharedPtr<SrsRtspSource> >::iterator it = pool.find(stream_url);
if (it != pool.end()) {
SrsSharedPtr<SrsRtspSource> source = it->second;
if (it != pool.end()) {
SrsSharedPtr<SrsRtspSource> source = it->second;
pps = source;
} else {
SrsSharedPtr<SrsRtspSource> source = SrsSharedPtr<SrsRtspSource>(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<SrsRtspSource> source = SrsSharedPtr<SrsRtspSource>(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<SrsRtspSource> SrsRtspSourceManager::fetch(SrsRequest *r)
SrsSharedPtr<SrsRtspSource> 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;

View File

@ -17,7 +17,7 @@
#include <string>
#include <vector>
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<SrsRtspSource> &pps);
virtual srs_error_t fetch_or_create(ISrsRequest *r, SrsSharedPtr<SrsRtspSource> &pps);
public:
// Get the exists source, NULL when not exists.
virtual SrsSharedPtr<SrsRtspSource> fetch(SrsRequest *r);
virtual SrsSharedPtr<SrsRtspSource> 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);

View File

@ -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;

View File

@ -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);
};

View File

@ -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);

View File

@ -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.

View File

@ -19,8 +19,10 @@ using namespace std;
#include <srs_app_hds.hpp>
#include <srs_app_hls.hpp>
#include <srs_app_http_hooks.hpp>
#include <srs_app_hybrid.hpp>
#include <srs_app_ng_exec.hpp>
#include <srs_app_rtc_source.hpp>
#include <srs_app_server.hpp>
#include <srs_app_statistic.hpp>
#include <srs_core_autofree.hpp>
#include <srs_kernel_buffer.hpp>
@ -857,7 +859,7 @@ SrsOriginHub::~SrsOriginHub()
#endif
}
srs_error_t SrsOriginHub::initialize(SrsSharedPtr<SrsLiveSource> s, SrsRequest *r)
srs_error_t SrsOriginHub::initialize(SrsSharedPtr<SrsLiveSource> 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<SrsRequest> req(new SrsRequest());
SrsUniquePtr<ISrsRequest> 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<SrsLiveSource> &pps)
srs_error_t SrsLiveSourceManager::fetch_or_create(ISrsRequest *r, SrsSharedPtr<SrsLiveSource> &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<std::string, SrsSharedPtr<SrsLiveSource> >::iterator it = pool.find(stream_url);
string stream_url = r->get_stream_url();
std::map<std::string, SrsSharedPtr<SrsLiveSource> >::iterator it = pool.find(stream_url);
if (it != pool.end()) {
SrsSharedPtr<SrsLiveSource> &source = it->second;
if (it != pool.end()) {
SrsSharedPtr<SrsLiveSource> &source = it->second;
pps = source;
} else {
SrsSharedPtr<SrsLiveSource> 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<SrsLiveSource> 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<SrsLiveSource> SrsLiveSourceManager::fetch(SrsRequest *r)
SrsSharedPtr<SrsLiveSource> 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<SrsLiveSource> 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<SrsLiveSource> 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<SrsLiveSource> 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<SrsLiveSource> 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);

View File

@ -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<SrsLiveSource> s, SrsRequest *r);
virtual srs_error_t initialize(SrsSharedPtr<SrsLiveSource> 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<SrsLiveSource> &pps);
virtual srs_error_t fetch_or_create(ISrsRequest *r, SrsSharedPtr<SrsLiveSource> &pps);
public:
// Get the exists source, NULL when not exists.
virtual SrsSharedPtr<SrsLiveSource> fetch(SrsRequest *r);
virtual SrsSharedPtr<SrsLiveSource> 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<SrsLiveConsumer *> 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<SrsLiveSource> wrapper, SrsRequest *r, ISrsLiveSourceHandler *h);
virtual srs_error_t initialize(SrsSharedPtr<SrsLiveSource> 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);

View File

@ -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");
}

View File

@ -134,7 +134,7 @@ private:
int port_;
SrsCoroutine *trd_;
SrsRequest *req_;
ISrsRequest *req_;
SrsSharedPtr<SrsSrtSource> srt_source_;
SrsSecurity *security_;
};

View File

@ -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<SrsSrtSource> &pps)
srs_error_t SrsSrtSourceManager::fetch_or_create(ISrsRequest *r, SrsSharedPtr<SrsSrtSource> &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<std::string, SrsSharedPtr<SrsSrtSource> >::iterator it = pool.find(stream_url);
if (it != pool.end()) {
SrsSharedPtr<SrsSrtSource> source = it->second;
pps = source;
} else {
SrsSharedPtr<SrsSrtSource> 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<SrsSrtSource> 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<std::string, SrsSharedPtr<SrsSrtSource> >::iterator it = pool.find(stream_url);
if (it != pool.end()) {
SrsSharedPtr<SrsSrtSource> 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<SrsSrtSource> source;
if (it == pool.end()) {
return source;
}
SrsSharedPtr<SrsSrtSource> 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);
}

View File

@ -19,7 +19,7 @@
#include <srs_protocol_st.hpp>
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<SrsSrtSource> &pps);
virtual srs_error_t fetch_or_create(ISrsRequest *r, SrsSharedPtr<SrsSrtSource> &pps);
public:
// Get the exists source, NULL when not exists.
virtual SrsSharedPtr<SrsSrtSource> 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<SrsSrtConsumer *> consumers;
bool can_publish_;

View File

@ -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);

View File

@ -14,7 +14,7 @@
#include <srs_kernel_log.hpp>
#include <srs_protocol_utility.hpp>
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

View File

@ -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

View File

@ -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.

View File

@ -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;

View File

@ -14,7 +14,7 @@
#include <vector>
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();

View File

@ -9,6 +9,6 @@
#define VERSION_MAJOR 7
#define VERSION_MINOR 0
#define VERSION_REVISION 60
#define VERSION_REVISION 61
#endif

View File

@ -661,7 +661,7 @@ private:
int64_t raw_aac_dts;
private:
SrsRequest *req;
ISrsRequest *req;
SrsBasicRtmpClient *sdk;
private:

View File

@ -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

View File

@ -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();

View File

@ -11,7 +11,7 @@
#include <string>
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;

View File

@ -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;

View File

@ -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.

View File

@ -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<SrsAmf0Object *>(cp->args);

View File

@ -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);
}

View File

@ -0,0 +1,817 @@
//
// Copyright (c) 2013-2025 The SRS Authors
//
// SPDX-License-Identifier: MIT
//
#include <srs_utest_source_lock.hpp>
using namespace std;
#include <srs_app_config.hpp>
#include <srs_app_rtc_source.hpp>
#include <srs_app_server.hpp>
#include <srs_app_source.hpp>
#include <srs_app_srt_source.hpp>
#include <srs_kernel_error.hpp>
#include <srs_protocol_amf0.hpp>
#include <srs_protocol_rtmp_stack.hpp>
#include <srs_protocol_st.hpp>
#include <st.h>
#ifdef SRS_RTSP
#include <srs_app_rtsp_source.hpp>
#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<ManagerType, SourceType>: 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 <typename ManagerType, typename SourceType>
class MockOtherSourceAsyncCreator : public ISrsCoroutineHandler
{
public:
SrsWaitGroup *wg_;
ManagerType *manager_;
MockAsyncSrsRequest *req_;
SrsSharedPtr<SourceType> 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<SrsLiveSourceManager, SrsLiveSource> 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<SrsLiveSource> 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<SrsLiveSource> 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<SrsLiveSource> 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<SrsRtcSourceManager, SrsRtcSource> 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<SrsRtcSource> 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<SrsRtcSource> 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<SrsRtcSource> source2;
HELPER_EXPECT_SUCCESS(manager.fetch_or_create(&req, source2));
EXPECT_EQ(source.get(), source2.get());
}
typedef MockOtherSourceAsyncCreator<SrsSrtSourceManager, SrsSrtSource> 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<SrsSrtSource> 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<SrsSrtSource> 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<SrsSrtSource> 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<SrsLiveSource> 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<SrsLiveSource> 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<SrsLiveSource> 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<SrsSharedPtr<SrsLiveSource> > sources;
const int concurrent_requests = 10;
for (int i = 0; i < concurrent_requests; i++) {
SrsSharedPtr<SrsLiveSource> 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<SrsLiveSource> 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<SrsLiveSource> fetched1 = manager.fetch(&req1);
SrsSharedPtr<SrsLiveSource> fetched2 = manager.fetch(&req2);
SrsSharedPtr<SrsLiveSource> 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<SrsLiveSource> 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<SrsLiveSource> 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<SrsLiveSource> 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<SrsLiveSource> live_source;
HELPER_EXPECT_SUCCESS(live_manager.fetch_or_create(&req, live_source));
EXPECT_TRUE(live_source.get() != NULL);
SrsSharedPtr<SrsRtcSource> rtc_source;
HELPER_EXPECT_SUCCESS(rtc_manager.fetch_or_create(&req, rtc_source));
EXPECT_TRUE(rtc_source.get() != NULL);
SrsSharedPtr<SrsSrtSource> 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<SrsSharedPtr<SrsLiveSource> > 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<SrsLiveSource> 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<SrsLiveSource> 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<SrsSharedPtr<SrsRtcSource> > rtc_sources;
for (int i = 0; i < 10; i++) {
SrsSharedPtr<SrsRtcSource> 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<SrsSharedPtr<SrsSrtSource> > srt_sources;
for (int i = 0; i < 10; i++) {
SrsSharedPtr<SrsSrtSource> 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<string> 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<string, SrsSharedPtr<SrsLiveSource> > 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<SrsLiveSource> 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<SrsLiveSource> 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<SrsLiveSource *> source_ptrs;
for (map<string, SrsSharedPtr<SrsLiveSource> >::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<string> 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<SrsLiveSource> source;
// Should handle edge cases gracefully
HELPER_EXPECT_SUCCESS(manager.fetch_or_create(&req, source));
EXPECT_TRUE(source.get() != NULL);
// Verify consistency
SrsSharedPtr<SrsLiveSource> 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<SrsRtcSource> 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<SrsRtcSource> 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<SrsRtcSource> 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<SrsSrtSource> 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<SrsSrtSource> 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<SrsSharedPtr<SrsRtcSource> > sources;
const int concurrent_requests = 10;
for (int i = 0; i < concurrent_requests; i++) {
SrsSharedPtr<SrsRtcSource> 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<SrsRtcSource> source = manager.fetch(&req);
EXPECT_TRUE(source.get() == NULL);
}
#ifdef SRS_RTSP
typedef MockOtherSourceAsyncCreator<SrsRtspSourceManager, SrsRtspSource> 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<SrsRtspSource> 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<SrsRtspSource> 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<SrsRtspSource> 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<SrsRtspSource> 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<SrsSharedPtr<SrsRtspSource> > rtsp_sources;
for (int i = 0; i < 10; i++) {
SrsSharedPtr<SrsRtspSource> 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<SrsRtspSource> 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<SrsRtspSource> 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<SrsRtspSource> source2;
HELPER_EXPECT_SUCCESS(manager.fetch_or_create(&req, source2));
EXPECT_EQ(source.get(), source2.get());
}
#endif

View File

@ -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 <srs_utest_source_lock.hpp>
*/
#include <srs_utest.hpp>
#endif