AI: Add utest to cover app http module.

This commit is contained in:
OSSRS-AI 2025-10-04 22:41:09 -04:00 committed by winlin
parent b5664747ac
commit 3948f0d4fe
42 changed files with 3382 additions and 330 deletions

View File

@ -125,6 +125,118 @@ codebase_structure:
description: "Smart pointer definitions for memory management"
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:
standard: "C++98"
description: |

2
trunk/configure vendored
View File

@ -384,7 +384,7 @@ if [[ $SRS_UTEST == YES ]]; then
"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_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
MODULE_FILES+=("srs_utest_srt")
if [[ $SRS_GB28181 == YES ]]; then

View File

@ -43,7 +43,9 @@ public:
virtual ~ISrsAsyncCallWorker();
public:
virtual srs_error_t execute(ISrsAsyncCallTask *t) = 0;
virtual srs_error_t start() = 0;
virtual void stop() = 0;
};
// The async callback for dvr, callback and other async worker.

View File

@ -287,6 +287,7 @@ public:
virtual srs_error_t reload(SrsReloadState *pstate) = 0;
virtual srs_error_t persistence() = 0;
virtual std::string config() = 0;
virtual SrsConfDirective *get_root() = 0;
public:
// Global server config
@ -373,6 +374,7 @@ public:
// Vhost config
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(SrsConfDirective *conf) = 0;
virtual bool get_debug_srs_upnode(std::string vhost) = 0;
virtual int get_out_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_reduce_sequence_header(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.

View File

@ -19,7 +19,7 @@ class SrsBuffer;
class SrsRtmpJitter;
class SrsMediaPacket;
class SrsFileWriter;
class SrsFlvTransmuxer;
class ISrsFlvTransmuxer;
class SrsDvrPlan;
class SrsJsonAny;
class SrsJsonObject;
@ -99,7 +99,7 @@ class SrsDvrFlvSegmenter : public SrsDvrSegmenter
{
private:
// The FLV encoder, for FLV target.
SrsFlvTransmuxer *enc_;
ISrsFlvTransmuxer *enc_;
private:
// The offset of file for duration value.

View File

@ -10,10 +10,10 @@
#include <srs_app_rtmp_source.hpp>
#include <srs_app_st.hpp>
#include <srs_kernel_file.hpp>
#include <srs_kernel_hourglass.hpp>
#include <srs_kernel_ts.hpp>
#include <srs_kernel_utility.hpp>
#include <srs_protocol_st.hpp>
#include <srs_kernel_hourglass.hpp>
SrsAppFactory::SrsAppFactory()
{

View File

@ -707,7 +707,7 @@ srs_error_t SrsGoApiVhosts::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessag
// path: {pattern}{vhost_id}
// 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;
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}
// 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;
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}
// 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;
if (!client_id.empty() && (client = stat->find_client(client_id)) == NULL) {

View File

@ -474,11 +474,12 @@ ISrsKbpsDelta *SrsHttpxConn::delta()
return conn_->delta();
}
SrsHttpServer::SrsHttpServer(SrsServer *svr)
SrsHttpServer::SrsHttpServer()
{
server_ = svr;
http_stream_ = new SrsHttpStreamServer(svr);
http_static_ = new SrsHttpStaticServer(svr);
http_stream_ = new SrsHttpStreamServer();
http_stream_->assemble();
http_static_ = new SrsHttpStaticServer();
}
SrsHttpServer::~SrsHttpServer()

View File

@ -183,12 +183,11 @@ public:
class SrsHttpServer : public ISrsHttpServeMux
{
private:
SrsServer *server_;
SrsHttpStaticServer *http_static_;
SrsHttpStreamServer *http_stream_;
public:
SrsHttpServer(SrsServer *svr);
SrsHttpServer();
virtual ~SrsHttpServer();
public:

View File

@ -599,9 +599,8 @@ srs_error_t SrsVodStream::serve_ts_ctx(ISrsHttpResponseWriter *w, ISrsHttpMessag
return err;
}
SrsHttpStaticServer::SrsHttpStaticServer(SrsServer *svr)
SrsHttpStaticServer::SrsHttpStaticServer()
{
server_ = svr;
_srs_config->subscribe(this);
}

View File

@ -89,14 +89,11 @@ protected:
// serve http static file and flv/mp4 vod stream.
class SrsHttpStaticServer : public ISrsReloadHandler
{
private:
SrsServer *server_;
public:
SrsHttpServeMux mux_;
public:
SrsHttpStaticServer(SrsServer *svr);
SrsHttpStaticServer();
virtual ~SrsHttpStaticServer();
public:

View File

@ -40,15 +40,23 @@ using namespace std;
#include <srs_protocol_stream.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();
queue_ = new SrsMessageQueue(true);
trd_ = new SrsSTCoroutine("http-stream", this);
fast_cache_ = 0;
// TODO: FIXME: support reload.
fast_cache_ = _srs_config->get_vhost_http_remux_fast_cache(req_->vhost_);
server_ = s;
config_ = _srs_config;
live_sources_ = _srs_sources;
}
SrsBufferCache::~SrsBufferCache()
@ -57,6 +65,9 @@ SrsBufferCache::~SrsBufferCache()
srs_freep(queue_);
srs_freep(req_);
config_ = NULL;
live_sources_ = NULL;
}
srs_error_t SrsBufferCache::update_auth(ISrsRequest *r)
@ -71,6 +82,8 @@ srs_error_t SrsBufferCache::start()
{
srs_error_t err = srs_success;
fast_cache_ = config_->get_vhost_http_remux_fast_cache(req_->vhost_);
// Not enabled.
if (fast_cache_ <= 0) {
return err;
@ -109,7 +122,7 @@ bool SrsBufferCache::alive()
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;
@ -133,7 +146,7 @@ srs_error_t SrsBufferCache::cycle()
srs_error_t err = srs_success;
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");
}
srs_assert(live_source.get() != NULL);
@ -214,7 +227,7 @@ SrsTsStreamEncoder::~SrsTsStreamEncoder()
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;
@ -258,7 +271,7 @@ bool SrsTsStreamEncoder::has_cache()
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.
return srs_success;
@ -293,7 +306,7 @@ SrsFlvStreamEncoder::~SrsFlvStreamEncoder()
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;
@ -363,7 +376,7 @@ bool SrsFlvStreamEncoder::has_cache()
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.
return srs_success;
@ -458,7 +471,7 @@ SrsAacStreamEncoder::~SrsAacStreamEncoder()
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;
@ -493,7 +506,7 @@ bool SrsAacStreamEncoder::has_cache()
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_);
return cache_->dump_cache(consumer, jitter);
@ -510,7 +523,7 @@ SrsMp3StreamEncoder::~SrsMp3StreamEncoder()
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;
@ -549,7 +562,7 @@ bool SrsMp3StreamEncoder::has_cache()
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_);
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);
}
SrsLiveStream::SrsLiveStream(SrsServer *s, ISrsRequest *r, SrsBufferCache *c)
ISrsLiveStream::ISrsLiveStream()
{
}
ISrsLiveStream::~ISrsLiveStream()
{
}
SrsLiveStream::SrsLiveStream(ISrsRequest *r, ISrsBufferCache *c)
{
cache_ = c;
req_ = r->copy()->as_http();
security_ = new SrsSecurity();
server_ = s;
config_ = _srs_config;
live_sources_ = _srs_sources;
stat_ = _srs_stat;
hooks_ = _srs_hooks;
}
SrsLiveStream::~SrsLiveStream()
@ -611,6 +636,11 @@ SrsLiveStream::~SrsLiveStream()
// The live stream should never be destroyed when it's serving any viewers.
srs_assert(viewers_.empty());
config_ = NULL;
live_sources_ = NULL;
stat_ = NULL;
hooks_ = NULL;
}
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();
// 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");
}
@ -679,19 +708,19 @@ srs_error_t SrsLiveStream::serve_http_impl(ISrsHttpResponseWriter *w, ISrsHttpMe
}
// 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");
}
// Always try to create the source, because http handler won't create it.
SrsSharedPtr<SrsLiveSource> live_source;
if ((err = _srs_sources->fetch_or_create(req_, live_source)) != srs_success) {
if ((err = live_sources_->fetch_or_create(req_, live_source)) != srs_success) {
return srs_error_wrap(err, "source create");
}
srs_assert(live_source.get() != NULL);
bool enabled_cache = _srs_config->get_gop_cache(req_->vhost_);
int gcmf = _srs_config->get_gop_cache_max_frames(req_->vhost_);
bool enabled_cache = config_->get_gop_cache(req_->vhost_);
int gcmf = config_->get_gop_cache_max_frames(req_->vhost_);
live_source->set_cache(enabled_cache);
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);
// 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");
}
@ -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;
string enc_desc;
ISrsBufferEncoder *enc_raw = NULL;
srs_assert(entry);
bool drop_if_not_match = _srs_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_video = _srs_config->get_vhost_http_remux_has_video(req_->vhost_);
bool guess_has_av = _srs_config->get_vhost_http_remux_guess_has_av(req_->vhost_);
srs_assert(entry_);
bool drop_if_not_match = config_->get_vhost_http_remux_drop_if_not_match(req_->vhost_);
bool has_audio = config_->get_vhost_http_remux_has_audio(req_->vhost_);
bool has_video = config_->get_vhost_http_remux_has_video(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");
enc_desc = "FLV";
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_video(has_video);
((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");
enc_desc = "AAC";
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");
enc_desc = "MP3";
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");
enc_desc = "TS";
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_guess_has_av(guess_has_av);
} 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);
@ -817,14 +846,14 @@ srs_error_t SrsLiveStream::do_serve_http(SrsLiveSource *source, SrsLiveConsumer
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",
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);
// TODO: free and erase the disabled entry after all related connections is closed.
// TODO: FXIME: Support timeout for player, quit infinite-loop.
while (entry->enabled) {
while (entry_->enabled) {
// Whether client closed the FD.
if ((err = trd->pull()) != srs_success) {
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;
if (!_srs_config->get_vhost_http_hooks_enabled(req_->vhost_)) {
if (!config_->get_vhost_http_hooks_enabled(req_->vhost_)) {
return err;
}
@ -896,7 +925,7 @@ srs_error_t SrsLiveStream::http_hooks_on_play(ISrsHttpMessage *r)
vector<string> hooks;
if (true) {
SrsConfDirective *conf = _srs_config->get_vhost_on_play(nreq->vhost_);
SrsConfDirective *conf = config_->get_vhost_on_play(nreq->vhost_);
if (!conf) {
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++) {
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());
}
}
@ -917,7 +946,7 @@ srs_error_t SrsLiveStream::http_hooks_on_play(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;
}
@ -931,7 +960,7 @@ void SrsLiveStream::http_hooks_on_stop(ISrsHttpMessage *r)
vector<string> hooks;
if (true) {
SrsConfDirective *conf = _srs_config->get_vhost_on_stop(nreq->vhost_);
SrsConfDirective *conf = config_->get_vhost_on_stop(nreq->vhost_);
if (!conf) {
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++) {
std::string url = hooks.at(i);
_srs_hooks->on_stop(url, nreq.get());
hooks_->on_stop(url, nreq.get());
}
return;
@ -1017,19 +1046,24 @@ bool SrsLiveEntry::is_mp3()
return is_mp3_;
}
SrsHttpStreamServer::SrsHttpStreamServer(SrsServer *svr)
SrsHttpStreamServer::SrsHttpStreamServer()
{
server_ = svr;
async_ = new SrsAsyncCallWorker();
mux_.add_dynamic_matcher(this);
_srs_config->subscribe(this);
config_ = _srs_config;
}
void SrsHttpStreamServer::assemble()
{
config_->subscribe(this);
}
SrsHttpStreamServer::~SrsHttpStreamServer()
{
mux_.remove_dynamic_matcher(this);
_srs_config->unsubscribe(this);
config_->unsubscribe(this);
async_->stop();
srs_freep(async_);
@ -1050,6 +1084,8 @@ SrsHttpStreamServer::~SrsHttpStreamServer()
}
streamHandlers_.clear();
}
config_ = NULL;
}
srs_error_t SrsHttpStreamServer::initialize()
@ -1098,8 +1134,8 @@ srs_error_t SrsHttpStreamServer::http_mount(ISrsRequest *r)
entry = new SrsLiveEntry(mount);
entry->req_ = r->copy()->as_http();
entry->cache_ = new SrsBufferCache(server_, r);
entry->stream_ = new SrsLiveStream(server_, r, entry->cache_);
entry->cache_ = new SrsBufferCache(r);
entry->stream_ = new SrsLiveStream(r, entry->cache_);
// TODO: FIXME: maybe refine the logic of http remux service.
// if user push streams followed:
@ -1139,7 +1175,7 @@ srs_error_t SrsHttpStreamServer::http_mount(ISrsRequest *r)
}
if (entry->stream_) {
entry->stream_->entry->enabled = true;
entry->stream_->entry_->enabled = true;
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.
ISrsHttpHandler *h = *ph ? *ph : NULL;
if (h && h->entry && h->entry->pattern != "/") {
if (h && h->entry_ && h->entry_->pattern != "/") {
return err;
}
@ -1187,8 +1223,8 @@ srs_error_t SrsHttpStreamServer::dynamic_match(ISrsHttpMessage *request, ISrsHtt
}
// find the actually request vhost.
SrsConfDirective *vhost = _srs_config->get_vhost(request->host());
if (!vhost || !_srs_config->get_vhost_enabled(vhost)) {
SrsConfDirective *vhost = config_->get_vhost(request->host());
if (!vhost || !config_->get_vhost_enabled(vhost)) {
return err;
}
@ -1254,11 +1290,11 @@ srs_error_t SrsHttpStreamServer::dynamic_match(ISrsHttpMessage *request, ISrsHtt
// for example, user disable the http flv then reload.
if (streamHandlers_.find(sid) != streamHandlers_.end()) {
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,
// 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.
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");
}
}
@ -1285,7 +1321,7 @@ srs_error_t SrsHttpStreamServer::initialize_flv_streaming()
srs_error_t err = srs_success;
// 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++) {
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;
if (!_srs_config->get_vhost_http_remux_enabled(vhost)) {
if (!config_->get_vhost_http_remux_enabled(vhost)) {
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;
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);
srs_assert(entry->disposing_);
SrsUniquePtr<SrsLiveStream> stream(entry->stream_);
SrsUniquePtr<SrsBufferCache> cache(entry->cache_);
SrsUniquePtr<ISrsLiveStream> stream(entry->stream_);
SrsUniquePtr<ISrsBufferCache> cache(entry->cache_);
// Notify cache and stream to stop.
if (stream->entry)
stream->entry->enabled = false;
if (stream->entry_)
stream->entry_->enabled = false;
stream->expire();
cache->stop();

View File

@ -16,24 +16,54 @@
class SrsAacTransmuxer;
class SrsMp3Transmuxer;
class SrsFlvTransmuxer;
class ISrsFlvTransmuxer;
class SrsTsTransmuxer;
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.
class SrsBufferCache : public ISrsCoroutineHandler
class SrsBufferCache : public ISrsCoroutineHandler, public ISrsBufferCache
{
private:
srs_utime_t fast_cache_;
SrsServer *server_;
ISrsAppConfig *config_;
ISrsLiveSourceManager *live_sources_;
private:
SrsMessageQueue *queue_;
srs_utime_t fast_cache_;
private:
ISrsMessageQueue *queue_;
ISrsRequest *req_;
ISrsCoroutine *trd_;
public:
SrsBufferCache(SrsServer *s, ISrsRequest *r);
SrsBufferCache(ISrsRequest *r);
virtual ~SrsBufferCache();
virtual srs_error_t update_auth(ISrsRequest *r);
@ -41,7 +71,7 @@ public:
virtual srs_error_t start();
virtual void stop();
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.
public:
virtual srs_error_t cycle();
@ -58,7 +88,7 @@ public:
// Initialize the encoder with file writer(to http response) and stream cache.
// @param w the writer to write to http response.
// @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.
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;
@ -70,14 +100,14 @@ public:
// @return true to use gop cache of encoder; otherwise, use SrsLiveSource.
virtual bool has_cache() = 0;
// 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.
class SrsFlvStreamEncoder : public ISrsBufferEncoder
{
private:
SrsFlvTransmuxer *enc_;
ISrsFlvTransmuxer *enc_;
bool header_written_;
bool has_audio_;
bool has_video_;
@ -88,7 +118,7 @@ public:
virtual ~SrsFlvStreamEncoder();
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_video(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:
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:
// Write the tags in a time.
@ -115,21 +145,21 @@ private:
class SrsTsStreamEncoder : public ISrsBufferEncoder
{
private:
SrsTsTransmuxer *enc_;
ISrsTsTransmuxer *enc_;
public:
SrsTsStreamEncoder();
virtual ~SrsTsStreamEncoder();
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_video(int64_t timestamp, char *data, int size);
virtual srs_error_t write_metadata(int64_t timestamp, char *data, int size);
public:
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:
void set_has_audio(bool v);
@ -141,44 +171,44 @@ public:
class SrsAacStreamEncoder : public ISrsBufferEncoder
{
private:
SrsAacTransmuxer *enc_;
SrsBufferCache *cache_;
ISrsAacTransmuxer *enc_;
ISrsBufferCache *cache_;
public:
SrsAacStreamEncoder();
virtual ~SrsAacStreamEncoder();
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_video(int64_t timestamp, char *data, int size);
virtual srs_error_t write_metadata(int64_t timestamp, char *data, int size);
public:
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.
class SrsMp3StreamEncoder : public ISrsBufferEncoder
{
private:
SrsMp3Transmuxer *enc_;
SrsBufferCache *cache_;
ISrsMp3Transmuxer *enc_;
ISrsBufferCache *cache_;
public:
SrsMp3StreamEncoder();
virtual ~SrsMp3StreamEncoder();
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_video(int64_t timestamp, char *data, int size);
virtual srs_error_t write_metadata(int64_t timestamp, char *data, int size);
public:
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.
@ -204,22 +234,39 @@ public:
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.
// 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:
ISrsRequest *req_;
SrsBufferCache *cache_;
SrsSecurity *security_;
SrsServer *server_;
ISrsBufferCache *cache_;
ISrsSecurity *security_;
// 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
// viewers closed the connection.
std::vector<ISrsExpire *> viewers_;
public:
SrsLiveStream(SrsServer *s, ISrsRequest *r, SrsBufferCache *c);
SrsLiveStream(ISrsRequest *r, ISrsBufferCache *c);
virtual ~SrsLiveStream();
virtual srs_error_t update_auth(ISrsRequest *r);
@ -236,7 +283,7 @@ public:
virtual void expire();
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 void http_hooks_on_stop(ISrsHttpMessage *r);
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.
std::string mount_;
SrsLiveStream *stream_;
SrsBufferCache *cache_;
ISrsLiveStream *stream_;
ISrsBufferCache *cache_;
// Whether is disposing the entry.
bool disposing_;
@ -279,8 +326,10 @@ public:
class SrsHttpStreamServer : public ISrsReloadHandler, public ISrsHttpDynamicMatcher
{
private:
SrsServer *server_;
SrsAsyncCallWorker *async_;
ISrsAppConfig *config_;
private:
ISrsAsyncCallWorker *async_;
public:
SrsHttpServeMux mux_;
@ -290,7 +339,8 @@ public:
std::map<std::string, SrsLiveEntry *> streamHandlers_;
public:
SrsHttpStreamServer(SrsServer *svr);
SrsHttpStreamServer();
void assemble();
virtual ~SrsHttpStreamServer();
public:

View File

@ -224,6 +224,14 @@ void SrsFastVector::free()
}
#endif
ISrsMessageQueue::ISrsMessageQueue()
{
}
ISrsMessageQueue::~ISrsMessageQueue()
{
}
SrsMessageQueue::SrsMessageQueue(bool ignore_shrink)
{
_ignore_shrink = ignore_shrink;
@ -316,7 +324,7 @@ srs_error_t SrsMessageQueue::dump_packets(int max_count, SrsMediaPacket **pmsgs,
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;
@ -404,6 +412,14 @@ ISrsWakable::~ISrsWakable()
{
}
ISrsLiveConsumer::ISrsLiveConsumer()
{
}
ISrsLiveConsumer::~ISrsLiveConsumer()
{
}
SrsLiveConsumer::SrsLiveConsumer(ISrsLiveSource *s)
{
source_ = s;
@ -681,7 +697,7 @@ void SrsGopCache::clear()
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;
@ -1441,7 +1457,7 @@ SrsFormat *SrsMetaCache::ash_format()
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;
@ -2495,7 +2511,7 @@ srs_error_t SrsLiveSource::create_consumer(SrsLiveConsumer *&consumer)
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;

View File

@ -61,6 +61,7 @@ class ISrsHds;
class ISrsNgExec;
class ISrsForwarder;
class SrsAppFactory;
class ISrsLiveConsumer;
// The time jitter algorithm:
// 1. full, to ensure stream start at zero, and ensure stream monotonically increasing.
@ -118,9 +119,26 @@ public:
};
#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.
// We limit the size in seconds, drop old messages(the whole gop) if full.
class SrsMessageQueue
class SrsMessageQueue : public ISrsMessageQueue
{
private:
// The start and end time.
@ -162,7 +180,7 @@ public:
virtual srs_error_t dump_packets(int max_count, SrsMediaPacket **pmsgs, int &count);
// Dumps packets to consumer, use specified args.
// @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:
// Remove a gop from the front.
@ -189,8 +207,22 @@ public:
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.
class SrsLiveConsumer : public ISrsWakable
class SrsLiveConsumer : public ISrsWakable, public ISrsLiveConsumer
{
private:
// Because source references to this object, so we should directly use the source ptr.
@ -297,7 +329,7 @@ public:
// clear the gop cache.
virtual void clear();
// 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,
// The atc will adjust the sequence header timestamp to gop cache.
virtual bool empty();
@ -495,7 +527,7 @@ public:
// Dumps cached metadata to consumer.
// @param dm Whether dumps the metadata.
// @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:
// Previous exists sequence header.
@ -720,7 +752,7 @@ public:
// @param ds, whether dumps the sequence header.
// @param dm, whether dumps the metadata.
// @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 set_cache(bool enabled);
virtual void set_gop_cache_max_frames(int v);

View File

@ -175,7 +175,7 @@ SrsServer::SrsServer()
stream_caster_gb28181_ = new SrsGbListener();
#endif
http_server_ = new SrsHttpServer(this);
http_server_ = new SrsHttpServer();
reuse_api_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);
}
}
return err;
}

View File

@ -258,6 +258,7 @@ public:
virtual srs_error_t dumps_clients(SrsJsonArray *arr, int start, int count);
// Dumps the hints about SRS server.
void dumps_hints_kv(std::stringstream &ss);
private:
virtual SrsStatisticVhost *create_vhost(ISrsRequest *req);
virtual SrsStatisticStream *create_stream(SrsStatisticVhost *vhost, ISrsRequest *req);

View File

@ -22,6 +22,14 @@ using namespace std;
#include <srs_kernel_io.hpp>
#include <srs_kernel_log.hpp>
ISrsAacTransmuxer::ISrsAacTransmuxer()
{
}
ISrsAacTransmuxer::~ISrsAacTransmuxer()
{
}
SrsAacTransmuxer::SrsAacTransmuxer()
{
writer_ = NULL;

View File

@ -16,8 +16,19 @@
class SrsBuffer;
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.
class SrsAacTransmuxer
class SrsAacTransmuxer : public ISrsAacTransmuxer
{
private:
ISrsStreamWriter *writer_;

View File

@ -29,6 +29,7 @@ public:
public:
virtual srs_error_t open(std::string p) = 0;
virtual void close() = 0;
virtual bool is_open() = 0;
};
// file writer, to write to file.
@ -89,6 +90,13 @@ public:
public:
virtual srs_error_t open(std::string p) = 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;
};
/**

View File

@ -331,6 +331,14 @@ void SrsRtmpCommonMessage::to_msg(SrsMediaPacket *msg)
msg->message_type_ = (SrsFrameType)header_.message_type_;
}
ISrsFlvTransmuxer::ISrsFlvTransmuxer()
{
}
ISrsFlvTransmuxer::~ISrsFlvTransmuxer()
{
}
SrsFlvTransmuxer::SrsFlvTransmuxer()
{
writer_ = NULL;
@ -777,7 +785,7 @@ srs_error_t SrsFlvVodStreamDecoder::initialize(ISrsReader *fr)
srs_error_t err = srs_success;
srs_assert(fr);
reader_ = dynamic_cast<SrsFileReader *>(fr);
reader_ = dynamic_cast<ISrsFileReader *>(fr);
if (!reader_) {
return srs_error_new(ERROR_EXPECT_FILE_IO, "stream is not file io");
}

View File

@ -25,7 +25,7 @@
class SrsBuffer;
class ISrsWriter;
class ISrsReader;
class SrsFileReader;
class ISrsFileReader;
class SrsRtmpCommand;
class SrsNaluSample;
@ -223,8 +223,50 @@ public:
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.
class SrsFlvTransmuxer
class SrsFlvTransmuxer : public ISrsFlvTransmuxer
{
private:
bool has_audio_;
@ -335,7 +377,7 @@ public:
class SrsFlvVodStreamDecoder
{
private:
SrsFileReader *reader_;
ISrsFileReader *reader_;
public:
SrsFlvVodStreamDecoder();

View File

@ -56,6 +56,7 @@ SrsPps::SrsPps()
SrsPps::~SrsPps()
{
clk_ = NULL;
}
void SrsPps::update()
@ -102,6 +103,14 @@ int SrsPps::r30s()
return sample_30s_.rate_;
}
ISrsClock::ISrsClock()
{
}
ISrsClock::~ISrsClock()
{
}
SrsWallClock::SrsWallClock()
{
}
@ -548,7 +557,7 @@ void srs_global_rtc_update(SrsKbsRtcStats *stats)
}
}
SrsKbpsSlice::SrsKbpsSlice(SrsWallClock *c)
SrsKbpsSlice::SrsKbpsSlice(ISrsClock *c)
{
clk_ = c;
starttime_ = 0;
@ -557,6 +566,7 @@ SrsKbpsSlice::SrsKbpsSlice(SrsWallClock *c)
SrsKbpsSlice::~SrsKbpsSlice()
{
clk_ = NULL;
}
void SrsKbpsSlice::sample()
@ -674,7 +684,7 @@ void SrsNetworkDelta::remark(int64_t *in, int64_t *out)
in_delta_ = out_delta_ = 0;
}
SrsKbps::SrsKbps(SrsWallClock *c)
SrsKbps::SrsKbps(ISrsClock *c)
{
clk_ = c ? c : _srs_clock;
is_ = new SrsKbpsSlice(clk_);
@ -685,6 +695,7 @@ SrsKbps::~SrsKbps()
{
srs_freep(is_);
srs_freep(os_);
clk_ = NULL;
}
int SrsKbps::get_send_kbps()
@ -764,7 +775,7 @@ int64_t SrsKbps::get_recv_bytes()
return is_->bytes_;
}
SrsNetworkKbps::SrsNetworkKbps(SrsWallClock *clock)
SrsNetworkKbps::SrsNetworkKbps(ISrsClock *clock)
{
delta_ = new SrsNetworkDelta();
kbps_ = new SrsKbps(clock);

View File

@ -13,9 +13,44 @@
#include <string>
class SrsWallClock;
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.
class SrsRateSample
{
@ -37,7 +72,7 @@ public:
class SrsPps
{
private:
SrsWallClock *clk_;
ISrsClock *clk_;
private:
// samples
@ -66,25 +101,6 @@ public:
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
// I/O operations statistics
extern SrsPps *_srs_pps_recvfrom;
@ -237,7 +253,7 @@ void srs_global_rtc_update(SrsKbsRtcStats *stats);
class SrsKbpsSlice
{
private:
SrsWallClock *clk_;
ISrsClock *clk_;
public:
// session startup bytes
@ -252,7 +268,7 @@ public:
SrsRateSample sample_60m_;
public:
SrsKbpsSlice(SrsWallClock *c);
SrsKbpsSlice(ISrsClock *c);
virtual ~SrsKbpsSlice();
public:
@ -340,11 +356,11 @@ class SrsKbps
private:
SrsKbpsSlice *is_;
SrsKbpsSlice *os_;
SrsWallClock *clk_;
ISrsClock *clk_;
public:
// Note that we won't free the clock c.
SrsKbps(SrsWallClock *c = NULL);
SrsKbps(ISrsClock *c = NULL);
virtual ~SrsKbps();
public:
@ -378,7 +394,7 @@ private:
SrsKbps *kbps_;
public:
SrsNetworkKbps(SrsWallClock *c = NULL);
SrsNetworkKbps(ISrsClock *c = NULL);
virtual ~SrsNetworkKbps();
public:

View File

@ -21,6 +21,14 @@ using namespace std;
#include <srs_kernel_file.hpp>
#include <srs_kernel_log.hpp>
ISrsMp3Transmuxer::ISrsMp3Transmuxer()
{
}
ISrsMp3Transmuxer::~ISrsMp3Transmuxer()
{
}
SrsMp3Transmuxer::SrsMp3Transmuxer()
{
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;

View File

@ -12,15 +12,28 @@
#include <string>
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.
*/
class SrsMp3Transmuxer
class SrsMp3Transmuxer : public ISrsMp3Transmuxer
{
private:
SrsFileWriter *writer_;
ISrsFileWriter *writer_;
public:
SrsMp3Transmuxer();
@ -32,7 +45,7 @@ public:
* @remark user can initialize multiple times to encode multiple mp3 files.
* @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:
/**

View File

@ -352,6 +352,14 @@ srs_error_t SrsParsedVideoPacket::parse_hevc_bframe(const SrsNaluSample *sample,
return err;
}
ISrsFormat::ISrsFormat()
{
}
ISrsFormat::~ISrsFormat()
{
}
SrsFormat::SrsFormat()
{
acodec_ = NULL;
@ -482,6 +490,26 @@ bool SrsFormat::is_avc_sequence_header()
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.
int srs_rbsp_remove_emulation_bytes(SrsBuffer *stream, std::vector<uint8_t> &rbsp)
{

View File

@ -162,11 +162,49 @@ public:
};
/**
* Interface for codec format.
* 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
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:
SrsParsedAudioPacket *audio_;
@ -207,6 +245,13 @@ public:
// TODO: is avc|hevc|av1 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:
// Demux the video packet in H.264 codec.
// The packet is muxed in FLV format, defined in flv specification.

View File

@ -311,6 +311,14 @@ ISrsTsHandler::~ISrsTsHandler()
{
}
ISrsTsContext::ISrsTsContext()
{
}
ISrsTsContext::~ISrsTsContext()
{
}
SrsTsContext::SrsTsContext()
{
ready_ = false;
@ -652,7 +660,7 @@ srs_error_t SrsTsContext::encode_pes(ISrsStreamWriter *writer, SrsTsMessage *msg
return err;
}
SrsTsPacket::SrsTsPacket(SrsTsContext *c)
SrsTsPacket::SrsTsPacket(ISrsTsContext *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);
pkt->sync_byte_ = 0x47;
@ -863,7 +871,7 @@ SrsTsPacket *SrsTsPacket::create_pat(SrsTsContext *context, int16_t pmt_number,
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)
{
SrsTsPacket *pkt = new SrsTsPacket(context);
@ -915,7 +923,7 @@ SrsTsPacket *SrsTsPacket::create_pmt(SrsTsContext *context,
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,
int64_t pcr, int64_t dts, int64_t pts, int size)
{
@ -974,7 +982,7 @@ SrsTsPacket *SrsTsPacket::create_pes_first(SrsTsContext *context,
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);
pkt->sync_byte_ = 0x47;
@ -2757,7 +2765,15 @@ srs_error_t SrsTsPayloadPMT::psi_encode(SrsBuffer *stream)
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;
context_ = c;
@ -2905,6 +2921,14 @@ void SrsEncFileWriter::close()
SrsFileWriter::close();
}
ISrsTsMessageCache::ISrsTsMessageCache()
{
}
ISrsTsMessageCache::~ISrsTsMessageCache()
{
}
SrsTsMessageCache::SrsTsMessageCache()
{
audio_ = NULL;
@ -2979,6 +3003,26 @@ srs_error_t SrsTsMessageCache::cache_video(SrsParsedVideoPacket *frame, int64_t
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 err = srs_success;
@ -3246,31 +3290,39 @@ srs_error_t SrsTsMessageCache::do_cache_hevc(SrsParsedVideoPacket *frame)
return err;
}
ISrsTsTransmuxer::ISrsTsTransmuxer()
{
}
ISrsTsTransmuxer::~ISrsTsTransmuxer()
{
}
SrsTsTransmuxer::SrsTsTransmuxer()
{
writer = NULL;
format = new SrsFormat();
tsmc = new SrsTsMessageCache();
context = new SrsTsContext();
tscw = NULL;
writer_ = NULL;
format_ = new SrsFormat();
tsmc_ = new SrsTsMessageCache();
context_ = new SrsTsContext();
tscw_ = NULL;
has_audio_ = has_video_ = true;
guess_has_av_ = true;
}
SrsTsTransmuxer::~SrsTsTransmuxer()
{
srs_freep(format);
srs_freep(tsmc);
srs_freep(tscw);
srs_freep(context);
srs_freep(format_);
srs_freep(tsmc_);
srs_freep(tscw_);
srs_freep(context_);
}
void SrsTsTransmuxer::set_has_audio(bool v)
{
has_audio_ = v;
if (tscw != NULL && !v) {
tscw->set_acodec(SrsAudioCodecIdForbidden);
if (tscw_ != NULL && !v) {
tscw_->set_acodec(SrsAudioCodecIdForbidden);
}
}
@ -3278,17 +3330,17 @@ void SrsTsTransmuxer::set_has_video(bool v)
{
has_video_ = v;
if (tscw != NULL && !v) {
tscw->set_vcodec(SrsVideoCodecIdForbidden);
if (tscw_ != NULL && !v) {
tscw_->set_vcodec(SrsVideoCodecIdForbidden);
}
}
void SrsTsTransmuxer::set_guess_has_av(bool v)
{
guess_has_av_ = v;
if (tscw != NULL && v) {
tscw->set_acodec(SrsAudioCodecIdForbidden);
tscw->set_vcodec(SrsVideoCodecIdForbidden);
if (tscw_ != NULL && v) {
tscw_->set_acodec(SrsAudioCodecIdForbidden);
tscw_->set_vcodec(SrsVideoCodecIdForbidden);
}
}
@ -3296,13 +3348,13 @@ srs_error_t SrsTsTransmuxer::initialize(ISrsStreamWriter *fw)
{
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");
}
srs_assert(fw);
writer = fw;
writer_ = fw;
SrsAudioCodecId acodec = has_audio_ ? SrsAudioCodecIdAAC : SrsAudioCodecIdForbidden;
SrsVideoCodecId vcodec = has_video_ ? SrsVideoCodecIdAVC : SrsVideoCodecIdForbidden;
@ -3312,8 +3364,8 @@ srs_error_t SrsTsTransmuxer::initialize(ISrsStreamWriter *fw)
vcodec = SrsVideoCodecIdForbidden;
}
srs_freep(tscw);
tscw = new SrsTsContextWriter(fw, context, acodec, vcodec);
srs_freep(tscw_);
tscw_ = new SrsTsContextWriter(fw, context_, acodec, vcodec);
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;
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");
}
if (!format->acodec_) {
if (!format_->acodec()) {
return err;
}
// ts support audio codec: aac/mp3
srs_assert(format->acodec_ && format->audio_);
if (format->acodec_->id_ != SrsAudioCodecIdAAC && format->acodec_->id_ != SrsAudioCodecIdMP3) {
srs_assert(format_->acodec() && format_->audio());
if (format_->acodec()->id_ != SrsAudioCodecIdAAC && format_->acodec()->id_ != SrsAudioCodecIdMP3) {
return err;
}
// 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;
}
// Switch audio codec if not AAC.
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(),
format->acodec_->id_, srs_audio_codec_id2str(format->acodec_->id_).c_str());
tscw->set_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(),
format_->acodec()->id_, srs_audio_codec_id2str(format_->acodec()->id_).c_str());
tscw_->set_acodec(format_->acodec()->id_);
}
// 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;
// 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");
}
@ -3369,39 +3421,39 @@ srs_error_t SrsTsTransmuxer::write_video(int64_t timestamp, char *data, int size
{
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");
}
if (!format->vcodec_) {
if (!format_->vcodec()) {
return err;
}
// ignore info frame,
// @see https://github.com/ossrs/srs/issues/288#issuecomment-69863909
srs_assert(format->video_ && format->vcodec_);
if (format->video_->frame_type_ == SrsVideoAvcFrameTypeVideoInfoFrame) {
srs_assert(format_->video() && format_->vcodec());
if (format_->video()->frame_type_ == SrsVideoAvcFrameTypeVideoInfoFrame) {
return err;
}
bool codec_ok = (format->vcodec_->id_ == SrsVideoCodecIdAVC);
codec_ok = codec_ok ? true : (format->vcodec_->id_ == SrsVideoCodecIdHEVC);
bool codec_ok = (format_->vcodec()->id_ == SrsVideoCodecIdAVC);
codec_ok = codec_ok ? true : (format_->vcodec()->id_ == SrsVideoCodecIdHEVC);
if (!codec_ok) {
return err;
}
// The video codec might change during streaming.
tscw->set_vcodec(format->vcodec_->id_);
tscw_->set_vcodec(format_->vcodec()->id_);
// 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;
}
int64_t dts = timestamp * 90;
// 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");
}
@ -3412,12 +3464,14 @@ srs_error_t SrsTsTransmuxer::flush_audio()
{
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");
}
// 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;
}
@ -3426,12 +3480,14 @@ srs_error_t SrsTsTransmuxer::flush_video()
{
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");
}
// 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;
}

View File

@ -19,15 +19,19 @@
class SrsBuffer;
class SrsTsMessageCache;
class ISrsTsMessageCache;
class SrsTsContextWriter;
class ISrsTsContextWriter;
class ISrsStreamWriter;
class SrsFileReader;
class SrsFormat;
class ISrsFormat;
class SrsSimpleStream;
class SrsTsAdaptationField;
class SrsTsPayload;
class SrsTsMessage;
class SrsTsPacket;
class ISrsTsContext;
class SrsTsContext;
class SrsPsPacket;
@ -142,7 +146,7 @@ struct SrsTsChannel {
SrsTsPidApply apply_;
SrsTsStream stream_;
SrsTsMessage *msg_;
SrsTsContext *context_;
ISrsTsContext *context_;
// for encoder.
uint8_t continuity_counter_;
@ -291,8 +295,48 @@ public:
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.
class SrsTsContext
class SrsTsContext : public ISrsTsContext
{
private:
// Whether context is ready, failed if try to write data when not ready.
@ -432,10 +476,10 @@ private:
SrsTsPayload *payload_;
public:
SrsTsContext *context_;
ISrsTsContext *context_;
public:
SrsTsPacket(SrsTsContext *c);
SrsTsPacket(ISrsTsContext *c);
virtual ~SrsTsPacket();
public:
@ -447,12 +491,12 @@ public:
virtual void padding(int nb_stuffings);
public:
static SrsTsPacket *create_pat(SrsTsContext *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_pat(ISrsTsContext *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);
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);
static SrsTsPacket *create_pes_continue(SrsTsContext *context,
static SrsTsPacket *create_pes_continue(ISrsTsContext *context,
int16_t pid, SrsTsPESStreamId sid, uint8_t continuity_counter);
};
@ -1295,8 +1339,32 @@ protected:
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.
class SrsTsContextWriter
class SrsTsContextWriter : public ISrsTsContextWriter
{
private:
// User must config the codec in right way.
@ -1304,12 +1372,12 @@ private:
SrsAudioCodecId acodec_;
private:
SrsTsContext *context_;
ISrsTsContext *context_;
ISrsStreamWriter *writer_;
std::string path_;
public:
SrsTsContextWriter(ISrsStreamWriter *w, SrsTsContext *c, SrsAudioCodecId ac, SrsVideoCodecId vc);
SrsTsContextWriter(ISrsStreamWriter *w, ISrsTsContext *c, SrsAudioCodecId ac, SrsVideoCodecId vc);
virtual ~SrsTsContextWriter();
public:
@ -1352,9 +1420,32 @@ private:
int nb_buf;
};
// Interface for TS messages cache.
// TS messages cache, to group frames to 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:
// The current ts message.
@ -1371,6 +1462,13 @@ public:
// Write video to muxer.
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:
virtual srs_error_t do_cache_mp3(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);
};
// 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.
class SrsTsTransmuxer
class SrsTsTransmuxer : public ISrsTsTransmuxer
{
private:
ISrsStreamWriter *writer;
ISrsStreamWriter *writer_;
bool has_audio_;
bool has_video_;
bool guess_has_av_;
private:
SrsFormat *format;
SrsTsMessageCache *tsmc;
SrsTsContextWriter *tscw;
SrsTsContext *context;
ISrsFormat *format_;
ISrsTsMessageCache *tsmc_;
ISrsTsContextWriter *tscw_;
ISrsTsContext *context_;
public:
SrsTsTransmuxer();

View File

@ -55,7 +55,7 @@ private:
// The underlayer st fd handler.
srs_netfd_t stfd_;
// The underlayer socket.
SrsStSocket *skt_;
ISrsProtocolReadWriter *skt_;
public:
SrsTcpConnection(srs_netfd_t c);

View File

@ -438,7 +438,7 @@ ISrsHttpRequestWriter::~ISrsHttpRequestWriter()
ISrsHttpHandler::ISrsHttpHandler()
{
entry = NULL;
entry_ = NULL;
}
ISrsHttpHandler::~ISrsHttpHandler()
@ -555,25 +555,25 @@ void SrsHttpFileServer::set_path(SrsPath *v)
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.
SrsHttpHeader *hdr = w->header();
hdr->set("Connection", "Close");
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;
string basename = path.filepath_base(upath);
// stat current dir, if exists, return error.
if (!path_->exists(fullpath)) {
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);
}
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.
// 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->handler = handler;
entry->pattern = pattern;
entry->handler->entry = entry;
entry->handler->entry_ = entry;
if (static_matchers_.find(pattern) != static_matchers_.end()) {
SrsHttpMuxEntry *exists = static_matchers_[pattern];
@ -908,7 +908,7 @@ srs_error_t SrsHttpServeMux::handle(std::string pattern, ISrsHttpHandler *handle
entry->explicit_match = false;
entry->handler = new SrsHttpRedirectHandler(pattern, SRS_CONSTS_HTTP_Found);
entry->pattern = pattern;
entry->handler->entry = entry;
entry->handler->entry_ = entry;
static_matchers_[rpattern] = entry;
}

View File

@ -290,7 +290,7 @@ public:
class ISrsHttpHandler
{
public:
SrsHttpMuxEntry *entry;
SrsHttpMuxEntry *entry_;
public:
ISrsHttpHandler();

View File

@ -7,25 +7,25 @@
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_source.hpp>
#include <srs_app_security.hpp>
#include <srs_app_http_hooks.hpp>
#include <srs_kernel_error.hpp>
#include <srs_kernel_utility.hpp>
#include <srs_app_server.hpp>
#include <srs_app_utility.hpp>
#include <srs_kernel_consts.hpp>
#include <srs_kernel_error.hpp>
#include <srs_kernel_hourglass.hpp>
#include <srs_app_factory.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_st.hpp>
#include <srs_utest_app6.hpp>
#include <srs_utest_app9.hpp>
#include <srs_app_utility.hpp>
#include <algorithm>
#include <sys/socket.h>
#include <srs_protocol_st.hpp>
#include <srs_protocol_json.hpp>
// Mock config implementation for SrsServer::listen() testing
MockAppConfigForServerListen::MockAppConfigForServerListen()
@ -265,14 +265,14 @@ VOID TEST(SrsServerTest, HttpHandleSuccess)
srs_error_t err = srs_success;
// Create mock HTTP API mux
MockHttpServeMux* mock_mux = new MockHttpServeMux();
MockHttpServeMux *mock_mux = new MockHttpServeMux();
// Create SrsServer instance
SrsUniquePtr<SrsServer> server(new SrsServer());
EXPECT_TRUE(server.get() != NULL);
// 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;
// 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;
for (size_t i = 0; i < mock_mux->patterns_.size(); i++) {
if (mock_mux->patterns_[i] == "/") has_root = true;
if (mock_mux->patterns_[i] == "/api/") has_api = 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;
if (mock_mux->patterns_[i] == "/")
has_root = true;
if (mock_mux->patterns_[i] == "/api/")
has_api = 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);
@ -370,13 +375,13 @@ VOID TEST(ServerTest, OnSignalHandling)
EXPECT_TRUE(server.get() != NULL);
// Create and inject mock config
MockAppConfigForSignal* mock_config = new MockAppConfigForSignal();
ISrsAppConfig* original_config = server->config_;
MockAppConfigForSignal *mock_config = new MockAppConfigForSignal();
ISrsAppConfig *original_config = server->config_;
server->config_ = mock_config;
// Create and inject mock log
MockLogForSignal* mock_log = new MockLogForSignal();
ISrsLog* original_log = server->log_;
MockLogForSignal *mock_log = new MockLogForSignal();
ISrsLog *original_log = server->log_;
server->log_ = mock_log;
// Test 1: SRS_SIGNAL_RELOAD should set signal_reload_ flag
@ -484,8 +489,8 @@ VOID TEST(ServerTest, Do2CycleReloadSuccess)
EXPECT_TRUE(server.get() != NULL);
// Create and inject mock config
MockAppConfigForDo2Cycle* mock_config = new MockAppConfigForDo2Cycle();
ISrsAppConfig* original_config = server->config_;
MockAppConfigForDo2Cycle *mock_config = new MockAppConfigForDo2Cycle();
ISrsAppConfig *original_config = server->config_;
server->config_ = mock_config;
// Test major use scenario: signal_reload_ triggers config reload with success
@ -495,8 +500,8 @@ VOID TEST(ServerTest, Do2CycleReloadSuccess)
server->signal_gracefully_quit_ = false;
mock_config->reload_state_ = SrsReloadStateFinished;
HELPER_EXPECT_SUCCESS(server->do2_cycle());
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_FALSE(server->signal_reload_); // Flag should be cleared after processing
EXPECT_EQ(1, mock_config->reload_count_); // Config reload should be called once
// Cleanup: restore original config
server->config_ = original_config;
@ -595,13 +600,13 @@ VOID TEST(ServerTest, SetupTicksWithStatsAndHeartbeat)
EXPECT_TRUE(server.get() != NULL);
// Create and inject mock config
MockAppConfigForSetupTicks* mock_config = new MockAppConfigForSetupTicks();
ISrsAppConfig* original_config = server->config_;
MockAppConfigForSetupTicks *mock_config = new MockAppConfigForSetupTicks();
ISrsAppConfig *original_config = server->config_;
server->config_ = mock_config;
// Create and inject mock app factory
MockAppFactoryForSetupTicks* mock_factory = new MockAppFactoryForSetupTicks();
SrsAppFactory* original_factory = server->app_factory_;
MockAppFactoryForSetupTicks *mock_factory = new MockAppFactoryForSetupTicks();
SrsAppFactory *original_factory = server->app_factory_;
server->app_factory_ = mock_factory;
// Test major use scenario: setup_ticks with stats and heartbeat enabled
@ -783,12 +788,12 @@ VOID TEST(SrsServerTest, NotifyEventDispatch)
SrsUniquePtr<SrsServer> server(new SrsServer());
// Create mock objects
MockRtcSessionManagerForNotify* mock_rtc_manager = new MockRtcSessionManagerForNotify();
MockHttpHeartbeatForNotify* mock_heartbeat = new MockHttpHeartbeatForNotify();
MockRtcSessionManagerForNotify *mock_rtc_manager = new MockRtcSessionManagerForNotify();
MockHttpHeartbeatForNotify *mock_heartbeat = new MockHttpHeartbeatForNotify();
// Save original pointers
SrsRtcSessionManager* original_rtc_manager = server->rtc_session_manager_;
SrsHttpHeartbeat* original_heartbeat = server->http_heartbeat_;
SrsRtcSessionManager *original_rtc_manager = server->rtc_session_manager_;
SrsHttpHeartbeat *original_heartbeat = server->http_heartbeat_;
// Inject mock objects (no cast needed since they inherit from the base classes)
server->rtc_session_manager_ = mock_rtc_manager;
@ -1234,7 +1239,7 @@ int64_t MockRtmpTransportForDoCycle::get_send_bytes()
VOID TEST(SrsRtmpConnTest, ConstructorAndAssemble)
{
// 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);
// Prevent destructor from closing dummy fd
transport->skt_->stfd_ = NULL;
@ -1344,7 +1349,7 @@ VOID TEST(SrsRtmpTransportTest, BasicOperations)
// 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
srs_netfd_t dummy_fd = (srs_netfd_t)((void*)0x1234);
srs_netfd_t dummy_fd = (srs_netfd_t)((void *)0x1234);
// Create SrsRtmpTransport instance
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)
*ppacket = decode_message_packet_;
decode_message_packet_ = NULL; // Transfer ownership
decode_message_packet_ = NULL; // Transfer ownership
return srs_success;
}
@ -1731,7 +1736,7 @@ VOID TEST(SrsUtilityTest, GetCpuInfo)
VOID TEST(SrsUtilityTest, UpdateDiskStat)
{
// 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;
// Test case 1: First call to srs_update_disk_stat() - should initialize the stat
@ -1740,11 +1745,9 @@ VOID TEST(SrsUtilityTest, UpdateDiskStat)
if (true) {
srs_update_disk_stat();
SrsDiskStat* stat = srs_get_disk_stat();
SrsDiskStat *stat = srs_get_disk_stat();
EXPECT_TRUE(stat->ok_);
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)
EXPECT_EQ(0.0f, stat->busy_);
}
@ -1764,7 +1767,7 @@ VOID TEST(SrsUtilityTest, UpdateDiskStat)
// Call srs_update_disk_stat() again to calculate deltas
srs_update_disk_stat();
SrsDiskStat* stat = srs_get_disk_stat();
SrsDiskStat *stat = srs_get_disk_stat();
EXPECT_TRUE(stat->ok_);
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_
// 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_ <= 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
// This tests the specific calculation logic for vmstat and diskstats
if (true) {
// 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
SrsDiskStat prev = *current;
prev.sample_time_ = current->sample_time_ - 1000; // 1 second ago
prev.pgpgin_ = 1000; // 1000 KB read
prev.pgpgout_ = 2000; // 2000 KB written
prev.ticks_ = 100; // 100 ticks
prev.sample_time_ = current->sample_time_ - 1000; // 1 second ago
prev.pgpgin_ = 1000; // 1000 KB read
prev.pgpgout_ = 2000; // 2000 KB written
prev.ticks_ = 100; // 100 ticks
prev.cpu_.ok_ = true;
prev.cpu_.user_ = 1000;
prev.cpu_.sys_ = 500;
@ -1805,8 +1808,8 @@ VOID TEST(SrsUtilityTest, UpdateDiskStat)
SrsDiskStat next = *current;
next.sample_time_ = current->sample_time_;
next.pgpgin_ = 2000; // 1000 KB more read
next.pgpgout_ = 4000; // 2000 KB more written
next.ticks_ = 200; // 100 ticks more
next.pgpgout_ = 4000; // 2000 KB more written
next.ticks_ = 200; // 100 ticks more
next.cpu_.ok_ = true;
next.cpu_.user_ = 1100;
next.cpu_.sys_ = 600;
@ -1829,7 +1832,7 @@ VOID TEST(SrsUtilityTest, UpdateDiskStat)
// Verify diskstats busy calculation formula
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_) {
// delta_ms = cpu_.total_delta_ * 10 / 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)
SrsSharedPtr<SrsLiveSource> source(new MockLiveSource());
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
err = conn->acquire_publish(source);
@ -2287,7 +2290,7 @@ VOID TEST(SrsRtmpConnTest, AcquirePublishStreamBusyCheck)
srs_freep(err);
// 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
srs_freep(mock_config);
@ -2347,7 +2350,7 @@ VOID TEST(SrsRtmpConnTest, HandlePublishMessageVideoSuccess)
EXPECT_EQ(0, mock_rtmp->decode_message_count_);
// 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
srs_freep(mock_config);
@ -2682,7 +2685,7 @@ VOID TEST(SrsRtmpConnTest, HttpHooksOnConnect)
// Restore original hooks
conn->hooks_ = original_hooks;
} // conn is destroyed here
} // conn is destroyed here
// Now safe to delete mock objects
srs_freep(mock_hooks);
@ -2757,7 +2760,7 @@ VOID TEST(SrsRtmpConnTest, ProcessPlayControlMsgPauseSuccess)
EXPECT_EQ(true, consumer->last_pause_state_);
// 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
srs_freep(mock_config);
@ -2811,8 +2814,8 @@ VOID TEST(SrsRtmpConnTest, HttpHooksOnClose)
// 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_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].recv_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
// Verify the second call
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,
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;
}
@ -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,
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;
}
@ -3326,9 +3329,6 @@ VOID TEST(UtilityTest, GetProcSelfStatSuccess)
EXPECT_TRUE(stat.state_ == 'R' || stat.state_ == 'S' || stat.state_ == 'D' ||
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)
EXPECT_TRUE(stat.num_threads_ >= 1);

View File

@ -11,14 +11,15 @@
#include <srs_utest_app10.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_rtc_server.hpp>
#include <srs_app_heartbeat.hpp>
#include <srs_app_rtc_server.hpp>
#include <srs_app_rtmp_conn.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()
class MockAppConfigForServerListen : public MockAppConfig
@ -416,7 +417,7 @@ class MockRtmpServerForHandlePublishMessage : public ISrsRtmpServer
{
public:
srs_error_t decode_message_error_;
SrsRtmpCommand* decode_message_packet_;
SrsRtmpCommand *decode_message_packet_;
int decode_message_count_;
srs_error_t fmle_unpublish_error_;
int fmle_unpublish_count_;
@ -461,7 +462,7 @@ public:
class MockRtmpServerForPlayControl : public ISrsRtmpServer
{
public:
SrsRtmpCommand* decode_message_packet_;
SrsRtmpCommand *decode_message_packet_;
int decode_message_count_;
int send_and_free_packet_count_;
int on_play_client_pause_count_;

File diff suppressed because it is too large Load Diff

View 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

View File

@ -383,6 +383,16 @@ public:
virtual bool get_atc_auto(std::string vhost);
virtual bool get_reduce_sequence_header(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_on_stop_urls(const std::vector<std::string> &urls);
void clear_on_stop_directive();

View File

@ -70,6 +70,12 @@ void MockLiveSourceForQueue::update_auth(ISrsRequest *r)
// 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)
: SrsLiveConsumer(source)
{

View File

@ -47,6 +47,7 @@ public:
virtual void on_consumer_destroy(SrsLiveConsumer *consumer);
virtual srs_error_t initialize(SrsSharedPtr<SrsLiveSource> wrapper, 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

View File

@ -935,7 +935,7 @@ VOID TEST(ProtocolHTTPTest, HTTPServerMuxerBasic)
MockHttpHandler *h1 = new MockHttpHandler("Done");
HELPER_ASSERT_SUCCESS(s.handle("/api/", h1));
h1->entry->enabled = false;
h1->entry_->enabled = false;
MockResponseWriter w;
SrsHttpMessage r(NULL, NULL);
@ -1480,7 +1480,7 @@ VOID TEST(ProtocolHTTPTest, VodStreamHandlers)
SrsVodStream h("/tmp");
h.set_fs_factory(new MockFileReaderFactory(fs));
h.set_path(new MockSrsPathAlwaysExists());
h.entry = &e;
h.entry_ = &e;
MockResponseWriter w;
SrsHttpMessage r(NULL, NULL);
@ -1503,7 +1503,7 @@ VOID TEST(ProtocolHTTPTest, VodStreamHandlers)
SrsVodStream h("/tmp");
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
h.set_path(new MockSrsPathAlwaysExists());
h.entry = &e;
h.entry_ = &e;
MockResponseWriter w;
SrsHttpMessage r(NULL, NULL);
@ -1520,7 +1520,7 @@ VOID TEST(ProtocolHTTPTest, VodStreamHandlers)
SrsVodStream h("/tmp");
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
h.set_path(new MockSrsPathAlwaysExists());
h.entry = &e;
h.entry_ = &e;
MockResponseWriter w;
SrsHttpMessage r(NULL, NULL);
@ -1538,7 +1538,7 @@ VOID TEST(ProtocolHTTPTest, VodStreamHandlers)
SrsVodStream h("/tmp");
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
h.set_path(new MockSrsPathAlwaysExists());
h.entry = &e;
h.entry_ = &e;
MockResponseWriter w;
SrsHttpMessage r(NULL, NULL);
@ -1556,7 +1556,7 @@ VOID TEST(ProtocolHTTPTest, VodStreamHandlers)
SrsVodStream h("/tmp");
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
h.set_path(new MockSrsPathAlwaysExists());
h.entry = &e;
h.entry_ = &e;
MockResponseWriter w;
SrsHttpMessage r(NULL, NULL);
@ -1574,7 +1574,7 @@ VOID TEST(ProtocolHTTPTest, VodStreamHandlers)
SrsVodStream h("/tmp");
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
h.set_path(new MockSrsPathAlwaysExists());
h.entry = &e;
h.entry_ = &e;
MockResponseWriter w;
SrsHttpMessage r(NULL, NULL);
@ -1592,7 +1592,7 @@ VOID TEST(ProtocolHTTPTest, VodStreamHandlers)
SrsVodStream h("/tmp");
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
h.set_path(new MockSrsPathAlwaysExists());
h.entry = &e;
h.entry_ = &e;
MockResponseWriter w;
SrsHttpMessage r(NULL, NULL);
@ -1614,7 +1614,7 @@ VOID TEST(ProtocolHTTPTest, VodStreamHandlers)
SrsVodStream h("/tmp");
h.set_fs_factory(new MockFileReaderFactory("livestream-13.ts"));
h.set_path(new MockSrsPathAlwaysExists());
h.entry = &e;
h.entry_ = &e;
MockResponseWriter w;
SrsHttpMessage r(NULL, NULL);
@ -1636,7 +1636,7 @@ VOID TEST(ProtocolHTTPTest, VodStreamHandlers)
SrsVodStream h("/tmp");
h.set_fs_factory(new MockFileReaderFactory("livestream-13.m4s"));
h.set_path(new MockSrsPathAlwaysExists());
h.entry = &e;
h.entry_ = &e;
MockResponseWriter w;
SrsHttpMessage r(NULL, NULL);
@ -1658,7 +1658,7 @@ VOID TEST(ProtocolHTTPTest, VodStreamHandlers)
SrsVodStream h("/tmp");
h.set_fs_factory(new MockFileReaderFactory("init.mp4"));
h.set_path(new MockSrsPathAlwaysExists());
h.entry = &e;
h.entry_ = &e;
MockResponseWriter w;
SrsHttpMessage r(NULL, NULL);
@ -1684,7 +1684,7 @@ VOID TEST(ProtocolHTTPTest, BasicHandlers)
SrsHttpFileServer h("/tmp");
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
h.set_path(new MockSrsPathAlwaysExists());
h.entry = &e;
h.entry_ = &e;
MockResponseWriter w;
SrsHttpMessage r(NULL, NULL);
@ -1701,7 +1701,7 @@ VOID TEST(ProtocolHTTPTest, BasicHandlers)
SrsHttpFileServer h("/tmp");
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
h.set_path(new MockSrsPathAlwaysExists());
h.entry = &e;
h.entry_ = &e;
MockResponseWriter w;
SrsHttpMessage r(NULL, NULL);
@ -1718,7 +1718,7 @@ VOID TEST(ProtocolHTTPTest, BasicHandlers)
SrsHttpFileServer h("/tmp");
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
h.set_path(new MockSrsPathAlwaysExists());
h.entry = &e;
h.entry_ = &e;
MockResponseWriter w;
SrsHttpMessage r(NULL, NULL);
@ -1735,7 +1735,7 @@ VOID TEST(ProtocolHTTPTest, BasicHandlers)
SrsHttpFileServer h("/tmp");
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
h.set_path(new MockSrsPathAlwaysExists());
h.entry = &e;
h.entry_ = &e;
MockResponseWriter w;
SrsHttpMessage r(NULL, NULL);
@ -1752,7 +1752,7 @@ VOID TEST(ProtocolHTTPTest, BasicHandlers)
SrsHttpFileServer h("/tmp");
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
h.set_path(new MockSrsPathAlwaysExists());
h.entry = &e;
h.entry_ = &e;
MockResponseWriter w;
SrsHttpMessage r(NULL, NULL);
@ -1769,7 +1769,7 @@ VOID TEST(ProtocolHTTPTest, BasicHandlers)
SrsHttpFileServer h("/tmp");
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
h.set_path(new MockSrsPathAlwaysExists());
h.entry = &e;
h.entry_ = &e;
MockResponseWriter w;
SrsHttpMessage r(NULL, NULL);
@ -1786,7 +1786,7 @@ VOID TEST(ProtocolHTTPTest, BasicHandlers)
SrsHttpFileServer h("/tmp");
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
h.set_path(new MockSrsPathAlwaysExists());
h.entry = &e;
h.entry_ = &e;
MockResponseWriter w;
SrsHttpMessage r(NULL, NULL);
@ -1803,7 +1803,7 @@ VOID TEST(ProtocolHTTPTest, BasicHandlers)
SrsHttpFileServer h("/tmp");
h.set_fs_factory(new MockFileReaderFactory("Hello, world!"));
h.set_path(new MockSrsPathNotExists());
h.entry = &e;
h.entry_ = &e;
MockResponseWriter w;
SrsHttpMessage r(NULL, NULL);

View File

@ -1302,7 +1302,7 @@ VOID TEST(KernelErrorTest, AsanReportCallback)
#ifdef SRS_SANITIZER_LOG
// Test asan_report_callback function with various input formats
// 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_;
mock_log->level_ = SrsLogLevelDisabled;