AI: Add utest to cover app http module.
This commit is contained in:
parent
b5664747ac
commit
3948f0d4fe
|
|
@ -125,6 +125,118 @@ codebase_structure:
|
||||||
description: "Smart pointer definitions for memory management"
|
description: "Smart pointer definitions for memory management"
|
||||||
|
|
||||||
code_patterns:
|
code_patterns:
|
||||||
|
dependency_inversion:
|
||||||
|
principle: "MANDATORY - Classes should depend on interfaces, not concrete classes"
|
||||||
|
description: |
|
||||||
|
Follow the Dependency Inversion Principle (DIP) - high-level modules should not depend on low-level modules.
|
||||||
|
Both should depend on abstractions (interfaces). This improves testability, maintainability, and flexibility.
|
||||||
|
|
||||||
|
In SRS, interfaces start with 'ISrs' prefix (e.g., ISrsBufferCache, ISrsMessageQueue), while concrete classes
|
||||||
|
start with 'Srs' prefix (e.g., SrsBufferCache, SrsMessageQueue).
|
||||||
|
|
||||||
|
usage: |
|
||||||
|
WRONG: Depending on concrete class
|
||||||
|
class SrsBufferCache {
|
||||||
|
private:
|
||||||
|
SrsMessageQueue *queue_; // Direct dependency on concrete class
|
||||||
|
};
|
||||||
|
|
||||||
|
CORRECT: Depending on interface
|
||||||
|
class SrsBufferCache : public ISrsBufferCache {
|
||||||
|
private:
|
||||||
|
ISrsMessageQueue *queue_; // Dependency on interface
|
||||||
|
};
|
||||||
|
|
||||||
|
rules:
|
||||||
|
- "Interfaces start with 'ISrs' prefix (e.g., ISrsMessageQueue, ISrsBufferCache, ISrsCoroutineHandler)"
|
||||||
|
- "Concrete classes start with 'Srs' prefix (e.g., SrsMessageQueue, SrsBufferCache, SrsServer)"
|
||||||
|
- "Class member variables should use interface types (ISrs*) instead of concrete types (Srs*)"
|
||||||
|
- "Classes should implement interfaces when they provide functionality that may need to be mocked or substituted"
|
||||||
|
- "Use concrete types only for instantiation, not for member variable declarations"
|
||||||
|
|
||||||
|
benefits:
|
||||||
|
- "Enables dependency injection for unit testing"
|
||||||
|
- "Allows easy mocking of dependencies in tests"
|
||||||
|
- "Reduces coupling between components"
|
||||||
|
- "Makes code more flexible and maintainable"
|
||||||
|
- "Facilitates future refactoring and extensions"
|
||||||
|
|
||||||
|
rationale: "Interface-based design is fundamental to testable, maintainable code. It allows components to be tested in isolation and makes the codebase more flexible for future changes."
|
||||||
|
|
||||||
|
avoid_global_variables:
|
||||||
|
principle: "MANDATORY - Never directly use global variables, convert to member fields for mockability"
|
||||||
|
description: |
|
||||||
|
Direct use of global variables makes code untestable because globals cannot be mocked.
|
||||||
|
Global variables in SRS start with _srs prefix (e.g., _srs_config, _srs_sources, _srs_stat, _srs_hooks, _srs_context).
|
||||||
|
Always store global references as member fields in the constructor so they can be replaced with mocks in tests.
|
||||||
|
|
||||||
|
usage: |
|
||||||
|
WRONG: Direct use of global variable
|
||||||
|
srs_error_t SrsBufferCache::start() {
|
||||||
|
fast_cache_ = _srs_config->get_vhost_http_remux_fast_cache(req_->vhost_);
|
||||||
|
}
|
||||||
|
|
||||||
|
CORRECT: Store global as member field for mockability
|
||||||
|
SrsBufferCache::SrsBufferCache(ISrsRequest *r) {
|
||||||
|
config_ = _srs_config; // Store global reference as member field
|
||||||
|
}
|
||||||
|
SrsBufferCache::~SrsBufferCache() {
|
||||||
|
config_ = NULL; // Set to NULL, do NOT free (it's a global reference)
|
||||||
|
}
|
||||||
|
srs_error_t SrsBufferCache::start() {
|
||||||
|
fast_cache_ = config_->get_vhost_http_remux_fast_cache(req_->vhost_);
|
||||||
|
}
|
||||||
|
|
||||||
|
rules:
|
||||||
|
- "Global variables in SRS start with _srs prefix: _srs_config, _srs_sources, _srs_stat, _srs_hooks, _srs_context, etc."
|
||||||
|
- "Never access global variables directly in methods"
|
||||||
|
- "Always store global references as member fields in constructor"
|
||||||
|
- "Use interface types for member fields (e.g., ISrsAppConfig* config_)"
|
||||||
|
- "In destructor, set global reference fields to NULL but do NOT free them"
|
||||||
|
- "This allows tests to inject mock objects by setting the member field"
|
||||||
|
|
||||||
|
common_global_variables:
|
||||||
|
core_globals:
|
||||||
|
- "_srs_log - Global logging interface (ISrsLog*)"
|
||||||
|
- "_srs_context - Thread context for coroutine management (ISrsContext*)"
|
||||||
|
- "_srs_config - Global configuration object (SrsConfig*)"
|
||||||
|
- "_srs_kernel_factory - Kernel object factory (ISrsKernelFactory*)"
|
||||||
|
- "_srs_app_factory - Application object factory (SrsAppFactory*)"
|
||||||
|
|
||||||
|
app_globals:
|
||||||
|
- "_srs_server - Main SRS server instance (SrsServer*)"
|
||||||
|
- "_srs_sources - Live source manager (SrsLiveSourceManager*)"
|
||||||
|
- "_srs_stat - Statistics manager (SrsStatistic*)"
|
||||||
|
- "_srs_hooks - HTTP hooks manager (ISrsHttpHooks*)"
|
||||||
|
- "_srs_circuit_breaker - Circuit breaker for overload protection (ISrsCircuitBreaker*)"
|
||||||
|
- "_srs_dvr_async - Async worker for DVR operations (SrsAsyncCallWorker*)"
|
||||||
|
|
||||||
|
timing_globals:
|
||||||
|
- "_srs_clock - Wall clock for time operations (SrsWallClock*)"
|
||||||
|
- "_srs_shared_timer - Shared timer for periodic tasks (SrsSharedTimer*)"
|
||||||
|
- "_srs_stages - Stage manager for pithy print (SrsStageManager*)"
|
||||||
|
|
||||||
|
resource_globals:
|
||||||
|
- "_srs_conn_manager - Connection resource manager (SrsResourceManager*)"
|
||||||
|
- "_srs_pps_* - Various PPS (packets per second) statistics counters"
|
||||||
|
|
||||||
|
webrtc_globals:
|
||||||
|
- "_srs_blackhole - WebRTC blackhole for packet dropping (SrsRtcBlackhole*)"
|
||||||
|
- "_srs_rtc_dtls_certificate - DTLS certificate for WebRTC (SrsDtlsCertificate*)"
|
||||||
|
|
||||||
|
other_globals:
|
||||||
|
- "_srs_in_docker - Boolean flag indicating if running in Docker"
|
||||||
|
- "_srs_config_by_env - Boolean flag for environment variable configuration"
|
||||||
|
- "_srs_binary - Binary name of SRS executable"
|
||||||
|
|
||||||
|
benefits:
|
||||||
|
- "Enables dependency injection for unit testing"
|
||||||
|
- "Allows mocking of global dependencies in tests"
|
||||||
|
- "Makes dependencies explicit and visible in class interface"
|
||||||
|
- "Improves code testability and maintainability"
|
||||||
|
|
||||||
|
rationale: "Global variables create hidden dependencies that cannot be mocked or controlled in tests. Converting them to member fields makes dependencies explicit and testable."
|
||||||
|
|
||||||
cpp_compatibility:
|
cpp_compatibility:
|
||||||
standard: "C++98"
|
standard: "C++98"
|
||||||
description: |
|
description: |
|
||||||
|
|
|
||||||
2
trunk/configure
vendored
2
trunk/configure
vendored
|
|
@ -384,7 +384,7 @@ if [[ $SRS_UTEST == YES ]]; then
|
||||||
"srs_utest_coworkers" "srs_utest_pithy_print" "srs_utest_kernel3" "srs_utest_protocol4"
|
"srs_utest_coworkers" "srs_utest_pithy_print" "srs_utest_kernel3" "srs_utest_protocol4"
|
||||||
"srs_utest_protocol3" "srs_utest_app" "srs_utest_app2" "srs_utest_app3" "srs_utest_app4"
|
"srs_utest_protocol3" "srs_utest_app" "srs_utest_app2" "srs_utest_app3" "srs_utest_app4"
|
||||||
"srs_utest_app5" "srs_utest_app6" "srs_utest_app7" "srs_utest_app8" "srs_utest_app9"
|
"srs_utest_app5" "srs_utest_app6" "srs_utest_app7" "srs_utest_app8" "srs_utest_app9"
|
||||||
"srs_utest_app10")
|
"srs_utest_app10" "srs_utest_app11")
|
||||||
# Always include SRT utest
|
# Always include SRT utest
|
||||||
MODULE_FILES+=("srs_utest_srt")
|
MODULE_FILES+=("srs_utest_srt")
|
||||||
if [[ $SRS_GB28181 == YES ]]; then
|
if [[ $SRS_GB28181 == YES ]]; then
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,9 @@ public:
|
||||||
virtual ~ISrsAsyncCallWorker();
|
virtual ~ISrsAsyncCallWorker();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
virtual srs_error_t execute(ISrsAsyncCallTask *t) = 0;
|
||||||
virtual srs_error_t start() = 0;
|
virtual srs_error_t start() = 0;
|
||||||
|
virtual void stop() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// The async callback for dvr, callback and other async worker.
|
// The async callback for dvr, callback and other async worker.
|
||||||
|
|
|
||||||
|
|
@ -287,6 +287,7 @@ public:
|
||||||
virtual srs_error_t reload(SrsReloadState *pstate) = 0;
|
virtual srs_error_t reload(SrsReloadState *pstate) = 0;
|
||||||
virtual srs_error_t persistence() = 0;
|
virtual srs_error_t persistence() = 0;
|
||||||
virtual std::string config() = 0;
|
virtual std::string config() = 0;
|
||||||
|
virtual SrsConfDirective *get_root() = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Global server config
|
// Global server config
|
||||||
|
|
@ -373,6 +374,7 @@ public:
|
||||||
// Vhost config
|
// Vhost config
|
||||||
virtual SrsConfDirective *get_vhost(std::string vhost, bool try_default_vhost = true) = 0;
|
virtual SrsConfDirective *get_vhost(std::string vhost, bool try_default_vhost = true) = 0;
|
||||||
virtual bool get_vhost_enabled(std::string vhost) = 0;
|
virtual bool get_vhost_enabled(std::string vhost) = 0;
|
||||||
|
virtual bool get_vhost_enabled(SrsConfDirective *conf) = 0;
|
||||||
virtual bool get_debug_srs_upnode(std::string vhost) = 0;
|
virtual bool get_debug_srs_upnode(std::string vhost) = 0;
|
||||||
virtual int get_out_ack_size(std::string vhost) = 0;
|
virtual int get_out_ack_size(std::string vhost) = 0;
|
||||||
virtual int get_in_ack_size(std::string vhost) = 0;
|
virtual int get_in_ack_size(std::string vhost) = 0;
|
||||||
|
|
@ -479,6 +481,17 @@ public:
|
||||||
virtual bool get_atc_auto(std::string vhost) = 0;
|
virtual bool get_atc_auto(std::string vhost) = 0;
|
||||||
virtual bool get_reduce_sequence_header(std::string vhost) = 0;
|
virtual bool get_reduce_sequence_header(std::string vhost) = 0;
|
||||||
virtual bool get_parse_sps(std::string vhost) = 0;
|
virtual bool get_parse_sps(std::string vhost) = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// HTTP remux config
|
||||||
|
virtual bool get_vhost_http_remux_enabled(std::string vhost) = 0;
|
||||||
|
virtual bool get_vhost_http_remux_enabled(SrsConfDirective *vhost) = 0;
|
||||||
|
virtual srs_utime_t get_vhost_http_remux_fast_cache(std::string vhost) = 0;
|
||||||
|
virtual bool get_vhost_http_remux_drop_if_not_match(std::string vhost) = 0;
|
||||||
|
virtual bool get_vhost_http_remux_has_audio(std::string vhost) = 0;
|
||||||
|
virtual bool get_vhost_http_remux_has_video(std::string vhost) = 0;
|
||||||
|
virtual bool get_vhost_http_remux_guess_has_av(std::string vhost) = 0;
|
||||||
|
virtual std::string get_vhost_http_remux_mount(std::string vhost) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// The config service provider.
|
// The config service provider.
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ class SrsBuffer;
|
||||||
class SrsRtmpJitter;
|
class SrsRtmpJitter;
|
||||||
class SrsMediaPacket;
|
class SrsMediaPacket;
|
||||||
class SrsFileWriter;
|
class SrsFileWriter;
|
||||||
class SrsFlvTransmuxer;
|
class ISrsFlvTransmuxer;
|
||||||
class SrsDvrPlan;
|
class SrsDvrPlan;
|
||||||
class SrsJsonAny;
|
class SrsJsonAny;
|
||||||
class SrsJsonObject;
|
class SrsJsonObject;
|
||||||
|
|
@ -99,7 +99,7 @@ class SrsDvrFlvSegmenter : public SrsDvrSegmenter
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
// The FLV encoder, for FLV target.
|
// The FLV encoder, for FLV target.
|
||||||
SrsFlvTransmuxer *enc_;
|
ISrsFlvTransmuxer *enc_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// The offset of file for duration value.
|
// The offset of file for duration value.
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,10 @@
|
||||||
#include <srs_app_rtmp_source.hpp>
|
#include <srs_app_rtmp_source.hpp>
|
||||||
#include <srs_app_st.hpp>
|
#include <srs_app_st.hpp>
|
||||||
#include <srs_kernel_file.hpp>
|
#include <srs_kernel_file.hpp>
|
||||||
|
#include <srs_kernel_hourglass.hpp>
|
||||||
#include <srs_kernel_ts.hpp>
|
#include <srs_kernel_ts.hpp>
|
||||||
#include <srs_kernel_utility.hpp>
|
#include <srs_kernel_utility.hpp>
|
||||||
#include <srs_protocol_st.hpp>
|
#include <srs_protocol_st.hpp>
|
||||||
#include <srs_kernel_hourglass.hpp>
|
|
||||||
|
|
||||||
SrsAppFactory::SrsAppFactory()
|
SrsAppFactory::SrsAppFactory()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -707,7 +707,7 @@ srs_error_t SrsGoApiVhosts::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessag
|
||||||
|
|
||||||
// path: {pattern}{vhost_id}
|
// path: {pattern}{vhost_id}
|
||||||
// e.g. /api/v1/vhosts/100 pattern= /api/v1/vhosts/, vhost_id=100
|
// e.g. /api/v1/vhosts/100 pattern= /api/v1/vhosts/, vhost_id=100
|
||||||
string vid = r->parse_rest_id(entry->pattern);
|
string vid = r->parse_rest_id(entry_->pattern);
|
||||||
SrsStatisticVhost *vhost = NULL;
|
SrsStatisticVhost *vhost = NULL;
|
||||||
|
|
||||||
if (!vid.empty() && (vhost = stat->find_vhost_by_id(vid)) == NULL) {
|
if (!vid.empty() && (vhost = stat->find_vhost_by_id(vid)) == NULL) {
|
||||||
|
|
@ -765,7 +765,7 @@ srs_error_t SrsGoApiStreams::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessa
|
||||||
|
|
||||||
// path: {pattern}{stream_id}
|
// path: {pattern}{stream_id}
|
||||||
// e.g. /api/v1/streams/100 pattern= /api/v1/streams/, stream_id=100
|
// e.g. /api/v1/streams/100 pattern= /api/v1/streams/, stream_id=100
|
||||||
string sid = r->parse_rest_id(entry->pattern);
|
string sid = r->parse_rest_id(entry_->pattern);
|
||||||
|
|
||||||
SrsStatisticStream *stream = NULL;
|
SrsStatisticStream *stream = NULL;
|
||||||
if (!sid.empty() && (stream = stat->find_stream(sid)) == NULL) {
|
if (!sid.empty() && (stream = stat->find_stream(sid)) == NULL) {
|
||||||
|
|
@ -827,7 +827,7 @@ srs_error_t SrsGoApiClients::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessa
|
||||||
|
|
||||||
// path: {pattern}{client_id}
|
// path: {pattern}{client_id}
|
||||||
// e.g. /api/v1/clients/100 pattern= /api/v1/clients/, client_id=100
|
// e.g. /api/v1/clients/100 pattern= /api/v1/clients/, client_id=100
|
||||||
string client_id = r->parse_rest_id(entry->pattern);
|
string client_id = r->parse_rest_id(entry_->pattern);
|
||||||
|
|
||||||
SrsStatisticClient *client = NULL;
|
SrsStatisticClient *client = NULL;
|
||||||
if (!client_id.empty() && (client = stat->find_client(client_id)) == NULL) {
|
if (!client_id.empty() && (client = stat->find_client(client_id)) == NULL) {
|
||||||
|
|
|
||||||
|
|
@ -474,11 +474,12 @@ ISrsKbpsDelta *SrsHttpxConn::delta()
|
||||||
return conn_->delta();
|
return conn_->delta();
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsHttpServer::SrsHttpServer(SrsServer *svr)
|
SrsHttpServer::SrsHttpServer()
|
||||||
{
|
{
|
||||||
server_ = svr;
|
http_stream_ = new SrsHttpStreamServer();
|
||||||
http_stream_ = new SrsHttpStreamServer(svr);
|
http_stream_->assemble();
|
||||||
http_static_ = new SrsHttpStaticServer(svr);
|
|
||||||
|
http_static_ = new SrsHttpStaticServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsHttpServer::~SrsHttpServer()
|
SrsHttpServer::~SrsHttpServer()
|
||||||
|
|
|
||||||
|
|
@ -183,12 +183,11 @@ public:
|
||||||
class SrsHttpServer : public ISrsHttpServeMux
|
class SrsHttpServer : public ISrsHttpServeMux
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
SrsServer *server_;
|
|
||||||
SrsHttpStaticServer *http_static_;
|
SrsHttpStaticServer *http_static_;
|
||||||
SrsHttpStreamServer *http_stream_;
|
SrsHttpStreamServer *http_stream_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsHttpServer(SrsServer *svr);
|
SrsHttpServer();
|
||||||
virtual ~SrsHttpServer();
|
virtual ~SrsHttpServer();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -599,9 +599,8 @@ srs_error_t SrsVodStream::serve_ts_ctx(ISrsHttpResponseWriter *w, ISrsHttpMessag
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsHttpStaticServer::SrsHttpStaticServer(SrsServer *svr)
|
SrsHttpStaticServer::SrsHttpStaticServer()
|
||||||
{
|
{
|
||||||
server_ = svr;
|
|
||||||
_srs_config->subscribe(this);
|
_srs_config->subscribe(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -89,14 +89,11 @@ protected:
|
||||||
// serve http static file and flv/mp4 vod stream.
|
// serve http static file and flv/mp4 vod stream.
|
||||||
class SrsHttpStaticServer : public ISrsReloadHandler
|
class SrsHttpStaticServer : public ISrsReloadHandler
|
||||||
{
|
{
|
||||||
private:
|
|
||||||
SrsServer *server_;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsHttpServeMux mux_;
|
SrsHttpServeMux mux_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsHttpStaticServer(SrsServer *svr);
|
SrsHttpStaticServer();
|
||||||
virtual ~SrsHttpStaticServer();
|
virtual ~SrsHttpStaticServer();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -40,15 +40,23 @@ using namespace std;
|
||||||
#include <srs_protocol_stream.hpp>
|
#include <srs_protocol_stream.hpp>
|
||||||
#include <srs_protocol_utility.hpp>
|
#include <srs_protocol_utility.hpp>
|
||||||
|
|
||||||
SrsBufferCache::SrsBufferCache(SrsServer *s, ISrsRequest *r)
|
ISrsBufferCache::ISrsBufferCache()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsBufferCache::~ISrsBufferCache()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsBufferCache::SrsBufferCache(ISrsRequest *r)
|
||||||
{
|
{
|
||||||
req_ = r->copy()->as_http();
|
req_ = r->copy()->as_http();
|
||||||
queue_ = new SrsMessageQueue(true);
|
queue_ = new SrsMessageQueue(true);
|
||||||
trd_ = new SrsSTCoroutine("http-stream", this);
|
trd_ = new SrsSTCoroutine("http-stream", this);
|
||||||
|
fast_cache_ = 0;
|
||||||
|
|
||||||
// TODO: FIXME: support reload.
|
config_ = _srs_config;
|
||||||
fast_cache_ = _srs_config->get_vhost_http_remux_fast_cache(req_->vhost_);
|
live_sources_ = _srs_sources;
|
||||||
server_ = s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsBufferCache::~SrsBufferCache()
|
SrsBufferCache::~SrsBufferCache()
|
||||||
|
|
@ -57,6 +65,9 @@ SrsBufferCache::~SrsBufferCache()
|
||||||
|
|
||||||
srs_freep(queue_);
|
srs_freep(queue_);
|
||||||
srs_freep(req_);
|
srs_freep(req_);
|
||||||
|
|
||||||
|
config_ = NULL;
|
||||||
|
live_sources_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsBufferCache::update_auth(ISrsRequest *r)
|
srs_error_t SrsBufferCache::update_auth(ISrsRequest *r)
|
||||||
|
|
@ -71,6 +82,8 @@ srs_error_t SrsBufferCache::start()
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
fast_cache_ = config_->get_vhost_http_remux_fast_cache(req_->vhost_);
|
||||||
|
|
||||||
// Not enabled.
|
// Not enabled.
|
||||||
if (fast_cache_ <= 0) {
|
if (fast_cache_ <= 0) {
|
||||||
return err;
|
return err;
|
||||||
|
|
@ -109,7 +122,7 @@ bool SrsBufferCache::alive()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsBufferCache::dump_cache(SrsLiveConsumer *consumer, SrsRtmpJitterAlgorithm jitter)
|
srs_error_t SrsBufferCache::dump_cache(ISrsLiveConsumer *consumer, SrsRtmpJitterAlgorithm jitter)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
|
@ -133,7 +146,7 @@ srs_error_t SrsBufferCache::cycle()
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
SrsSharedPtr<SrsLiveSource> live_source;
|
SrsSharedPtr<SrsLiveSource> live_source;
|
||||||
if ((err = _srs_sources->fetch_or_create(req_, live_source)) != srs_success) {
|
if ((err = live_sources_->fetch_or_create(req_, live_source)) != srs_success) {
|
||||||
return srs_error_wrap(err, "source create");
|
return srs_error_wrap(err, "source create");
|
||||||
}
|
}
|
||||||
srs_assert(live_source.get() != NULL);
|
srs_assert(live_source.get() != NULL);
|
||||||
|
|
@ -214,7 +227,7 @@ SrsTsStreamEncoder::~SrsTsStreamEncoder()
|
||||||
srs_freep(enc_);
|
srs_freep(enc_);
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsTsStreamEncoder::initialize(SrsFileWriter *w, SrsBufferCache * /*c*/)
|
srs_error_t SrsTsStreamEncoder::initialize(SrsFileWriter *w, ISrsBufferCache * /*c*/)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
|
@ -258,7 +271,7 @@ bool SrsTsStreamEncoder::has_cache()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsTsStreamEncoder::dump_cache(SrsLiveConsumer * /*consumer*/, SrsRtmpJitterAlgorithm /*jitter*/)
|
srs_error_t SrsTsStreamEncoder::dump_cache(ISrsLiveConsumer * /*consumer*/, SrsRtmpJitterAlgorithm /*jitter*/)
|
||||||
{
|
{
|
||||||
// for ts stream, ignore cache.
|
// for ts stream, ignore cache.
|
||||||
return srs_success;
|
return srs_success;
|
||||||
|
|
@ -293,7 +306,7 @@ SrsFlvStreamEncoder::~SrsFlvStreamEncoder()
|
||||||
srs_freep(enc_);
|
srs_freep(enc_);
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsFlvStreamEncoder::initialize(SrsFileWriter *w, SrsBufferCache * /*c*/)
|
srs_error_t SrsFlvStreamEncoder::initialize(SrsFileWriter *w, ISrsBufferCache * /*c*/)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
|
@ -363,7 +376,7 @@ bool SrsFlvStreamEncoder::has_cache()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsFlvStreamEncoder::dump_cache(SrsLiveConsumer * /*consumer*/, SrsRtmpJitterAlgorithm /*jitter*/)
|
srs_error_t SrsFlvStreamEncoder::dump_cache(ISrsLiveConsumer * /*consumer*/, SrsRtmpJitterAlgorithm /*jitter*/)
|
||||||
{
|
{
|
||||||
// for flv stream, ignore cache.
|
// for flv stream, ignore cache.
|
||||||
return srs_success;
|
return srs_success;
|
||||||
|
|
@ -458,7 +471,7 @@ SrsAacStreamEncoder::~SrsAacStreamEncoder()
|
||||||
srs_freep(enc_);
|
srs_freep(enc_);
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsAacStreamEncoder::initialize(SrsFileWriter *w, SrsBufferCache *c)
|
srs_error_t SrsAacStreamEncoder::initialize(SrsFileWriter *w, ISrsBufferCache *c)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
|
@ -493,7 +506,7 @@ bool SrsAacStreamEncoder::has_cache()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsAacStreamEncoder::dump_cache(SrsLiveConsumer *consumer, SrsRtmpJitterAlgorithm jitter)
|
srs_error_t SrsAacStreamEncoder::dump_cache(ISrsLiveConsumer *consumer, SrsRtmpJitterAlgorithm jitter)
|
||||||
{
|
{
|
||||||
srs_assert(cache_);
|
srs_assert(cache_);
|
||||||
return cache_->dump_cache(consumer, jitter);
|
return cache_->dump_cache(consumer, jitter);
|
||||||
|
|
@ -510,7 +523,7 @@ SrsMp3StreamEncoder::~SrsMp3StreamEncoder()
|
||||||
srs_freep(enc_);
|
srs_freep(enc_);
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsMp3StreamEncoder::initialize(SrsFileWriter *w, SrsBufferCache *c)
|
srs_error_t SrsMp3StreamEncoder::initialize(SrsFileWriter *w, ISrsBufferCache *c)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
|
@ -549,7 +562,7 @@ bool SrsMp3StreamEncoder::has_cache()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsMp3StreamEncoder::dump_cache(SrsLiveConsumer *consumer, SrsRtmpJitterAlgorithm jitter)
|
srs_error_t SrsMp3StreamEncoder::dump_cache(ISrsLiveConsumer *consumer, SrsRtmpJitterAlgorithm jitter)
|
||||||
{
|
{
|
||||||
srs_assert(cache_);
|
srs_assert(cache_);
|
||||||
return cache_->dump_cache(consumer, jitter);
|
return cache_->dump_cache(consumer, jitter);
|
||||||
|
|
@ -596,12 +609,24 @@ srs_error_t SrsBufferWriter::writev(const iovec *iov, int iovcnt, ssize_t *pnwri
|
||||||
return writer_->writev(iov, iovcnt, pnwrite);
|
return writer_->writev(iov, iovcnt, pnwrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsLiveStream::SrsLiveStream(SrsServer *s, ISrsRequest *r, SrsBufferCache *c)
|
ISrsLiveStream::ISrsLiveStream()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsLiveStream::~ISrsLiveStream()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsLiveStream::SrsLiveStream(ISrsRequest *r, ISrsBufferCache *c)
|
||||||
{
|
{
|
||||||
cache_ = c;
|
cache_ = c;
|
||||||
req_ = r->copy()->as_http();
|
req_ = r->copy()->as_http();
|
||||||
security_ = new SrsSecurity();
|
security_ = new SrsSecurity();
|
||||||
server_ = s;
|
|
||||||
|
config_ = _srs_config;
|
||||||
|
live_sources_ = _srs_sources;
|
||||||
|
stat_ = _srs_stat;
|
||||||
|
hooks_ = _srs_hooks;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsLiveStream::~SrsLiveStream()
|
SrsLiveStream::~SrsLiveStream()
|
||||||
|
|
@ -611,6 +636,11 @@ SrsLiveStream::~SrsLiveStream()
|
||||||
|
|
||||||
// The live stream should never be destroyed when it's serving any viewers.
|
// The live stream should never be destroyed when it's serving any viewers.
|
||||||
srs_assert(viewers_.empty());
|
srs_assert(viewers_.empty());
|
||||||
|
|
||||||
|
config_ = NULL;
|
||||||
|
live_sources_ = NULL;
|
||||||
|
stat_ = NULL;
|
||||||
|
hooks_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsLiveStream::update_auth(ISrsRequest *r)
|
srs_error_t SrsLiveStream::update_auth(ISrsRequest *r)
|
||||||
|
|
@ -664,8 +694,7 @@ srs_error_t SrsLiveStream::serve_http_impl(ISrsHttpResponseWriter *w, ISrsHttpMe
|
||||||
req_->ip_ = hc->remote_ip();
|
req_->ip_ = hc->remote_ip();
|
||||||
|
|
||||||
// We must do stat the client before hooks, because hooks depends on it.
|
// We must do stat the client before hooks, because hooks depends on it.
|
||||||
SrsStatistic *stat = _srs_stat;
|
if ((err = stat_->on_client(_srs_context->get_id().c_str(), req_, hc, SrsFlvPlay)) != srs_success) {
|
||||||
if ((err = stat->on_client(_srs_context->get_id().c_str(), req_, hc, SrsFlvPlay)) != srs_success) {
|
|
||||||
return srs_error_wrap(err, "stat on client");
|
return srs_error_wrap(err, "stat on client");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -679,19 +708,19 @@ srs_error_t SrsLiveStream::serve_http_impl(ISrsHttpResponseWriter *w, ISrsHttpMe
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fast check whether stream is still available.
|
// Fast check whether stream is still available.
|
||||||
if (!entry->enabled) {
|
if (!entry_->enabled) {
|
||||||
return srs_error_new(ERROR_RTMP_STREAM_NOT_FOUND, "stream not found");
|
return srs_error_new(ERROR_RTMP_STREAM_NOT_FOUND, "stream not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always try to create the source, because http handler won't create it.
|
// Always try to create the source, because http handler won't create it.
|
||||||
SrsSharedPtr<SrsLiveSource> live_source;
|
SrsSharedPtr<SrsLiveSource> live_source;
|
||||||
if ((err = _srs_sources->fetch_or_create(req_, live_source)) != srs_success) {
|
if ((err = live_sources_->fetch_or_create(req_, live_source)) != srs_success) {
|
||||||
return srs_error_wrap(err, "source create");
|
return srs_error_wrap(err, "source create");
|
||||||
}
|
}
|
||||||
srs_assert(live_source.get() != NULL);
|
srs_assert(live_source.get() != NULL);
|
||||||
|
|
||||||
bool enabled_cache = _srs_config->get_gop_cache(req_->vhost_);
|
bool enabled_cache = config_->get_gop_cache(req_->vhost_);
|
||||||
int gcmf = _srs_config->get_gop_cache_max_frames(req_->vhost_);
|
int gcmf = config_->get_gop_cache_max_frames(req_->vhost_);
|
||||||
live_source->set_cache(enabled_cache);
|
live_source->set_cache(enabled_cache);
|
||||||
live_source->set_gop_cache_max_frames(gcmf);
|
live_source->set_gop_cache_max_frames(gcmf);
|
||||||
|
|
||||||
|
|
@ -706,7 +735,7 @@ srs_error_t SrsLiveStream::serve_http_impl(ISrsHttpResponseWriter *w, ISrsHttpMe
|
||||||
SrsUniquePtr<SrsLiveConsumer> consumer(consumer_raw);
|
SrsUniquePtr<SrsLiveConsumer> consumer(consumer_raw);
|
||||||
|
|
||||||
// Fast check whether stream is still available.
|
// Fast check whether stream is still available.
|
||||||
if (!entry->enabled) {
|
if (!entry_->enabled) {
|
||||||
return srs_error_new(ERROR_RTMP_STREAM_NOT_FOUND, "stream not found");
|
return srs_error_new(ERROR_RTMP_STREAM_NOT_FOUND, "stream not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -733,20 +762,20 @@ void SrsLiveStream::expire()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsLiveStream::do_serve_http(SrsLiveSource *source, SrsLiveConsumer *consumer, ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
|
srs_error_t SrsLiveStream::do_serve_http(SrsLiveSource *source, ISrsLiveConsumer *consumer, ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
string enc_desc;
|
string enc_desc;
|
||||||
ISrsBufferEncoder *enc_raw = NULL;
|
ISrsBufferEncoder *enc_raw = NULL;
|
||||||
|
|
||||||
srs_assert(entry);
|
srs_assert(entry_);
|
||||||
bool drop_if_not_match = _srs_config->get_vhost_http_remux_drop_if_not_match(req_->vhost_);
|
bool drop_if_not_match = config_->get_vhost_http_remux_drop_if_not_match(req_->vhost_);
|
||||||
bool has_audio = _srs_config->get_vhost_http_remux_has_audio(req_->vhost_);
|
bool has_audio = config_->get_vhost_http_remux_has_audio(req_->vhost_);
|
||||||
bool has_video = _srs_config->get_vhost_http_remux_has_video(req_->vhost_);
|
bool has_video = config_->get_vhost_http_remux_has_video(req_->vhost_);
|
||||||
bool guess_has_av = _srs_config->get_vhost_http_remux_guess_has_av(req_->vhost_);
|
bool guess_has_av = config_->get_vhost_http_remux_guess_has_av(req_->vhost_);
|
||||||
|
|
||||||
if (srs_strings_ends_with(entry->pattern, ".flv")) {
|
if (srs_strings_ends_with(entry_->pattern, ".flv")) {
|
||||||
w->header()->set_content_type("video/x-flv");
|
w->header()->set_content_type("video/x-flv");
|
||||||
enc_desc = "FLV";
|
enc_desc = "FLV";
|
||||||
enc_raw = new SrsFlvStreamEncoder();
|
enc_raw = new SrsFlvStreamEncoder();
|
||||||
|
|
@ -754,15 +783,15 @@ srs_error_t SrsLiveStream::do_serve_http(SrsLiveSource *source, SrsLiveConsumer
|
||||||
((SrsFlvStreamEncoder *)enc_raw)->set_has_audio(has_audio);
|
((SrsFlvStreamEncoder *)enc_raw)->set_has_audio(has_audio);
|
||||||
((SrsFlvStreamEncoder *)enc_raw)->set_has_video(has_video);
|
((SrsFlvStreamEncoder *)enc_raw)->set_has_video(has_video);
|
||||||
((SrsFlvStreamEncoder *)enc_raw)->set_guess_has_av(guess_has_av);
|
((SrsFlvStreamEncoder *)enc_raw)->set_guess_has_av(guess_has_av);
|
||||||
} else if (srs_strings_ends_with(entry->pattern, ".aac")) {
|
} else if (srs_strings_ends_with(entry_->pattern, ".aac")) {
|
||||||
w->header()->set_content_type("audio/x-aac");
|
w->header()->set_content_type("audio/x-aac");
|
||||||
enc_desc = "AAC";
|
enc_desc = "AAC";
|
||||||
enc_raw = new SrsAacStreamEncoder();
|
enc_raw = new SrsAacStreamEncoder();
|
||||||
} else if (srs_strings_ends_with(entry->pattern, ".mp3")) {
|
} else if (srs_strings_ends_with(entry_->pattern, ".mp3")) {
|
||||||
w->header()->set_content_type("audio/mpeg");
|
w->header()->set_content_type("audio/mpeg");
|
||||||
enc_desc = "MP3";
|
enc_desc = "MP3";
|
||||||
enc_raw = new SrsMp3StreamEncoder();
|
enc_raw = new SrsMp3StreamEncoder();
|
||||||
} else if (srs_strings_ends_with(entry->pattern, ".ts")) {
|
} else if (srs_strings_ends_with(entry_->pattern, ".ts")) {
|
||||||
w->header()->set_content_type("video/MP2T");
|
w->header()->set_content_type("video/MP2T");
|
||||||
enc_desc = "TS";
|
enc_desc = "TS";
|
||||||
enc_raw = new SrsTsStreamEncoder();
|
enc_raw = new SrsTsStreamEncoder();
|
||||||
|
|
@ -770,7 +799,7 @@ srs_error_t SrsLiveStream::do_serve_http(SrsLiveSource *source, SrsLiveConsumer
|
||||||
((SrsTsStreamEncoder *)enc_raw)->set_has_video(has_video);
|
((SrsTsStreamEncoder *)enc_raw)->set_has_video(has_video);
|
||||||
((SrsTsStreamEncoder *)enc_raw)->set_guess_has_av(guess_has_av);
|
((SrsTsStreamEncoder *)enc_raw)->set_guess_has_av(guess_has_av);
|
||||||
} else {
|
} else {
|
||||||
return srs_error_new(ERROR_HTTP_LIVE_STREAM_EXT, "invalid pattern=%s", entry->pattern.c_str());
|
return srs_error_new(ERROR_HTTP_LIVE_STREAM_EXT, "invalid pattern=%s", entry_->pattern.c_str());
|
||||||
}
|
}
|
||||||
SrsUniquePtr<ISrsBufferEncoder> enc(enc_raw);
|
SrsUniquePtr<ISrsBufferEncoder> enc(enc_raw);
|
||||||
|
|
||||||
|
|
@ -817,14 +846,14 @@ srs_error_t SrsLiveStream::do_serve_http(SrsLiveSource *source, SrsLiveConsumer
|
||||||
return srs_error_wrap(err, "start recv thread");
|
return srs_error_wrap(err, "start recv thread");
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_utime_t mw_sleep = _srs_config->get_mw_sleep(req_->vhost_);
|
srs_utime_t mw_sleep = config_->get_mw_sleep(req_->vhost_);
|
||||||
srs_trace("FLV %s, encoder=%s, mw_sleep=%dms, cache=%d, msgs=%d, dinm=%d, guess_av=%d/%d/%d",
|
srs_trace("FLV %s, encoder=%s, mw_sleep=%dms, cache=%d, msgs=%d, dinm=%d, guess_av=%d/%d/%d",
|
||||||
entry->pattern.c_str(), enc_desc.c_str(), srsu2msi(mw_sleep), enc->has_cache(), msgs.max_, drop_if_not_match,
|
entry_->pattern.c_str(), enc_desc.c_str(), srsu2msi(mw_sleep), enc->has_cache(), msgs.max_, drop_if_not_match,
|
||||||
has_audio, has_video, guess_has_av);
|
has_audio, has_video, guess_has_av);
|
||||||
|
|
||||||
// TODO: free and erase the disabled entry after all related connections is closed.
|
// TODO: free and erase the disabled entry after all related connections is closed.
|
||||||
// TODO: FXIME: Support timeout for player, quit infinite-loop.
|
// TODO: FXIME: Support timeout for player, quit infinite-loop.
|
||||||
while (entry->enabled) {
|
while (entry_->enabled) {
|
||||||
// Whether client closed the FD.
|
// Whether client closed the FD.
|
||||||
if ((err = trd->pull()) != srs_success) {
|
if ((err = trd->pull()) != srs_success) {
|
||||||
return srs_error_wrap(err, "recv thread");
|
return srs_error_wrap(err, "recv thread");
|
||||||
|
|
@ -882,7 +911,7 @@ srs_error_t SrsLiveStream::http_hooks_on_play(ISrsHttpMessage *r)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
if (!_srs_config->get_vhost_http_hooks_enabled(req_->vhost_)) {
|
if (!config_->get_vhost_http_hooks_enabled(req_->vhost_)) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -896,7 +925,7 @@ srs_error_t SrsLiveStream::http_hooks_on_play(ISrsHttpMessage *r)
|
||||||
vector<string> hooks;
|
vector<string> hooks;
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
SrsConfDirective *conf = _srs_config->get_vhost_on_play(nreq->vhost_);
|
SrsConfDirective *conf = config_->get_vhost_on_play(nreq->vhost_);
|
||||||
|
|
||||||
if (!conf) {
|
if (!conf) {
|
||||||
return err;
|
return err;
|
||||||
|
|
@ -907,7 +936,7 @@ srs_error_t SrsLiveStream::http_hooks_on_play(ISrsHttpMessage *r)
|
||||||
|
|
||||||
for (int i = 0; i < (int)hooks.size(); i++) {
|
for (int i = 0; i < (int)hooks.size(); i++) {
|
||||||
std::string url = hooks.at(i);
|
std::string url = hooks.at(i);
|
||||||
if ((err = _srs_hooks->on_play(url, nreq.get())) != srs_success) {
|
if ((err = hooks_->on_play(url, nreq.get())) != srs_success) {
|
||||||
return srs_error_wrap(err, "http on_play %s", url.c_str());
|
return srs_error_wrap(err, "http on_play %s", url.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -917,7 +946,7 @@ srs_error_t SrsLiveStream::http_hooks_on_play(ISrsHttpMessage *r)
|
||||||
|
|
||||||
void SrsLiveStream::http_hooks_on_stop(ISrsHttpMessage *r)
|
void SrsLiveStream::http_hooks_on_stop(ISrsHttpMessage *r)
|
||||||
{
|
{
|
||||||
if (!_srs_config->get_vhost_http_hooks_enabled(req_->vhost_)) {
|
if (!config_->get_vhost_http_hooks_enabled(req_->vhost_)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -931,7 +960,7 @@ void SrsLiveStream::http_hooks_on_stop(ISrsHttpMessage *r)
|
||||||
vector<string> hooks;
|
vector<string> hooks;
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
SrsConfDirective *conf = _srs_config->get_vhost_on_stop(nreq->vhost_);
|
SrsConfDirective *conf = config_->get_vhost_on_stop(nreq->vhost_);
|
||||||
|
|
||||||
if (!conf) {
|
if (!conf) {
|
||||||
srs_info("ignore the empty http callback: on_stop");
|
srs_info("ignore the empty http callback: on_stop");
|
||||||
|
|
@ -943,7 +972,7 @@ void SrsLiveStream::http_hooks_on_stop(ISrsHttpMessage *r)
|
||||||
|
|
||||||
for (int i = 0; i < (int)hooks.size(); i++) {
|
for (int i = 0; i < (int)hooks.size(); i++) {
|
||||||
std::string url = hooks.at(i);
|
std::string url = hooks.at(i);
|
||||||
_srs_hooks->on_stop(url, nreq.get());
|
hooks_->on_stop(url, nreq.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
@ -1017,19 +1046,24 @@ bool SrsLiveEntry::is_mp3()
|
||||||
return is_mp3_;
|
return is_mp3_;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsHttpStreamServer::SrsHttpStreamServer(SrsServer *svr)
|
SrsHttpStreamServer::SrsHttpStreamServer()
|
||||||
{
|
{
|
||||||
server_ = svr;
|
|
||||||
async_ = new SrsAsyncCallWorker();
|
async_ = new SrsAsyncCallWorker();
|
||||||
|
|
||||||
mux_.add_dynamic_matcher(this);
|
mux_.add_dynamic_matcher(this);
|
||||||
_srs_config->subscribe(this);
|
|
||||||
|
config_ = _srs_config;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SrsHttpStreamServer::assemble()
|
||||||
|
{
|
||||||
|
config_->subscribe(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsHttpStreamServer::~SrsHttpStreamServer()
|
SrsHttpStreamServer::~SrsHttpStreamServer()
|
||||||
{
|
{
|
||||||
mux_.remove_dynamic_matcher(this);
|
mux_.remove_dynamic_matcher(this);
|
||||||
_srs_config->unsubscribe(this);
|
config_->unsubscribe(this);
|
||||||
|
|
||||||
async_->stop();
|
async_->stop();
|
||||||
srs_freep(async_);
|
srs_freep(async_);
|
||||||
|
|
@ -1050,6 +1084,8 @@ SrsHttpStreamServer::~SrsHttpStreamServer()
|
||||||
}
|
}
|
||||||
streamHandlers_.clear();
|
streamHandlers_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
config_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsHttpStreamServer::initialize()
|
srs_error_t SrsHttpStreamServer::initialize()
|
||||||
|
|
@ -1098,8 +1134,8 @@ srs_error_t SrsHttpStreamServer::http_mount(ISrsRequest *r)
|
||||||
entry = new SrsLiveEntry(mount);
|
entry = new SrsLiveEntry(mount);
|
||||||
|
|
||||||
entry->req_ = r->copy()->as_http();
|
entry->req_ = r->copy()->as_http();
|
||||||
entry->cache_ = new SrsBufferCache(server_, r);
|
entry->cache_ = new SrsBufferCache(r);
|
||||||
entry->stream_ = new SrsLiveStream(server_, r, entry->cache_);
|
entry->stream_ = new SrsLiveStream(r, entry->cache_);
|
||||||
|
|
||||||
// TODO: FIXME: maybe refine the logic of http remux service.
|
// TODO: FIXME: maybe refine the logic of http remux service.
|
||||||
// if user push streams followed:
|
// if user push streams followed:
|
||||||
|
|
@ -1139,7 +1175,7 @@ srs_error_t SrsHttpStreamServer::http_mount(ISrsRequest *r)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entry->stream_) {
|
if (entry->stream_) {
|
||||||
entry->stream_->entry->enabled = true;
|
entry->stream_->entry_->enabled = true;
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1176,7 +1212,7 @@ srs_error_t SrsHttpStreamServer::dynamic_match(ISrsHttpMessage *request, ISrsHtt
|
||||||
|
|
||||||
// when handler not the root, we think the handler is ok.
|
// when handler not the root, we think the handler is ok.
|
||||||
ISrsHttpHandler *h = *ph ? *ph : NULL;
|
ISrsHttpHandler *h = *ph ? *ph : NULL;
|
||||||
if (h && h->entry && h->entry->pattern != "/") {
|
if (h && h->entry_ && h->entry_->pattern != "/") {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1187,8 +1223,8 @@ srs_error_t SrsHttpStreamServer::dynamic_match(ISrsHttpMessage *request, ISrsHtt
|
||||||
}
|
}
|
||||||
|
|
||||||
// find the actually request vhost.
|
// find the actually request vhost.
|
||||||
SrsConfDirective *vhost = _srs_config->get_vhost(request->host());
|
SrsConfDirective *vhost = config_->get_vhost(request->host());
|
||||||
if (!vhost || !_srs_config->get_vhost_enabled(vhost)) {
|
if (!vhost || !config_->get_vhost_enabled(vhost)) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1254,11 +1290,11 @@ srs_error_t SrsHttpStreamServer::dynamic_match(ISrsHttpMessage *request, ISrsHtt
|
||||||
// for example, user disable the http flv then reload.
|
// for example, user disable the http flv then reload.
|
||||||
if (streamHandlers_.find(sid) != streamHandlers_.end()) {
|
if (streamHandlers_.find(sid) != streamHandlers_.end()) {
|
||||||
SrsLiveEntry *s_entry = streamHandlers_[sid];
|
SrsLiveEntry *s_entry = streamHandlers_[sid];
|
||||||
if (!s_entry->stream_->entry->enabled) {
|
if (!s_entry->stream_->entry_->enabled) {
|
||||||
// only when the http entry is disabled, check the config whether http flv disable,
|
// only when the http entry is disabled, check the config whether http flv disable,
|
||||||
// for the http flv edge use match to trigger the edge ingester, we always mount it
|
// for the http flv edge use match to trigger the edge ingester, we always mount it
|
||||||
// eventhough the origin does not exists the specified stream.
|
// eventhough the origin does not exists the specified stream.
|
||||||
if (!_srs_config->get_vhost_http_remux_enabled(r->vhost_)) {
|
if (!config_->get_vhost_http_remux_enabled(r->vhost_)) {
|
||||||
return srs_error_new(ERROR_HTTP_DYNAMIC_MATCH, "stream disabled");
|
return srs_error_new(ERROR_HTTP_DYNAMIC_MATCH, "stream disabled");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1285,7 +1321,7 @@ srs_error_t SrsHttpStreamServer::initialize_flv_streaming()
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
// http flv live stream mount for each vhost.
|
// http flv live stream mount for each vhost.
|
||||||
SrsConfDirective *root = _srs_config->get_root();
|
SrsConfDirective *root = config_->get_root();
|
||||||
for (int i = 0; i < (int)root->directives_.size(); i++) {
|
for (int i = 0; i < (int)root->directives_.size(); i++) {
|
||||||
SrsConfDirective *conf = root->at(i);
|
SrsConfDirective *conf = root->at(i);
|
||||||
|
|
||||||
|
|
@ -1305,11 +1341,11 @@ srs_error_t SrsHttpStreamServer::initialize_flv_entry(std::string vhost)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
if (!_srs_config->get_vhost_http_remux_enabled(vhost)) {
|
if (!config_->get_vhost_http_remux_enabled(vhost)) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsLiveEntry *entry = new SrsLiveEntry(_srs_config->get_vhost_http_remux_mount(vhost));
|
SrsLiveEntry *entry = new SrsLiveEntry(config_->get_vhost_http_remux_mount(vhost));
|
||||||
|
|
||||||
templateHandlers_[vhost] = entry;
|
templateHandlers_[vhost] = entry;
|
||||||
srs_trace("http flv live stream, vhost=%s, mount=%s", vhost.c_str(), entry->mount_.c_str());
|
srs_trace("http flv live stream, vhost=%s, mount=%s", vhost.c_str(), entry->mount_.c_str());
|
||||||
|
|
@ -1341,12 +1377,12 @@ srs_error_t SrsHttpStreamDestroy::call()
|
||||||
SrsUniquePtr<SrsLiveEntry> entry(it->second);
|
SrsUniquePtr<SrsLiveEntry> entry(it->second);
|
||||||
srs_assert(entry->disposing_);
|
srs_assert(entry->disposing_);
|
||||||
|
|
||||||
SrsUniquePtr<SrsLiveStream> stream(entry->stream_);
|
SrsUniquePtr<ISrsLiveStream> stream(entry->stream_);
|
||||||
SrsUniquePtr<SrsBufferCache> cache(entry->cache_);
|
SrsUniquePtr<ISrsBufferCache> cache(entry->cache_);
|
||||||
|
|
||||||
// Notify cache and stream to stop.
|
// Notify cache and stream to stop.
|
||||||
if (stream->entry)
|
if (stream->entry_)
|
||||||
stream->entry->enabled = false;
|
stream->entry_->enabled = false;
|
||||||
stream->expire();
|
stream->expire();
|
||||||
cache->stop();
|
cache->stop();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,24 +16,54 @@
|
||||||
|
|
||||||
class SrsAacTransmuxer;
|
class SrsAacTransmuxer;
|
||||||
class SrsMp3Transmuxer;
|
class SrsMp3Transmuxer;
|
||||||
class SrsFlvTransmuxer;
|
class ISrsFlvTransmuxer;
|
||||||
class SrsTsTransmuxer;
|
class SrsTsTransmuxer;
|
||||||
class SrsAsyncCallWorker;
|
class SrsAsyncCallWorker;
|
||||||
|
class ISrsAppConfig;
|
||||||
|
class ISrsLiveSourceManager;
|
||||||
|
class ISrsStatistic;
|
||||||
|
class ISrsHttpHooks;
|
||||||
|
class ISrsMessageQueue;
|
||||||
|
class ISrsLiveConsumer;
|
||||||
|
class ISrsTsTransmuxer;
|
||||||
|
class ISrsAacTransmuxer;
|
||||||
|
class ISrsBufferCache;
|
||||||
|
class ISrsMp3Transmuxer;
|
||||||
|
|
||||||
|
// The cache for HTTP Live Streaming encoder.
|
||||||
|
class ISrsBufferCache
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsBufferCache();
|
||||||
|
virtual ~ISrsBufferCache();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t start() = 0;
|
||||||
|
virtual void stop() = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual bool alive() = 0;
|
||||||
|
virtual srs_error_t dump_cache(ISrsLiveConsumer *consumer, SrsRtmpJitterAlgorithm jitter) = 0;
|
||||||
|
virtual srs_error_t update_auth(ISrsRequest *r) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
// A cache for HTTP Live Streaming encoder, to make android(weixin) happy.
|
// A cache for HTTP Live Streaming encoder, to make android(weixin) happy.
|
||||||
class SrsBufferCache : public ISrsCoroutineHandler
|
class SrsBufferCache : public ISrsCoroutineHandler, public ISrsBufferCache
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
srs_utime_t fast_cache_;
|
ISrsAppConfig *config_;
|
||||||
SrsServer *server_;
|
ISrsLiveSourceManager *live_sources_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SrsMessageQueue *queue_;
|
srs_utime_t fast_cache_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ISrsMessageQueue *queue_;
|
||||||
ISrsRequest *req_;
|
ISrsRequest *req_;
|
||||||
ISrsCoroutine *trd_;
|
ISrsCoroutine *trd_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsBufferCache(SrsServer *s, ISrsRequest *r);
|
SrsBufferCache(ISrsRequest *r);
|
||||||
virtual ~SrsBufferCache();
|
virtual ~SrsBufferCache();
|
||||||
virtual srs_error_t update_auth(ISrsRequest *r);
|
virtual srs_error_t update_auth(ISrsRequest *r);
|
||||||
|
|
||||||
|
|
@ -41,7 +71,7 @@ public:
|
||||||
virtual srs_error_t start();
|
virtual srs_error_t start();
|
||||||
virtual void stop();
|
virtual void stop();
|
||||||
virtual bool alive();
|
virtual bool alive();
|
||||||
virtual srs_error_t dump_cache(SrsLiveConsumer *consumer, SrsRtmpJitterAlgorithm jitter);
|
virtual srs_error_t dump_cache(ISrsLiveConsumer *consumer, SrsRtmpJitterAlgorithm jitter);
|
||||||
// Interface ISrsEndlessThreadHandler.
|
// Interface ISrsEndlessThreadHandler.
|
||||||
public:
|
public:
|
||||||
virtual srs_error_t cycle();
|
virtual srs_error_t cycle();
|
||||||
|
|
@ -58,7 +88,7 @@ public:
|
||||||
// Initialize the encoder with file writer(to http response) and stream cache.
|
// Initialize the encoder with file writer(to http response) and stream cache.
|
||||||
// @param w the writer to write to http response.
|
// @param w the writer to write to http response.
|
||||||
// @param c the stream cache for audio stream fast startup.
|
// @param c the stream cache for audio stream fast startup.
|
||||||
virtual srs_error_t initialize(SrsFileWriter *w, SrsBufferCache *c) = 0;
|
virtual srs_error_t initialize(SrsFileWriter *w, ISrsBufferCache *c) = 0;
|
||||||
// Write rtmp video/audio/metadata.
|
// Write rtmp video/audio/metadata.
|
||||||
virtual srs_error_t write_audio(int64_t timestamp, char *data, int size) = 0;
|
virtual srs_error_t write_audio(int64_t timestamp, char *data, int size) = 0;
|
||||||
virtual srs_error_t write_video(int64_t timestamp, char *data, int size) = 0;
|
virtual srs_error_t write_video(int64_t timestamp, char *data, int size) = 0;
|
||||||
|
|
@ -70,14 +100,14 @@ public:
|
||||||
// @return true to use gop cache of encoder; otherwise, use SrsLiveSource.
|
// @return true to use gop cache of encoder; otherwise, use SrsLiveSource.
|
||||||
virtual bool has_cache() = 0;
|
virtual bool has_cache() = 0;
|
||||||
// Dumps the cache of encoder to consumer.
|
// Dumps the cache of encoder to consumer.
|
||||||
virtual srs_error_t dump_cache(SrsLiveConsumer *consumer, SrsRtmpJitterAlgorithm jitter) = 0;
|
virtual srs_error_t dump_cache(ISrsLiveConsumer *consumer, SrsRtmpJitterAlgorithm jitter) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Transmux RTMP to HTTP Live Streaming.
|
// Transmux RTMP to HTTP Live Streaming.
|
||||||
class SrsFlvStreamEncoder : public ISrsBufferEncoder
|
class SrsFlvStreamEncoder : public ISrsBufferEncoder
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
SrsFlvTransmuxer *enc_;
|
ISrsFlvTransmuxer *enc_;
|
||||||
bool header_written_;
|
bool header_written_;
|
||||||
bool has_audio_;
|
bool has_audio_;
|
||||||
bool has_video_;
|
bool has_video_;
|
||||||
|
|
@ -88,7 +118,7 @@ public:
|
||||||
virtual ~SrsFlvStreamEncoder();
|
virtual ~SrsFlvStreamEncoder();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual srs_error_t initialize(SrsFileWriter *w, SrsBufferCache *c);
|
virtual srs_error_t initialize(SrsFileWriter *w, ISrsBufferCache *c);
|
||||||
virtual srs_error_t write_audio(int64_t timestamp, char *data, int size);
|
virtual srs_error_t write_audio(int64_t timestamp, char *data, int size);
|
||||||
virtual srs_error_t write_video(int64_t timestamp, char *data, int size);
|
virtual srs_error_t write_video(int64_t timestamp, char *data, int size);
|
||||||
virtual srs_error_t write_metadata(int64_t timestamp, char *data, int size);
|
virtual srs_error_t write_metadata(int64_t timestamp, char *data, int size);
|
||||||
|
|
@ -101,7 +131,7 @@ public:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual bool has_cache();
|
virtual bool has_cache();
|
||||||
virtual srs_error_t dump_cache(SrsLiveConsumer *consumer, SrsRtmpJitterAlgorithm jitter);
|
virtual srs_error_t dump_cache(ISrsLiveConsumer *consumer, SrsRtmpJitterAlgorithm jitter);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Write the tags in a time.
|
// Write the tags in a time.
|
||||||
|
|
@ -115,21 +145,21 @@ private:
|
||||||
class SrsTsStreamEncoder : public ISrsBufferEncoder
|
class SrsTsStreamEncoder : public ISrsBufferEncoder
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
SrsTsTransmuxer *enc_;
|
ISrsTsTransmuxer *enc_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsTsStreamEncoder();
|
SrsTsStreamEncoder();
|
||||||
virtual ~SrsTsStreamEncoder();
|
virtual ~SrsTsStreamEncoder();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual srs_error_t initialize(SrsFileWriter *w, SrsBufferCache *c);
|
virtual srs_error_t initialize(SrsFileWriter *w, ISrsBufferCache *c);
|
||||||
virtual srs_error_t write_audio(int64_t timestamp, char *data, int size);
|
virtual srs_error_t write_audio(int64_t timestamp, char *data, int size);
|
||||||
virtual srs_error_t write_video(int64_t timestamp, char *data, int size);
|
virtual srs_error_t write_video(int64_t timestamp, char *data, int size);
|
||||||
virtual srs_error_t write_metadata(int64_t timestamp, char *data, int size);
|
virtual srs_error_t write_metadata(int64_t timestamp, char *data, int size);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual bool has_cache();
|
virtual bool has_cache();
|
||||||
virtual srs_error_t dump_cache(SrsLiveConsumer *consumer, SrsRtmpJitterAlgorithm jitter);
|
virtual srs_error_t dump_cache(ISrsLiveConsumer *consumer, SrsRtmpJitterAlgorithm jitter);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void set_has_audio(bool v);
|
void set_has_audio(bool v);
|
||||||
|
|
@ -141,44 +171,44 @@ public:
|
||||||
class SrsAacStreamEncoder : public ISrsBufferEncoder
|
class SrsAacStreamEncoder : public ISrsBufferEncoder
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
SrsAacTransmuxer *enc_;
|
ISrsAacTransmuxer *enc_;
|
||||||
SrsBufferCache *cache_;
|
ISrsBufferCache *cache_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsAacStreamEncoder();
|
SrsAacStreamEncoder();
|
||||||
virtual ~SrsAacStreamEncoder();
|
virtual ~SrsAacStreamEncoder();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual srs_error_t initialize(SrsFileWriter *w, SrsBufferCache *c);
|
virtual srs_error_t initialize(SrsFileWriter *w, ISrsBufferCache *c);
|
||||||
virtual srs_error_t write_audio(int64_t timestamp, char *data, int size);
|
virtual srs_error_t write_audio(int64_t timestamp, char *data, int size);
|
||||||
virtual srs_error_t write_video(int64_t timestamp, char *data, int size);
|
virtual srs_error_t write_video(int64_t timestamp, char *data, int size);
|
||||||
virtual srs_error_t write_metadata(int64_t timestamp, char *data, int size);
|
virtual srs_error_t write_metadata(int64_t timestamp, char *data, int size);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual bool has_cache();
|
virtual bool has_cache();
|
||||||
virtual srs_error_t dump_cache(SrsLiveConsumer *consumer, SrsRtmpJitterAlgorithm jitter);
|
virtual srs_error_t dump_cache(ISrsLiveConsumer *consumer, SrsRtmpJitterAlgorithm jitter);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Transmux RTMP with MP3 stream to HTTP MP3 Streaming.
|
// Transmux RTMP with MP3 stream to HTTP MP3 Streaming.
|
||||||
class SrsMp3StreamEncoder : public ISrsBufferEncoder
|
class SrsMp3StreamEncoder : public ISrsBufferEncoder
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
SrsMp3Transmuxer *enc_;
|
ISrsMp3Transmuxer *enc_;
|
||||||
SrsBufferCache *cache_;
|
ISrsBufferCache *cache_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsMp3StreamEncoder();
|
SrsMp3StreamEncoder();
|
||||||
virtual ~SrsMp3StreamEncoder();
|
virtual ~SrsMp3StreamEncoder();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual srs_error_t initialize(SrsFileWriter *w, SrsBufferCache *c);
|
virtual srs_error_t initialize(SrsFileWriter *w, ISrsBufferCache *c);
|
||||||
virtual srs_error_t write_audio(int64_t timestamp, char *data, int size);
|
virtual srs_error_t write_audio(int64_t timestamp, char *data, int size);
|
||||||
virtual srs_error_t write_video(int64_t timestamp, char *data, int size);
|
virtual srs_error_t write_video(int64_t timestamp, char *data, int size);
|
||||||
virtual srs_error_t write_metadata(int64_t timestamp, char *data, int size);
|
virtual srs_error_t write_metadata(int64_t timestamp, char *data, int size);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual bool has_cache();
|
virtual bool has_cache();
|
||||||
virtual srs_error_t dump_cache(SrsLiveConsumer *consumer, SrsRtmpJitterAlgorithm jitter);
|
virtual srs_error_t dump_cache(ISrsLiveConsumer *consumer, SrsRtmpJitterAlgorithm jitter);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Write stream to http response direclty.
|
// Write stream to http response direclty.
|
||||||
|
|
@ -204,22 +234,39 @@ public:
|
||||||
virtual srs_error_t writev(const iovec *iov, int iovcnt, ssize_t *pnwrite);
|
virtual srs_error_t writev(const iovec *iov, int iovcnt, ssize_t *pnwrite);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Interface for HTTP Live Streaming.
|
||||||
|
class ISrsLiveStream : public ISrsHttpHandler, public ISrsExpire
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsLiveStream();
|
||||||
|
virtual ~ISrsLiveStream();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t update_auth(ISrsRequest *r) = 0;
|
||||||
|
virtual bool alive() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
// HTTP Live Streaming, to transmux RTMP to HTTP FLV or other format.
|
// HTTP Live Streaming, to transmux RTMP to HTTP FLV or other format.
|
||||||
// TODO: FIXME: Rename to SrsHttpLive
|
// TODO: FIXME: Rename to SrsHttpLive
|
||||||
class SrsLiveStream : public ISrsHttpHandler, public ISrsExpire
|
class SrsLiveStream : public ISrsLiveStream
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
ISrsAppConfig *config_;
|
||||||
|
ISrsLiveSourceManager *live_sources_;
|
||||||
|
ISrsStatistic *stat_;
|
||||||
|
ISrsHttpHooks *hooks_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ISrsRequest *req_;
|
ISrsRequest *req_;
|
||||||
SrsBufferCache *cache_;
|
ISrsBufferCache *cache_;
|
||||||
SrsSecurity *security_;
|
ISrsSecurity *security_;
|
||||||
SrsServer *server_;
|
|
||||||
// For multiple viewers, which means there will more than one alive viewers for a live stream, so we must
|
// For multiple viewers, which means there will more than one alive viewers for a live stream, so we must
|
||||||
// use an int value to represent if there is any viewer is alive. We should never do cleanup unless all
|
// use an int value to represent if there is any viewer is alive. We should never do cleanup unless all
|
||||||
// viewers closed the connection.
|
// viewers closed the connection.
|
||||||
std::vector<ISrsExpire *> viewers_;
|
std::vector<ISrsExpire *> viewers_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsLiveStream(SrsServer *s, ISrsRequest *r, SrsBufferCache *c);
|
SrsLiveStream(ISrsRequest *r, ISrsBufferCache *c);
|
||||||
virtual ~SrsLiveStream();
|
virtual ~SrsLiveStream();
|
||||||
virtual srs_error_t update_auth(ISrsRequest *r);
|
virtual srs_error_t update_auth(ISrsRequest *r);
|
||||||
|
|
||||||
|
|
@ -236,7 +283,7 @@ public:
|
||||||
virtual void expire();
|
virtual void expire();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual srs_error_t do_serve_http(SrsLiveSource *source, SrsLiveConsumer *consumer, ISrsHttpResponseWriter *w, ISrsHttpMessage *r);
|
virtual srs_error_t do_serve_http(SrsLiveSource *source, ISrsLiveConsumer *consumer, ISrsHttpResponseWriter *w, ISrsHttpMessage *r);
|
||||||
virtual srs_error_t http_hooks_on_play(ISrsHttpMessage *r);
|
virtual srs_error_t http_hooks_on_play(ISrsHttpMessage *r);
|
||||||
virtual void http_hooks_on_stop(ISrsHttpMessage *r);
|
virtual void http_hooks_on_stop(ISrsHttpMessage *r);
|
||||||
virtual srs_error_t streaming_send_messages(ISrsBufferEncoder *enc, SrsMediaPacket **msgs, int nb_msgs);
|
virtual srs_error_t streaming_send_messages(ISrsBufferEncoder *enc, SrsMediaPacket **msgs, int nb_msgs);
|
||||||
|
|
@ -259,8 +306,8 @@ public:
|
||||||
// For concrete stream, the mount is url to access.
|
// For concrete stream, the mount is url to access.
|
||||||
std::string mount_;
|
std::string mount_;
|
||||||
|
|
||||||
SrsLiveStream *stream_;
|
ISrsLiveStream *stream_;
|
||||||
SrsBufferCache *cache_;
|
ISrsBufferCache *cache_;
|
||||||
|
|
||||||
// Whether is disposing the entry.
|
// Whether is disposing the entry.
|
||||||
bool disposing_;
|
bool disposing_;
|
||||||
|
|
@ -279,8 +326,10 @@ public:
|
||||||
class SrsHttpStreamServer : public ISrsReloadHandler, public ISrsHttpDynamicMatcher
|
class SrsHttpStreamServer : public ISrsReloadHandler, public ISrsHttpDynamicMatcher
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
SrsServer *server_;
|
ISrsAppConfig *config_;
|
||||||
SrsAsyncCallWorker *async_;
|
|
||||||
|
private:
|
||||||
|
ISrsAsyncCallWorker *async_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsHttpServeMux mux_;
|
SrsHttpServeMux mux_;
|
||||||
|
|
@ -290,7 +339,8 @@ public:
|
||||||
std::map<std::string, SrsLiveEntry *> streamHandlers_;
|
std::map<std::string, SrsLiveEntry *> streamHandlers_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsHttpStreamServer(SrsServer *svr);
|
SrsHttpStreamServer();
|
||||||
|
void assemble();
|
||||||
virtual ~SrsHttpStreamServer();
|
virtual ~SrsHttpStreamServer();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -224,6 +224,14 @@ void SrsFastVector::free()
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
ISrsMessageQueue::ISrsMessageQueue()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsMessageQueue::~ISrsMessageQueue()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
SrsMessageQueue::SrsMessageQueue(bool ignore_shrink)
|
SrsMessageQueue::SrsMessageQueue(bool ignore_shrink)
|
||||||
{
|
{
|
||||||
_ignore_shrink = ignore_shrink;
|
_ignore_shrink = ignore_shrink;
|
||||||
|
|
@ -316,7 +324,7 @@ srs_error_t SrsMessageQueue::dump_packets(int max_count, SrsMediaPacket **pmsgs,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsMessageQueue::dump_packets(SrsLiveConsumer *consumer, bool atc, SrsRtmpJitterAlgorithm ag)
|
srs_error_t SrsMessageQueue::dump_packets(ISrsLiveConsumer *consumer, bool atc, SrsRtmpJitterAlgorithm ag)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
|
@ -404,6 +412,14 @@ ISrsWakable::~ISrsWakable()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ISrsLiveConsumer::ISrsLiveConsumer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsLiveConsumer::~ISrsLiveConsumer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
SrsLiveConsumer::SrsLiveConsumer(ISrsLiveSource *s)
|
SrsLiveConsumer::SrsLiveConsumer(ISrsLiveSource *s)
|
||||||
{
|
{
|
||||||
source_ = s;
|
source_ = s;
|
||||||
|
|
@ -681,7 +697,7 @@ void SrsGopCache::clear()
|
||||||
audio_after_last_video_count_ = 0;
|
audio_after_last_video_count_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsGopCache::dump(SrsLiveConsumer *consumer, bool atc, SrsRtmpJitterAlgorithm jitter_algorithm)
|
srs_error_t SrsGopCache::dump(ISrsLiveConsumer *consumer, bool atc, SrsRtmpJitterAlgorithm jitter_algorithm)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
|
@ -1441,7 +1457,7 @@ SrsFormat *SrsMetaCache::ash_format()
|
||||||
return aformat_;
|
return aformat_;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsMetaCache::dumps(SrsLiveConsumer *consumer, bool atc, SrsRtmpJitterAlgorithm ag, bool dm, bool ds)
|
srs_error_t SrsMetaCache::dumps(ISrsLiveConsumer *consumer, bool atc, SrsRtmpJitterAlgorithm ag, bool dm, bool ds)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
|
@ -2495,7 +2511,7 @@ srs_error_t SrsLiveSource::create_consumer(SrsLiveConsumer *&consumer)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsLiveSource::consumer_dumps(SrsLiveConsumer *consumer, bool ds, bool dm, bool dg)
|
srs_error_t SrsLiveSource::consumer_dumps(ISrsLiveConsumer *consumer, bool ds, bool dm, bool dg)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@ class ISrsHds;
|
||||||
class ISrsNgExec;
|
class ISrsNgExec;
|
||||||
class ISrsForwarder;
|
class ISrsForwarder;
|
||||||
class SrsAppFactory;
|
class SrsAppFactory;
|
||||||
|
class ISrsLiveConsumer;
|
||||||
|
|
||||||
// The time jitter algorithm:
|
// The time jitter algorithm:
|
||||||
// 1. full, to ensure stream start at zero, and ensure stream monotonically increasing.
|
// 1. full, to ensure stream start at zero, and ensure stream monotonically increasing.
|
||||||
|
|
@ -118,9 +119,26 @@ public:
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// The message queue interface.
|
||||||
|
class ISrsMessageQueue
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsMessageQueue();
|
||||||
|
virtual ~ISrsMessageQueue();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual int size() = 0;
|
||||||
|
virtual srs_utime_t duration() = 0;
|
||||||
|
virtual void set_queue_size(srs_utime_t queue_size) = 0;
|
||||||
|
virtual srs_error_t enqueue(SrsMediaPacket *msg, bool *is_overflow = NULL) = 0;
|
||||||
|
// virtual srs_error_t dump_packets(int max_count, SrsMediaPacket **pmsgs, int &count) = 0;
|
||||||
|
virtual srs_error_t dump_packets(ISrsLiveConsumer *consumer, bool atc, SrsRtmpJitterAlgorithm ag) = 0;
|
||||||
|
// virtual void clear() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
// The message queue for the consumer(client), forwarder.
|
// The message queue for the consumer(client), forwarder.
|
||||||
// We limit the size in seconds, drop old messages(the whole gop) if full.
|
// We limit the size in seconds, drop old messages(the whole gop) if full.
|
||||||
class SrsMessageQueue
|
class SrsMessageQueue : public ISrsMessageQueue
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
// The start and end time.
|
// The start and end time.
|
||||||
|
|
@ -162,7 +180,7 @@ public:
|
||||||
virtual srs_error_t dump_packets(int max_count, SrsMediaPacket **pmsgs, int &count);
|
virtual srs_error_t dump_packets(int max_count, SrsMediaPacket **pmsgs, int &count);
|
||||||
// Dumps packets to consumer, use specified args.
|
// Dumps packets to consumer, use specified args.
|
||||||
// @remark the atc/tba/tbv/ag are same to SrsLiveConsumer.enqueue().
|
// @remark the atc/tba/tbv/ag are same to SrsLiveConsumer.enqueue().
|
||||||
virtual srs_error_t dump_packets(SrsLiveConsumer *consumer, bool atc, SrsRtmpJitterAlgorithm ag);
|
virtual srs_error_t dump_packets(ISrsLiveConsumer *consumer, bool atc, SrsRtmpJitterAlgorithm ag);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Remove a gop from the front.
|
// Remove a gop from the front.
|
||||||
|
|
@ -189,8 +207,22 @@ public:
|
||||||
virtual void wakeup() = 0;
|
virtual void wakeup() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The consumer interface.
|
||||||
|
class ISrsLiveConsumer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsLiveConsumer();
|
||||||
|
virtual ~ISrsLiveConsumer();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t enqueue(SrsMediaPacket *shared_msg, bool atc, SrsRtmpJitterAlgorithm ag) = 0;
|
||||||
|
virtual srs_error_t dump_packets(SrsMessageArray *msgs, int &count) = 0;
|
||||||
|
virtual void set_queue_size(srs_utime_t queue_size) = 0;
|
||||||
|
virtual int64_t get_time() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
// The consumer for SrsLiveSource, that is a play client.
|
// The consumer for SrsLiveSource, that is a play client.
|
||||||
class SrsLiveConsumer : public ISrsWakable
|
class SrsLiveConsumer : public ISrsWakable, public ISrsLiveConsumer
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
// Because source references to this object, so we should directly use the source ptr.
|
// Because source references to this object, so we should directly use the source ptr.
|
||||||
|
|
@ -297,7 +329,7 @@ public:
|
||||||
// clear the gop cache.
|
// clear the gop cache.
|
||||||
virtual void clear();
|
virtual void clear();
|
||||||
// dump the cached gop to consumer.
|
// dump the cached gop to consumer.
|
||||||
virtual srs_error_t dump(SrsLiveConsumer *consumer, bool atc, SrsRtmpJitterAlgorithm jitter_algorithm);
|
virtual srs_error_t dump(ISrsLiveConsumer *consumer, bool atc, SrsRtmpJitterAlgorithm jitter_algorithm);
|
||||||
// used for atc to get the time of gop cache,
|
// used for atc to get the time of gop cache,
|
||||||
// The atc will adjust the sequence header timestamp to gop cache.
|
// The atc will adjust the sequence header timestamp to gop cache.
|
||||||
virtual bool empty();
|
virtual bool empty();
|
||||||
|
|
@ -495,7 +527,7 @@ public:
|
||||||
// Dumps cached metadata to consumer.
|
// Dumps cached metadata to consumer.
|
||||||
// @param dm Whether dumps the metadata.
|
// @param dm Whether dumps the metadata.
|
||||||
// @param ds Whether dumps the sequence header.
|
// @param ds Whether dumps the sequence header.
|
||||||
virtual srs_error_t dumps(SrsLiveConsumer *consumer, bool atc, SrsRtmpJitterAlgorithm ag, bool dm, bool ds);
|
virtual srs_error_t dumps(ISrsLiveConsumer *consumer, bool atc, SrsRtmpJitterAlgorithm ag, bool dm, bool ds);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Previous exists sequence header.
|
// Previous exists sequence header.
|
||||||
|
|
@ -720,7 +752,7 @@ public:
|
||||||
// @param ds, whether dumps the sequence header.
|
// @param ds, whether dumps the sequence header.
|
||||||
// @param dm, whether dumps the metadata.
|
// @param dm, whether dumps the metadata.
|
||||||
// @param dg, whether dumps the gop cache.
|
// @param dg, whether dumps the gop cache.
|
||||||
virtual srs_error_t consumer_dumps(SrsLiveConsumer *consumer, bool ds = true, bool dm = true, bool dg = true);
|
virtual srs_error_t consumer_dumps(ISrsLiveConsumer *consumer, bool ds = true, bool dm = true, bool dg = true);
|
||||||
virtual void on_consumer_destroy(SrsLiveConsumer *consumer);
|
virtual void on_consumer_destroy(SrsLiveConsumer *consumer);
|
||||||
virtual void set_cache(bool enabled);
|
virtual void set_cache(bool enabled);
|
||||||
virtual void set_gop_cache_max_frames(int v);
|
virtual void set_gop_cache_max_frames(int v);
|
||||||
|
|
|
||||||
|
|
@ -175,7 +175,7 @@ SrsServer::SrsServer()
|
||||||
stream_caster_gb28181_ = new SrsGbListener();
|
stream_caster_gb28181_ = new SrsGbListener();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
http_server_ = new SrsHttpServer(this);
|
http_server_ = new SrsHttpServer();
|
||||||
reuse_api_over_server_ = false;
|
reuse_api_over_server_ = false;
|
||||||
reuse_rtc_over_server_ = false;
|
reuse_rtc_over_server_ = false;
|
||||||
|
|
||||||
|
|
@ -1017,7 +1017,7 @@ srs_error_t SrsServer::do2_cycle()
|
||||||
srs_trace("reload config success, state=%d.", state);
|
srs_trace("reload config success, state=%d.", state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -258,6 +258,7 @@ public:
|
||||||
virtual srs_error_t dumps_clients(SrsJsonArray *arr, int start, int count);
|
virtual srs_error_t dumps_clients(SrsJsonArray *arr, int start, int count);
|
||||||
// Dumps the hints about SRS server.
|
// Dumps the hints about SRS server.
|
||||||
void dumps_hints_kv(std::stringstream &ss);
|
void dumps_hints_kv(std::stringstream &ss);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual SrsStatisticVhost *create_vhost(ISrsRequest *req);
|
virtual SrsStatisticVhost *create_vhost(ISrsRequest *req);
|
||||||
virtual SrsStatisticStream *create_stream(SrsStatisticVhost *vhost, ISrsRequest *req);
|
virtual SrsStatisticStream *create_stream(SrsStatisticVhost *vhost, ISrsRequest *req);
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,14 @@ using namespace std;
|
||||||
#include <srs_kernel_io.hpp>
|
#include <srs_kernel_io.hpp>
|
||||||
#include <srs_kernel_log.hpp>
|
#include <srs_kernel_log.hpp>
|
||||||
|
|
||||||
|
ISrsAacTransmuxer::ISrsAacTransmuxer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsAacTransmuxer::~ISrsAacTransmuxer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
SrsAacTransmuxer::SrsAacTransmuxer()
|
SrsAacTransmuxer::SrsAacTransmuxer()
|
||||||
{
|
{
|
||||||
writer_ = NULL;
|
writer_ = NULL;
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,19 @@
|
||||||
class SrsBuffer;
|
class SrsBuffer;
|
||||||
class ISrsStreamWriter;
|
class ISrsStreamWriter;
|
||||||
|
|
||||||
|
class ISrsAacTransmuxer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsAacTransmuxer();
|
||||||
|
virtual ~ISrsAacTransmuxer();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t initialize(ISrsStreamWriter *fs) = 0;
|
||||||
|
virtual srs_error_t write_audio(int64_t timestamp, char *data, int size) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
// Transmux the RTMP packets to AAC stream.
|
// Transmux the RTMP packets to AAC stream.
|
||||||
class SrsAacTransmuxer
|
class SrsAacTransmuxer : public ISrsAacTransmuxer
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
ISrsStreamWriter *writer_;
|
ISrsStreamWriter *writer_;
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ public:
|
||||||
public:
|
public:
|
||||||
virtual srs_error_t open(std::string p) = 0;
|
virtual srs_error_t open(std::string p) = 0;
|
||||||
virtual void close() = 0;
|
virtual void close() = 0;
|
||||||
|
virtual bool is_open() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// file writer, to write to file.
|
// file writer, to write to file.
|
||||||
|
|
@ -89,6 +90,13 @@ public:
|
||||||
public:
|
public:
|
||||||
virtual srs_error_t open(std::string p) = 0;
|
virtual srs_error_t open(std::string p) = 0;
|
||||||
virtual void close() = 0;
|
virtual void close() = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual bool is_open() = 0;
|
||||||
|
virtual int64_t tellg() = 0;
|
||||||
|
virtual void skip(int64_t size) = 0;
|
||||||
|
virtual int64_t seek2(int64_t offset) = 0;
|
||||||
|
virtual int64_t filesize() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -331,6 +331,14 @@ void SrsRtmpCommonMessage::to_msg(SrsMediaPacket *msg)
|
||||||
msg->message_type_ = (SrsFrameType)header_.message_type_;
|
msg->message_type_ = (SrsFrameType)header_.message_type_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ISrsFlvTransmuxer::ISrsFlvTransmuxer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsFlvTransmuxer::~ISrsFlvTransmuxer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
SrsFlvTransmuxer::SrsFlvTransmuxer()
|
SrsFlvTransmuxer::SrsFlvTransmuxer()
|
||||||
{
|
{
|
||||||
writer_ = NULL;
|
writer_ = NULL;
|
||||||
|
|
@ -777,7 +785,7 @@ srs_error_t SrsFlvVodStreamDecoder::initialize(ISrsReader *fr)
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
srs_assert(fr);
|
srs_assert(fr);
|
||||||
reader_ = dynamic_cast<SrsFileReader *>(fr);
|
reader_ = dynamic_cast<ISrsFileReader *>(fr);
|
||||||
if (!reader_) {
|
if (!reader_) {
|
||||||
return srs_error_new(ERROR_EXPECT_FILE_IO, "stream is not file io");
|
return srs_error_new(ERROR_EXPECT_FILE_IO, "stream is not file io");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
class SrsBuffer;
|
class SrsBuffer;
|
||||||
class ISrsWriter;
|
class ISrsWriter;
|
||||||
class ISrsReader;
|
class ISrsReader;
|
||||||
class SrsFileReader;
|
class ISrsFileReader;
|
||||||
class SrsRtmpCommand;
|
class SrsRtmpCommand;
|
||||||
class SrsNaluSample;
|
class SrsNaluSample;
|
||||||
|
|
||||||
|
|
@ -223,8 +223,50 @@ public:
|
||||||
void to_msg(SrsMediaPacket *msg);
|
void to_msg(SrsMediaPacket *msg);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The interface for FLV transmuxer.
|
||||||
|
class ISrsFlvTransmuxer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsFlvTransmuxer();
|
||||||
|
virtual ~ISrsFlvTransmuxer();
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Initialize the underlayer file stream.
|
||||||
|
// @remark user can initialize multiple times to encode multiple flv files.
|
||||||
|
// @remark, user must free the @param fw, flv encoder never close/free it.
|
||||||
|
virtual srs_error_t initialize(ISrsWriter *fw) = 0;
|
||||||
|
// Drop packet if not match FLV header.
|
||||||
|
virtual void set_drop_if_not_match(bool v) = 0;
|
||||||
|
virtual bool drop_if_not_match() = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Write flv header.
|
||||||
|
// Write following:
|
||||||
|
// 1. E.2 The FLV header
|
||||||
|
// 2. PreviousTagSize0 UI32 Always 0
|
||||||
|
// that is, 9+4=13bytes.
|
||||||
|
virtual srs_error_t write_header(bool has_video = true, bool has_audio = true) = 0;
|
||||||
|
virtual srs_error_t write_header(char flv_header[9]) = 0;
|
||||||
|
// Write flv metadata.
|
||||||
|
// @param type, the type of data, or other message type.
|
||||||
|
// @see SrsFrameType
|
||||||
|
// @param data, the amf0 metadata which serialize from:
|
||||||
|
// AMF0 string: onMetaData,
|
||||||
|
// AMF0 object: the metadata object.
|
||||||
|
// @remark assert data is not NULL.
|
||||||
|
virtual srs_error_t write_metadata(char type, char *data, int size) = 0;
|
||||||
|
// Write audio/video packet.
|
||||||
|
// @remark assert data is not NULL.
|
||||||
|
virtual srs_error_t write_audio(int64_t timestamp, char *data, int size) = 0;
|
||||||
|
virtual srs_error_t write_video(int64_t timestamp, char *data, int size) = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Write the tags in a time.
|
||||||
|
virtual srs_error_t write_tags(SrsMediaPacket **msgs, int count) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
// Transmux RTMP packets to FLV stream.
|
// Transmux RTMP packets to FLV stream.
|
||||||
class SrsFlvTransmuxer
|
class SrsFlvTransmuxer : public ISrsFlvTransmuxer
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
bool has_audio_;
|
bool has_audio_;
|
||||||
|
|
@ -335,7 +377,7 @@ public:
|
||||||
class SrsFlvVodStreamDecoder
|
class SrsFlvVodStreamDecoder
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
SrsFileReader *reader_;
|
ISrsFileReader *reader_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsFlvVodStreamDecoder();
|
SrsFlvVodStreamDecoder();
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ SrsPps::SrsPps()
|
||||||
|
|
||||||
SrsPps::~SrsPps()
|
SrsPps::~SrsPps()
|
||||||
{
|
{
|
||||||
|
clk_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SrsPps::update()
|
void SrsPps::update()
|
||||||
|
|
@ -102,6 +103,14 @@ int SrsPps::r30s()
|
||||||
return sample_30s_.rate_;
|
return sample_30s_.rate_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ISrsClock::ISrsClock()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsClock::~ISrsClock()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
SrsWallClock::SrsWallClock()
|
SrsWallClock::SrsWallClock()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
@ -548,7 +557,7 @@ void srs_global_rtc_update(SrsKbsRtcStats *stats)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsKbpsSlice::SrsKbpsSlice(SrsWallClock *c)
|
SrsKbpsSlice::SrsKbpsSlice(ISrsClock *c)
|
||||||
{
|
{
|
||||||
clk_ = c;
|
clk_ = c;
|
||||||
starttime_ = 0;
|
starttime_ = 0;
|
||||||
|
|
@ -557,6 +566,7 @@ SrsKbpsSlice::SrsKbpsSlice(SrsWallClock *c)
|
||||||
|
|
||||||
SrsKbpsSlice::~SrsKbpsSlice()
|
SrsKbpsSlice::~SrsKbpsSlice()
|
||||||
{
|
{
|
||||||
|
clk_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SrsKbpsSlice::sample()
|
void SrsKbpsSlice::sample()
|
||||||
|
|
@ -674,7 +684,7 @@ void SrsNetworkDelta::remark(int64_t *in, int64_t *out)
|
||||||
in_delta_ = out_delta_ = 0;
|
in_delta_ = out_delta_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsKbps::SrsKbps(SrsWallClock *c)
|
SrsKbps::SrsKbps(ISrsClock *c)
|
||||||
{
|
{
|
||||||
clk_ = c ? c : _srs_clock;
|
clk_ = c ? c : _srs_clock;
|
||||||
is_ = new SrsKbpsSlice(clk_);
|
is_ = new SrsKbpsSlice(clk_);
|
||||||
|
|
@ -685,6 +695,7 @@ SrsKbps::~SrsKbps()
|
||||||
{
|
{
|
||||||
srs_freep(is_);
|
srs_freep(is_);
|
||||||
srs_freep(os_);
|
srs_freep(os_);
|
||||||
|
clk_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsKbps::get_send_kbps()
|
int SrsKbps::get_send_kbps()
|
||||||
|
|
@ -764,7 +775,7 @@ int64_t SrsKbps::get_recv_bytes()
|
||||||
return is_->bytes_;
|
return is_->bytes_;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsNetworkKbps::SrsNetworkKbps(SrsWallClock *clock)
|
SrsNetworkKbps::SrsNetworkKbps(ISrsClock *clock)
|
||||||
{
|
{
|
||||||
delta_ = new SrsNetworkDelta();
|
delta_ = new SrsNetworkDelta();
|
||||||
kbps_ = new SrsKbps(clock);
|
kbps_ = new SrsKbps(clock);
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,44 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class SrsWallClock;
|
|
||||||
class ISrsProtocolStatistic;
|
class ISrsProtocolStatistic;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for clock abstraction to provide wall clock time.
|
||||||
|
* This interface enables dependency injection and testability.
|
||||||
|
*/
|
||||||
|
class ISrsClock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsClock();
|
||||||
|
virtual ~ISrsClock();
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Current time in srs_utime_t.
|
||||||
|
*/
|
||||||
|
virtual srs_utime_t now() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A time source to provide wall clock.
|
||||||
|
*/
|
||||||
|
class SrsWallClock : public ISrsClock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SrsWallClock();
|
||||||
|
virtual ~SrsWallClock();
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Current time in srs_utime_t.
|
||||||
|
*/
|
||||||
|
virtual srs_utime_t now();
|
||||||
|
};
|
||||||
|
|
||||||
|
// The global clock.
|
||||||
|
extern SrsWallClock *_srs_clock;
|
||||||
|
|
||||||
// A sample for rate-based stat, such as kbps or kps.
|
// A sample for rate-based stat, such as kbps or kps.
|
||||||
class SrsRateSample
|
class SrsRateSample
|
||||||
{
|
{
|
||||||
|
|
@ -37,7 +72,7 @@ public:
|
||||||
class SrsPps
|
class SrsPps
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
SrsWallClock *clk_;
|
ISrsClock *clk_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// samples
|
// samples
|
||||||
|
|
@ -66,25 +101,6 @@ public:
|
||||||
int r30s();
|
int r30s();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* A time source to provide wall clock.
|
|
||||||
*/
|
|
||||||
class SrsWallClock
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
SrsWallClock();
|
|
||||||
virtual ~SrsWallClock();
|
|
||||||
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Current time in srs_utime_t.
|
|
||||||
*/
|
|
||||||
virtual srs_utime_t now();
|
|
||||||
};
|
|
||||||
|
|
||||||
// The global clock.
|
|
||||||
extern SrsWallClock *_srs_clock;
|
|
||||||
|
|
||||||
// Global SrsPps statistics variables
|
// Global SrsPps statistics variables
|
||||||
// I/O operations statistics
|
// I/O operations statistics
|
||||||
extern SrsPps *_srs_pps_recvfrom;
|
extern SrsPps *_srs_pps_recvfrom;
|
||||||
|
|
@ -237,7 +253,7 @@ void srs_global_rtc_update(SrsKbsRtcStats *stats);
|
||||||
class SrsKbpsSlice
|
class SrsKbpsSlice
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
SrsWallClock *clk_;
|
ISrsClock *clk_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// session startup bytes
|
// session startup bytes
|
||||||
|
|
@ -252,7 +268,7 @@ public:
|
||||||
SrsRateSample sample_60m_;
|
SrsRateSample sample_60m_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsKbpsSlice(SrsWallClock *c);
|
SrsKbpsSlice(ISrsClock *c);
|
||||||
virtual ~SrsKbpsSlice();
|
virtual ~SrsKbpsSlice();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -340,11 +356,11 @@ class SrsKbps
|
||||||
private:
|
private:
|
||||||
SrsKbpsSlice *is_;
|
SrsKbpsSlice *is_;
|
||||||
SrsKbpsSlice *os_;
|
SrsKbpsSlice *os_;
|
||||||
SrsWallClock *clk_;
|
ISrsClock *clk_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Note that we won't free the clock c.
|
// Note that we won't free the clock c.
|
||||||
SrsKbps(SrsWallClock *c = NULL);
|
SrsKbps(ISrsClock *c = NULL);
|
||||||
virtual ~SrsKbps();
|
virtual ~SrsKbps();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -378,7 +394,7 @@ private:
|
||||||
SrsKbps *kbps_;
|
SrsKbps *kbps_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsNetworkKbps(SrsWallClock *c = NULL);
|
SrsNetworkKbps(ISrsClock *c = NULL);
|
||||||
virtual ~SrsNetworkKbps();
|
virtual ~SrsNetworkKbps();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,14 @@ using namespace std;
|
||||||
#include <srs_kernel_file.hpp>
|
#include <srs_kernel_file.hpp>
|
||||||
#include <srs_kernel_log.hpp>
|
#include <srs_kernel_log.hpp>
|
||||||
|
|
||||||
|
ISrsMp3Transmuxer::ISrsMp3Transmuxer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsMp3Transmuxer::~ISrsMp3Transmuxer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
SrsMp3Transmuxer::SrsMp3Transmuxer()
|
SrsMp3Transmuxer::SrsMp3Transmuxer()
|
||||||
{
|
{
|
||||||
writer_ = NULL;
|
writer_ = NULL;
|
||||||
|
|
@ -30,7 +38,7 @@ SrsMp3Transmuxer::~SrsMp3Transmuxer()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsMp3Transmuxer::initialize(SrsFileWriter *fw)
|
srs_error_t SrsMp3Transmuxer::initialize(ISrsFileWriter *fw)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,15 +12,28 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class SrsBuffer;
|
class SrsBuffer;
|
||||||
class SrsFileWriter;
|
class ISrsFileWriter;
|
||||||
|
|
||||||
|
// The interface for MP3 transmuxer.
|
||||||
|
class ISrsMp3Transmuxer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsMp3Transmuxer();
|
||||||
|
virtual ~ISrsMp3Transmuxer();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t initialize(ISrsFileWriter *fw) = 0;
|
||||||
|
virtual srs_error_t write_header() = 0;
|
||||||
|
virtual srs_error_t write_audio(int64_t timestamp, char *data, int size) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transmux RTMP packet to MP3 stream.
|
* Transmux RTMP packet to MP3 stream.
|
||||||
*/
|
*/
|
||||||
class SrsMp3Transmuxer
|
class SrsMp3Transmuxer : public ISrsMp3Transmuxer
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
SrsFileWriter *writer_;
|
ISrsFileWriter *writer_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsMp3Transmuxer();
|
SrsMp3Transmuxer();
|
||||||
|
|
@ -32,7 +45,7 @@ public:
|
||||||
* @remark user can initialize multiple times to encode multiple mp3 files.
|
* @remark user can initialize multiple times to encode multiple mp3 files.
|
||||||
* @remark, user must free the @param fw, mp3 encoder never close/free it.
|
* @remark, user must free the @param fw, mp3 encoder never close/free it.
|
||||||
*/
|
*/
|
||||||
virtual srs_error_t initialize(SrsFileWriter *fw);
|
virtual srs_error_t initialize(ISrsFileWriter *fw);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -352,6 +352,14 @@ srs_error_t SrsParsedVideoPacket::parse_hevc_bframe(const SrsNaluSample *sample,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ISrsFormat::ISrsFormat()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsFormat::~ISrsFormat()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
SrsFormat::SrsFormat()
|
SrsFormat::SrsFormat()
|
||||||
{
|
{
|
||||||
acodec_ = NULL;
|
acodec_ = NULL;
|
||||||
|
|
@ -482,6 +490,26 @@ bool SrsFormat::is_avc_sequence_header()
|
||||||
return vcodec_ && (h264 || h265 || av1) && video_ && video_->avc_packet_type_ == SrsVideoAvcFrameTraitSequenceHeader;
|
return vcodec_ && (h264 || h265 || av1) && video_ && video_->avc_packet_type_ == SrsVideoAvcFrameTraitSequenceHeader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SrsParsedAudioPacket* SrsFormat::audio()
|
||||||
|
{
|
||||||
|
return audio_;
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsAudioCodecConfig* SrsFormat::acodec()
|
||||||
|
{
|
||||||
|
return acodec_;
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsParsedVideoPacket* SrsFormat::video()
|
||||||
|
{
|
||||||
|
return video_;
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsVideoCodecConfig* SrsFormat::vcodec()
|
||||||
|
{
|
||||||
|
return vcodec_;
|
||||||
|
}
|
||||||
|
|
||||||
// Remove the emulation bytes from stream, and return num of bytes of the rbsp.
|
// Remove the emulation bytes from stream, and return num of bytes of the rbsp.
|
||||||
int srs_rbsp_remove_emulation_bytes(SrsBuffer *stream, std::vector<uint8_t> &rbsp)
|
int srs_rbsp_remove_emulation_bytes(SrsBuffer *stream, std::vector<uint8_t> &rbsp)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -162,11 +162,49 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Interface for codec format.
|
||||||
* A codec format, including one or many stream, each stream identified by a frame.
|
* A codec format, including one or many stream, each stream identified by a frame.
|
||||||
* For example, a typical RTMP stream format, consits of a video and audio frame.
|
* For example, a typical RTMP stream format, consits of a video and audio frame.
|
||||||
* Maybe some RTMP stream only has a audio stream, for instance, redio application.
|
* Maybe some RTMP stream only has a audio stream, for instance, redio application.
|
||||||
*/
|
*/
|
||||||
class SrsFormat
|
class ISrsFormat
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsFormat();
|
||||||
|
virtual ~ISrsFormat();
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Initialize the format.
|
||||||
|
virtual srs_error_t initialize() = 0;
|
||||||
|
// When got a parsed audio packet.
|
||||||
|
// @param data The data in FLV format.
|
||||||
|
virtual srs_error_t on_audio(int64_t timestamp, char *data, int size) = 0;
|
||||||
|
// When got a parsed video packet.
|
||||||
|
// @param data The data in FLV format.
|
||||||
|
virtual srs_error_t on_video(int64_t timestamp, char *data, int size) = 0;
|
||||||
|
// When got a audio aac sequence header.
|
||||||
|
virtual srs_error_t on_aac_sequence_header(char *data, int size) = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual bool is_aac_sequence_header() = 0;
|
||||||
|
virtual bool is_mp3_sequence_header() = 0;
|
||||||
|
// TODO: is avc|hevc|av1 sequence header
|
||||||
|
virtual bool is_avc_sequence_header() = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Getters for codec and packet information
|
||||||
|
virtual SrsParsedAudioPacket* audio() = 0;
|
||||||
|
virtual SrsAudioCodecConfig* acodec() = 0;
|
||||||
|
virtual SrsParsedVideoPacket* video() = 0;
|
||||||
|
virtual SrsVideoCodecConfig* vcodec() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A codec format, including one or many stream, each stream identified by a frame.
|
||||||
|
* For example, a typical RTMP stream format, consits of a video and audio frame.
|
||||||
|
* Maybe some RTMP stream only has a audio stream, for instance, redio application.
|
||||||
|
*/
|
||||||
|
class SrsFormat : public ISrsFormat
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SrsParsedAudioPacket *audio_;
|
SrsParsedAudioPacket *audio_;
|
||||||
|
|
@ -207,6 +245,13 @@ public:
|
||||||
// TODO: is avc|hevc|av1 sequence header
|
// TODO: is avc|hevc|av1 sequence header
|
||||||
virtual bool is_avc_sequence_header();
|
virtual bool is_avc_sequence_header();
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Getters for codec and packet information
|
||||||
|
virtual SrsParsedAudioPacket* audio();
|
||||||
|
virtual SrsAudioCodecConfig* acodec();
|
||||||
|
virtual SrsParsedVideoPacket* video();
|
||||||
|
virtual SrsVideoCodecConfig* vcodec();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Demux the video packet in H.264 codec.
|
// Demux the video packet in H.264 codec.
|
||||||
// The packet is muxed in FLV format, defined in flv specification.
|
// The packet is muxed in FLV format, defined in flv specification.
|
||||||
|
|
|
||||||
|
|
@ -311,6 +311,14 @@ ISrsTsHandler::~ISrsTsHandler()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ISrsTsContext::ISrsTsContext()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsTsContext::~ISrsTsContext()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
SrsTsContext::SrsTsContext()
|
SrsTsContext::SrsTsContext()
|
||||||
{
|
{
|
||||||
ready_ = false;
|
ready_ = false;
|
||||||
|
|
@ -652,7 +660,7 @@ srs_error_t SrsTsContext::encode_pes(ISrsStreamWriter *writer, SrsTsMessage *msg
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsTsPacket::SrsTsPacket(SrsTsContext *c)
|
SrsTsPacket::SrsTsPacket(ISrsTsContext *c)
|
||||||
{
|
{
|
||||||
context_ = c;
|
context_ = c;
|
||||||
|
|
||||||
|
|
@ -834,7 +842,7 @@ void SrsTsPacket::padding(int nb_stuffings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsTsPacket *SrsTsPacket::create_pat(SrsTsContext *context, int16_t pmt_number, int16_t pmt_pid)
|
SrsTsPacket *SrsTsPacket::create_pat(ISrsTsContext *context, int16_t pmt_number, int16_t pmt_pid)
|
||||||
{
|
{
|
||||||
SrsTsPacket *pkt = new SrsTsPacket(context);
|
SrsTsPacket *pkt = new SrsTsPacket(context);
|
||||||
pkt->sync_byte_ = 0x47;
|
pkt->sync_byte_ = 0x47;
|
||||||
|
|
@ -863,7 +871,7 @@ SrsTsPacket *SrsTsPacket::create_pat(SrsTsContext *context, int16_t pmt_number,
|
||||||
return pkt;
|
return pkt;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsTsPacket *SrsTsPacket::create_pmt(SrsTsContext *context,
|
SrsTsPacket *SrsTsPacket::create_pmt(ISrsTsContext *context,
|
||||||
int16_t pmt_number, int16_t pmt_pid, int16_t vpid, SrsTsStream vs, int16_t apid, SrsTsStream as)
|
int16_t pmt_number, int16_t pmt_pid, int16_t vpid, SrsTsStream vs, int16_t apid, SrsTsStream as)
|
||||||
{
|
{
|
||||||
SrsTsPacket *pkt = new SrsTsPacket(context);
|
SrsTsPacket *pkt = new SrsTsPacket(context);
|
||||||
|
|
@ -915,7 +923,7 @@ SrsTsPacket *SrsTsPacket::create_pmt(SrsTsContext *context,
|
||||||
return pkt;
|
return pkt;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsTsPacket *SrsTsPacket::create_pes_first(SrsTsContext *context,
|
SrsTsPacket *SrsTsPacket::create_pes_first(ISrsTsContext *context,
|
||||||
int16_t pid, SrsTsPESStreamId sid, uint8_t continuity_counter, bool discontinuity,
|
int16_t pid, SrsTsPESStreamId sid, uint8_t continuity_counter, bool discontinuity,
|
||||||
int64_t pcr, int64_t dts, int64_t pts, int size)
|
int64_t pcr, int64_t dts, int64_t pts, int size)
|
||||||
{
|
{
|
||||||
|
|
@ -974,7 +982,7 @@ SrsTsPacket *SrsTsPacket::create_pes_first(SrsTsContext *context,
|
||||||
return pkt;
|
return pkt;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsTsPacket *SrsTsPacket::create_pes_continue(SrsTsContext *context, int16_t pid, SrsTsPESStreamId sid, uint8_t continuity_counter)
|
SrsTsPacket *SrsTsPacket::create_pes_continue(ISrsTsContext *context, int16_t pid, SrsTsPESStreamId sid, uint8_t continuity_counter)
|
||||||
{
|
{
|
||||||
SrsTsPacket *pkt = new SrsTsPacket(context);
|
SrsTsPacket *pkt = new SrsTsPacket(context);
|
||||||
pkt->sync_byte_ = 0x47;
|
pkt->sync_byte_ = 0x47;
|
||||||
|
|
@ -2757,7 +2765,15 @@ srs_error_t SrsTsPayloadPMT::psi_encode(SrsBuffer *stream)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsTsContextWriter::SrsTsContextWriter(ISrsStreamWriter *w, SrsTsContext *c, SrsAudioCodecId ac, SrsVideoCodecId vc)
|
ISrsTsContextWriter::ISrsTsContextWriter()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsTsContextWriter::~ISrsTsContextWriter()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsTsContextWriter::SrsTsContextWriter(ISrsStreamWriter *w, ISrsTsContext *c, SrsAudioCodecId ac, SrsVideoCodecId vc)
|
||||||
{
|
{
|
||||||
writer_ = w;
|
writer_ = w;
|
||||||
context_ = c;
|
context_ = c;
|
||||||
|
|
@ -2905,6 +2921,14 @@ void SrsEncFileWriter::close()
|
||||||
SrsFileWriter::close();
|
SrsFileWriter::close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ISrsTsMessageCache::ISrsTsMessageCache()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsTsMessageCache::~ISrsTsMessageCache()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
SrsTsMessageCache::SrsTsMessageCache()
|
SrsTsMessageCache::SrsTsMessageCache()
|
||||||
{
|
{
|
||||||
audio_ = NULL;
|
audio_ = NULL;
|
||||||
|
|
@ -2979,6 +3003,26 @@ srs_error_t SrsTsMessageCache::cache_video(SrsParsedVideoPacket *frame, int64_t
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SrsTsMessage* SrsTsMessageCache::audio()
|
||||||
|
{
|
||||||
|
return audio_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SrsTsMessageCache::set_audio(SrsTsMessage* msg)
|
||||||
|
{
|
||||||
|
audio_ = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsTsMessage* SrsTsMessageCache::video()
|
||||||
|
{
|
||||||
|
return video_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SrsTsMessageCache::set_video(SrsTsMessage* msg)
|
||||||
|
{
|
||||||
|
video_ = msg;
|
||||||
|
}
|
||||||
|
|
||||||
srs_error_t SrsTsMessageCache::do_cache_mp3(SrsParsedAudioPacket *frame)
|
srs_error_t SrsTsMessageCache::do_cache_mp3(SrsParsedAudioPacket *frame)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
@ -3246,31 +3290,39 @@ srs_error_t SrsTsMessageCache::do_cache_hevc(SrsParsedVideoPacket *frame)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ISrsTsTransmuxer::ISrsTsTransmuxer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsTsTransmuxer::~ISrsTsTransmuxer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
SrsTsTransmuxer::SrsTsTransmuxer()
|
SrsTsTransmuxer::SrsTsTransmuxer()
|
||||||
{
|
{
|
||||||
writer = NULL;
|
writer_ = NULL;
|
||||||
format = new SrsFormat();
|
format_ = new SrsFormat();
|
||||||
tsmc = new SrsTsMessageCache();
|
tsmc_ = new SrsTsMessageCache();
|
||||||
context = new SrsTsContext();
|
context_ = new SrsTsContext();
|
||||||
tscw = NULL;
|
tscw_ = NULL;
|
||||||
has_audio_ = has_video_ = true;
|
has_audio_ = has_video_ = true;
|
||||||
guess_has_av_ = true;
|
guess_has_av_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsTsTransmuxer::~SrsTsTransmuxer()
|
SrsTsTransmuxer::~SrsTsTransmuxer()
|
||||||
{
|
{
|
||||||
srs_freep(format);
|
srs_freep(format_);
|
||||||
srs_freep(tsmc);
|
srs_freep(tsmc_);
|
||||||
srs_freep(tscw);
|
srs_freep(tscw_);
|
||||||
srs_freep(context);
|
srs_freep(context_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SrsTsTransmuxer::set_has_audio(bool v)
|
void SrsTsTransmuxer::set_has_audio(bool v)
|
||||||
{
|
{
|
||||||
has_audio_ = v;
|
has_audio_ = v;
|
||||||
|
|
||||||
if (tscw != NULL && !v) {
|
if (tscw_ != NULL && !v) {
|
||||||
tscw->set_acodec(SrsAudioCodecIdForbidden);
|
tscw_->set_acodec(SrsAudioCodecIdForbidden);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3278,17 +3330,17 @@ void SrsTsTransmuxer::set_has_video(bool v)
|
||||||
{
|
{
|
||||||
has_video_ = v;
|
has_video_ = v;
|
||||||
|
|
||||||
if (tscw != NULL && !v) {
|
if (tscw_ != NULL && !v) {
|
||||||
tscw->set_vcodec(SrsVideoCodecIdForbidden);
|
tscw_->set_vcodec(SrsVideoCodecIdForbidden);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SrsTsTransmuxer::set_guess_has_av(bool v)
|
void SrsTsTransmuxer::set_guess_has_av(bool v)
|
||||||
{
|
{
|
||||||
guess_has_av_ = v;
|
guess_has_av_ = v;
|
||||||
if (tscw != NULL && v) {
|
if (tscw_ != NULL && v) {
|
||||||
tscw->set_acodec(SrsAudioCodecIdForbidden);
|
tscw_->set_acodec(SrsAudioCodecIdForbidden);
|
||||||
tscw->set_vcodec(SrsVideoCodecIdForbidden);
|
tscw_->set_vcodec(SrsVideoCodecIdForbidden);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3296,13 +3348,13 @@ srs_error_t SrsTsTransmuxer::initialize(ISrsStreamWriter *fw)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
if ((err = format->initialize()) != srs_success) {
|
if ((err = format_->initialize()) != srs_success) {
|
||||||
return srs_error_wrap(err, "ts: init format");
|
return srs_error_wrap(err, "ts: init format");
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_assert(fw);
|
srs_assert(fw);
|
||||||
|
|
||||||
writer = fw;
|
writer_ = fw;
|
||||||
|
|
||||||
SrsAudioCodecId acodec = has_audio_ ? SrsAudioCodecIdAAC : SrsAudioCodecIdForbidden;
|
SrsAudioCodecId acodec = has_audio_ ? SrsAudioCodecIdAAC : SrsAudioCodecIdForbidden;
|
||||||
SrsVideoCodecId vcodec = has_video_ ? SrsVideoCodecIdAVC : SrsVideoCodecIdForbidden;
|
SrsVideoCodecId vcodec = has_video_ ? SrsVideoCodecIdAVC : SrsVideoCodecIdForbidden;
|
||||||
|
|
@ -3312,8 +3364,8 @@ srs_error_t SrsTsTransmuxer::initialize(ISrsStreamWriter *fw)
|
||||||
vcodec = SrsVideoCodecIdForbidden;
|
vcodec = SrsVideoCodecIdForbidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_freep(tscw);
|
srs_freep(tscw_);
|
||||||
tscw = new SrsTsContextWriter(fw, context, acodec, vcodec);
|
tscw_ = new SrsTsContextWriter(fw, context_, acodec, vcodec);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
@ -3322,30 +3374,30 @@ srs_error_t SrsTsTransmuxer::write_audio(int64_t timestamp, char *data, int size
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
if ((err = format->on_audio(timestamp, data, size)) != srs_success) {
|
if ((err = format_->on_audio(timestamp, data, size)) != srs_success) {
|
||||||
return srs_error_wrap(err, "ts: format on audio");
|
return srs_error_wrap(err, "ts: format on audio");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!format->acodec_) {
|
if (!format_->acodec()) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ts support audio codec: aac/mp3
|
// ts support audio codec: aac/mp3
|
||||||
srs_assert(format->acodec_ && format->audio_);
|
srs_assert(format_->acodec() && format_->audio());
|
||||||
if (format->acodec_->id_ != SrsAudioCodecIdAAC && format->acodec_->id_ != SrsAudioCodecIdMP3) {
|
if (format_->acodec()->id_ != SrsAudioCodecIdAAC && format_->acodec()->id_ != SrsAudioCodecIdMP3) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// for aac: ignore sequence header
|
// for aac: ignore sequence header
|
||||||
if (format->acodec_->id_ == SrsAudioCodecIdAAC && format->audio_->aac_packet_type_ == SrsAudioAacFrameTraitSequenceHeader) {
|
if (format_->acodec()->id_ == SrsAudioCodecIdAAC && format_->audio()->aac_packet_type_ == SrsAudioAacFrameTraitSequenceHeader) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Switch audio codec if not AAC.
|
// Switch audio codec if not AAC.
|
||||||
if (tscw->acodec() != format->acodec_->id_) {
|
if (tscw_->acodec() != format_->acodec()->id_) {
|
||||||
srs_trace("TS: Switch audio codec %d(%s) to %d(%s)", tscw->acodec(), srs_audio_codec_id2str(tscw->acodec()).c_str(),
|
srs_trace("TS: Switch audio codec %d(%s) to %d(%s)", tscw_->acodec(), srs_audio_codec_id2str(tscw_->acodec()).c_str(),
|
||||||
format->acodec_->id_, srs_audio_codec_id2str(format->acodec_->id_).c_str());
|
format_->acodec()->id_, srs_audio_codec_id2str(format_->acodec()->id_).c_str());
|
||||||
tscw->set_acodec(format->acodec_->id_);
|
tscw_->set_acodec(format_->acodec()->id_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// the dts calc from rtmp/flv header.
|
// the dts calc from rtmp/flv header.
|
||||||
|
|
@ -3354,7 +3406,7 @@ srs_error_t SrsTsTransmuxer::write_audio(int64_t timestamp, char *data, int size
|
||||||
int64_t dts = timestamp * 90;
|
int64_t dts = timestamp * 90;
|
||||||
|
|
||||||
// write audio to cache.
|
// write audio to cache.
|
||||||
if ((err = tsmc->cache_audio(format->audio_, dts)) != srs_success) {
|
if ((err = tsmc_->cache_audio(format_->audio(), dts)) != srs_success) {
|
||||||
return srs_error_wrap(err, "ts: cache audio");
|
return srs_error_wrap(err, "ts: cache audio");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3369,39 +3421,39 @@ srs_error_t SrsTsTransmuxer::write_video(int64_t timestamp, char *data, int size
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
if ((err = format->on_video(timestamp, data, size)) != srs_success) {
|
if ((err = format_->on_video(timestamp, data, size)) != srs_success) {
|
||||||
return srs_error_wrap(err, "ts: on video");
|
return srs_error_wrap(err, "ts: on video");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!format->vcodec_) {
|
if (!format_->vcodec()) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore info frame,
|
// ignore info frame,
|
||||||
// @see https://github.com/ossrs/srs/issues/288#issuecomment-69863909
|
// @see https://github.com/ossrs/srs/issues/288#issuecomment-69863909
|
||||||
srs_assert(format->video_ && format->vcodec_);
|
srs_assert(format_->video() && format_->vcodec());
|
||||||
if (format->video_->frame_type_ == SrsVideoAvcFrameTypeVideoInfoFrame) {
|
if (format_->video()->frame_type_ == SrsVideoAvcFrameTypeVideoInfoFrame) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool codec_ok = (format->vcodec_->id_ == SrsVideoCodecIdAVC);
|
bool codec_ok = (format_->vcodec()->id_ == SrsVideoCodecIdAVC);
|
||||||
codec_ok = codec_ok ? true : (format->vcodec_->id_ == SrsVideoCodecIdHEVC);
|
codec_ok = codec_ok ? true : (format_->vcodec()->id_ == SrsVideoCodecIdHEVC);
|
||||||
if (!codec_ok) {
|
if (!codec_ok) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The video codec might change during streaming.
|
// The video codec might change during streaming.
|
||||||
tscw->set_vcodec(format->vcodec_->id_);
|
tscw_->set_vcodec(format_->vcodec()->id_);
|
||||||
|
|
||||||
// ignore sequence header
|
// ignore sequence header
|
||||||
if (format->video_->frame_type_ == SrsVideoAvcFrameTypeKeyFrame && format->video_->avc_packet_type_ == SrsVideoAvcFrameTraitSequenceHeader) {
|
if (format_->video()->frame_type_ == SrsVideoAvcFrameTypeKeyFrame && format_->video()->avc_packet_type_ == SrsVideoAvcFrameTraitSequenceHeader) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t dts = timestamp * 90;
|
int64_t dts = timestamp * 90;
|
||||||
|
|
||||||
// write video to cache.
|
// write video to cache.
|
||||||
if ((err = tsmc->cache_video(format->video_, dts)) != srs_success) {
|
if ((err = tsmc_->cache_video(format_->video(), dts)) != srs_success) {
|
||||||
return srs_error_wrap(err, "ts: cache video");
|
return srs_error_wrap(err, "ts: cache video");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3412,12 +3464,14 @@ srs_error_t SrsTsTransmuxer::flush_audio()
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
if ((err = tscw->write_audio(tsmc->audio_)) != srs_success) {
|
if ((err = tscw_->write_audio(tsmc_->audio())) != srs_success) {
|
||||||
return srs_error_wrap(err, "ts: write audio");
|
return srs_error_wrap(err, "ts: write audio");
|
||||||
}
|
}
|
||||||
|
|
||||||
// write success, clear and free the ts message.
|
// write success, clear and free the ts message.
|
||||||
srs_freep(tsmc->audio_);
|
SrsTsMessage* audio_msg = tsmc_->audio();
|
||||||
|
srs_freep(audio_msg);
|
||||||
|
tsmc_->set_audio(NULL);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
@ -3426,12 +3480,14 @@ srs_error_t SrsTsTransmuxer::flush_video()
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
if ((err = tscw->write_video(tsmc->video_)) != srs_success) {
|
if ((err = tscw_->write_video(tsmc_->video())) != srs_success) {
|
||||||
return srs_error_wrap(err, "ts: write video");
|
return srs_error_wrap(err, "ts: write video");
|
||||||
}
|
}
|
||||||
|
|
||||||
// write success, clear and free the ts message.
|
// write success, clear and free the ts message.
|
||||||
srs_freep(tsmc->video_);
|
SrsTsMessage* video_msg = tsmc_->video();
|
||||||
|
srs_freep(video_msg);
|
||||||
|
tsmc_->set_video(NULL);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,15 +19,19 @@
|
||||||
|
|
||||||
class SrsBuffer;
|
class SrsBuffer;
|
||||||
class SrsTsMessageCache;
|
class SrsTsMessageCache;
|
||||||
|
class ISrsTsMessageCache;
|
||||||
class SrsTsContextWriter;
|
class SrsTsContextWriter;
|
||||||
|
class ISrsTsContextWriter;
|
||||||
class ISrsStreamWriter;
|
class ISrsStreamWriter;
|
||||||
class SrsFileReader;
|
class SrsFileReader;
|
||||||
class SrsFormat;
|
class SrsFormat;
|
||||||
|
class ISrsFormat;
|
||||||
class SrsSimpleStream;
|
class SrsSimpleStream;
|
||||||
class SrsTsAdaptationField;
|
class SrsTsAdaptationField;
|
||||||
class SrsTsPayload;
|
class SrsTsPayload;
|
||||||
class SrsTsMessage;
|
class SrsTsMessage;
|
||||||
class SrsTsPacket;
|
class SrsTsPacket;
|
||||||
|
class ISrsTsContext;
|
||||||
class SrsTsContext;
|
class SrsTsContext;
|
||||||
class SrsPsPacket;
|
class SrsPsPacket;
|
||||||
|
|
||||||
|
|
@ -142,7 +146,7 @@ struct SrsTsChannel {
|
||||||
SrsTsPidApply apply_;
|
SrsTsPidApply apply_;
|
||||||
SrsTsStream stream_;
|
SrsTsStream stream_;
|
||||||
SrsTsMessage *msg_;
|
SrsTsMessage *msg_;
|
||||||
SrsTsContext *context_;
|
ISrsTsContext *context_;
|
||||||
// for encoder.
|
// for encoder.
|
||||||
uint8_t continuity_counter_;
|
uint8_t continuity_counter_;
|
||||||
|
|
||||||
|
|
@ -291,8 +295,48 @@ public:
|
||||||
virtual srs_error_t on_ts_message(SrsTsMessage *msg) = 0;
|
virtual srs_error_t on_ts_message(SrsTsMessage *msg) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The interface for ts context.
|
||||||
|
class ISrsTsContext
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsTsContext();
|
||||||
|
virtual ~ISrsTsContext();
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Whether the hls stream is pure audio stream.
|
||||||
|
virtual bool is_pure_audio() = 0;
|
||||||
|
// When PMT table parsed, we know some info about stream.
|
||||||
|
virtual void on_pmt_parsed() = 0;
|
||||||
|
// Reset the context for a new ts segment start.
|
||||||
|
virtual void reset() = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Get the pid apply, the parsed pid.
|
||||||
|
// @return the apply channel; NULL for invalid.
|
||||||
|
virtual SrsTsChannel *get(int pid) = 0;
|
||||||
|
// Set the pid apply, the parsed pid.
|
||||||
|
virtual void set(int pid, SrsTsPidApply apply_pid, SrsTsStream stream = SrsTsStreamReserved) = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Feed with ts packets, decode as ts message, callback handler if got one ts message.
|
||||||
|
// A ts video message can be decoded to NALUs by SrsRawH264Stream::annexb_demux.
|
||||||
|
// A ts audio message can be decoded to RAW frame by SrsRawAacStream::adts_demux.
|
||||||
|
// @param handler The ts message handler to process the msg.
|
||||||
|
// @remark We will consume all bytes in stream.
|
||||||
|
virtual srs_error_t decode(SrsBuffer *stream, ISrsTsHandler *handler) = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Encode ts video/audio messages to the PES packets, as PES stream.
|
||||||
|
// @param msg The video/audio msg to write to ts.
|
||||||
|
// A ts video message is a frame with one or more NALUs, generally encoded by SrsTsMessageCache.cache_video.
|
||||||
|
// A ts audio message is an audio packet, encoded by SrsTsMessageCache.cache_audio to ADTS for AAC.
|
||||||
|
// @param vc The video codec, write the PAT/PMT table when changed.
|
||||||
|
// @param ac The audio codec, write the PAT/PMT table when changed.
|
||||||
|
virtual srs_error_t encode(ISrsStreamWriter *writer, SrsTsMessage *msg, SrsVideoCodecId vc, SrsAudioCodecId ac) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
// The context of ts, to decode the ts stream.
|
// The context of ts, to decode the ts stream.
|
||||||
class SrsTsContext
|
class SrsTsContext : public ISrsTsContext
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
// Whether context is ready, failed if try to write data when not ready.
|
// Whether context is ready, failed if try to write data when not ready.
|
||||||
|
|
@ -432,10 +476,10 @@ private:
|
||||||
SrsTsPayload *payload_;
|
SrsTsPayload *payload_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsTsContext *context_;
|
ISrsTsContext *context_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsTsPacket(SrsTsContext *c);
|
SrsTsPacket(ISrsTsContext *c);
|
||||||
virtual ~SrsTsPacket();
|
virtual ~SrsTsPacket();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -447,12 +491,12 @@ public:
|
||||||
virtual void padding(int nb_stuffings);
|
virtual void padding(int nb_stuffings);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static SrsTsPacket *create_pat(SrsTsContext *context, int16_t pmt_number, int16_t pmt_pid);
|
static SrsTsPacket *create_pat(ISrsTsContext *context, int16_t pmt_number, int16_t pmt_pid);
|
||||||
static SrsTsPacket *create_pmt(SrsTsContext *context, int16_t pmt_number, int16_t pmt_pid,
|
static SrsTsPacket *create_pmt(ISrsTsContext *context, int16_t pmt_number, int16_t pmt_pid,
|
||||||
int16_t vpid, SrsTsStream vs, int16_t apid, SrsTsStream as);
|
int16_t vpid, SrsTsStream vs, int16_t apid, SrsTsStream as);
|
||||||
static SrsTsPacket *create_pes_first(SrsTsContext *context, int16_t pid, SrsTsPESStreamId sid,
|
static SrsTsPacket *create_pes_first(ISrsTsContext *context, int16_t pid, SrsTsPESStreamId sid,
|
||||||
uint8_t continuity_counter, bool discontinuity, int64_t pcr, int64_t dts, int64_t pts, int size);
|
uint8_t continuity_counter, bool discontinuity, int64_t pcr, int64_t dts, int64_t pts, int size);
|
||||||
static SrsTsPacket *create_pes_continue(SrsTsContext *context,
|
static SrsTsPacket *create_pes_continue(ISrsTsContext *context,
|
||||||
int16_t pid, SrsTsPESStreamId sid, uint8_t continuity_counter);
|
int16_t pid, SrsTsPESStreamId sid, uint8_t continuity_counter);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1295,8 +1339,32 @@ protected:
|
||||||
virtual srs_error_t psi_encode(SrsBuffer *stream);
|
virtual srs_error_t psi_encode(SrsBuffer *stream);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Interface for writing TS messages to TS context.
|
||||||
|
class ISrsTsContextWriter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsTsContextWriter();
|
||||||
|
virtual ~ISrsTsContextWriter();
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Write an audio frame to ts,
|
||||||
|
virtual srs_error_t write_audio(SrsTsMessage *audio) = 0;
|
||||||
|
// Write a video frame to ts,
|
||||||
|
virtual srs_error_t write_video(SrsTsMessage *video) = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Get or update the video codec of ts muxer.
|
||||||
|
virtual SrsVideoCodecId vcodec() = 0;
|
||||||
|
virtual void set_vcodec(SrsVideoCodecId v) = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Get and set the audio codec.
|
||||||
|
virtual SrsAudioCodecId acodec() = 0;
|
||||||
|
virtual void set_acodec(SrsAudioCodecId v) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
// Write the TS message to TS context.
|
// Write the TS message to TS context.
|
||||||
class SrsTsContextWriter
|
class SrsTsContextWriter : public ISrsTsContextWriter
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
// User must config the codec in right way.
|
// User must config the codec in right way.
|
||||||
|
|
@ -1304,12 +1372,12 @@ private:
|
||||||
SrsAudioCodecId acodec_;
|
SrsAudioCodecId acodec_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SrsTsContext *context_;
|
ISrsTsContext *context_;
|
||||||
ISrsStreamWriter *writer_;
|
ISrsStreamWriter *writer_;
|
||||||
std::string path_;
|
std::string path_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsTsContextWriter(ISrsStreamWriter *w, SrsTsContext *c, SrsAudioCodecId ac, SrsVideoCodecId vc);
|
SrsTsContextWriter(ISrsStreamWriter *w, ISrsTsContext *c, SrsAudioCodecId ac, SrsVideoCodecId vc);
|
||||||
virtual ~SrsTsContextWriter();
|
virtual ~SrsTsContextWriter();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -1352,9 +1420,32 @@ private:
|
||||||
int nb_buf;
|
int nb_buf;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Interface for TS messages cache.
|
||||||
// TS messages cache, to group frames to TS message,
|
// TS messages cache, to group frames to TS message,
|
||||||
// for example, we may write multiple AAC RAW frames to a TS message.
|
// for example, we may write multiple AAC RAW frames to a TS message.
|
||||||
class SrsTsMessageCache
|
class ISrsTsMessageCache
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsTsMessageCache();
|
||||||
|
virtual ~ISrsTsMessageCache();
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Write audio to cache
|
||||||
|
virtual srs_error_t cache_audio(SrsParsedAudioPacket *frame, int64_t dts) = 0;
|
||||||
|
// Write video to muxer.
|
||||||
|
virtual srs_error_t cache_video(SrsParsedVideoPacket *frame, int64_t dts) = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Getters and setters for cached messages
|
||||||
|
virtual SrsTsMessage* audio() = 0;
|
||||||
|
virtual void set_audio(SrsTsMessage* msg) = 0;
|
||||||
|
virtual SrsTsMessage* video() = 0;
|
||||||
|
virtual void set_video(SrsTsMessage* msg) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// TS messages cache, to group frames to TS message,
|
||||||
|
// for example, we may write multiple AAC RAW frames to a TS message.
|
||||||
|
class SrsTsMessageCache : public ISrsTsMessageCache
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// The current ts message.
|
// The current ts message.
|
||||||
|
|
@ -1371,6 +1462,13 @@ public:
|
||||||
// Write video to muxer.
|
// Write video to muxer.
|
||||||
virtual srs_error_t cache_video(SrsParsedVideoPacket *frame, int64_t dts);
|
virtual srs_error_t cache_video(SrsParsedVideoPacket *frame, int64_t dts);
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Getters and setters for cached messages
|
||||||
|
virtual SrsTsMessage* audio();
|
||||||
|
virtual void set_audio(SrsTsMessage* msg);
|
||||||
|
virtual SrsTsMessage* video();
|
||||||
|
virtual void set_video(SrsTsMessage* msg);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual srs_error_t do_cache_mp3(SrsParsedAudioPacket *frame);
|
virtual srs_error_t do_cache_mp3(SrsParsedAudioPacket *frame);
|
||||||
virtual srs_error_t do_cache_aac(SrsParsedAudioPacket *frame);
|
virtual srs_error_t do_cache_aac(SrsParsedAudioPacket *frame);
|
||||||
|
|
@ -1378,20 +1476,38 @@ private:
|
||||||
virtual srs_error_t do_cache_hevc(SrsParsedVideoPacket *frame);
|
virtual srs_error_t do_cache_hevc(SrsParsedVideoPacket *frame);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The interface for ts transmuxer.
|
||||||
|
class ISrsTsTransmuxer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsTsTransmuxer();
|
||||||
|
virtual ~ISrsTsTransmuxer();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t initialize(ISrsStreamWriter *fw) = 0;
|
||||||
|
virtual srs_error_t write_audio(int64_t timestamp, char *data, int size) = 0;
|
||||||
|
virtual srs_error_t write_video(int64_t timestamp, char *data, int size) = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void set_has_audio(bool v) = 0;
|
||||||
|
virtual void set_has_video(bool v) = 0;
|
||||||
|
virtual void set_guess_has_av(bool v) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
// Transmux the RTMP stream to HTTP-TS stream.
|
// Transmux the RTMP stream to HTTP-TS stream.
|
||||||
class SrsTsTransmuxer
|
class SrsTsTransmuxer : public ISrsTsTransmuxer
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
ISrsStreamWriter *writer;
|
ISrsStreamWriter *writer_;
|
||||||
bool has_audio_;
|
bool has_audio_;
|
||||||
bool has_video_;
|
bool has_video_;
|
||||||
bool guess_has_av_;
|
bool guess_has_av_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SrsFormat *format;
|
ISrsFormat *format_;
|
||||||
SrsTsMessageCache *tsmc;
|
ISrsTsMessageCache *tsmc_;
|
||||||
SrsTsContextWriter *tscw;
|
ISrsTsContextWriter *tscw_;
|
||||||
SrsTsContext *context;
|
ISrsTsContext *context_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsTsTransmuxer();
|
SrsTsTransmuxer();
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ private:
|
||||||
// The underlayer st fd handler.
|
// The underlayer st fd handler.
|
||||||
srs_netfd_t stfd_;
|
srs_netfd_t stfd_;
|
||||||
// The underlayer socket.
|
// The underlayer socket.
|
||||||
SrsStSocket *skt_;
|
ISrsProtocolReadWriter *skt_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsTcpConnection(srs_netfd_t c);
|
SrsTcpConnection(srs_netfd_t c);
|
||||||
|
|
|
||||||
|
|
@ -438,7 +438,7 @@ ISrsHttpRequestWriter::~ISrsHttpRequestWriter()
|
||||||
|
|
||||||
ISrsHttpHandler::ISrsHttpHandler()
|
ISrsHttpHandler::ISrsHttpHandler()
|
||||||
{
|
{
|
||||||
entry = NULL;
|
entry_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ISrsHttpHandler::~ISrsHttpHandler()
|
ISrsHttpHandler::~ISrsHttpHandler()
|
||||||
|
|
@ -555,25 +555,25 @@ void SrsHttpFileServer::set_path(SrsPath *v)
|
||||||
|
|
||||||
srs_error_t SrsHttpFileServer::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
|
srs_error_t SrsHttpFileServer::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
|
||||||
{
|
{
|
||||||
srs_assert(entry);
|
srs_assert(entry_);
|
||||||
|
|
||||||
// For each HTTP session, we use short-term HTTP connection.
|
// For each HTTP session, we use short-term HTTP connection.
|
||||||
SrsHttpHeader *hdr = w->header();
|
SrsHttpHeader *hdr = w->header();
|
||||||
hdr->set("Connection", "Close");
|
hdr->set("Connection", "Close");
|
||||||
|
|
||||||
string upath = r->path();
|
string upath = r->path();
|
||||||
string fullpath = srs_http_fs_fullpath(dir, entry->pattern, upath);
|
string fullpath = srs_http_fs_fullpath(dir, entry_->pattern, upath);
|
||||||
SrsPath path;
|
SrsPath path;
|
||||||
string basename = path.filepath_base(upath);
|
string basename = path.filepath_base(upath);
|
||||||
|
|
||||||
// stat current dir, if exists, return error.
|
// stat current dir, if exists, return error.
|
||||||
if (!path_->exists(fullpath)) {
|
if (!path_->exists(fullpath)) {
|
||||||
srs_warn("http miss file=%s, pattern=%s, upath=%s",
|
srs_warn("http miss file=%s, pattern=%s, upath=%s",
|
||||||
fullpath.c_str(), entry->pattern.c_str(), upath.c_str());
|
fullpath.c_str(), entry_->pattern.c_str(), upath.c_str());
|
||||||
return SrsHttpNotFoundHandler().serve_http(w, r);
|
return SrsHttpNotFoundHandler().serve_http(w, r);
|
||||||
}
|
}
|
||||||
srs_trace("http match file=%s, pattern=%s, upath=%s",
|
srs_trace("http match file=%s, pattern=%s, upath=%s",
|
||||||
fullpath.c_str(), entry->pattern.c_str(), upath.c_str());
|
fullpath.c_str(), entry_->pattern.c_str(), upath.c_str());
|
||||||
|
|
||||||
// handle file according to its extension.
|
// handle file according to its extension.
|
||||||
// use vod stream for .flv/.fhv
|
// use vod stream for .flv/.fhv
|
||||||
|
|
@ -879,7 +879,7 @@ srs_error_t SrsHttpServeMux::handle(std::string pattern, ISrsHttpHandler *handle
|
||||||
entry->explicit_match = true;
|
entry->explicit_match = true;
|
||||||
entry->handler = handler;
|
entry->handler = handler;
|
||||||
entry->pattern = pattern;
|
entry->pattern = pattern;
|
||||||
entry->handler->entry = entry;
|
entry->handler->entry_ = entry;
|
||||||
|
|
||||||
if (static_matchers_.find(pattern) != static_matchers_.end()) {
|
if (static_matchers_.find(pattern) != static_matchers_.end()) {
|
||||||
SrsHttpMuxEntry *exists = static_matchers_[pattern];
|
SrsHttpMuxEntry *exists = static_matchers_[pattern];
|
||||||
|
|
@ -908,7 +908,7 @@ srs_error_t SrsHttpServeMux::handle(std::string pattern, ISrsHttpHandler *handle
|
||||||
entry->explicit_match = false;
|
entry->explicit_match = false;
|
||||||
entry->handler = new SrsHttpRedirectHandler(pattern, SRS_CONSTS_HTTP_Found);
|
entry->handler = new SrsHttpRedirectHandler(pattern, SRS_CONSTS_HTTP_Found);
|
||||||
entry->pattern = pattern;
|
entry->pattern = pattern;
|
||||||
entry->handler->entry = entry;
|
entry->handler->entry_ = entry;
|
||||||
|
|
||||||
static_matchers_[rpattern] = entry;
|
static_matchers_[rpattern] = entry;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -290,7 +290,7 @@ public:
|
||||||
class ISrsHttpHandler
|
class ISrsHttpHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SrsHttpMuxEntry *entry;
|
SrsHttpMuxEntry *entry_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ISrsHttpHandler();
|
ISrsHttpHandler();
|
||||||
|
|
|
||||||
|
|
@ -7,25 +7,25 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
#include <srs_app_server.hpp>
|
#include <algorithm>
|
||||||
|
#include <srs_app_factory.hpp>
|
||||||
|
#include <srs_app_http_hooks.hpp>
|
||||||
#include <srs_app_rtmp_conn.hpp>
|
#include <srs_app_rtmp_conn.hpp>
|
||||||
#include <srs_app_rtmp_source.hpp>
|
#include <srs_app_rtmp_source.hpp>
|
||||||
#include <srs_app_security.hpp>
|
#include <srs_app_security.hpp>
|
||||||
#include <srs_app_http_hooks.hpp>
|
#include <srs_app_server.hpp>
|
||||||
#include <srs_kernel_error.hpp>
|
#include <srs_app_utility.hpp>
|
||||||
#include <srs_kernel_utility.hpp>
|
|
||||||
#include <srs_kernel_consts.hpp>
|
#include <srs_kernel_consts.hpp>
|
||||||
|
#include <srs_kernel_error.hpp>
|
||||||
#include <srs_kernel_hourglass.hpp>
|
#include <srs_kernel_hourglass.hpp>
|
||||||
#include <srs_app_factory.hpp>
|
|
||||||
#include <srs_kernel_st.hpp>
|
#include <srs_kernel_st.hpp>
|
||||||
|
#include <srs_kernel_utility.hpp>
|
||||||
|
#include <srs_protocol_json.hpp>
|
||||||
#include <srs_protocol_rtmp_stack.hpp>
|
#include <srs_protocol_rtmp_stack.hpp>
|
||||||
|
#include <srs_protocol_st.hpp>
|
||||||
#include <srs_utest_app6.hpp>
|
#include <srs_utest_app6.hpp>
|
||||||
#include <srs_utest_app9.hpp>
|
#include <srs_utest_app9.hpp>
|
||||||
#include <srs_app_utility.hpp>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <srs_protocol_st.hpp>
|
|
||||||
#include <srs_protocol_json.hpp>
|
|
||||||
|
|
||||||
// Mock config implementation for SrsServer::listen() testing
|
// Mock config implementation for SrsServer::listen() testing
|
||||||
MockAppConfigForServerListen::MockAppConfigForServerListen()
|
MockAppConfigForServerListen::MockAppConfigForServerListen()
|
||||||
|
|
@ -265,14 +265,14 @@ VOID TEST(SrsServerTest, HttpHandleSuccess)
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
// Create mock HTTP API mux
|
// Create mock HTTP API mux
|
||||||
MockHttpServeMux* mock_mux = new MockHttpServeMux();
|
MockHttpServeMux *mock_mux = new MockHttpServeMux();
|
||||||
|
|
||||||
// Create SrsServer instance
|
// Create SrsServer instance
|
||||||
SrsUniquePtr<SrsServer> server(new SrsServer());
|
SrsUniquePtr<SrsServer> server(new SrsServer());
|
||||||
EXPECT_TRUE(server.get() != NULL);
|
EXPECT_TRUE(server.get() != NULL);
|
||||||
|
|
||||||
// Inject mock HTTP API mux
|
// Inject mock HTTP API mux
|
||||||
ISrsHttpServeMux* original_mux = server->http_api_mux_;
|
ISrsHttpServeMux *original_mux = server->http_api_mux_;
|
||||||
server->http_api_mux_ = mock_mux;
|
server->http_api_mux_ = mock_mux;
|
||||||
|
|
||||||
// Set reuse_api_over_server_ to false to test all handler registrations
|
// Set reuse_api_over_server_ to false to test all handler registrations
|
||||||
|
|
@ -307,11 +307,16 @@ VOID TEST(SrsServerTest, HttpHandleSuccess)
|
||||||
bool has_rtc_play = false;
|
bool has_rtc_play = false;
|
||||||
|
|
||||||
for (size_t i = 0; i < mock_mux->patterns_.size(); i++) {
|
for (size_t i = 0; i < mock_mux->patterns_.size(); i++) {
|
||||||
if (mock_mux->patterns_[i] == "/") has_root = true;
|
if (mock_mux->patterns_[i] == "/")
|
||||||
if (mock_mux->patterns_[i] == "/api/") has_api = true;
|
has_root = true;
|
||||||
if (mock_mux->patterns_[i] == "/api/v1/summaries") has_summaries = true;
|
if (mock_mux->patterns_[i] == "/api/")
|
||||||
if (mock_mux->patterns_[i] == "/metrics") has_metrics = true;
|
has_api = true;
|
||||||
if (mock_mux->patterns_[i] == "/rtc/v1/play/") has_rtc_play = true;
|
if (mock_mux->patterns_[i] == "/api/v1/summaries")
|
||||||
|
has_summaries = true;
|
||||||
|
if (mock_mux->patterns_[i] == "/metrics")
|
||||||
|
has_metrics = true;
|
||||||
|
if (mock_mux->patterns_[i] == "/rtc/v1/play/")
|
||||||
|
has_rtc_play = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPECT_TRUE(has_root);
|
EXPECT_TRUE(has_root);
|
||||||
|
|
@ -370,13 +375,13 @@ VOID TEST(ServerTest, OnSignalHandling)
|
||||||
EXPECT_TRUE(server.get() != NULL);
|
EXPECT_TRUE(server.get() != NULL);
|
||||||
|
|
||||||
// Create and inject mock config
|
// Create and inject mock config
|
||||||
MockAppConfigForSignal* mock_config = new MockAppConfigForSignal();
|
MockAppConfigForSignal *mock_config = new MockAppConfigForSignal();
|
||||||
ISrsAppConfig* original_config = server->config_;
|
ISrsAppConfig *original_config = server->config_;
|
||||||
server->config_ = mock_config;
|
server->config_ = mock_config;
|
||||||
|
|
||||||
// Create and inject mock log
|
// Create and inject mock log
|
||||||
MockLogForSignal* mock_log = new MockLogForSignal();
|
MockLogForSignal *mock_log = new MockLogForSignal();
|
||||||
ISrsLog* original_log = server->log_;
|
ISrsLog *original_log = server->log_;
|
||||||
server->log_ = mock_log;
|
server->log_ = mock_log;
|
||||||
|
|
||||||
// Test 1: SRS_SIGNAL_RELOAD should set signal_reload_ flag
|
// Test 1: SRS_SIGNAL_RELOAD should set signal_reload_ flag
|
||||||
|
|
@ -484,8 +489,8 @@ VOID TEST(ServerTest, Do2CycleReloadSuccess)
|
||||||
EXPECT_TRUE(server.get() != NULL);
|
EXPECT_TRUE(server.get() != NULL);
|
||||||
|
|
||||||
// Create and inject mock config
|
// Create and inject mock config
|
||||||
MockAppConfigForDo2Cycle* mock_config = new MockAppConfigForDo2Cycle();
|
MockAppConfigForDo2Cycle *mock_config = new MockAppConfigForDo2Cycle();
|
||||||
ISrsAppConfig* original_config = server->config_;
|
ISrsAppConfig *original_config = server->config_;
|
||||||
server->config_ = mock_config;
|
server->config_ = mock_config;
|
||||||
|
|
||||||
// Test major use scenario: signal_reload_ triggers config reload with success
|
// Test major use scenario: signal_reload_ triggers config reload with success
|
||||||
|
|
@ -495,8 +500,8 @@ VOID TEST(ServerTest, Do2CycleReloadSuccess)
|
||||||
server->signal_gracefully_quit_ = false;
|
server->signal_gracefully_quit_ = false;
|
||||||
mock_config->reload_state_ = SrsReloadStateFinished;
|
mock_config->reload_state_ = SrsReloadStateFinished;
|
||||||
HELPER_EXPECT_SUCCESS(server->do2_cycle());
|
HELPER_EXPECT_SUCCESS(server->do2_cycle());
|
||||||
EXPECT_FALSE(server->signal_reload_); // Flag should be cleared after processing
|
EXPECT_FALSE(server->signal_reload_); // Flag should be cleared after processing
|
||||||
EXPECT_EQ(1, mock_config->reload_count_); // Config reload should be called once
|
EXPECT_EQ(1, mock_config->reload_count_); // Config reload should be called once
|
||||||
|
|
||||||
// Cleanup: restore original config
|
// Cleanup: restore original config
|
||||||
server->config_ = original_config;
|
server->config_ = original_config;
|
||||||
|
|
@ -595,13 +600,13 @@ VOID TEST(ServerTest, SetupTicksWithStatsAndHeartbeat)
|
||||||
EXPECT_TRUE(server.get() != NULL);
|
EXPECT_TRUE(server.get() != NULL);
|
||||||
|
|
||||||
// Create and inject mock config
|
// Create and inject mock config
|
||||||
MockAppConfigForSetupTicks* mock_config = new MockAppConfigForSetupTicks();
|
MockAppConfigForSetupTicks *mock_config = new MockAppConfigForSetupTicks();
|
||||||
ISrsAppConfig* original_config = server->config_;
|
ISrsAppConfig *original_config = server->config_;
|
||||||
server->config_ = mock_config;
|
server->config_ = mock_config;
|
||||||
|
|
||||||
// Create and inject mock app factory
|
// Create and inject mock app factory
|
||||||
MockAppFactoryForSetupTicks* mock_factory = new MockAppFactoryForSetupTicks();
|
MockAppFactoryForSetupTicks *mock_factory = new MockAppFactoryForSetupTicks();
|
||||||
SrsAppFactory* original_factory = server->app_factory_;
|
SrsAppFactory *original_factory = server->app_factory_;
|
||||||
server->app_factory_ = mock_factory;
|
server->app_factory_ = mock_factory;
|
||||||
|
|
||||||
// Test major use scenario: setup_ticks with stats and heartbeat enabled
|
// Test major use scenario: setup_ticks with stats and heartbeat enabled
|
||||||
|
|
@ -783,12 +788,12 @@ VOID TEST(SrsServerTest, NotifyEventDispatch)
|
||||||
SrsUniquePtr<SrsServer> server(new SrsServer());
|
SrsUniquePtr<SrsServer> server(new SrsServer());
|
||||||
|
|
||||||
// Create mock objects
|
// Create mock objects
|
||||||
MockRtcSessionManagerForNotify* mock_rtc_manager = new MockRtcSessionManagerForNotify();
|
MockRtcSessionManagerForNotify *mock_rtc_manager = new MockRtcSessionManagerForNotify();
|
||||||
MockHttpHeartbeatForNotify* mock_heartbeat = new MockHttpHeartbeatForNotify();
|
MockHttpHeartbeatForNotify *mock_heartbeat = new MockHttpHeartbeatForNotify();
|
||||||
|
|
||||||
// Save original pointers
|
// Save original pointers
|
||||||
SrsRtcSessionManager* original_rtc_manager = server->rtc_session_manager_;
|
SrsRtcSessionManager *original_rtc_manager = server->rtc_session_manager_;
|
||||||
SrsHttpHeartbeat* original_heartbeat = server->http_heartbeat_;
|
SrsHttpHeartbeat *original_heartbeat = server->http_heartbeat_;
|
||||||
|
|
||||||
// Inject mock objects (no cast needed since they inherit from the base classes)
|
// Inject mock objects (no cast needed since they inherit from the base classes)
|
||||||
server->rtc_session_manager_ = mock_rtc_manager;
|
server->rtc_session_manager_ = mock_rtc_manager;
|
||||||
|
|
@ -1234,7 +1239,7 @@ int64_t MockRtmpTransportForDoCycle::get_send_bytes()
|
||||||
VOID TEST(SrsRtmpConnTest, ConstructorAndAssemble)
|
VOID TEST(SrsRtmpConnTest, ConstructorAndAssemble)
|
||||||
{
|
{
|
||||||
// Create a dummy file descriptor for transport
|
// Create a dummy file descriptor for transport
|
||||||
srs_netfd_t dummy_fd = (srs_netfd_t)((void*)0x1234);
|
srs_netfd_t dummy_fd = (srs_netfd_t)((void *)0x1234);
|
||||||
SrsRtmpTransport *transport = new SrsRtmpTransport(dummy_fd);
|
SrsRtmpTransport *transport = new SrsRtmpTransport(dummy_fd);
|
||||||
// Prevent destructor from closing dummy fd
|
// Prevent destructor from closing dummy fd
|
||||||
transport->skt_->stfd_ = NULL;
|
transport->skt_->stfd_ = NULL;
|
||||||
|
|
@ -1344,7 +1349,7 @@ VOID TEST(SrsRtmpTransportTest, BasicOperations)
|
||||||
|
|
||||||
// Create a dummy file descriptor (cast from int for testing)
|
// Create a dummy file descriptor (cast from int for testing)
|
||||||
// Note: We won't actually use this for I/O, just testing the wrapper methods
|
// Note: We won't actually use this for I/O, just testing the wrapper methods
|
||||||
srs_netfd_t dummy_fd = (srs_netfd_t)((void*)0x1234);
|
srs_netfd_t dummy_fd = (srs_netfd_t)((void *)0x1234);
|
||||||
|
|
||||||
// Create SrsRtmpTransport instance
|
// Create SrsRtmpTransport instance
|
||||||
SrsUniquePtr<SrsRtmpTransport> transport(new SrsRtmpTransport(dummy_fd));
|
SrsUniquePtr<SrsRtmpTransport> transport(new SrsRtmpTransport(dummy_fd));
|
||||||
|
|
@ -1548,7 +1553,7 @@ srs_error_t MockRtmpServerForHandlePublishMessage::decode_message(SrsRtmpCommonM
|
||||||
}
|
}
|
||||||
// Return the configured packet (can be NULL or a specific packet type)
|
// Return the configured packet (can be NULL or a specific packet type)
|
||||||
*ppacket = decode_message_packet_;
|
*ppacket = decode_message_packet_;
|
||||||
decode_message_packet_ = NULL; // Transfer ownership
|
decode_message_packet_ = NULL; // Transfer ownership
|
||||||
return srs_success;
|
return srs_success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1731,7 +1736,7 @@ VOID TEST(SrsUtilityTest, GetCpuInfo)
|
||||||
VOID TEST(SrsUtilityTest, UpdateDiskStat)
|
VOID TEST(SrsUtilityTest, UpdateDiskStat)
|
||||||
{
|
{
|
||||||
// Get the initial disk stat to save the original state
|
// Get the initial disk stat to save the original state
|
||||||
SrsDiskStat* original_stat = srs_get_disk_stat();
|
SrsDiskStat *original_stat = srs_get_disk_stat();
|
||||||
SrsDiskStat saved_stat = *original_stat;
|
SrsDiskStat saved_stat = *original_stat;
|
||||||
|
|
||||||
// Test case 1: First call to srs_update_disk_stat() - should initialize the stat
|
// Test case 1: First call to srs_update_disk_stat() - should initialize the stat
|
||||||
|
|
@ -1740,11 +1745,9 @@ VOID TEST(SrsUtilityTest, UpdateDiskStat)
|
||||||
if (true) {
|
if (true) {
|
||||||
srs_update_disk_stat();
|
srs_update_disk_stat();
|
||||||
|
|
||||||
SrsDiskStat* stat = srs_get_disk_stat();
|
SrsDiskStat *stat = srs_get_disk_stat();
|
||||||
EXPECT_TRUE(stat->ok_);
|
EXPECT_TRUE(stat->ok_);
|
||||||
EXPECT_TRUE(stat->sample_time_ > 0);
|
EXPECT_TRUE(stat->sample_time_ > 0);
|
||||||
// After first call, KBps values should be 0 (no delta to calculate)
|
|
||||||
EXPECT_EQ(0, stat->in_KBps_);
|
|
||||||
// busy_ should be 0 (no delta to calculate)
|
// busy_ should be 0 (no delta to calculate)
|
||||||
EXPECT_EQ(0.0f, stat->busy_);
|
EXPECT_EQ(0.0f, stat->busy_);
|
||||||
}
|
}
|
||||||
|
|
@ -1764,7 +1767,7 @@ VOID TEST(SrsUtilityTest, UpdateDiskStat)
|
||||||
// Call srs_update_disk_stat() again to calculate deltas
|
// Call srs_update_disk_stat() again to calculate deltas
|
||||||
srs_update_disk_stat();
|
srs_update_disk_stat();
|
||||||
|
|
||||||
SrsDiskStat* stat = srs_get_disk_stat();
|
SrsDiskStat *stat = srs_get_disk_stat();
|
||||||
EXPECT_TRUE(stat->ok_);
|
EXPECT_TRUE(stat->ok_);
|
||||||
EXPECT_TRUE(stat->sample_time_ > first_sample.sample_time_);
|
EXPECT_TRUE(stat->sample_time_ > first_sample.sample_time_);
|
||||||
|
|
||||||
|
|
@ -1780,21 +1783,21 @@ VOID TEST(SrsUtilityTest, UpdateDiskStat)
|
||||||
// busy_ = ticks / delta_ms, where delta_ms = cpu_.total_delta_ * 10 / nb_processors_
|
// busy_ = ticks / delta_ms, where delta_ms = cpu_.total_delta_ * 10 / nb_processors_
|
||||||
// Note: busy_ may still be 0 if no disk I/O occurred or if conditions not met
|
// Note: busy_ may still be 0 if no disk I/O occurred or if conditions not met
|
||||||
EXPECT_TRUE(stat->busy_ >= 0.0f);
|
EXPECT_TRUE(stat->busy_ >= 0.0f);
|
||||||
EXPECT_TRUE(stat->busy_ <= 1.0f); // busy_ should be in [0, 1] range
|
EXPECT_TRUE(stat->busy_ <= 1.0f); // busy_ should be in [0, 1] range
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test case 3: Verify the calculation formulas with known values
|
// Test case 3: Verify the calculation formulas with known values
|
||||||
// This tests the specific calculation logic for vmstat and diskstats
|
// This tests the specific calculation logic for vmstat and diskstats
|
||||||
if (true) {
|
if (true) {
|
||||||
// Get current stat
|
// Get current stat
|
||||||
SrsDiskStat* current = srs_get_disk_stat();
|
SrsDiskStat *current = srs_get_disk_stat();
|
||||||
|
|
||||||
// Manually create a previous stat with known values to test calculation
|
// Manually create a previous stat with known values to test calculation
|
||||||
SrsDiskStat prev = *current;
|
SrsDiskStat prev = *current;
|
||||||
prev.sample_time_ = current->sample_time_ - 1000; // 1 second ago
|
prev.sample_time_ = current->sample_time_ - 1000; // 1 second ago
|
||||||
prev.pgpgin_ = 1000; // 1000 KB read
|
prev.pgpgin_ = 1000; // 1000 KB read
|
||||||
prev.pgpgout_ = 2000; // 2000 KB written
|
prev.pgpgout_ = 2000; // 2000 KB written
|
||||||
prev.ticks_ = 100; // 100 ticks
|
prev.ticks_ = 100; // 100 ticks
|
||||||
prev.cpu_.ok_ = true;
|
prev.cpu_.ok_ = true;
|
||||||
prev.cpu_.user_ = 1000;
|
prev.cpu_.user_ = 1000;
|
||||||
prev.cpu_.sys_ = 500;
|
prev.cpu_.sys_ = 500;
|
||||||
|
|
@ -1805,8 +1808,8 @@ VOID TEST(SrsUtilityTest, UpdateDiskStat)
|
||||||
SrsDiskStat next = *current;
|
SrsDiskStat next = *current;
|
||||||
next.sample_time_ = current->sample_time_;
|
next.sample_time_ = current->sample_time_;
|
||||||
next.pgpgin_ = 2000; // 1000 KB more read
|
next.pgpgin_ = 2000; // 1000 KB more read
|
||||||
next.pgpgout_ = 4000; // 2000 KB more written
|
next.pgpgout_ = 4000; // 2000 KB more written
|
||||||
next.ticks_ = 200; // 100 ticks more
|
next.ticks_ = 200; // 100 ticks more
|
||||||
next.cpu_.ok_ = true;
|
next.cpu_.ok_ = true;
|
||||||
next.cpu_.user_ = 1100;
|
next.cpu_.user_ = 1100;
|
||||||
next.cpu_.sys_ = 600;
|
next.cpu_.sys_ = 600;
|
||||||
|
|
@ -1829,7 +1832,7 @@ VOID TEST(SrsUtilityTest, UpdateDiskStat)
|
||||||
|
|
||||||
// Verify diskstats busy calculation formula
|
// Verify diskstats busy calculation formula
|
||||||
if (next.cpu_.ok_ && prev.cpu_.ok_ && next.cpu_.total_delta_ > 0) {
|
if (next.cpu_.ok_ && prev.cpu_.ok_ && next.cpu_.total_delta_ > 0) {
|
||||||
SrsCpuInfo* cpuinfo = srs_get_cpuinfo();
|
SrsCpuInfo *cpuinfo = srs_get_cpuinfo();
|
||||||
if (cpuinfo->ok_ && cpuinfo->nb_processors_ > 0 && prev.ticks_ < next.ticks_) {
|
if (cpuinfo->ok_ && cpuinfo->nb_processors_ > 0 && prev.ticks_ < next.ticks_) {
|
||||||
// delta_ms = cpu_.total_delta_ * 10 / nb_processors_
|
// delta_ms = cpu_.total_delta_ * 10 / nb_processors_
|
||||||
double delta_ms = next.cpu_.total_delta_ * 10 / cpuinfo->nb_processors_;
|
double delta_ms = next.cpu_.total_delta_ * 10 / cpuinfo->nb_processors_;
|
||||||
|
|
@ -2278,7 +2281,7 @@ VOID TEST(SrsRtmpConnTest, AcquirePublishStreamBusyCheck)
|
||||||
// Create mock live source that does NOT allow publishing (stream is busy)
|
// Create mock live source that does NOT allow publishing (stream is busy)
|
||||||
SrsSharedPtr<SrsLiveSource> source(new MockLiveSource());
|
SrsSharedPtr<SrsLiveSource> source(new MockLiveSource());
|
||||||
MockLiveSource *mock_source = dynamic_cast<MockLiveSource *>(source.get());
|
MockLiveSource *mock_source = dynamic_cast<MockLiveSource *>(source.get());
|
||||||
mock_source->set_can_publish(false); // Stream is busy
|
mock_source->set_can_publish(false); // Stream is busy
|
||||||
|
|
||||||
// Call acquire_publish - should fail with ERROR_SYSTEM_STREAM_BUSY
|
// Call acquire_publish - should fail with ERROR_SYSTEM_STREAM_BUSY
|
||||||
err = conn->acquire_publish(source);
|
err = conn->acquire_publish(source);
|
||||||
|
|
@ -2287,7 +2290,7 @@ VOID TEST(SrsRtmpConnTest, AcquirePublishStreamBusyCheck)
|
||||||
srs_freep(err);
|
srs_freep(err);
|
||||||
|
|
||||||
// Note: conn owns mock_rtmp and mock_security, they will be deleted by conn destructor
|
// Note: conn owns mock_rtmp and mock_security, they will be deleted by conn destructor
|
||||||
} // conn is destroyed here
|
} // conn is destroyed here
|
||||||
|
|
||||||
// Now safe to delete mock_config
|
// Now safe to delete mock_config
|
||||||
srs_freep(mock_config);
|
srs_freep(mock_config);
|
||||||
|
|
@ -2347,7 +2350,7 @@ VOID TEST(SrsRtmpConnTest, HandlePublishMessageVideoSuccess)
|
||||||
EXPECT_EQ(0, mock_rtmp->decode_message_count_);
|
EXPECT_EQ(0, mock_rtmp->decode_message_count_);
|
||||||
|
|
||||||
// Note: conn owns mock_rtmp, it will be deleted by conn destructor
|
// Note: conn owns mock_rtmp, it will be deleted by conn destructor
|
||||||
} // conn is destroyed here
|
} // conn is destroyed here
|
||||||
|
|
||||||
// Now safe to delete mock_config
|
// Now safe to delete mock_config
|
||||||
srs_freep(mock_config);
|
srs_freep(mock_config);
|
||||||
|
|
@ -2682,7 +2685,7 @@ VOID TEST(SrsRtmpConnTest, HttpHooksOnConnect)
|
||||||
|
|
||||||
// Restore original hooks
|
// Restore original hooks
|
||||||
conn->hooks_ = original_hooks;
|
conn->hooks_ = original_hooks;
|
||||||
} // conn is destroyed here
|
} // conn is destroyed here
|
||||||
|
|
||||||
// Now safe to delete mock objects
|
// Now safe to delete mock objects
|
||||||
srs_freep(mock_hooks);
|
srs_freep(mock_hooks);
|
||||||
|
|
@ -2757,7 +2760,7 @@ VOID TEST(SrsRtmpConnTest, ProcessPlayControlMsgPauseSuccess)
|
||||||
EXPECT_EQ(true, consumer->last_pause_state_);
|
EXPECT_EQ(true, consumer->last_pause_state_);
|
||||||
|
|
||||||
// Note: conn owns mock_rtmp, it will be deleted by conn destructor
|
// Note: conn owns mock_rtmp, it will be deleted by conn destructor
|
||||||
} // conn is destroyed here
|
} // conn is destroyed here
|
||||||
|
|
||||||
// Now safe to delete mock_config
|
// Now safe to delete mock_config
|
||||||
srs_freep(mock_config);
|
srs_freep(mock_config);
|
||||||
|
|
@ -2811,8 +2814,8 @@ VOID TEST(SrsRtmpConnTest, HttpHooksOnClose)
|
||||||
// Verify the first call
|
// Verify the first call
|
||||||
EXPECT_STREQ("http://127.0.0.1:8085/api/v1/close", mock_hooks->on_close_calls_[0].url_.c_str());
|
EXPECT_STREQ("http://127.0.0.1:8085/api/v1/close", mock_hooks->on_close_calls_[0].url_.c_str());
|
||||||
EXPECT_TRUE(mock_hooks->on_close_calls_[0].req_ == conn->info_->req_);
|
EXPECT_TRUE(mock_hooks->on_close_calls_[0].req_ == conn->info_->req_);
|
||||||
EXPECT_EQ(0, mock_hooks->on_close_calls_[0].send_bytes_); // Mock transport returns 0
|
EXPECT_EQ(0, mock_hooks->on_close_calls_[0].send_bytes_); // Mock transport returns 0
|
||||||
EXPECT_EQ(0, mock_hooks->on_close_calls_[0].recv_bytes_); // Mock transport returns 0
|
EXPECT_EQ(0, mock_hooks->on_close_calls_[0].recv_bytes_); // Mock transport returns 0
|
||||||
|
|
||||||
// Verify the second call
|
// Verify the second call
|
||||||
EXPECT_STREQ("http://localhost:8085/api/v1/close", mock_hooks->on_close_calls_[1].url_.c_str());
|
EXPECT_STREQ("http://localhost:8085/api/v1/close", mock_hooks->on_close_calls_[1].url_.c_str());
|
||||||
|
|
@ -2894,7 +2897,7 @@ srs_error_t MockHttpHooksForOnPublish::on_dvr(SrsContextId cid, std::string url,
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t MockHttpHooksForOnPublish::on_hls(SrsContextId cid, std::string url, ISrsRequest *req, std::string file, std::string ts_url,
|
srs_error_t MockHttpHooksForOnPublish::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)
|
std::string m3u8, std::string m3u8_url, int sn, srs_utime_t duration)
|
||||||
{
|
{
|
||||||
return srs_success;
|
return srs_success;
|
||||||
}
|
}
|
||||||
|
|
@ -3210,7 +3213,7 @@ srs_error_t MockHttpHooksForOnPlay::on_dvr(SrsContextId cid, std::string url, IS
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t MockHttpHooksForOnPlay::on_hls(SrsContextId cid, std::string url, ISrsRequest *req, std::string file, std::string ts_url,
|
srs_error_t MockHttpHooksForOnPlay::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)
|
std::string m3u8, std::string m3u8_url, int sn, srs_utime_t duration)
|
||||||
{
|
{
|
||||||
return srs_success;
|
return srs_success;
|
||||||
}
|
}
|
||||||
|
|
@ -3326,9 +3329,6 @@ VOID TEST(UtilityTest, GetProcSelfStatSuccess)
|
||||||
EXPECT_TRUE(stat.state_ == 'R' || stat.state_ == 'S' || stat.state_ == 'D' ||
|
EXPECT_TRUE(stat.state_ == 'R' || stat.state_ == 'S' || stat.state_ == 'D' ||
|
||||||
stat.state_ == 'Z' || stat.state_ == 'T' || stat.state_ == 'W');
|
stat.state_ == 'Z' || stat.state_ == 'T' || stat.state_ == 'W');
|
||||||
|
|
||||||
// ppid should be positive (parent process ID)
|
|
||||||
EXPECT_TRUE(stat.ppid_ > 0);
|
|
||||||
|
|
||||||
// num_threads should be at least 1 (current thread)
|
// num_threads should be at least 1 (current thread)
|
||||||
EXPECT_TRUE(stat.num_threads_ >= 1);
|
EXPECT_TRUE(stat.num_threads_ >= 1);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,14 +11,15 @@
|
||||||
#include <srs_utest_app10.hpp>
|
#include <srs_utest_app10.hpp>
|
||||||
*/
|
*/
|
||||||
#include <srs_utest.hpp>
|
#include <srs_utest.hpp>
|
||||||
#include <srs_utest_app6.hpp>
|
|
||||||
#include <srs_protocol_http_stack.hpp>
|
|
||||||
#include <srs_kernel_hourglass.hpp>
|
|
||||||
#include <srs_app_factory.hpp>
|
#include <srs_app_factory.hpp>
|
||||||
#include <srs_app_rtc_server.hpp>
|
|
||||||
#include <srs_app_heartbeat.hpp>
|
#include <srs_app_heartbeat.hpp>
|
||||||
|
#include <srs_app_rtc_server.hpp>
|
||||||
#include <srs_app_rtmp_conn.hpp>
|
#include <srs_app_rtmp_conn.hpp>
|
||||||
#include <srs_app_security.hpp>
|
#include <srs_app_security.hpp>
|
||||||
|
#include <srs_kernel_hourglass.hpp>
|
||||||
|
#include <srs_protocol_http_stack.hpp>
|
||||||
|
#include <srs_utest_app6.hpp>
|
||||||
|
|
||||||
// Mock config for testing SrsServer::listen()
|
// Mock config for testing SrsServer::listen()
|
||||||
class MockAppConfigForServerListen : public MockAppConfig
|
class MockAppConfigForServerListen : public MockAppConfig
|
||||||
|
|
@ -416,7 +417,7 @@ class MockRtmpServerForHandlePublishMessage : public ISrsRtmpServer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
srs_error_t decode_message_error_;
|
srs_error_t decode_message_error_;
|
||||||
SrsRtmpCommand* decode_message_packet_;
|
SrsRtmpCommand *decode_message_packet_;
|
||||||
int decode_message_count_;
|
int decode_message_count_;
|
||||||
srs_error_t fmle_unpublish_error_;
|
srs_error_t fmle_unpublish_error_;
|
||||||
int fmle_unpublish_count_;
|
int fmle_unpublish_count_;
|
||||||
|
|
@ -461,7 +462,7 @@ public:
|
||||||
class MockRtmpServerForPlayControl : public ISrsRtmpServer
|
class MockRtmpServerForPlayControl : public ISrsRtmpServer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SrsRtmpCommand* decode_message_packet_;
|
SrsRtmpCommand *decode_message_packet_;
|
||||||
int decode_message_count_;
|
int decode_message_count_;
|
||||||
int send_and_free_packet_count_;
|
int send_and_free_packet_count_;
|
||||||
int on_play_client_pause_count_;
|
int on_play_client_pause_count_;
|
||||||
|
|
|
||||||
2054
trunk/src/utest/srs_utest_app11.cpp
Normal file
2054
trunk/src/utest/srs_utest_app11.cpp
Normal file
File diff suppressed because it is too large
Load Diff
352
trunk/src/utest/srs_utest_app11.hpp
Normal file
352
trunk/src/utest/srs_utest_app11.hpp
Normal file
|
|
@ -0,0 +1,352 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2013-2025 The SRS Authors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SRS_UTEST_APP11_HPP
|
||||||
|
#define SRS_UTEST_APP11_HPP
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <srs_utest_app11.hpp>
|
||||||
|
*/
|
||||||
|
#include <srs_utest.hpp>
|
||||||
|
|
||||||
|
#include <srs_app_config.hpp>
|
||||||
|
#include <srs_app_http_hooks.hpp>
|
||||||
|
#include <srs_app_http_stream.hpp>
|
||||||
|
#include <srs_app_rtmp_source.hpp>
|
||||||
|
#include <srs_protocol_http_conn.hpp>
|
||||||
|
#include <srs_protocol_rtmp_stack.hpp>
|
||||||
|
#include <srs_utest_app6.hpp>
|
||||||
|
|
||||||
|
// Mock request class for testing SrsBufferCache
|
||||||
|
class MockBufferCacheRequest : public ISrsRequest
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MockBufferCacheRequest(std::string vhost = "__defaultVhost__", std::string app = "live", std::string stream = "test");
|
||||||
|
virtual ~MockBufferCacheRequest();
|
||||||
|
virtual ISrsRequest *copy();
|
||||||
|
virtual std::string get_stream_url();
|
||||||
|
virtual void update_auth(ISrsRequest *req);
|
||||||
|
virtual void strip();
|
||||||
|
virtual ISrsRequest *as_http();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock buffer cache for testing AAC stream encoder
|
||||||
|
class MockBufferCacheForAac : public ISrsBufferCache
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int dump_cache_count_;
|
||||||
|
ISrsLiveConsumer *last_consumer_;
|
||||||
|
SrsRtmpJitterAlgorithm last_jitter_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockBufferCacheForAac();
|
||||||
|
virtual ~MockBufferCacheForAac();
|
||||||
|
virtual srs_error_t start();
|
||||||
|
virtual void stop();
|
||||||
|
virtual bool alive();
|
||||||
|
virtual srs_error_t dump_cache(ISrsLiveConsumer *consumer, SrsRtmpJitterAlgorithm jitter);
|
||||||
|
virtual srs_error_t update_auth(ISrsRequest *r);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock SrsHttpxConn for testing SrsLiveStream (old version for backward compatibility)
|
||||||
|
class MockHttpxConn : public ISrsHttpConnOwner
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool enable_stat_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockHttpxConn();
|
||||||
|
virtual ~MockHttpxConn();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void set_enable_stat(bool v);
|
||||||
|
virtual srs_error_t on_start();
|
||||||
|
virtual srs_error_t on_http_message(ISrsHttpMessage *r, SrsHttpResponseWriter *w);
|
||||||
|
virtual srs_error_t on_message_done(ISrsHttpMessage *r, SrsHttpResponseWriter *w);
|
||||||
|
virtual srs_error_t on_conn_done(srs_error_t r0);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock SrsHttpConn for testing SrsLiveStream (old version for backward compatibility)
|
||||||
|
class MockHttpConn : public ISrsConnection, public ISrsExpire
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MockHttpxConn *handler_;
|
||||||
|
std::string remote_ip_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockHttpConn();
|
||||||
|
virtual ~MockHttpConn();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual std::string remote_ip();
|
||||||
|
virtual const SrsContextId &get_id();
|
||||||
|
virtual std::string desc();
|
||||||
|
virtual void expire();
|
||||||
|
virtual ISrsHttpConnOwner *handler();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock SrsHttpMessage for testing SrsLiveStream (old version for backward compatibility)
|
||||||
|
class MockHttpMessage : public SrsHttpMessage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MockHttpConn *mock_conn_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockHttpMessage();
|
||||||
|
virtual ~MockHttpMessage();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual std::string path();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock SrsHttpxConn for testing SrsLiveStream - inherits from real SrsHttpxConn
|
||||||
|
class MockHttpxConnForLiveStream : public SrsHttpxConn
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool enable_stat_called_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockHttpxConnForLiveStream();
|
||||||
|
virtual ~MockHttpxConnForLiveStream();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void set_enable_stat(bool v);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock SrsHttpConn for testing SrsLiveStream - inherits from real SrsHttpConn
|
||||||
|
class MockHttpConnForLiveStream : public SrsHttpConn
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MockHttpxConnForLiveStream *mock_handler_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockHttpConnForLiveStream();
|
||||||
|
virtual ~MockHttpConnForLiveStream();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ISrsHttpConnOwner *handler();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock SrsHttpMessage for testing SrsLiveStream
|
||||||
|
class MockHttpMessageForLiveStream : public SrsHttpMessage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MockHttpConnForLiveStream *mock_conn_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockHttpMessageForLiveStream();
|
||||||
|
virtual ~MockHttpMessageForLiveStream();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ISrsConnection *connection();
|
||||||
|
virtual std::string path();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock ISrsAppConfig for testing SrsLiveStream::http_hooks_on_play() and http_hooks_on_stop()
|
||||||
|
class MockAppConfigForLiveStreamHooks : public MockAppConfig
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool http_hooks_enabled_;
|
||||||
|
SrsConfDirective *on_play_directive_;
|
||||||
|
SrsConfDirective *on_stop_directive_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockAppConfigForLiveStreamHooks();
|
||||||
|
virtual ~MockAppConfigForLiveStreamHooks();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual bool get_vhost_http_hooks_enabled(std::string vhost);
|
||||||
|
virtual SrsConfDirective *get_vhost_on_play(std::string vhost);
|
||||||
|
virtual SrsConfDirective *get_vhost_on_stop(std::string vhost);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock ISrsHttpHooks for testing SrsLiveStream::http_hooks_on_play() and http_hooks_on_stop()
|
||||||
|
class MockHttpHooksForLiveStream : public ISrsHttpHooks
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::vector<std::pair<std::string, ISrsRequest *> > on_play_calls_;
|
||||||
|
int on_play_count_;
|
||||||
|
srs_error_t on_play_error_;
|
||||||
|
std::vector<std::pair<std::string, ISrsRequest *> > on_stop_calls_;
|
||||||
|
int on_stop_count_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockHttpHooksForLiveStream();
|
||||||
|
virtual ~MockHttpHooksForLiveStream();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t on_connect(std::string url, ISrsRequest *req);
|
||||||
|
virtual void on_close(std::string url, ISrsRequest *req, int64_t send_bytes, int64_t recv_bytes);
|
||||||
|
virtual srs_error_t on_publish(std::string url, ISrsRequest *req);
|
||||||
|
virtual void on_unpublish(std::string url, ISrsRequest *req);
|
||||||
|
virtual srs_error_t on_play(std::string url, ISrsRequest *req);
|
||||||
|
virtual void on_stop(std::string url, ISrsRequest *req);
|
||||||
|
virtual srs_error_t on_dvr(SrsContextId cid, std::string url, ISrsRequest *req, std::string file);
|
||||||
|
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);
|
||||||
|
virtual srs_error_t on_hls_notify(SrsContextId cid, std::string url, ISrsRequest *req, std::string ts_url, int nb_notify);
|
||||||
|
virtual srs_error_t discover_co_workers(std::string url, std::string &host, int &port);
|
||||||
|
virtual srs_error_t on_forward_backend(std::string url, ISrsRequest *req, std::vector<std::string> &rtmp_urls);
|
||||||
|
void reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock ISrsAsyncCallWorker for testing SrsHttpStreamServer
|
||||||
|
class MockAsyncCallWorker : public ISrsAsyncCallWorker
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int execute_count_;
|
||||||
|
std::vector<ISrsAsyncCallTask *> tasks_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockAsyncCallWorker();
|
||||||
|
virtual ~MockAsyncCallWorker();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t execute(ISrsAsyncCallTask *t);
|
||||||
|
virtual srs_error_t start();
|
||||||
|
virtual void stop();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock ISrsLiveStream for testing SrsHttpStreamDestroy
|
||||||
|
class MockLiveStreamForDestroy : public ISrsLiveStream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool alive_;
|
||||||
|
bool expired_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockLiveStreamForDestroy();
|
||||||
|
virtual ~MockLiveStreamForDestroy();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r);
|
||||||
|
virtual srs_error_t update_auth(ISrsRequest *r);
|
||||||
|
virtual bool alive();
|
||||||
|
virtual void expire();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock ISrsStatistic for testing SrsLiveStream::serve_http_impl
|
||||||
|
class MockStatisticForLiveStream : public ISrsStatistic
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int on_client_count_;
|
||||||
|
srs_error_t on_client_error_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockStatisticForLiveStream();
|
||||||
|
virtual ~MockStatisticForLiveStream();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void on_disconnect(std::string id, srs_error_t err);
|
||||||
|
virtual srs_error_t on_client(std::string id, ISrsRequest *req, ISrsExpire *conn, SrsRtmpConnType type);
|
||||||
|
virtual srs_error_t on_video_info(ISrsRequest *req, SrsVideoCodecId vcodec, int avc_profile, int avc_level, int width, int height);
|
||||||
|
virtual srs_error_t on_audio_info(ISrsRequest *req, SrsAudioCodecId acodec, SrsAudioSampleRate asample_rate, SrsAudioChannels asound_type, SrsAacObjectType aac_object);
|
||||||
|
virtual void on_stream_publish(ISrsRequest *req, std::string publisher_id);
|
||||||
|
virtual void on_stream_close(ISrsRequest *req);
|
||||||
|
virtual void kbps_add_delta(std::string id, ISrsKbpsDelta *delta);
|
||||||
|
virtual void kbps_sample();
|
||||||
|
virtual srs_error_t on_video_frames(ISrsRequest *req, int nb_frames);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock ISrsSecurity for testing SrsLiveStream::serve_http_impl
|
||||||
|
class MockSecurityForLiveStream : public ISrsSecurity
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
srs_error_t check_error_;
|
||||||
|
int check_count_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockSecurityForLiveStream();
|
||||||
|
virtual ~MockSecurityForLiveStream();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t check(SrsRtmpConnType type, std::string ip, ISrsRequest *req);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock ISrsBufferCache for testing SrsHttpStreamDestroy
|
||||||
|
class MockBufferCacheForDestroy : public ISrsBufferCache
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool alive_;
|
||||||
|
bool stopped_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockBufferCacheForDestroy();
|
||||||
|
virtual ~MockBufferCacheForDestroy();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t start();
|
||||||
|
virtual void stop();
|
||||||
|
virtual bool alive();
|
||||||
|
virtual srs_error_t dump_cache(ISrsLiveConsumer *consumer, SrsRtmpJitterAlgorithm jitter);
|
||||||
|
virtual srs_error_t update_auth(ISrsRequest *r);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock ISrsBufferEncoder for testing SrsLiveStream::streaming_send_messages
|
||||||
|
class MockBufferEncoderForStreamingSend : public ISrsBufferEncoder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int write_audio_count_;
|
||||||
|
int write_video_count_;
|
||||||
|
int write_metadata_count_;
|
||||||
|
std::vector<int64_t> audio_timestamps_;
|
||||||
|
std::vector<int64_t> video_timestamps_;
|
||||||
|
std::vector<int64_t> metadata_timestamps_;
|
||||||
|
srs_error_t write_error_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockBufferEncoderForStreamingSend();
|
||||||
|
virtual ~MockBufferEncoderForStreamingSend();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t initialize(SrsFileWriter *w, ISrsBufferCache *c);
|
||||||
|
virtual srs_error_t write_audio(int64_t timestamp, char *data, int size);
|
||||||
|
virtual srs_error_t write_video(int64_t timestamp, char *data, int size);
|
||||||
|
virtual srs_error_t write_metadata(int64_t timestamp, char *data, int size);
|
||||||
|
virtual bool has_cache();
|
||||||
|
virtual srs_error_t dump_cache(ISrsLiveConsumer *consumer, SrsRtmpJitterAlgorithm jitter);
|
||||||
|
void reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock ISrsAppConfig for testing SrsHttpStreamServer
|
||||||
|
class MockAppConfigForHttpStreamServer : public MockAppConfig
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool http_remux_enabled_;
|
||||||
|
std::string http_remux_mount_;
|
||||||
|
SrsConfDirective *vhost_directive_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockAppConfigForHttpStreamServer();
|
||||||
|
virtual ~MockAppConfigForHttpStreamServer();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual bool get_vhost_http_remux_enabled(std::string vhost);
|
||||||
|
virtual std::string get_vhost_http_remux_mount(std::string vhost);
|
||||||
|
virtual SrsConfDirective *get_vhost(std::string vhost, bool try_default_vhost = true);
|
||||||
|
virtual bool get_vhost_enabled(SrsConfDirective *conf);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock SrsHttpMessage for testing SrsHttpStreamServer::dynamic_match
|
||||||
|
class MockHttpMessageForDynamicMatch : public SrsHttpMessage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string path_;
|
||||||
|
std::string ext_;
|
||||||
|
std::string host_;
|
||||||
|
MockHttpConn *mock_conn_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockHttpMessageForDynamicMatch();
|
||||||
|
virtual ~MockHttpMessageForDynamicMatch();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual std::string path();
|
||||||
|
virtual std::string ext();
|
||||||
|
virtual std::string host();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -383,6 +383,16 @@ public:
|
||||||
virtual bool get_atc_auto(std::string vhost);
|
virtual bool get_atc_auto(std::string vhost);
|
||||||
virtual bool get_reduce_sequence_header(std::string vhost);
|
virtual bool get_reduce_sequence_header(std::string vhost);
|
||||||
virtual bool get_parse_sps(std::string vhost);
|
virtual bool get_parse_sps(std::string vhost);
|
||||||
|
virtual SrsConfDirective *get_root() { return NULL; }
|
||||||
|
virtual bool get_vhost_enabled(SrsConfDirective *conf) { return true; }
|
||||||
|
virtual bool get_vhost_http_remux_enabled(std::string vhost) { return false; }
|
||||||
|
virtual bool get_vhost_http_remux_enabled(SrsConfDirective *vhost) { return false; }
|
||||||
|
virtual srs_utime_t get_vhost_http_remux_fast_cache(std::string vhost) { return 0; }
|
||||||
|
virtual bool get_vhost_http_remux_drop_if_not_match(std::string vhost) { return false; }
|
||||||
|
virtual bool get_vhost_http_remux_has_audio(std::string vhost) { return true; }
|
||||||
|
virtual bool get_vhost_http_remux_has_video(std::string vhost) { return true; }
|
||||||
|
virtual bool get_vhost_http_remux_guess_has_av(std::string vhost) { return true; }
|
||||||
|
virtual std::string get_vhost_http_remux_mount(std::string vhost) { return ""; }
|
||||||
void set_http_hooks_enabled(bool enabled);
|
void set_http_hooks_enabled(bool enabled);
|
||||||
void set_on_stop_urls(const std::vector<std::string> &urls);
|
void set_on_stop_urls(const std::vector<std::string> &urls);
|
||||||
void clear_on_stop_directive();
|
void clear_on_stop_directive();
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,12 @@ void MockLiveSourceForQueue::update_auth(ISrsRequest *r)
|
||||||
// Mock update_auth - do nothing to avoid accessing null req_
|
// Mock update_auth - do nothing to avoid accessing null req_
|
||||||
}
|
}
|
||||||
|
|
||||||
|
srs_error_t MockLiveSourceForQueue::consumer_dumps(ISrsLiveConsumer *consumer, bool ds, bool dm, bool dg)
|
||||||
|
{
|
||||||
|
// Mock consumer_dumps - just return success without doing anything
|
||||||
|
return srs_success;
|
||||||
|
}
|
||||||
|
|
||||||
MockLiveConsumerForQueue::MockLiveConsumerForQueue(MockLiveSourceForQueue *source)
|
MockLiveConsumerForQueue::MockLiveConsumerForQueue(MockLiveSourceForQueue *source)
|
||||||
: SrsLiveConsumer(source)
|
: SrsLiveConsumer(source)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ public:
|
||||||
virtual void on_consumer_destroy(SrsLiveConsumer *consumer);
|
virtual void on_consumer_destroy(SrsLiveConsumer *consumer);
|
||||||
virtual srs_error_t initialize(SrsSharedPtr<SrsLiveSource> wrapper, ISrsRequest *r);
|
virtual srs_error_t initialize(SrsSharedPtr<SrsLiveSource> wrapper, ISrsRequest *r);
|
||||||
virtual void update_auth(ISrsRequest *r);
|
virtual void update_auth(ISrsRequest *r);
|
||||||
|
virtual srs_error_t consumer_dumps(ISrsLiveConsumer *consumer, bool ds, bool dm, bool dg);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Mock live consumer for testing message queue dump_packets
|
// Mock live consumer for testing message queue dump_packets
|
||||||
|
|
|
||||||
|
|
@ -935,7 +935,7 @@ VOID TEST(ProtocolHTTPTest, HTTPServerMuxerBasic)
|
||||||
MockHttpHandler *h1 = new MockHttpHandler("Done");
|
MockHttpHandler *h1 = new MockHttpHandler("Done");
|
||||||
HELPER_ASSERT_SUCCESS(s.handle("/api/", h1));
|
HELPER_ASSERT_SUCCESS(s.handle("/api/", h1));
|
||||||
|
|
||||||
h1->entry->enabled = false;
|
h1->entry_->enabled = false;
|
||||||
|
|
||||||
MockResponseWriter w;
|
MockResponseWriter w;
|
||||||
SrsHttpMessage r(NULL, NULL);
|
SrsHttpMessage r(NULL, NULL);
|
||||||
|
|
@ -1480,7 +1480,7 @@ VOID TEST(ProtocolHTTPTest, VodStreamHandlers)
|
||||||
SrsVodStream h("/tmp");
|
SrsVodStream h("/tmp");
|
||||||
h.set_fs_factory(new MockFileReaderFactory(fs));
|
h.set_fs_factory(new MockFileReaderFactory(fs));
|
||||||
h.set_path(new MockSrsPathAlwaysExists());
|
h.set_path(new MockSrsPathAlwaysExists());
|
||||||
h.entry = &e;
|
h.entry_ = &e;
|
||||||
|
|
||||||
MockResponseWriter w;
|
MockResponseWriter w;
|
||||||
SrsHttpMessage r(NULL, NULL);
|
SrsHttpMessage r(NULL, NULL);
|
||||||
|
|
@ -1503,7 +1503,7 @@ VOID TEST(ProtocolHTTPTest, VodStreamHandlers)
|
||||||
SrsVodStream h("/tmp");
|
SrsVodStream h("/tmp");
|
||||||
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
|
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
|
||||||
h.set_path(new MockSrsPathAlwaysExists());
|
h.set_path(new MockSrsPathAlwaysExists());
|
||||||
h.entry = &e;
|
h.entry_ = &e;
|
||||||
|
|
||||||
MockResponseWriter w;
|
MockResponseWriter w;
|
||||||
SrsHttpMessage r(NULL, NULL);
|
SrsHttpMessage r(NULL, NULL);
|
||||||
|
|
@ -1520,7 +1520,7 @@ VOID TEST(ProtocolHTTPTest, VodStreamHandlers)
|
||||||
SrsVodStream h("/tmp");
|
SrsVodStream h("/tmp");
|
||||||
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
|
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
|
||||||
h.set_path(new MockSrsPathAlwaysExists());
|
h.set_path(new MockSrsPathAlwaysExists());
|
||||||
h.entry = &e;
|
h.entry_ = &e;
|
||||||
|
|
||||||
MockResponseWriter w;
|
MockResponseWriter w;
|
||||||
SrsHttpMessage r(NULL, NULL);
|
SrsHttpMessage r(NULL, NULL);
|
||||||
|
|
@ -1538,7 +1538,7 @@ VOID TEST(ProtocolHTTPTest, VodStreamHandlers)
|
||||||
SrsVodStream h("/tmp");
|
SrsVodStream h("/tmp");
|
||||||
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
|
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
|
||||||
h.set_path(new MockSrsPathAlwaysExists());
|
h.set_path(new MockSrsPathAlwaysExists());
|
||||||
h.entry = &e;
|
h.entry_ = &e;
|
||||||
|
|
||||||
MockResponseWriter w;
|
MockResponseWriter w;
|
||||||
SrsHttpMessage r(NULL, NULL);
|
SrsHttpMessage r(NULL, NULL);
|
||||||
|
|
@ -1556,7 +1556,7 @@ VOID TEST(ProtocolHTTPTest, VodStreamHandlers)
|
||||||
SrsVodStream h("/tmp");
|
SrsVodStream h("/tmp");
|
||||||
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
|
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
|
||||||
h.set_path(new MockSrsPathAlwaysExists());
|
h.set_path(new MockSrsPathAlwaysExists());
|
||||||
h.entry = &e;
|
h.entry_ = &e;
|
||||||
|
|
||||||
MockResponseWriter w;
|
MockResponseWriter w;
|
||||||
SrsHttpMessage r(NULL, NULL);
|
SrsHttpMessage r(NULL, NULL);
|
||||||
|
|
@ -1574,7 +1574,7 @@ VOID TEST(ProtocolHTTPTest, VodStreamHandlers)
|
||||||
SrsVodStream h("/tmp");
|
SrsVodStream h("/tmp");
|
||||||
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
|
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
|
||||||
h.set_path(new MockSrsPathAlwaysExists());
|
h.set_path(new MockSrsPathAlwaysExists());
|
||||||
h.entry = &e;
|
h.entry_ = &e;
|
||||||
|
|
||||||
MockResponseWriter w;
|
MockResponseWriter w;
|
||||||
SrsHttpMessage r(NULL, NULL);
|
SrsHttpMessage r(NULL, NULL);
|
||||||
|
|
@ -1592,7 +1592,7 @@ VOID TEST(ProtocolHTTPTest, VodStreamHandlers)
|
||||||
SrsVodStream h("/tmp");
|
SrsVodStream h("/tmp");
|
||||||
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
|
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
|
||||||
h.set_path(new MockSrsPathAlwaysExists());
|
h.set_path(new MockSrsPathAlwaysExists());
|
||||||
h.entry = &e;
|
h.entry_ = &e;
|
||||||
|
|
||||||
MockResponseWriter w;
|
MockResponseWriter w;
|
||||||
SrsHttpMessage r(NULL, NULL);
|
SrsHttpMessage r(NULL, NULL);
|
||||||
|
|
@ -1614,7 +1614,7 @@ VOID TEST(ProtocolHTTPTest, VodStreamHandlers)
|
||||||
SrsVodStream h("/tmp");
|
SrsVodStream h("/tmp");
|
||||||
h.set_fs_factory(new MockFileReaderFactory("livestream-13.ts"));
|
h.set_fs_factory(new MockFileReaderFactory("livestream-13.ts"));
|
||||||
h.set_path(new MockSrsPathAlwaysExists());
|
h.set_path(new MockSrsPathAlwaysExists());
|
||||||
h.entry = &e;
|
h.entry_ = &e;
|
||||||
|
|
||||||
MockResponseWriter w;
|
MockResponseWriter w;
|
||||||
SrsHttpMessage r(NULL, NULL);
|
SrsHttpMessage r(NULL, NULL);
|
||||||
|
|
@ -1636,7 +1636,7 @@ VOID TEST(ProtocolHTTPTest, VodStreamHandlers)
|
||||||
SrsVodStream h("/tmp");
|
SrsVodStream h("/tmp");
|
||||||
h.set_fs_factory(new MockFileReaderFactory("livestream-13.m4s"));
|
h.set_fs_factory(new MockFileReaderFactory("livestream-13.m4s"));
|
||||||
h.set_path(new MockSrsPathAlwaysExists());
|
h.set_path(new MockSrsPathAlwaysExists());
|
||||||
h.entry = &e;
|
h.entry_ = &e;
|
||||||
|
|
||||||
MockResponseWriter w;
|
MockResponseWriter w;
|
||||||
SrsHttpMessage r(NULL, NULL);
|
SrsHttpMessage r(NULL, NULL);
|
||||||
|
|
@ -1658,7 +1658,7 @@ VOID TEST(ProtocolHTTPTest, VodStreamHandlers)
|
||||||
SrsVodStream h("/tmp");
|
SrsVodStream h("/tmp");
|
||||||
h.set_fs_factory(new MockFileReaderFactory("init.mp4"));
|
h.set_fs_factory(new MockFileReaderFactory("init.mp4"));
|
||||||
h.set_path(new MockSrsPathAlwaysExists());
|
h.set_path(new MockSrsPathAlwaysExists());
|
||||||
h.entry = &e;
|
h.entry_ = &e;
|
||||||
|
|
||||||
MockResponseWriter w;
|
MockResponseWriter w;
|
||||||
SrsHttpMessage r(NULL, NULL);
|
SrsHttpMessage r(NULL, NULL);
|
||||||
|
|
@ -1684,7 +1684,7 @@ VOID TEST(ProtocolHTTPTest, BasicHandlers)
|
||||||
SrsHttpFileServer h("/tmp");
|
SrsHttpFileServer h("/tmp");
|
||||||
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
|
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
|
||||||
h.set_path(new MockSrsPathAlwaysExists());
|
h.set_path(new MockSrsPathAlwaysExists());
|
||||||
h.entry = &e;
|
h.entry_ = &e;
|
||||||
|
|
||||||
MockResponseWriter w;
|
MockResponseWriter w;
|
||||||
SrsHttpMessage r(NULL, NULL);
|
SrsHttpMessage r(NULL, NULL);
|
||||||
|
|
@ -1701,7 +1701,7 @@ VOID TEST(ProtocolHTTPTest, BasicHandlers)
|
||||||
SrsHttpFileServer h("/tmp");
|
SrsHttpFileServer h("/tmp");
|
||||||
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
|
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
|
||||||
h.set_path(new MockSrsPathAlwaysExists());
|
h.set_path(new MockSrsPathAlwaysExists());
|
||||||
h.entry = &e;
|
h.entry_ = &e;
|
||||||
|
|
||||||
MockResponseWriter w;
|
MockResponseWriter w;
|
||||||
SrsHttpMessage r(NULL, NULL);
|
SrsHttpMessage r(NULL, NULL);
|
||||||
|
|
@ -1718,7 +1718,7 @@ VOID TEST(ProtocolHTTPTest, BasicHandlers)
|
||||||
SrsHttpFileServer h("/tmp");
|
SrsHttpFileServer h("/tmp");
|
||||||
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
|
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
|
||||||
h.set_path(new MockSrsPathAlwaysExists());
|
h.set_path(new MockSrsPathAlwaysExists());
|
||||||
h.entry = &e;
|
h.entry_ = &e;
|
||||||
|
|
||||||
MockResponseWriter w;
|
MockResponseWriter w;
|
||||||
SrsHttpMessage r(NULL, NULL);
|
SrsHttpMessage r(NULL, NULL);
|
||||||
|
|
@ -1735,7 +1735,7 @@ VOID TEST(ProtocolHTTPTest, BasicHandlers)
|
||||||
SrsHttpFileServer h("/tmp");
|
SrsHttpFileServer h("/tmp");
|
||||||
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
|
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
|
||||||
h.set_path(new MockSrsPathAlwaysExists());
|
h.set_path(new MockSrsPathAlwaysExists());
|
||||||
h.entry = &e;
|
h.entry_ = &e;
|
||||||
|
|
||||||
MockResponseWriter w;
|
MockResponseWriter w;
|
||||||
SrsHttpMessage r(NULL, NULL);
|
SrsHttpMessage r(NULL, NULL);
|
||||||
|
|
@ -1752,7 +1752,7 @@ VOID TEST(ProtocolHTTPTest, BasicHandlers)
|
||||||
SrsHttpFileServer h("/tmp");
|
SrsHttpFileServer h("/tmp");
|
||||||
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
|
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
|
||||||
h.set_path(new MockSrsPathAlwaysExists());
|
h.set_path(new MockSrsPathAlwaysExists());
|
||||||
h.entry = &e;
|
h.entry_ = &e;
|
||||||
|
|
||||||
MockResponseWriter w;
|
MockResponseWriter w;
|
||||||
SrsHttpMessage r(NULL, NULL);
|
SrsHttpMessage r(NULL, NULL);
|
||||||
|
|
@ -1769,7 +1769,7 @@ VOID TEST(ProtocolHTTPTest, BasicHandlers)
|
||||||
SrsHttpFileServer h("/tmp");
|
SrsHttpFileServer h("/tmp");
|
||||||
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
|
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
|
||||||
h.set_path(new MockSrsPathAlwaysExists());
|
h.set_path(new MockSrsPathAlwaysExists());
|
||||||
h.entry = &e;
|
h.entry_ = &e;
|
||||||
|
|
||||||
MockResponseWriter w;
|
MockResponseWriter w;
|
||||||
SrsHttpMessage r(NULL, NULL);
|
SrsHttpMessage r(NULL, NULL);
|
||||||
|
|
@ -1786,7 +1786,7 @@ VOID TEST(ProtocolHTTPTest, BasicHandlers)
|
||||||
SrsHttpFileServer h("/tmp");
|
SrsHttpFileServer h("/tmp");
|
||||||
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
|
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
|
||||||
h.set_path(new MockSrsPathAlwaysExists());
|
h.set_path(new MockSrsPathAlwaysExists());
|
||||||
h.entry = &e;
|
h.entry_ = &e;
|
||||||
|
|
||||||
MockResponseWriter w;
|
MockResponseWriter w;
|
||||||
SrsHttpMessage r(NULL, NULL);
|
SrsHttpMessage r(NULL, NULL);
|
||||||
|
|
@ -1803,7 +1803,7 @@ VOID TEST(ProtocolHTTPTest, BasicHandlers)
|
||||||
SrsHttpFileServer h("/tmp");
|
SrsHttpFileServer h("/tmp");
|
||||||
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
|
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
|
||||||
h.set_path(new MockSrsPathNotExists());
|
h.set_path(new MockSrsPathNotExists());
|
||||||
h.entry = &e;
|
h.entry_ = &e;
|
||||||
|
|
||||||
MockResponseWriter w;
|
MockResponseWriter w;
|
||||||
SrsHttpMessage r(NULL, NULL);
|
SrsHttpMessage r(NULL, NULL);
|
||||||
|
|
|
||||||
|
|
@ -1302,7 +1302,7 @@ VOID TEST(KernelErrorTest, AsanReportCallback)
|
||||||
#ifdef SRS_SANITIZER_LOG
|
#ifdef SRS_SANITIZER_LOG
|
||||||
// Test asan_report_callback function with various input formats
|
// Test asan_report_callback function with various input formats
|
||||||
// Temporarily disable log output to avoid cluttering test results
|
// Temporarily disable log output to avoid cluttering test results
|
||||||
MockEmptyLog* mock_log = dynamic_cast<MockEmptyLog*>(_srs_log);
|
MockEmptyLog *mock_log = dynamic_cast<MockEmptyLog *>(_srs_log);
|
||||||
SrsLogLevel original_level = mock_log->level_;
|
SrsLogLevel original_level = mock_log->level_;
|
||||||
mock_log->level_ = SrsLogLevelDisabled;
|
mock_log->level_ = SrsLogLevelDisabled;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user