AI: Add utest to cover dash module.
This commit is contained in:
parent
646b833757
commit
de3d5bd1f5
3
trunk/configure
vendored
3
trunk/configure
vendored
|
|
@ -384,7 +384,8 @@ if [[ $SRS_UTEST == YES ]]; then
|
||||||
"srs_utest_coworkers" "srs_utest_pithy_print" "srs_utest_kernel3" "srs_utest_protocol4"
|
"srs_utest_coworkers" "srs_utest_pithy_print" "srs_utest_kernel3" "srs_utest_protocol4"
|
||||||
"srs_utest_protocol3" "srs_utest_app" "srs_utest_app2" "srs_utest_app3" "srs_utest_app4"
|
"srs_utest_protocol3" "srs_utest_app" "srs_utest_app2" "srs_utest_app3" "srs_utest_app4"
|
||||||
"srs_utest_app5" "srs_utest_app6" "srs_utest_app7" "srs_utest_app8" "srs_utest_app9"
|
"srs_utest_app5" "srs_utest_app6" "srs_utest_app7" "srs_utest_app8" "srs_utest_app9"
|
||||||
"srs_utest_app10" "srs_utest_app11" "srs_utest_app12" "srs_utest_app13" "srs_utest_app14")
|
"srs_utest_app10" "srs_utest_app11" "srs_utest_app12" "srs_utest_app13" "srs_utest_app14"
|
||||||
|
"srs_utest_app15")
|
||||||
# Always include SRT utest
|
# Always include SRT utest
|
||||||
MODULE_FILES+=("srs_utest_srt")
|
MODULE_FILES+=("srs_utest_srt")
|
||||||
if [[ $SRS_GB28181 == YES ]]; then
|
if [[ $SRS_GB28181 == YES ]]; then
|
||||||
|
|
|
||||||
|
|
@ -344,6 +344,7 @@ public:
|
||||||
virtual std::string get_rtc_server_protocol() = 0;
|
virtual std::string get_rtc_server_protocol() = 0;
|
||||||
virtual std::vector<std::string> get_rtc_server_listens() = 0;
|
virtual std::vector<std::string> get_rtc_server_listens() = 0;
|
||||||
virtual int get_rtc_server_reuseport() = 0;
|
virtual int get_rtc_server_reuseport() = 0;
|
||||||
|
virtual bool get_rtc_server_encrypt() = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// RTSP config
|
// RTSP config
|
||||||
|
|
@ -453,6 +454,8 @@ public:
|
||||||
virtual bool get_rtc_to_rtmp(std::string vhost) = 0;
|
virtual bool get_rtc_to_rtmp(std::string vhost) = 0;
|
||||||
virtual srs_utime_t get_rtc_stun_timeout(std::string vhost) = 0;
|
virtual srs_utime_t get_rtc_stun_timeout(std::string vhost) = 0;
|
||||||
virtual bool get_rtc_stun_strict_check(std::string vhost) = 0;
|
virtual bool get_rtc_stun_strict_check(std::string vhost) = 0;
|
||||||
|
virtual std::string get_rtc_dtls_role(std::string vhost) = 0;
|
||||||
|
virtual std::string get_rtc_dtls_version(std::string vhost) = 0;
|
||||||
virtual SrsConfDirective *get_vhost_on_hls(std::string vhost) = 0;
|
virtual SrsConfDirective *get_vhost_on_hls(std::string vhost) = 0;
|
||||||
virtual SrsConfDirective *get_vhost_on_hls_notify(std::string vhost) = 0;
|
virtual SrsConfDirective *get_vhost_on_hls_notify(std::string vhost) = 0;
|
||||||
virtual bool get_hls_enabled(std::string vhost) = 0;
|
virtual bool get_hls_enabled(std::string vhost) = 0;
|
||||||
|
|
@ -483,6 +486,16 @@ public:
|
||||||
virtual bool get_hls_ctx_enabled(std::string vhost) = 0;
|
virtual bool get_hls_ctx_enabled(std::string vhost) = 0;
|
||||||
virtual bool get_hls_ts_ctx_enabled(std::string vhost) = 0;
|
virtual bool get_hls_ts_ctx_enabled(std::string vhost) = 0;
|
||||||
virtual bool get_hls_recover(std::string vhost) = 0;
|
virtual bool get_hls_recover(std::string vhost) = 0;
|
||||||
|
virtual bool get_dash_enabled(std::string vhost) = 0;
|
||||||
|
virtual bool get_dash_enabled(SrsConfDirective *vhost) = 0;
|
||||||
|
virtual srs_utime_t get_dash_fragment(std::string vhost) = 0;
|
||||||
|
virtual srs_utime_t get_dash_update_period(std::string vhost) = 0;
|
||||||
|
virtual srs_utime_t get_dash_timeshift(std::string vhost) = 0;
|
||||||
|
virtual std::string get_dash_path(std::string vhost) = 0;
|
||||||
|
virtual std::string get_dash_mpd_file(std::string vhost) = 0;
|
||||||
|
virtual int get_dash_window_size(std::string vhost) = 0;
|
||||||
|
virtual bool get_dash_cleanup(std::string vhost) = 0;
|
||||||
|
virtual srs_utime_t get_dash_dispose(std::string vhost) = 0;
|
||||||
virtual bool get_forward_enabled(std::string vhost) = 0;
|
virtual bool get_forward_enabled(std::string vhost) = 0;
|
||||||
virtual SrsConfDirective *get_forwards(std::string vhost) = 0;
|
virtual SrsConfDirective *get_forwards(std::string vhost) = 0;
|
||||||
virtual srs_utime_t get_queue_length(std::string vhost) = 0;
|
virtual srs_utime_t get_queue_length(std::string vhost) = 0;
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
#include <srs_app_dash.hpp>
|
#include <srs_app_dash.hpp>
|
||||||
|
|
||||||
#include <srs_app_config.hpp>
|
#include <srs_app_config.hpp>
|
||||||
|
#include <srs_app_factory.hpp>
|
||||||
#include <srs_app_rtmp_source.hpp>
|
#include <srs_app_rtmp_source.hpp>
|
||||||
#include <srs_app_utility.hpp>
|
#include <srs_app_utility.hpp>
|
||||||
#include <srs_core_autofree.hpp>
|
#include <srs_core_autofree.hpp>
|
||||||
|
|
@ -35,23 +36,33 @@ string srs_time_to_utc_format_str(srs_utime_t u)
|
||||||
return std::string(print_buf, ret);
|
return std::string(print_buf, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ISrsInitMp4::ISrsInitMp4()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsInitMp4::~ISrsInitMp4()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
SrsInitMp4::SrsInitMp4()
|
SrsInitMp4::SrsInitMp4()
|
||||||
{
|
{
|
||||||
fw_ = new SrsFileWriter();
|
fw_ = new SrsFileWriter();
|
||||||
init_ = new SrsMp4M2tsInitEncoder();
|
init_ = new SrsMp4M2tsInitEncoder();
|
||||||
|
fragment_ = new SrsFragment();
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsInitMp4::~SrsInitMp4()
|
SrsInitMp4::~SrsInitMp4()
|
||||||
{
|
{
|
||||||
srs_freep(init_);
|
srs_freep(init_);
|
||||||
srs_freep(fw_);
|
srs_freep(fw_);
|
||||||
|
srs_freep(fragment_);
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsInitMp4::write(SrsFormat *format, bool video, int tid)
|
srs_error_t SrsInitMp4::write(SrsFormat *format, bool video, int tid)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
string path_tmp = tmppath();
|
string path_tmp = fragment_->tmppath();
|
||||||
if ((err = fw_->open(path_tmp)) != srs_success) {
|
if ((err = fw_->open(path_tmp)) != srs_success) {
|
||||||
return srs_error_wrap(err, "Open init mp4 failed, path=%s", path_tmp.c_str());
|
return srs_error_wrap(err, "Open init mp4 failed, path=%s", path_tmp.c_str());
|
||||||
}
|
}
|
||||||
|
|
@ -67,19 +78,88 @@ srs_error_t SrsInitMp4::write(SrsFormat *format, bool video, int tid)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SrsInitMp4::set_path(std::string v)
|
||||||
|
{
|
||||||
|
fragment_->set_path(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SrsInitMp4::tmppath()
|
||||||
|
{
|
||||||
|
return fragment_->tmppath();
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_error_t SrsInitMp4::rename()
|
||||||
|
{
|
||||||
|
return fragment_->rename();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SrsInitMp4::append(int64_t dts)
|
||||||
|
{
|
||||||
|
fragment_->append(dts);
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_error_t SrsInitMp4::create_dir()
|
||||||
|
{
|
||||||
|
return fragment_->create_dir();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SrsInitMp4::set_number(uint64_t n)
|
||||||
|
{
|
||||||
|
fragment_->set_number(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t SrsInitMp4::number()
|
||||||
|
{
|
||||||
|
return fragment_->number();
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_utime_t SrsInitMp4::duration()
|
||||||
|
{
|
||||||
|
return fragment_->duration();
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_error_t SrsInitMp4::unlink_tmpfile()
|
||||||
|
{
|
||||||
|
return fragment_->unlink_tmpfile();
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_utime_t SrsInitMp4::get_start_dts()
|
||||||
|
{
|
||||||
|
return fragment_->get_start_dts();
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_error_t SrsInitMp4::unlink_file()
|
||||||
|
{
|
||||||
|
return fragment_->unlink_file();
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsFragmentedMp4::ISrsFragmentedMp4()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsFragmentedMp4::~ISrsFragmentedMp4()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
SrsFragmentedMp4::SrsFragmentedMp4()
|
SrsFragmentedMp4::SrsFragmentedMp4()
|
||||||
{
|
{
|
||||||
fw_ = new SrsFileWriter();
|
fw_ = new SrsFileWriter();
|
||||||
enc_ = new SrsMp4M2tsSegmentEncoder();
|
enc_ = new SrsMp4M2tsSegmentEncoder();
|
||||||
|
fragment_ = new SrsFragment();
|
||||||
|
|
||||||
|
config_ = _srs_config;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsFragmentedMp4::~SrsFragmentedMp4()
|
SrsFragmentedMp4::~SrsFragmentedMp4()
|
||||||
{
|
{
|
||||||
srs_freep(enc_);
|
srs_freep(enc_);
|
||||||
srs_freep(fw_);
|
srs_freep(fw_);
|
||||||
|
srs_freep(fragment_);
|
||||||
|
|
||||||
|
config_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsFragmentedMp4::initialize(ISrsRequest *r, bool video, int64_t time, SrsMpdWriter *mpd, uint32_t tid)
|
srs_error_t SrsFragmentedMp4::initialize(ISrsRequest *r, bool video, int64_t time, ISrsMpdWriter *mpd, uint32_t tid)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
|
@ -91,16 +171,16 @@ srs_error_t SrsFragmentedMp4::initialize(ISrsRequest *r, bool video, int64_t tim
|
||||||
(uint32_t)sequence_number, file_home.c_str(), file_name.c_str());
|
(uint32_t)sequence_number, file_home.c_str(), file_name.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
string home = _srs_config->get_dash_path(r->vhost_);
|
string home = config_->get_dash_path(r->vhost_);
|
||||||
set_path(home + "/" + file_home + "/" + file_name);
|
fragment_->set_path(home + "/" + file_home + "/" + file_name);
|
||||||
// Set number of the fragment, use in mpd SegmentTemplate@startNumber later.
|
// Set number of the fragment, use in mpd SegmentTemplate@startNumber later.
|
||||||
set_number(sequence_number);
|
fragment_->set_number(sequence_number);
|
||||||
|
|
||||||
if ((err = create_dir()) != srs_success) {
|
if ((err = fragment_->create_dir()) != srs_success) {
|
||||||
return srs_error_wrap(err, "create dir");
|
return srs_error_wrap(err, "create dir");
|
||||||
}
|
}
|
||||||
|
|
||||||
string path_tmp = tmppath();
|
string path_tmp = fragment_->tmppath();
|
||||||
if ((err = fw_->open(path_tmp)) != srs_success) {
|
if ((err = fw_->open(path_tmp)) != srs_success) {
|
||||||
return srs_error_wrap(err, "Open fmp4 failed, path=%s", path_tmp.c_str());
|
return srs_error_wrap(err, "Open fmp4 failed, path=%s", path_tmp.c_str());
|
||||||
}
|
}
|
||||||
|
|
@ -136,7 +216,7 @@ srs_error_t SrsFragmentedMp4::write(SrsMediaPacket *shared_msg, SrsFormat *forma
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
append(shared_msg->timestamp_);
|
fragment_->append(shared_msg->timestamp_);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
@ -151,13 +231,76 @@ srs_error_t SrsFragmentedMp4::reap(uint64_t &dts)
|
||||||
|
|
||||||
srs_freep(fw_);
|
srs_freep(fw_);
|
||||||
|
|
||||||
if ((err = rename()) != srs_success) {
|
if ((err = fragment_->rename()) != srs_success) {
|
||||||
return srs_error_wrap(err, "rename");
|
return srs_error_wrap(err, "rename");
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SrsFragmentedMp4::set_path(std::string v)
|
||||||
|
{
|
||||||
|
fragment_->set_path(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SrsFragmentedMp4::tmppath()
|
||||||
|
{
|
||||||
|
return fragment_->tmppath();
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_error_t SrsFragmentedMp4::rename()
|
||||||
|
{
|
||||||
|
return fragment_->rename();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SrsFragmentedMp4::append(int64_t dts)
|
||||||
|
{
|
||||||
|
fragment_->append(dts);
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_error_t SrsFragmentedMp4::create_dir()
|
||||||
|
{
|
||||||
|
return fragment_->create_dir();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SrsFragmentedMp4::set_number(uint64_t n)
|
||||||
|
{
|
||||||
|
fragment_->set_number(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_utime_t SrsFragmentedMp4::duration()
|
||||||
|
{
|
||||||
|
return fragment_->duration();
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_error_t SrsFragmentedMp4::unlink_tmpfile()
|
||||||
|
{
|
||||||
|
return fragment_->unlink_tmpfile();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t SrsFragmentedMp4::number()
|
||||||
|
{
|
||||||
|
return fragment_->number();
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_utime_t SrsFragmentedMp4::get_start_dts()
|
||||||
|
{
|
||||||
|
return fragment_->get_start_dts();
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_error_t SrsFragmentedMp4::unlink_file()
|
||||||
|
{
|
||||||
|
return fragment_->unlink_file();
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsMpdWriter::ISrsMpdWriter()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsMpdWriter::~ISrsMpdWriter()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
SrsMpdWriter::SrsMpdWriter()
|
SrsMpdWriter::SrsMpdWriter()
|
||||||
{
|
{
|
||||||
req_ = NULL;
|
req_ = NULL;
|
||||||
|
|
@ -168,10 +311,15 @@ SrsMpdWriter::SrsMpdWriter()
|
||||||
|
|
||||||
video_number_ = 0;
|
video_number_ = 0;
|
||||||
audio_number_ = 0;
|
audio_number_ = 0;
|
||||||
|
|
||||||
|
config_ = _srs_config;
|
||||||
|
app_factory_ = _srs_app_factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsMpdWriter::~SrsMpdWriter()
|
SrsMpdWriter::~SrsMpdWriter()
|
||||||
{
|
{
|
||||||
|
config_ = NULL;
|
||||||
|
app_factory_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SrsMpdWriter::dispose()
|
void SrsMpdWriter::dispose()
|
||||||
|
|
@ -204,16 +352,16 @@ srs_error_t SrsMpdWriter::on_publish()
|
||||||
{
|
{
|
||||||
ISrsRequest *r = req_;
|
ISrsRequest *r = req_;
|
||||||
|
|
||||||
fragment_ = _srs_config->get_dash_fragment(r->vhost_);
|
fragment_ = config_->get_dash_fragment(r->vhost_);
|
||||||
update_period_ = _srs_config->get_dash_update_period(r->vhost_);
|
update_period_ = config_->get_dash_update_period(r->vhost_);
|
||||||
timeshit_ = _srs_config->get_dash_timeshift(r->vhost_);
|
timeshit_ = config_->get_dash_timeshift(r->vhost_);
|
||||||
home_ = _srs_config->get_dash_path(r->vhost_);
|
home_ = config_->get_dash_path(r->vhost_);
|
||||||
mpd_file_ = _srs_config->get_dash_mpd_file(r->vhost_);
|
mpd_file_ = config_->get_dash_mpd_file(r->vhost_);
|
||||||
|
|
||||||
SrsPath path;
|
SrsPath path;
|
||||||
string mpd_path = srs_path_build_stream(mpd_file_, req_->vhost_, req_->app_, req_->stream_);
|
string mpd_path = srs_path_build_stream(mpd_file_, req_->vhost_, req_->app_, req_->stream_);
|
||||||
fragment_home_ = path.filepath_dir(mpd_path) + "/" + req_->stream_;
|
fragment_home_ = path.filepath_dir(mpd_path) + "/" + req_->stream_;
|
||||||
window_size_ = _srs_config->get_dash_window_size(r->vhost_);
|
window_size_ = config_->get_dash_window_size(r->vhost_);
|
||||||
|
|
||||||
srs_trace("DASH: Config fragment=%dms, period=%dms, window=%d, timeshit=%dms, home=%s, mpd=%s",
|
srs_trace("DASH: Config fragment=%dms, period=%dms, window=%d, timeshit=%dms, home=%s, mpd=%s",
|
||||||
srsu2msi(fragment_), srsu2msi(update_period_), window_size_, srsu2msi(timeshit_), home_.c_str(), mpd_file_.c_str());
|
srsu2msi(fragment_), srsu2msi(update_period_), window_size_, srsu2msi(timeshit_), home_.c_str(), mpd_file_.c_str());
|
||||||
|
|
@ -225,7 +373,7 @@ void SrsMpdWriter::on_unpublish()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsMpdWriter::write(SrsFormat *format, SrsFragmentWindow *afragments, SrsFragmentWindow *vfragments)
|
srs_error_t SrsMpdWriter::write(SrsFormat *format, ISrsFragmentWindow *afragments, ISrsFragmentWindow *vfragments)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
|
@ -305,7 +453,7 @@ srs_error_t SrsMpdWriter::write(SrsFormat *format, SrsFragmentWindow *afragments
|
||||||
ss << " </Period>" << endl;
|
ss << " </Period>" << endl;
|
||||||
ss << "</MPD>" << endl;
|
ss << "</MPD>" << endl;
|
||||||
|
|
||||||
SrsUniquePtr<SrsFileWriter> fw(new SrsFileWriter());
|
SrsUniquePtr<ISrsFileWriter> fw(app_factory_->create_file_writer());
|
||||||
|
|
||||||
string full_path_tmp = full_path + ".tmp";
|
string full_path_tmp = full_path + ".tmp";
|
||||||
if ((err = fw->open(full_path_tmp)) != srs_success) {
|
if ((err = fw->open(full_path_tmp)) != srs_success) {
|
||||||
|
|
@ -357,6 +505,14 @@ srs_utime_t SrsMpdWriter::get_availability_start_time()
|
||||||
return availability_start_time_;
|
return availability_start_time_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ISrsDashController::ISrsDashController()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsDashController::~ISrsDashController()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
SrsDashController::SrsDashController()
|
SrsDashController::SrsDashController()
|
||||||
{
|
{
|
||||||
req_ = NULL;
|
req_ = NULL;
|
||||||
|
|
@ -372,6 +528,9 @@ SrsDashController::SrsDashController()
|
||||||
first_dts_ = -1;
|
first_dts_ = -1;
|
||||||
video_reaped_ = false;
|
video_reaped_ = false;
|
||||||
fragment_ = 0;
|
fragment_ = 0;
|
||||||
|
|
||||||
|
app_factory_ = _srs_app_factory;
|
||||||
|
config_ = _srs_config;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsDashController::~SrsDashController()
|
SrsDashController::~SrsDashController()
|
||||||
|
|
@ -381,6 +540,9 @@ SrsDashController::~SrsDashController()
|
||||||
srs_freep(acurrent_);
|
srs_freep(acurrent_);
|
||||||
srs_freep(vfragments_);
|
srs_freep(vfragments_);
|
||||||
srs_freep(afragments_);
|
srs_freep(afragments_);
|
||||||
|
|
||||||
|
app_factory_ = NULL;
|
||||||
|
config_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SrsDashController::dispose()
|
void SrsDashController::dispose()
|
||||||
|
|
@ -430,8 +592,8 @@ srs_error_t SrsDashController::on_publish()
|
||||||
|
|
||||||
ISrsRequest *r = req_;
|
ISrsRequest *r = req_;
|
||||||
|
|
||||||
fragment_ = _srs_config->get_dash_fragment(r->vhost_);
|
fragment_ = config_->get_dash_fragment(r->vhost_);
|
||||||
home_ = _srs_config->get_dash_path(r->vhost_);
|
home_ = config_->get_dash_path(r->vhost_);
|
||||||
|
|
||||||
if ((err = mpd_->on_publish()) != srs_success) {
|
if ((err = mpd_->on_publish()) != srs_success) {
|
||||||
return srs_error_wrap(err, "mpd");
|
return srs_error_wrap(err, "mpd");
|
||||||
|
|
@ -439,11 +601,11 @@ srs_error_t SrsDashController::on_publish()
|
||||||
|
|
||||||
srs_freep(vcurrent_);
|
srs_freep(vcurrent_);
|
||||||
srs_freep(vfragments_);
|
srs_freep(vfragments_);
|
||||||
vfragments_ = new SrsFragmentWindow();
|
vfragments_ = app_factory_->create_fragment_window();
|
||||||
|
|
||||||
srs_freep(acurrent_);
|
srs_freep(acurrent_);
|
||||||
srs_freep(afragments_);
|
srs_freep(afragments_);
|
||||||
afragments_ = new SrsFragmentWindow();
|
afragments_ = app_factory_->create_fragment_window();
|
||||||
|
|
||||||
audio_dts_ = 0;
|
audio_dts_ = 0;
|
||||||
video_dts_ = 0;
|
video_dts_ = 0;
|
||||||
|
|
@ -498,7 +660,7 @@ srs_error_t SrsDashController::on_audio(SrsMediaPacket *shared_audio, SrsFormat
|
||||||
audio_dts_ = shared_audio->timestamp_;
|
audio_dts_ = shared_audio->timestamp_;
|
||||||
|
|
||||||
if (!acurrent_) {
|
if (!acurrent_) {
|
||||||
acurrent_ = new SrsFragmentedMp4();
|
acurrent_ = app_factory_->create_fragmented_mp4();
|
||||||
|
|
||||||
if ((err = acurrent_->initialize(req_, false, audio_dts_ * SRS_UTIME_MILLISECONDS, mpd_, audio_track_id_)) != srs_success) {
|
if ((err = acurrent_->initialize(req_, false, audio_dts_ * SRS_UTIME_MILLISECONDS, mpd_, audio_track_id_)) != srs_success) {
|
||||||
return srs_error_wrap(err, "Initialize the audio fragment failed");
|
return srs_error_wrap(err, "Initialize the audio fragment failed");
|
||||||
|
|
@ -521,7 +683,7 @@ srs_error_t SrsDashController::on_audio(SrsMediaPacket *shared_audio, SrsFormat
|
||||||
}
|
}
|
||||||
|
|
||||||
afragments_->append(acurrent_);
|
afragments_->append(acurrent_);
|
||||||
acurrent_ = new SrsFragmentedMp4();
|
acurrent_ = app_factory_->create_fragmented_mp4();
|
||||||
|
|
||||||
if ((err = acurrent_->initialize(req_, false, audio_dts_ * SRS_UTIME_MILLISECONDS, mpd_, audio_track_id_)) != srs_success) {
|
if ((err = acurrent_->initialize(req_, false, audio_dts_ * SRS_UTIME_MILLISECONDS, mpd_, audio_track_id_)) != srs_success) {
|
||||||
return srs_error_wrap(err, "Initialize the audio fragment failed");
|
return srs_error_wrap(err, "Initialize the audio fragment failed");
|
||||||
|
|
@ -536,8 +698,8 @@ srs_error_t SrsDashController::on_audio(SrsMediaPacket *shared_audio, SrsFormat
|
||||||
return srs_error_wrap(err, "Write audio to fragment failed");
|
return srs_error_wrap(err, "Write audio to fragment failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_utime_t fragment = _srs_config->get_dash_fragment(req_->vhost_);
|
srs_utime_t fragment = config_->get_dash_fragment(req_->vhost_);
|
||||||
int window_size = _srs_config->get_dash_window_size(req_->vhost_);
|
int window_size = config_->get_dash_window_size(req_->vhost_);
|
||||||
int dash_window = 2 * window_size * fragment;
|
int dash_window = 2 * window_size * fragment;
|
||||||
if (afragments_->size() > window_size) {
|
if (afragments_->size() > window_size) {
|
||||||
int w = 0;
|
int w = 0;
|
||||||
|
|
@ -550,7 +712,7 @@ srs_error_t SrsDashController::on_audio(SrsMediaPacket *shared_audio, SrsFormat
|
||||||
afragments_->shrink(dash_window);
|
afragments_->shrink(dash_window);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dash_cleanup = _srs_config->get_dash_cleanup(req_->vhost_);
|
bool dash_cleanup = config_->get_dash_cleanup(req_->vhost_);
|
||||||
// remove the m4s file.
|
// remove the m4s file.
|
||||||
afragments_->clear_expired(dash_cleanup);
|
afragments_->clear_expired(dash_cleanup);
|
||||||
|
|
||||||
|
|
@ -570,7 +732,7 @@ srs_error_t SrsDashController::on_video(SrsMediaPacket *shared_video, SrsFormat
|
||||||
video_dts_ = shared_video->timestamp_;
|
video_dts_ = shared_video->timestamp_;
|
||||||
|
|
||||||
if (!vcurrent_) {
|
if (!vcurrent_) {
|
||||||
vcurrent_ = new SrsFragmentedMp4();
|
vcurrent_ = app_factory_->create_fragmented_mp4();
|
||||||
|
|
||||||
if ((err = vcurrent_->initialize(req_, true, video_dts_ * SRS_UTIME_MILLISECONDS, mpd_, video_track_id_)) != srs_success) {
|
if ((err = vcurrent_->initialize(req_, true, video_dts_ * SRS_UTIME_MILLISECONDS, mpd_, video_track_id_)) != srs_success) {
|
||||||
return srs_error_wrap(err, "Initialize the video fragment failed");
|
return srs_error_wrap(err, "Initialize the video fragment failed");
|
||||||
|
|
@ -594,7 +756,7 @@ srs_error_t SrsDashController::on_video(SrsMediaPacket *shared_video, SrsFormat
|
||||||
video_reaped_ = true;
|
video_reaped_ = true;
|
||||||
|
|
||||||
vfragments_->append(vcurrent_);
|
vfragments_->append(vcurrent_);
|
||||||
vcurrent_ = new SrsFragmentedMp4();
|
vcurrent_ = app_factory_->create_fragmented_mp4();
|
||||||
|
|
||||||
if ((err = vcurrent_->initialize(req_, true, video_dts_ * SRS_UTIME_MILLISECONDS, mpd_, video_track_id_)) != srs_success) {
|
if ((err = vcurrent_->initialize(req_, true, video_dts_ * SRS_UTIME_MILLISECONDS, mpd_, video_track_id_)) != srs_success) {
|
||||||
return srs_error_wrap(err, "Initialize the video fragment failed");
|
return srs_error_wrap(err, "Initialize the video fragment failed");
|
||||||
|
|
@ -609,8 +771,8 @@ srs_error_t SrsDashController::on_video(SrsMediaPacket *shared_video, SrsFormat
|
||||||
return srs_error_wrap(err, "Write video to fragment failed");
|
return srs_error_wrap(err, "Write video to fragment failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_utime_t fragment = _srs_config->get_dash_fragment(req_->vhost_);
|
srs_utime_t fragment = config_->get_dash_fragment(req_->vhost_);
|
||||||
int window_size = _srs_config->get_dash_window_size(req_->vhost_);
|
int window_size = config_->get_dash_window_size(req_->vhost_);
|
||||||
int dash_window = 2 * window_size * fragment;
|
int dash_window = 2 * window_size * fragment;
|
||||||
if (vfragments_->size() > window_size) {
|
if (vfragments_->size() > window_size) {
|
||||||
int w = 0;
|
int w = 0;
|
||||||
|
|
@ -623,7 +785,7 @@ srs_error_t SrsDashController::on_video(SrsMediaPacket *shared_video, SrsFormat
|
||||||
vfragments_->shrink(dash_window);
|
vfragments_->shrink(dash_window);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dash_cleanup = _srs_config->get_dash_cleanup(req_->vhost_);
|
bool dash_cleanup = config_->get_dash_cleanup(req_->vhost_);
|
||||||
// remove the m4s file.
|
// remove the m4s file.
|
||||||
vfragments_->clear_expired(dash_cleanup);
|
vfragments_->clear_expired(dash_cleanup);
|
||||||
|
|
||||||
|
|
@ -668,7 +830,7 @@ srs_error_t SrsDashController::refresh_init_mp4(SrsMediaPacket *msg, SrsFormat *
|
||||||
path += "/audio-init.mp4";
|
path += "/audio-init.mp4";
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsUniquePtr<SrsInitMp4> init_mp4(new SrsInitMp4());
|
SrsUniquePtr<ISrsInitMp4> init_mp4(app_factory_->create_init_mp4());
|
||||||
|
|
||||||
init_mp4->set_path(path);
|
init_mp4->set_path(path);
|
||||||
|
|
||||||
|
|
@ -703,11 +865,15 @@ SrsDash::SrsDash()
|
||||||
enabled_ = false;
|
enabled_ = false;
|
||||||
disposable_ = false;
|
disposable_ = false;
|
||||||
last_update_time_ = 0;
|
last_update_time_ = 0;
|
||||||
|
|
||||||
|
config_ = _srs_config;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsDash::~SrsDash()
|
SrsDash::~SrsDash()
|
||||||
{
|
{
|
||||||
srs_freep(controller_);
|
srs_freep(controller_);
|
||||||
|
|
||||||
|
config_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SrsDash::dispose()
|
void SrsDash::dispose()
|
||||||
|
|
@ -717,7 +883,7 @@ void SrsDash::dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore when dash_dispose disabled.
|
// Ignore when dash_dispose disabled.
|
||||||
srs_utime_t dash_dispose = _srs_config->get_dash_dispose(req_->vhost_);
|
srs_utime_t dash_dispose = config_->get_dash_dispose(req_->vhost_);
|
||||||
if (!dash_dispose) {
|
if (!dash_dispose) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -737,7 +903,7 @@ srs_error_t SrsDash::cycle()
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_utime_t dash_dispose = _srs_config->get_dash_dispose(req_->vhost_);
|
srs_utime_t dash_dispose = config_->get_dash_dispose(req_->vhost_);
|
||||||
if (dash_dispose <= 0) {
|
if (dash_dispose <= 0) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
@ -760,7 +926,7 @@ srs_error_t SrsDash::cycle()
|
||||||
srs_utime_t SrsDash::cleanup_delay()
|
srs_utime_t SrsDash::cleanup_delay()
|
||||||
{
|
{
|
||||||
// We use larger timeout to cleanup the HLS, after disposed it if required.
|
// We use larger timeout to cleanup the HLS, after disposed it if required.
|
||||||
return _srs_config->get_dash_dispose(req_->vhost_) * 1.1;
|
return config_->get_dash_dispose(req_->vhost_) * 1.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// CRITICAL: This method is called AFTER the source has been added to the source pool
|
// CRITICAL: This method is called AFTER the source has been added to the source pool
|
||||||
|
|
@ -769,7 +935,7 @@ srs_utime_t SrsDash::cleanup_delay()
|
||||||
// IMPORTANT: All field initialization in this method MUST NOT cause coroutine context switches.
|
// IMPORTANT: All field initialization in this method MUST NOT cause coroutine context switches.
|
||||||
// This prevents the race condition where multiple coroutines could create duplicate sources
|
// This prevents the race condition where multiple coroutines could create duplicate sources
|
||||||
// for the same stream when context switches occurred during initialization.
|
// for the same stream when context switches occurred during initialization.
|
||||||
srs_error_t SrsDash::initialize(SrsOriginHub *h, ISrsRequest *r)
|
srs_error_t SrsDash::initialize(ISrsOriginHub *h, ISrsRequest *r)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
|
@ -792,7 +958,7 @@ srs_error_t SrsDash::on_publish()
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_srs_config->get_dash_enabled(req_->vhost_)) {
|
if (!config_->get_dash_enabled(req_->vhost_)) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
enabled_ = true;
|
enabled_ = true;
|
||||||
|
|
|
||||||
|
|
@ -16,19 +16,43 @@
|
||||||
|
|
||||||
class ISrsRequest;
|
class ISrsRequest;
|
||||||
class SrsOriginHub;
|
class SrsOriginHub;
|
||||||
|
class ISrsOriginHub;
|
||||||
class SrsMediaPacket;
|
class SrsMediaPacket;
|
||||||
class SrsFormat;
|
class SrsFormat;
|
||||||
class SrsFileWriter;
|
class SrsFileWriter;
|
||||||
|
class ISrsFileWriter;
|
||||||
class SrsMpdWriter;
|
class SrsMpdWriter;
|
||||||
|
class ISrsMpdWriter;
|
||||||
class SrsMp4M2tsInitEncoder;
|
class SrsMp4M2tsInitEncoder;
|
||||||
|
class ISrsMp4M2tsInitEncoder;
|
||||||
class SrsMp4M2tsSegmentEncoder;
|
class SrsMp4M2tsSegmentEncoder;
|
||||||
|
class ISrsMp4M2tsSegmentEncoder;
|
||||||
|
class SrsFragment;
|
||||||
|
class ISrsFragment;
|
||||||
|
class ISrsAppFactory;
|
||||||
|
class ISrsDashController;
|
||||||
|
class ISrsFragmentWindow;
|
||||||
|
class ISrsAppConfig;
|
||||||
|
|
||||||
|
// The init mp4 fragment interface.
|
||||||
|
class ISrsInitMp4 : public ISrsFragment
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsInitMp4();
|
||||||
|
virtual ~ISrsInitMp4();
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Write the init mp4 file, with the tid(track id).
|
||||||
|
virtual srs_error_t write(SrsFormat *format, bool video, int tid) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
// The init mp4 for FMP4.
|
// The init mp4 for FMP4.
|
||||||
class SrsInitMp4 : public SrsFragment
|
class SrsInitMp4 : public ISrsInitMp4
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
SrsFileWriter *fw_;
|
ISrsFileWriter *fw_;
|
||||||
SrsMp4M2tsInitEncoder *init_;
|
ISrsMp4M2tsInitEncoder *init_;
|
||||||
|
ISrsFragment *fragment_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsInitMp4();
|
SrsInitMp4();
|
||||||
|
|
@ -37,14 +61,48 @@ public:
|
||||||
public:
|
public:
|
||||||
// Write the init mp4 file, with the tid(track id).
|
// Write the init mp4 file, with the tid(track id).
|
||||||
virtual srs_error_t write(SrsFormat *format, bool video, int tid);
|
virtual srs_error_t write(SrsFormat *format, bool video, int tid);
|
||||||
|
|
||||||
|
public:
|
||||||
|
// ISrsFragment interface implementations - delegate to fragment_
|
||||||
|
virtual void set_path(std::string v);
|
||||||
|
virtual std::string tmppath();
|
||||||
|
virtual srs_error_t rename();
|
||||||
|
virtual void append(int64_t dts);
|
||||||
|
virtual srs_error_t create_dir();
|
||||||
|
virtual void set_number(uint64_t n);
|
||||||
|
virtual uint64_t number();
|
||||||
|
virtual srs_utime_t duration();
|
||||||
|
virtual srs_error_t unlink_tmpfile();
|
||||||
|
virtual srs_utime_t get_start_dts();
|
||||||
|
virtual srs_error_t unlink_file();
|
||||||
};
|
};
|
||||||
|
|
||||||
// The FMP4(Fragmented MP4) for DASH streaming.
|
// The FMP4(Fragmented MP4) for DASH streaming.
|
||||||
class SrsFragmentedMp4 : public SrsFragment
|
class ISrsFragmentedMp4 : public ISrsFragment
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsFragmentedMp4();
|
||||||
|
virtual ~ISrsFragmentedMp4();
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Initialize the fragment, create the home dir, open the file.
|
||||||
|
virtual srs_error_t initialize(ISrsRequest *r, bool video, int64_t time, ISrsMpdWriter *mpd, uint32_t tid) = 0;
|
||||||
|
// Write media message to fragment.
|
||||||
|
virtual srs_error_t write(SrsMediaPacket *shared_msg, SrsFormat *format) = 0;
|
||||||
|
// Reap the fragment, close the fd and rename tmp to official file.
|
||||||
|
virtual srs_error_t reap(uint64_t &dts) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The FMP4(Fragmented MP4) for DASH streaming.
|
||||||
|
class SrsFragmentedMp4 : public ISrsFragmentedMp4
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
SrsFileWriter *fw_;
|
ISrsAppConfig *config_;
|
||||||
SrsMp4M2tsSegmentEncoder *enc_;
|
|
||||||
|
private:
|
||||||
|
ISrsFileWriter *fw_;
|
||||||
|
ISrsMp4M2tsSegmentEncoder *enc_;
|
||||||
|
ISrsFragment *fragment_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsFragmentedMp4();
|
SrsFragmentedMp4();
|
||||||
|
|
@ -52,16 +110,60 @@ public:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Initialize the fragment, create the home dir, open the file.
|
// Initialize the fragment, create the home dir, open the file.
|
||||||
virtual srs_error_t initialize(ISrsRequest *r, bool video, int64_t time, SrsMpdWriter *mpd, uint32_t tid);
|
virtual srs_error_t initialize(ISrsRequest *r, bool video, int64_t time, ISrsMpdWriter *mpd, uint32_t tid);
|
||||||
// Write media message to fragment.
|
// Write media message to fragment.
|
||||||
virtual srs_error_t write(SrsMediaPacket *shared_msg, SrsFormat *format);
|
virtual srs_error_t write(SrsMediaPacket *shared_msg, SrsFormat *format);
|
||||||
// Reap the fragment, close the fd and rename tmp to official file.
|
// Reap the fragment, close the fd and rename tmp to official file.
|
||||||
virtual srs_error_t reap(uint64_t &dts);
|
virtual srs_error_t reap(uint64_t &dts);
|
||||||
|
|
||||||
|
public:
|
||||||
|
// ISrsFragment interface implementations - delegate to fragment_
|
||||||
|
virtual void set_path(std::string v);
|
||||||
|
virtual std::string tmppath();
|
||||||
|
virtual srs_error_t rename();
|
||||||
|
virtual void append(int64_t dts);
|
||||||
|
virtual srs_error_t create_dir();
|
||||||
|
virtual void set_number(uint64_t n);
|
||||||
|
virtual uint64_t number();
|
||||||
|
virtual srs_utime_t duration();
|
||||||
|
virtual srs_error_t unlink_tmpfile();
|
||||||
|
virtual srs_utime_t get_start_dts();
|
||||||
|
virtual srs_error_t unlink_file();
|
||||||
};
|
};
|
||||||
|
|
||||||
// The writer to write MPD for DASH.
|
// The writer to write MPD for DASH.
|
||||||
class SrsMpdWriter
|
class ISrsMpdWriter
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
ISrsMpdWriter();
|
||||||
|
virtual ~ISrsMpdWriter();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void dispose() = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t initialize(ISrsRequest *r) = 0;
|
||||||
|
virtual srs_error_t on_publish() = 0;
|
||||||
|
virtual void on_unpublish() = 0;
|
||||||
|
// Write MPD according to parsed format of stream.
|
||||||
|
virtual srs_error_t write(SrsFormat *format, ISrsFragmentWindow *afragments, ISrsFragmentWindow *vfragments) = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Get the fragment relative home and filename.
|
||||||
|
// The basetime is the absolute time in srs_utime_t, while the sn(sequence number) is basetime/fragment.
|
||||||
|
virtual srs_error_t get_fragment(bool video, std::string &home, std::string &filename, int64_t time, int64_t &sn) = 0;
|
||||||
|
// Set the availabilityStartTime once, map the timestamp in media to utc time.
|
||||||
|
virtual void set_availability_start_time(srs_utime_t t) = 0;
|
||||||
|
virtual srs_utime_t get_availability_start_time() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The writer to write MPD for DASH.
|
||||||
|
class SrsMpdWriter : public ISrsMpdWriter
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
ISrsAppConfig *config_;
|
||||||
|
ISrsAppFactory *app_factory_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ISrsRequest *req_;
|
ISrsRequest *req_;
|
||||||
|
|
||||||
|
|
@ -101,7 +203,7 @@ public:
|
||||||
virtual srs_error_t on_publish();
|
virtual srs_error_t on_publish();
|
||||||
virtual void on_unpublish();
|
virtual void on_unpublish();
|
||||||
// Write MPD according to parsed format of stream.
|
// Write MPD according to parsed format of stream.
|
||||||
virtual srs_error_t write(SrsFormat *format, SrsFragmentWindow *afragments, SrsFragmentWindow *vfragments);
|
virtual srs_error_t write(SrsFormat *format, ISrsFragmentWindow *afragments, ISrsFragmentWindow *vfragments);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Get the fragment relative home and filename.
|
// Get the fragment relative home and filename.
|
||||||
|
|
@ -112,19 +214,41 @@ public:
|
||||||
virtual srs_utime_t get_availability_start_time();
|
virtual srs_utime_t get_availability_start_time();
|
||||||
};
|
};
|
||||||
|
|
||||||
// The controller for DASH, control the MPD and FMP4 generating system.
|
// The DASH controller interface.
|
||||||
class SrsDashController
|
class ISrsDashController
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
ISrsDashController();
|
||||||
|
virtual ~ISrsDashController();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void dispose() = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t initialize(ISrsRequest *r) = 0;
|
||||||
|
virtual srs_error_t on_publish() = 0;
|
||||||
|
virtual void on_unpublish() = 0;
|
||||||
|
virtual srs_error_t on_audio(SrsMediaPacket *shared_audio, SrsFormat *format) = 0;
|
||||||
|
virtual srs_error_t on_video(SrsMediaPacket *shared_video, SrsFormat *format) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The controller for DASH, control the MPD and FMP4 generating system.
|
||||||
|
class SrsDashController : public ISrsDashController
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
ISrsAppConfig *config_;
|
||||||
|
ISrsAppFactory *app_factory_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ISrsRequest *req_;
|
ISrsRequest *req_;
|
||||||
SrsFormat *format_;
|
SrsFormat *format_;
|
||||||
SrsMpdWriter *mpd_;
|
ISrsMpdWriter *mpd_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SrsFragmentedMp4 *vcurrent_;
|
ISrsFragmentedMp4 *vcurrent_;
|
||||||
SrsFragmentWindow *vfragments_;
|
ISrsFragmentWindow *vfragments_;
|
||||||
SrsFragmentedMp4 *acurrent_;
|
ISrsFragmentedMp4 *acurrent_;
|
||||||
SrsFragmentWindow *afragments_;
|
ISrsFragmentWindow *afragments_;
|
||||||
// Current audio dts.
|
// Current audio dts.
|
||||||
uint64_t audio_dts_;
|
uint64_t audio_dts_;
|
||||||
// Current video dts.
|
// Current video dts.
|
||||||
|
|
@ -175,7 +299,7 @@ public:
|
||||||
virtual srs_utime_t cleanup_delay() = 0;
|
virtual srs_utime_t cleanup_delay() = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual srs_error_t initialize(SrsOriginHub *h, ISrsRequest *r) = 0;
|
virtual srs_error_t initialize(ISrsOriginHub *h, ISrsRequest *r) = 0;
|
||||||
virtual srs_error_t on_publish() = 0;
|
virtual srs_error_t on_publish() = 0;
|
||||||
virtual srs_error_t on_audio(SrsMediaPacket *shared_audio, SrsFormat *format) = 0;
|
virtual srs_error_t on_audio(SrsMediaPacket *shared_audio, SrsFormat *format) = 0;
|
||||||
virtual srs_error_t on_video(SrsMediaPacket *shared_video, SrsFormat *format) = 0;
|
virtual srs_error_t on_video(SrsMediaPacket *shared_video, SrsFormat *format) = 0;
|
||||||
|
|
@ -185,6 +309,9 @@ public:
|
||||||
// The MPEG-DASH encoder, transmux RTMP to DASH.
|
// The MPEG-DASH encoder, transmux RTMP to DASH.
|
||||||
class SrsDash : public ISrsDash
|
class SrsDash : public ISrsDash
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
ISrsAppConfig *config_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool enabled_;
|
bool enabled_;
|
||||||
bool disposable_;
|
bool disposable_;
|
||||||
|
|
@ -192,8 +319,8 @@ private:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ISrsRequest *req_;
|
ISrsRequest *req_;
|
||||||
SrsOriginHub *hub_;
|
ISrsOriginHub *hub_;
|
||||||
SrsDashController *controller_;
|
ISrsDashController *controller_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsDash();
|
SrsDash();
|
||||||
|
|
@ -206,7 +333,7 @@ public:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Initalize the encoder.
|
// Initalize the encoder.
|
||||||
virtual srs_error_t initialize(SrsOriginHub *h, ISrsRequest *r);
|
virtual srs_error_t initialize(ISrsOriginHub *h, ISrsRequest *r);
|
||||||
// When stream start publishing.
|
// When stream start publishing.
|
||||||
virtual srs_error_t on_publish();
|
virtual srs_error_t on_publish();
|
||||||
// When got an shared audio message.
|
// When got an shared audio message.
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,9 @@
|
||||||
|
|
||||||
#include <srs_app_caster_flv.hpp>
|
#include <srs_app_caster_flv.hpp>
|
||||||
#include <srs_app_config.hpp>
|
#include <srs_app_config.hpp>
|
||||||
|
#include <srs_app_dash.hpp>
|
||||||
#include <srs_app_dvr.hpp>
|
#include <srs_app_dvr.hpp>
|
||||||
|
#include <srs_app_fragment.hpp>
|
||||||
#include <srs_app_gb28181.hpp>
|
#include <srs_app_gb28181.hpp>
|
||||||
#include <srs_app_rtmp_conn.hpp>
|
#include <srs_app_rtmp_conn.hpp>
|
||||||
#include <srs_app_rtmp_source.hpp>
|
#include <srs_app_rtmp_source.hpp>
|
||||||
|
|
@ -140,6 +142,21 @@ ISrsGbSession *SrsAppFactory::create_gb_session()
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
ISrsInitMp4 *SrsAppFactory::create_init_mp4()
|
||||||
|
{
|
||||||
|
return new SrsInitMp4();
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsFragmentWindow *SrsAppFactory::create_fragment_window()
|
||||||
|
{
|
||||||
|
return new SrsFragmentWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsFragmentedMp4 *SrsAppFactory::create_fragmented_mp4()
|
||||||
|
{
|
||||||
|
return new SrsFragmentedMp4();
|
||||||
|
}
|
||||||
|
|
||||||
SrsFinalFactory::SrsFinalFactory()
|
SrsFinalFactory::SrsFinalFactory()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,10 @@ class ISrsMp4Encoder;
|
||||||
class ISrsDvrSegmenter;
|
class ISrsDvrSegmenter;
|
||||||
class ISrsGbMediaTcpConn;
|
class ISrsGbMediaTcpConn;
|
||||||
class ISrsGbSession;
|
class ISrsGbSession;
|
||||||
|
class ISrsFragment;
|
||||||
|
class ISrsInitMp4;
|
||||||
|
class ISrsFragmentWindow;
|
||||||
|
class ISrsFragmentedMp4;
|
||||||
|
|
||||||
// The factory to create app objects.
|
// The factory to create app objects.
|
||||||
class ISrsAppFactory
|
class ISrsAppFactory
|
||||||
|
|
@ -63,6 +67,9 @@ public:
|
||||||
virtual ISrsGbMediaTcpConn *create_gb_media_tcp_conn() = 0;
|
virtual ISrsGbMediaTcpConn *create_gb_media_tcp_conn() = 0;
|
||||||
virtual ISrsGbSession *create_gb_session() = 0;
|
virtual ISrsGbSession *create_gb_session() = 0;
|
||||||
#endif
|
#endif
|
||||||
|
virtual ISrsInitMp4 *create_init_mp4() = 0;
|
||||||
|
virtual ISrsFragmentWindow *create_fragment_window() = 0;
|
||||||
|
virtual ISrsFragmentedMp4 *create_fragmented_mp4() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// The factory to create app objects.
|
// The factory to create app objects.
|
||||||
|
|
@ -96,6 +103,9 @@ public:
|
||||||
virtual ISrsGbMediaTcpConn *create_gb_media_tcp_conn();
|
virtual ISrsGbMediaTcpConn *create_gb_media_tcp_conn();
|
||||||
virtual ISrsGbSession *create_gb_session();
|
virtual ISrsGbSession *create_gb_session();
|
||||||
#endif
|
#endif
|
||||||
|
virtual ISrsInitMp4 *create_init_mp4();
|
||||||
|
virtual ISrsFragmentWindow *create_fragment_window();
|
||||||
|
virtual ISrsFragmentedMp4 *create_fragmented_mp4();
|
||||||
};
|
};
|
||||||
|
|
||||||
extern ISrsAppFactory *_srs_app_factory;
|
extern ISrsAppFactory *_srs_app_factory;
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,14 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
ISrsFragment::ISrsFragment()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsFragment::~ISrsFragment()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
SrsFragment::SrsFragment()
|
SrsFragment::SrsFragment()
|
||||||
{
|
{
|
||||||
dur_ = 0;
|
dur_ = 0;
|
||||||
|
|
@ -155,22 +163,30 @@ uint64_t SrsFragment::number()
|
||||||
return number_;
|
return number_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ISrsFragmentWindow::ISrsFragmentWindow()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsFragmentWindow::~ISrsFragmentWindow()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
SrsFragmentWindow::SrsFragmentWindow()
|
SrsFragmentWindow::SrsFragmentWindow()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsFragmentWindow::~SrsFragmentWindow()
|
SrsFragmentWindow::~SrsFragmentWindow()
|
||||||
{
|
{
|
||||||
vector<SrsFragment *>::iterator it;
|
vector<ISrsFragment *>::iterator it;
|
||||||
|
|
||||||
for (it = fragments_.begin(); it != fragments_.end(); ++it) {
|
for (it = fragments_.begin(); it != fragments_.end(); ++it) {
|
||||||
SrsFragment *fragment = *it;
|
ISrsFragment *fragment = *it;
|
||||||
srs_freep(fragment);
|
srs_freep(fragment);
|
||||||
}
|
}
|
||||||
fragments_.clear();
|
fragments_.clear();
|
||||||
|
|
||||||
for (it = expired_fragments_.begin(); it != expired_fragments_.end(); ++it) {
|
for (it = expired_fragments_.begin(); it != expired_fragments_.end(); ++it) {
|
||||||
SrsFragment *fragment = *it;
|
ISrsFragment *fragment = *it;
|
||||||
srs_freep(fragment);
|
srs_freep(fragment);
|
||||||
}
|
}
|
||||||
expired_fragments_.clear();
|
expired_fragments_.clear();
|
||||||
|
|
@ -180,10 +196,10 @@ void SrsFragmentWindow::dispose()
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
std::vector<SrsFragment *>::iterator it;
|
std::vector<ISrsFragment *>::iterator it;
|
||||||
|
|
||||||
for (it = fragments_.begin(); it != fragments_.end(); ++it) {
|
for (it = fragments_.begin(); it != fragments_.end(); ++it) {
|
||||||
SrsFragment *fragment = *it;
|
ISrsFragment *fragment = *it;
|
||||||
if ((err = fragment->unlink_file()) != srs_success) {
|
if ((err = fragment->unlink_file()) != srs_success) {
|
||||||
srs_warn("Unlink ts failed %s", srs_error_desc(err).c_str());
|
srs_warn("Unlink ts failed %s", srs_error_desc(err).c_str());
|
||||||
srs_freep(err);
|
srs_freep(err);
|
||||||
|
|
@ -193,7 +209,7 @@ void SrsFragmentWindow::dispose()
|
||||||
fragments_.clear();
|
fragments_.clear();
|
||||||
|
|
||||||
for (it = expired_fragments_.begin(); it != expired_fragments_.end(); ++it) {
|
for (it = expired_fragments_.begin(); it != expired_fragments_.end(); ++it) {
|
||||||
SrsFragment *fragment = *it;
|
ISrsFragment *fragment = *it;
|
||||||
if ((err = fragment->unlink_file()) != srs_success) {
|
if ((err = fragment->unlink_file()) != srs_success) {
|
||||||
srs_warn("Unlink ts failed %s", srs_error_desc(err).c_str());
|
srs_warn("Unlink ts failed %s", srs_error_desc(err).c_str());
|
||||||
srs_freep(err);
|
srs_freep(err);
|
||||||
|
|
@ -203,7 +219,7 @@ void SrsFragmentWindow::dispose()
|
||||||
expired_fragments_.clear();
|
expired_fragments_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SrsFragmentWindow::append(SrsFragment *fragment)
|
void SrsFragmentWindow::append(ISrsFragment *fragment)
|
||||||
{
|
{
|
||||||
fragments_.push_back(fragment);
|
fragments_.push_back(fragment);
|
||||||
}
|
}
|
||||||
|
|
@ -215,7 +231,7 @@ void SrsFragmentWindow::shrink(srs_utime_t window)
|
||||||
int remove_index = -1;
|
int remove_index = -1;
|
||||||
|
|
||||||
for (int i = (int)fragments_.size() - 1; i >= 0; i--) {
|
for (int i = (int)fragments_.size() - 1; i >= 0; i--) {
|
||||||
SrsFragment *fragment = fragments_[i];
|
ISrsFragment *fragment = fragments_[i];
|
||||||
duration += fragment->duration();
|
duration += fragment->duration();
|
||||||
|
|
||||||
if (duration > window) {
|
if (duration > window) {
|
||||||
|
|
@ -225,7 +241,7 @@ void SrsFragmentWindow::shrink(srs_utime_t window)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < remove_index && !fragments_.empty(); i++) {
|
for (int i = 0; i < remove_index && !fragments_.empty(); i++) {
|
||||||
SrsFragment *fragment = *fragments_.begin();
|
ISrsFragment *fragment = *fragments_.begin();
|
||||||
fragments_.erase(fragments_.begin());
|
fragments_.erase(fragments_.begin());
|
||||||
expired_fragments_.push_back(fragment);
|
expired_fragments_.push_back(fragment);
|
||||||
}
|
}
|
||||||
|
|
@ -235,10 +251,10 @@ void SrsFragmentWindow::clear_expired(bool delete_files)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
std::vector<SrsFragment *>::iterator it;
|
std::vector<ISrsFragment *>::iterator it;
|
||||||
|
|
||||||
for (it = expired_fragments_.begin(); it != expired_fragments_.end(); ++it) {
|
for (it = expired_fragments_.begin(); it != expired_fragments_.end(); ++it) {
|
||||||
SrsFragment *fragment = *it;
|
ISrsFragment *fragment = *it;
|
||||||
if (delete_files && (err = fragment->unlink_file()) != srs_success) {
|
if (delete_files && (err = fragment->unlink_file()) != srs_success) {
|
||||||
srs_warn("Unlink ts failed, %s", srs_error_desc(err).c_str());
|
srs_warn("Unlink ts failed, %s", srs_error_desc(err).c_str());
|
||||||
srs_freep(err);
|
srs_freep(err);
|
||||||
|
|
@ -253,10 +269,10 @@ srs_utime_t SrsFragmentWindow::max_duration()
|
||||||
{
|
{
|
||||||
srs_utime_t v = 0;
|
srs_utime_t v = 0;
|
||||||
|
|
||||||
std::vector<SrsFragment *>::iterator it;
|
std::vector<ISrsFragment *>::iterator it;
|
||||||
|
|
||||||
for (it = fragments_.begin(); it != fragments_.end(); ++it) {
|
for (it = fragments_.begin(); it != fragments_.end(); ++it) {
|
||||||
SrsFragment *fragment = *it;
|
ISrsFragment *fragment = *it;
|
||||||
v = srs_max(v, fragment->duration());
|
v = srs_max(v, fragment->duration());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -268,7 +284,7 @@ bool SrsFragmentWindow::empty()
|
||||||
return fragments_.empty();
|
return fragments_.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsFragment *SrsFragmentWindow::first()
|
ISrsFragment *SrsFragmentWindow::first()
|
||||||
{
|
{
|
||||||
return fragments_.at(0);
|
return fragments_.at(0);
|
||||||
}
|
}
|
||||||
|
|
@ -278,7 +294,7 @@ int SrsFragmentWindow::size()
|
||||||
return (int)fragments_.size();
|
return (int)fragments_.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsFragment *SrsFragmentWindow::at(int index)
|
ISrsFragment *SrsFragmentWindow::at(int index)
|
||||||
{
|
{
|
||||||
return fragments_.at(index);
|
return fragments_.at(index);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,44 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
class SrsFormat;
|
||||||
|
|
||||||
|
// The fragment interface.
|
||||||
|
class ISrsFragment
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsFragment();
|
||||||
|
virtual ~ISrsFragment();
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Set the full path of fragment.
|
||||||
|
virtual void set_path(std::string v) = 0;
|
||||||
|
// Get the temporary path for file.
|
||||||
|
virtual std::string tmppath() = 0;
|
||||||
|
// Rename the temp file to final file.
|
||||||
|
virtual srs_error_t rename() = 0;
|
||||||
|
// Append a frame with dts into fragment.
|
||||||
|
virtual void append(int64_t dts) = 0;
|
||||||
|
// Create the dir for file recursively.
|
||||||
|
virtual srs_error_t create_dir() = 0;
|
||||||
|
// Set the number of this fragment.
|
||||||
|
virtual void set_number(uint64_t n) = 0;
|
||||||
|
// Get the number of this fragment.
|
||||||
|
virtual uint64_t number() = 0;
|
||||||
|
// Get the duration of fragment in srs_utime_t.
|
||||||
|
virtual srs_utime_t duration() = 0;
|
||||||
|
// Unlink the temporary file.
|
||||||
|
virtual srs_error_t unlink_tmpfile() = 0;
|
||||||
|
// Get the start dts of fragment.
|
||||||
|
virtual srs_utime_t get_start_dts() = 0;
|
||||||
|
// Unlink the fragment, to delete the file.
|
||||||
|
virtual srs_error_t unlink_file() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
// Represent a fragment, such as HLS segment, DVR segment or DASH segment.
|
// Represent a fragment, such as HLS segment, DVR segment or DASH segment.
|
||||||
// It's a media file, for example FLV or MP4, with duration.
|
// It's a media file, for example FLV or MP4, with duration.
|
||||||
class SrsFragment
|
class SrsFragment : public ISrsFragment
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
// The duration in srs_utime_t.
|
// The duration in srs_utime_t.
|
||||||
|
|
@ -68,13 +103,39 @@ public:
|
||||||
virtual uint64_t number();
|
virtual uint64_t number();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The fragment window interface.
|
||||||
|
class ISrsFragmentWindow
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsFragmentWindow();
|
||||||
|
virtual ~ISrsFragmentWindow();
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Dispose all fragments, delete the files.
|
||||||
|
virtual void dispose() = 0;
|
||||||
|
// Append a new fragment, which is ready to delivery to client.
|
||||||
|
virtual void append(ISrsFragment *fragment) = 0;
|
||||||
|
// Shrink the window, push the expired fragment to a queue.
|
||||||
|
virtual void shrink(srs_utime_t window) = 0;
|
||||||
|
// Clear the expired fragments.
|
||||||
|
virtual void clear_expired(bool delete_files) = 0;
|
||||||
|
// Get the max duration in srs_utime_t of all fragments.
|
||||||
|
virtual srs_utime_t max_duration() = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual bool empty() = 0;
|
||||||
|
virtual ISrsFragment *first() = 0;
|
||||||
|
virtual int size() = 0;
|
||||||
|
virtual ISrsFragment *at(int index) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
// The fragment window manage a series of fragment.
|
// The fragment window manage a series of fragment.
|
||||||
class SrsFragmentWindow
|
class SrsFragmentWindow : public ISrsFragmentWindow
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::vector<SrsFragment *> fragments_;
|
std::vector<ISrsFragment *> fragments_;
|
||||||
// The expired fragments, need to be free in future.
|
// The expired fragments, need to be free in future.
|
||||||
std::vector<SrsFragment *> expired_fragments_;
|
std::vector<ISrsFragment *> expired_fragments_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsFragmentWindow();
|
SrsFragmentWindow();
|
||||||
|
|
@ -84,7 +145,7 @@ public:
|
||||||
// Dispose all fragments, delete the files.
|
// Dispose all fragments, delete the files.
|
||||||
virtual void dispose();
|
virtual void dispose();
|
||||||
// Append a new fragment, which is ready to delivery to client.
|
// Append a new fragment, which is ready to delivery to client.
|
||||||
virtual void append(SrsFragment *fragment);
|
virtual void append(ISrsFragment *fragment);
|
||||||
// Shrink the window, push the expired fragment to a queue.
|
// Shrink the window, push the expired fragment to a queue.
|
||||||
virtual void shrink(srs_utime_t window);
|
virtual void shrink(srs_utime_t window);
|
||||||
// Clear the expired fragments.
|
// Clear the expired fragments.
|
||||||
|
|
@ -94,9 +155,9 @@ public:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual bool empty();
|
virtual bool empty();
|
||||||
virtual SrsFragment *first();
|
virtual ISrsFragment *first();
|
||||||
virtual int size();
|
virtual int size();
|
||||||
virtual SrsFragment *at(int index);
|
virtual ISrsFragment *at(int index);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -328,7 +328,7 @@ SrsGbListener::SrsGbListener()
|
||||||
media_listener_ = new SrsTcpListener(this);
|
media_listener_ = new SrsTcpListener(this);
|
||||||
|
|
||||||
config_ = _srs_config;
|
config_ = _srs_config;
|
||||||
api_server_owner_ = _srs_server;
|
api_server_owner_ = NULL;
|
||||||
gb_manager_ = _srs_gb_manager;
|
gb_manager_ = _srs_gb_manager;
|
||||||
app_factory_ = _srs_app_factory;
|
app_factory_ = _srs_app_factory;
|
||||||
}
|
}
|
||||||
|
|
@ -348,6 +348,12 @@ srs_error_t SrsGbListener::initialize(SrsConfDirective *conf)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
// We should initialize the owner in initialize, because the SRS server
|
||||||
|
// is not ready in the constructor.
|
||||||
|
if (!api_server_owner_) {
|
||||||
|
api_server_owner_ = _srs_server;
|
||||||
|
}
|
||||||
|
|
||||||
srs_freep(conf_);
|
srs_freep(conf_);
|
||||||
conf_ = conf->copy();
|
conf_ = conf->copy();
|
||||||
|
|
||||||
|
|
@ -381,6 +387,10 @@ srs_error_t SrsGbListener::listen_api()
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
ISrsHttpServeMux *mux = api_server_owner_->api_server();
|
ISrsHttpServeMux *mux = api_server_owner_->api_server();
|
||||||
|
if (!mux) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
if ((err = mux->handle("/gb/v1/publish/", new SrsGoApiGbPublish(conf_))) != srs_success) {
|
if ((err = mux->handle("/gb/v1/publish/", new SrsGoApiGbPublish(conf_))) != srs_success) {
|
||||||
return srs_error_wrap(err, "handle publish");
|
return srs_error_wrap(err, "handle publish");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,15 +29,27 @@ using namespace std;
|
||||||
// To limit user to use too long password, to cause unknown issue.
|
// To limit user to use too long password, to cause unknown issue.
|
||||||
#define SRS_ICE_PWD_MAX 32
|
#define SRS_ICE_PWD_MAX 32
|
||||||
|
|
||||||
SrsGoApiRtcPlay::SrsGoApiRtcPlay(SrsServer *server)
|
SrsGoApiRtcPlay::SrsGoApiRtcPlay(ISrsRtcApiServer *server)
|
||||||
{
|
{
|
||||||
server_ = server;
|
server_ = server;
|
||||||
security_ = new SrsSecurity();
|
security_ = new SrsSecurity();
|
||||||
|
|
||||||
|
config_ = _srs_config;
|
||||||
|
stat_ = _srs_stat;
|
||||||
|
rtc_sources_ = _srs_rtc_sources;
|
||||||
|
live_sources_ = _srs_sources;
|
||||||
|
hooks_ = _srs_hooks;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsGoApiRtcPlay::~SrsGoApiRtcPlay()
|
SrsGoApiRtcPlay::~SrsGoApiRtcPlay()
|
||||||
{
|
{
|
||||||
srs_freep(security_);
|
srs_freep(security_);
|
||||||
|
|
||||||
|
config_ = NULL;
|
||||||
|
stat_ = NULL;
|
||||||
|
rtc_sources_ = NULL;
|
||||||
|
live_sources_ = NULL;
|
||||||
|
hooks_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request:
|
// Request:
|
||||||
|
|
@ -135,7 +147,7 @@ srs_error_t SrsGoApiRtcPlay::do_serve_http(ISrsHttpResponseWriter *w, ISrsHttpMe
|
||||||
ruc.req_->app_, ruc.req_->stream_, ruc.req_->port_, ruc.req_->param_);
|
ruc.req_->app_, ruc.req_->stream_, ruc.req_->port_, ruc.req_->param_);
|
||||||
|
|
||||||
// discovery vhost, resolve the vhost from config
|
// discovery vhost, resolve the vhost from config
|
||||||
SrsConfDirective *parsed_vhost = _srs_config->get_vhost(ruc.req_->vhost_);
|
SrsConfDirective *parsed_vhost = config_->get_vhost(ruc.req_->vhost_);
|
||||||
if (parsed_vhost) {
|
if (parsed_vhost) {
|
||||||
ruc.req_->vhost_ = parsed_vhost->arg0();
|
ruc.req_->vhost_ = parsed_vhost->arg0();
|
||||||
}
|
}
|
||||||
|
|
@ -162,7 +174,7 @@ srs_error_t SrsGoApiRtcPlay::do_serve_http(ISrsHttpResponseWriter *w, ISrsHttpMe
|
||||||
ruc.dtls_ = (dtls != "false");
|
ruc.dtls_ = (dtls != "false");
|
||||||
|
|
||||||
if (srtp.empty()) {
|
if (srtp.empty()) {
|
||||||
ruc.srtp_ = _srs_config->get_rtc_server_encrypt();
|
ruc.srtp_ = config_->get_rtc_server_encrypt();
|
||||||
} else {
|
} else {
|
||||||
ruc.srtp_ = (srtp != "false");
|
ruc.srtp_ = (srtp != "false");
|
||||||
}
|
}
|
||||||
|
|
@ -178,9 +190,9 @@ srs_error_t SrsGoApiRtcPlay::do_serve_http(ISrsHttpResponseWriter *w, ISrsHttpMe
|
||||||
}
|
}
|
||||||
|
|
||||||
res->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
|
res->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
|
||||||
res->set("server", SrsJsonAny::str(_srs_stat->server_id().c_str()));
|
res->set("server", SrsJsonAny::str(stat_->server_id().c_str()));
|
||||||
res->set("service", SrsJsonAny::str(_srs_stat->service_id().c_str()));
|
res->set("service", SrsJsonAny::str(stat_->service_id().c_str()));
|
||||||
res->set("pid", SrsJsonAny::str(_srs_stat->service_pid().c_str()));
|
res->set("pid", SrsJsonAny::str(stat_->service_pid().c_str()));
|
||||||
|
|
||||||
// TODO: add candidates in response json?
|
// TODO: add candidates in response json?
|
||||||
res->set("sdp", SrsJsonAny::str(ruc.local_sdp_str_.c_str()));
|
res->set("sdp", SrsJsonAny::str(ruc.local_sdp_str_.c_str()));
|
||||||
|
|
@ -200,13 +212,13 @@ srs_error_t SrsGoApiRtcPlay::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessa
|
||||||
SrsSdp local_sdp;
|
SrsSdp local_sdp;
|
||||||
|
|
||||||
// Config for SDP and session.
|
// Config for SDP and session.
|
||||||
local_sdp.session_config_.dtls_role_ = _srs_config->get_rtc_dtls_role(ruc->req_->vhost_);
|
local_sdp.session_config_.dtls_role_ = config_->get_rtc_dtls_role(ruc->req_->vhost_);
|
||||||
local_sdp.session_config_.dtls_version_ = _srs_config->get_rtc_dtls_version(ruc->req_->vhost_);
|
local_sdp.session_config_.dtls_version_ = config_->get_rtc_dtls_version(ruc->req_->vhost_);
|
||||||
|
|
||||||
// Whether enabled.
|
// Whether enabled.
|
||||||
bool server_enabled = _srs_config->get_rtc_server_enabled();
|
bool server_enabled = config_->get_rtc_server_enabled();
|
||||||
bool rtc_enabled = _srs_config->get_rtc_enabled(ruc->req_->vhost_);
|
bool rtc_enabled = config_->get_rtc_enabled(ruc->req_->vhost_);
|
||||||
bool edge = _srs_config->get_vhost_is_edge(ruc->req_->vhost_);
|
bool edge = config_->get_vhost_is_edge(ruc->req_->vhost_);
|
||||||
|
|
||||||
if (rtc_enabled && edge) {
|
if (rtc_enabled && edge) {
|
||||||
rtc_enabled = false;
|
rtc_enabled = false;
|
||||||
|
|
@ -224,19 +236,19 @@ srs_error_t SrsGoApiRtcPlay::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessa
|
||||||
// Whether RTC stream is active.
|
// Whether RTC stream is active.
|
||||||
bool is_rtc_stream_active = false;
|
bool is_rtc_stream_active = false;
|
||||||
if (true) {
|
if (true) {
|
||||||
SrsSharedPtr<SrsRtcSource> source = _srs_rtc_sources->fetch(ruc->req_);
|
SrsSharedPtr<SrsRtcSource> source = rtc_sources_->fetch(ruc->req_);
|
||||||
is_rtc_stream_active = (source.get() && !source->can_publish());
|
is_rtc_stream_active = (source.get() && !source->can_publish());
|
||||||
}
|
}
|
||||||
|
|
||||||
// For RTMP to RTC, fail if disabled and RTMP is active, see https://github.com/ossrs/srs/issues/2728
|
// For RTMP to RTC, fail if disabled and RTMP is active, see https://github.com/ossrs/srs/issues/2728
|
||||||
bool rtmp_to_rtc = _srs_config->get_rtc_from_rtmp(ruc->req_->vhost_);
|
bool rtmp_to_rtc = config_->get_rtc_from_rtmp(ruc->req_->vhost_);
|
||||||
if (rtmp_to_rtc && edge) {
|
if (rtmp_to_rtc && edge) {
|
||||||
rtmp_to_rtc = false;
|
rtmp_to_rtc = false;
|
||||||
srs_warn("disable RTMP to WebRTC for edge vhost=%s", ruc->req_->vhost_.c_str());
|
srs_warn("disable RTMP to WebRTC for edge vhost=%s", ruc->req_->vhost_.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_rtc_stream_active && !rtmp_to_rtc) {
|
if (!is_rtc_stream_active && !rtmp_to_rtc) {
|
||||||
SrsSharedPtr<SrsLiveSource> live_source = _srs_sources->fetch(ruc->req_);
|
SrsSharedPtr<SrsLiveSource> live_source = live_sources_->fetch(ruc->req_);
|
||||||
if (live_source.get() && !live_source->inactive()) {
|
if (live_source.get() && !live_source->inactive()) {
|
||||||
return srs_error_new(ERROR_RTC_DISABLED, "Disabled rtmp_to_rtc of %s, see #2728", ruc->req_->vhost_.c_str());
|
return srs_error_new(ERROR_RTC_DISABLED, "Disabled rtmp_to_rtc of %s, see #2728", ruc->req_->vhost_.c_str());
|
||||||
}
|
}
|
||||||
|
|
@ -310,7 +322,7 @@ srs_error_t SrsGoApiRtcPlay::http_hooks_on_play(ISrsRequest *req)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
if (!_srs_config->get_vhost_http_hooks_enabled(req->vhost_)) {
|
if (!config_->get_vhost_http_hooks_enabled(req->vhost_)) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -320,7 +332,7 @@ srs_error_t SrsGoApiRtcPlay::http_hooks_on_play(ISrsRequest *req)
|
||||||
vector<string> hooks;
|
vector<string> hooks;
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
SrsConfDirective *conf = _srs_config->get_vhost_on_play(req->vhost_);
|
SrsConfDirective *conf = config_->get_vhost_on_play(req->vhost_);
|
||||||
|
|
||||||
if (!conf) {
|
if (!conf) {
|
||||||
return err;
|
return err;
|
||||||
|
|
@ -331,7 +343,7 @@ srs_error_t SrsGoApiRtcPlay::http_hooks_on_play(ISrsRequest *req)
|
||||||
|
|
||||||
for (int i = 0; i < (int)hooks.size(); i++) {
|
for (int i = 0; i < (int)hooks.size(); i++) {
|
||||||
std::string url = hooks.at(i);
|
std::string url = hooks.at(i);
|
||||||
if ((err = _srs_hooks->on_play(url, req)) != srs_success) {
|
if ((err = hooks_->on_play(url, req)) != srs_success) {
|
||||||
return srs_error_wrap(err, "on_play %s", url.c_str());
|
return srs_error_wrap(err, "on_play %s", url.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -339,15 +351,23 @@ srs_error_t SrsGoApiRtcPlay::http_hooks_on_play(ISrsRequest *req)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsGoApiRtcPublish::SrsGoApiRtcPublish(SrsServer *server)
|
SrsGoApiRtcPublish::SrsGoApiRtcPublish(ISrsRtcApiServer *server)
|
||||||
{
|
{
|
||||||
server_ = server;
|
server_ = server;
|
||||||
security_ = new SrsSecurity();
|
security_ = new SrsSecurity();
|
||||||
|
|
||||||
|
config_ = _srs_config;
|
||||||
|
stat_ = _srs_stat;
|
||||||
|
hooks_ = _srs_hooks;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsGoApiRtcPublish::~SrsGoApiRtcPublish()
|
SrsGoApiRtcPublish::~SrsGoApiRtcPublish()
|
||||||
{
|
{
|
||||||
srs_freep(security_);
|
srs_freep(security_);
|
||||||
|
|
||||||
|
config_ = NULL;
|
||||||
|
stat_ = NULL;
|
||||||
|
hooks_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request:
|
// Request:
|
||||||
|
|
@ -446,7 +466,7 @@ srs_error_t SrsGoApiRtcPublish::do_serve_http(ISrsHttpResponseWriter *w, ISrsHtt
|
||||||
ruc.req_->param_ = srs_strings_trim_start(ruc.req_->param_ + "&upstream=rtc", "&");
|
ruc.req_->param_ = srs_strings_trim_start(ruc.req_->param_ + "&upstream=rtc", "&");
|
||||||
|
|
||||||
// discovery vhost, resolve the vhost from config
|
// discovery vhost, resolve the vhost from config
|
||||||
SrsConfDirective *parsed_vhost = _srs_config->get_vhost(ruc.req_->vhost_);
|
SrsConfDirective *parsed_vhost = config_->get_vhost(ruc.req_->vhost_);
|
||||||
if (parsed_vhost) {
|
if (parsed_vhost) {
|
||||||
ruc.req_->vhost_ = parsed_vhost->arg0();
|
ruc.req_->vhost_ = parsed_vhost->arg0();
|
||||||
}
|
}
|
||||||
|
|
@ -478,9 +498,9 @@ srs_error_t SrsGoApiRtcPublish::do_serve_http(ISrsHttpResponseWriter *w, ISrsHtt
|
||||||
}
|
}
|
||||||
|
|
||||||
res->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
|
res->set("code", SrsJsonAny::integer(ERROR_SUCCESS));
|
||||||
res->set("server", SrsJsonAny::str(_srs_stat->server_id().c_str()));
|
res->set("server", SrsJsonAny::str(stat_->server_id().c_str()));
|
||||||
res->set("service", SrsJsonAny::str(_srs_stat->service_id().c_str()));
|
res->set("service", SrsJsonAny::str(stat_->service_id().c_str()));
|
||||||
res->set("pid", SrsJsonAny::str(_srs_stat->service_pid().c_str()));
|
res->set("pid", SrsJsonAny::str(stat_->service_pid().c_str()));
|
||||||
|
|
||||||
// TODO: add candidates in response json?
|
// TODO: add candidates in response json?
|
||||||
res->set("sdp", SrsJsonAny::str(ruc.local_sdp_str_.c_str()));
|
res->set("sdp", SrsJsonAny::str(ruc.local_sdp_str_.c_str()));
|
||||||
|
|
@ -501,13 +521,13 @@ srs_error_t SrsGoApiRtcPublish::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMe
|
||||||
|
|
||||||
// TODO: FIXME: move to create_session.
|
// TODO: FIXME: move to create_session.
|
||||||
// Config for SDP and session.
|
// Config for SDP and session.
|
||||||
local_sdp.session_config_.dtls_role_ = _srs_config->get_rtc_dtls_role(ruc->req_->vhost_);
|
local_sdp.session_config_.dtls_role_ = config_->get_rtc_dtls_role(ruc->req_->vhost_);
|
||||||
local_sdp.session_config_.dtls_version_ = _srs_config->get_rtc_dtls_version(ruc->req_->vhost_);
|
local_sdp.session_config_.dtls_version_ = config_->get_rtc_dtls_version(ruc->req_->vhost_);
|
||||||
|
|
||||||
// Whether enabled.
|
// Whether enabled.
|
||||||
bool server_enabled = _srs_config->get_rtc_server_enabled();
|
bool server_enabled = config_->get_rtc_server_enabled();
|
||||||
bool rtc_enabled = _srs_config->get_rtc_enabled(ruc->req_->vhost_);
|
bool rtc_enabled = config_->get_rtc_enabled(ruc->req_->vhost_);
|
||||||
bool edge = _srs_config->get_vhost_is_edge(ruc->req_->vhost_);
|
bool edge = config_->get_vhost_is_edge(ruc->req_->vhost_);
|
||||||
|
|
||||||
if (rtc_enabled && edge) {
|
if (rtc_enabled && edge) {
|
||||||
rtc_enabled = false;
|
rtc_enabled = false;
|
||||||
|
|
@ -592,7 +612,7 @@ srs_error_t SrsGoApiRtcPublish::http_hooks_on_publish(ISrsRequest *req)
|
||||||
{
|
{
|
||||||
srs_error_t err = srs_success;
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
if (!_srs_config->get_vhost_http_hooks_enabled(req->vhost_)) {
|
if (!config_->get_vhost_http_hooks_enabled(req->vhost_)) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -602,7 +622,7 @@ srs_error_t SrsGoApiRtcPublish::http_hooks_on_publish(ISrsRequest *req)
|
||||||
vector<string> hooks;
|
vector<string> hooks;
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
SrsConfDirective *conf = _srs_config->get_vhost_on_publish(req->vhost_);
|
SrsConfDirective *conf = config_->get_vhost_on_publish(req->vhost_);
|
||||||
if (!conf) {
|
if (!conf) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
@ -611,7 +631,7 @@ srs_error_t SrsGoApiRtcPublish::http_hooks_on_publish(ISrsRequest *req)
|
||||||
|
|
||||||
for (int i = 0; i < (int)hooks.size(); i++) {
|
for (int i = 0; i < (int)hooks.size(); i++) {
|
||||||
std::string url = hooks.at(i);
|
std::string url = hooks.at(i);
|
||||||
if ((err = _srs_hooks->on_publish(url, req)) != srs_success) {
|
if ((err = hooks_->on_publish(url, req)) != srs_success) {
|
||||||
return srs_error_wrap(err, "rtmp on_publish %s", url.c_str());
|
return srs_error_wrap(err, "rtmp on_publish %s", url.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -619,17 +639,21 @@ srs_error_t SrsGoApiRtcPublish::http_hooks_on_publish(ISrsRequest *req)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsGoApiRtcWhip::SrsGoApiRtcWhip(SrsServer *server)
|
SrsGoApiRtcWhip::SrsGoApiRtcWhip(ISrsRtcApiServer *server)
|
||||||
{
|
{
|
||||||
server_ = server;
|
server_ = server;
|
||||||
publish_ = new SrsGoApiRtcPublish(server);
|
publish_ = new SrsGoApiRtcPublish(server);
|
||||||
play_ = new SrsGoApiRtcPlay(server);
|
play_ = new SrsGoApiRtcPlay(server);
|
||||||
|
|
||||||
|
config_ = _srs_config;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsGoApiRtcWhip::~SrsGoApiRtcWhip()
|
SrsGoApiRtcWhip::~SrsGoApiRtcWhip()
|
||||||
{
|
{
|
||||||
srs_freep(publish_);
|
srs_freep(publish_);
|
||||||
srs_freep(play_);
|
srs_freep(play_);
|
||||||
|
|
||||||
|
config_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsGoApiRtcWhip::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
|
srs_error_t SrsGoApiRtcWhip::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessage *r)
|
||||||
|
|
@ -740,7 +764,7 @@ srs_error_t SrsGoApiRtcWhip::do_serve_http(ISrsHttpResponseWriter *w, ISrsHttpMe
|
||||||
}
|
}
|
||||||
|
|
||||||
// discovery vhost, resolve the vhost from config
|
// discovery vhost, resolve the vhost from config
|
||||||
SrsConfDirective *parsed_vhost = _srs_config->get_vhost(ruc->req_->vhost_);
|
SrsConfDirective *parsed_vhost = config_->get_vhost(ruc->req_->vhost_);
|
||||||
if (parsed_vhost) {
|
if (parsed_vhost) {
|
||||||
ruc->req_->vhost_ = parsed_vhost->arg0();
|
ruc->req_->vhost_ = parsed_vhost->arg0();
|
||||||
}
|
}
|
||||||
|
|
@ -761,7 +785,7 @@ srs_error_t SrsGoApiRtcWhip::do_serve_http(ISrsHttpResponseWriter *w, ISrsHttpMe
|
||||||
// For client to specifies whether encrypt by SRTP.
|
// For client to specifies whether encrypt by SRTP.
|
||||||
ruc->dtls_ = (dtls != "false");
|
ruc->dtls_ = (dtls != "false");
|
||||||
if (srtp.empty()) {
|
if (srtp.empty()) {
|
||||||
ruc->srtp_ = _srs_config->get_rtc_server_encrypt();
|
ruc->srtp_ = config_->get_rtc_server_encrypt();
|
||||||
} else {
|
} else {
|
||||||
ruc->srtp_ = (srtp != "false");
|
ruc->srtp_ = (srtp != "false");
|
||||||
}
|
}
|
||||||
|
|
@ -780,7 +804,7 @@ srs_error_t SrsGoApiRtcWhip::do_serve_http(ISrsHttpResponseWriter *w, ISrsHttpMe
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsGoApiRtcNACK::SrsGoApiRtcNACK(SrsServer *server)
|
SrsGoApiRtcNACK::SrsGoApiRtcNACK(ISrsRtcApiServer *server)
|
||||||
{
|
{
|
||||||
server_ = server;
|
server_ = server;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,15 +15,29 @@ class SrsServer;
|
||||||
class ISrsRequest;
|
class ISrsRequest;
|
||||||
class SrsSdp;
|
class SrsSdp;
|
||||||
class SrsRtcUserConfig;
|
class SrsRtcUserConfig;
|
||||||
|
class ISrsRtcApiServer;
|
||||||
|
class ISrsSecurity;
|
||||||
|
class ISrsAppConfig;
|
||||||
|
class ISrsStatistic;
|
||||||
|
class ISrsRtcSourceManager;
|
||||||
|
class ISrsLiveSourceManager;
|
||||||
|
class ISrsHttpHooks;
|
||||||
|
|
||||||
class SrsGoApiRtcPlay : public ISrsHttpHandler
|
class SrsGoApiRtcPlay : public ISrsHttpHandler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
SrsServer *server_;
|
ISrsAppConfig *config_;
|
||||||
SrsSecurity *security_;
|
ISrsStatistic *stat_;
|
||||||
|
ISrsRtcSourceManager *rtc_sources_;
|
||||||
|
ISrsLiveSourceManager *live_sources_;
|
||||||
|
ISrsHttpHooks *hooks_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ISrsRtcApiServer *server_;
|
||||||
|
ISrsSecurity *security_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsGoApiRtcPlay(SrsServer *server);
|
SrsGoApiRtcPlay(ISrsRtcApiServer *server);
|
||||||
virtual ~SrsGoApiRtcPlay();
|
virtual ~SrsGoApiRtcPlay();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -45,11 +59,16 @@ private:
|
||||||
class SrsGoApiRtcPublish : public ISrsHttpHandler
|
class SrsGoApiRtcPublish : public ISrsHttpHandler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
SrsServer *server_;
|
ISrsAppConfig *config_;
|
||||||
SrsSecurity *security_;
|
ISrsStatistic *stat_;
|
||||||
|
ISrsHttpHooks *hooks_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ISrsRtcApiServer *server_;
|
||||||
|
ISrsSecurity *security_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsGoApiRtcPublish(SrsServer *server);
|
SrsGoApiRtcPublish(ISrsRtcApiServer *server);
|
||||||
virtual ~SrsGoApiRtcPublish();
|
virtual ~SrsGoApiRtcPublish();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -72,12 +91,15 @@ private:
|
||||||
class SrsGoApiRtcWhip : public ISrsHttpHandler
|
class SrsGoApiRtcWhip : public ISrsHttpHandler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
SrsServer *server_;
|
ISrsAppConfig *config_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ISrsRtcApiServer *server_;
|
||||||
SrsGoApiRtcPublish *publish_;
|
SrsGoApiRtcPublish *publish_;
|
||||||
SrsGoApiRtcPlay *play_;
|
SrsGoApiRtcPlay *play_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsGoApiRtcWhip(SrsServer *server);
|
SrsGoApiRtcWhip(ISrsRtcApiServer *server);
|
||||||
virtual ~SrsGoApiRtcWhip();
|
virtual ~SrsGoApiRtcWhip();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -90,10 +112,10 @@ private:
|
||||||
class SrsGoApiRtcNACK : public ISrsHttpHandler
|
class SrsGoApiRtcNACK : public ISrsHttpHandler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
SrsServer *server_;
|
ISrsRtcApiServer *server_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SrsGoApiRtcNACK(SrsServer *server);
|
SrsGoApiRtcNACK(ISrsRtcApiServer *server);
|
||||||
virtual ~SrsGoApiRtcNACK();
|
virtual ~SrsGoApiRtcNACK();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -158,6 +158,14 @@ ISrsApiServerOwner::~ISrsApiServerOwner()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ISrsRtcApiServer::ISrsRtcApiServer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsRtcApiServer::~ISrsRtcApiServer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
SrsServer::SrsServer()
|
SrsServer::SrsServer()
|
||||||
{
|
{
|
||||||
signal_reload_ = false;
|
signal_reload_ = false;
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,18 @@ public:
|
||||||
virtual ISrsHttpServeMux *api_server() = 0;
|
virtual ISrsHttpServeMux *api_server() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The RTC API server owner interface.
|
||||||
|
class ISrsRtcApiServer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsRtcApiServer();
|
||||||
|
virtual ~ISrsRtcApiServer();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t create_rtc_session(SrsRtcUserConfig *ruc, SrsSdp &local_sdp, SrsRtcConnection **psession) = 0;
|
||||||
|
virtual SrsRtcConnection *find_rtc_session_by_username(const std::string &ufrag) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
// SrsServer is the main server class of SRS (Simple Realtime Server) that provides comprehensive
|
// SrsServer is the main server class of SRS (Simple Realtime Server) that provides comprehensive
|
||||||
// streaming media server functionality. It serves as the central orchestrator for all streaming
|
// streaming media server functionality. It serves as the central orchestrator for all streaming
|
||||||
// protocols and services in a single-threaded, coroutine-based architecture.
|
// protocols and services in a single-threaded, coroutine-based architecture.
|
||||||
|
|
@ -105,7 +117,8 @@ class SrsServer : public ISrsReloadHandler, // Reload framework for permormance
|
||||||
public ISrsSrtClientHandler,
|
public ISrsSrtClientHandler,
|
||||||
public ISrsUdpMuxHandler,
|
public ISrsUdpMuxHandler,
|
||||||
public ISrsSignalHandler,
|
public ISrsSignalHandler,
|
||||||
public ISrsApiServerOwner
|
public ISrsApiServerOwner,
|
||||||
|
public ISrsRtcApiServer
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
ISrsAppConfig *config_;
|
ISrsAppConfig *config_;
|
||||||
|
|
|
||||||
|
|
@ -6990,6 +6990,14 @@ SrsMp4ObjectType SrsMp4Encoder::get_audio_object_type()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ISrsMp4M2tsInitEncoder::ISrsMp4M2tsInitEncoder()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsMp4M2tsInitEncoder::~ISrsMp4M2tsInitEncoder()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
SrsMp4M2tsInitEncoder::SrsMp4M2tsInitEncoder()
|
SrsMp4M2tsInitEncoder::SrsMp4M2tsInitEncoder()
|
||||||
{
|
{
|
||||||
writer_ = NULL;
|
writer_ = NULL;
|
||||||
|
|
@ -7580,6 +7588,14 @@ srs_error_t SrsMp4M2tsInitEncoder::config_sample_description_encryption(SrsMp4Sa
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ISrsMp4M2tsSegmentEncoder::ISrsMp4M2tsSegmentEncoder()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsMp4M2tsSegmentEncoder::~ISrsMp4M2tsSegmentEncoder()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
SrsMp4M2tsSegmentEncoder::SrsMp4M2tsSegmentEncoder()
|
SrsMp4M2tsSegmentEncoder::SrsMp4M2tsSegmentEncoder()
|
||||||
{
|
{
|
||||||
writer_ = NULL;
|
writer_ = NULL;
|
||||||
|
|
|
||||||
|
|
@ -2721,9 +2721,23 @@ private:
|
||||||
virtual SrsMp4ObjectType get_audio_object_type();
|
virtual SrsMp4ObjectType get_audio_object_type();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The fMP4 init encoder interface.
|
||||||
|
class ISrsMp4M2tsInitEncoder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsMp4M2tsInitEncoder();
|
||||||
|
virtual ~ISrsMp4M2tsInitEncoder();
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Initialize the encoder with a writer w.
|
||||||
|
virtual srs_error_t initialize(ISrsWriter *w) = 0;
|
||||||
|
// Write the sequence header.
|
||||||
|
virtual srs_error_t write(SrsFormat *format, bool video, int tid) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
// A fMP4 encoder, to write the init.mp4 with sequence header.
|
// A fMP4 encoder, to write the init.mp4 with sequence header.
|
||||||
// TODO: What the M2ts short for?
|
// TODO: What the M2ts short for?
|
||||||
class SrsMp4M2tsInitEncoder
|
class SrsMp4M2tsInitEncoder : public ISrsMp4M2tsInitEncoder
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
ISrsWriter *writer_;
|
ISrsWriter *writer_;
|
||||||
|
|
@ -2781,10 +2795,34 @@ private:
|
||||||
virtual srs_error_t config_sample_description_encryption(SrsMp4SampleEntry *box);
|
virtual srs_error_t config_sample_description_encryption(SrsMp4SampleEntry *box);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The fMP4 segment encoder interface.
|
||||||
|
class ISrsMp4M2tsSegmentEncoder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISrsMp4M2tsSegmentEncoder();
|
||||||
|
virtual ~ISrsMp4M2tsSegmentEncoder();
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Initialize the encoder with a writer w.
|
||||||
|
virtual srs_error_t initialize(ISrsWriter *w, uint32_t sequence, srs_utime_t basetime, uint32_t tid) = 0;
|
||||||
|
// Cache a sample.
|
||||||
|
// @param ht, The sample handler type, audio/soun or video/vide.
|
||||||
|
// @param ft, The frame type. For video, it's SrsVideoAvcFrameType.
|
||||||
|
// @param dts The output dts in milliseconds.
|
||||||
|
// @param pts The output pts in milliseconds.
|
||||||
|
// @param sample The output payload, user must free it.
|
||||||
|
// @param nb_sample The output size of payload.
|
||||||
|
// @remark All samples are RAW AAC/AVC data, because sequence header is writen to init.mp4.
|
||||||
|
virtual srs_error_t write_sample(SrsMp4HandlerType ht, uint16_t ft,
|
||||||
|
uint32_t dts, uint32_t pts, uint8_t *sample, uint32_t nb_sample) = 0;
|
||||||
|
// Flush the encoder, to write the moof and mdat.
|
||||||
|
virtual srs_error_t flush(uint64_t &dts) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
// A fMP4 encoder, to cache segments then flush to disk, because the fMP4 should write
|
// A fMP4 encoder, to cache segments then flush to disk, because the fMP4 should write
|
||||||
// trun box before mdat.
|
// trun box before mdat.
|
||||||
// TODO: fmp4 support package more than one tracks.
|
// TODO: fmp4 support package more than one tracks.
|
||||||
class SrsMp4M2tsSegmentEncoder
|
class SrsMp4M2tsSegmentEncoder : public ISrsMp4M2tsSegmentEncoder
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
ISrsWriter *writer_;
|
ISrsWriter *writer_;
|
||||||
|
|
|
||||||
|
|
@ -3219,6 +3219,21 @@ ISrsGbSession *MockDvrAppFactory::create_gb_session()
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ISrsInitMp4 *MockDvrAppFactory::create_init_mp4()
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsFragmentWindow *MockDvrAppFactory::create_fragment_window()
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsFragmentedMp4 *MockDvrAppFactory::create_fragmented_mp4()
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
VOID TEST(DvrSegmenterTest, OpenTypicalScenario)
|
VOID TEST(DvrSegmenterTest, OpenTypicalScenario)
|
||||||
{
|
{
|
||||||
srs_error_t err;
|
srs_error_t err;
|
||||||
|
|
|
||||||
|
|
@ -637,6 +637,9 @@ public:
|
||||||
virtual ISrsDvrSegmenter *create_dvr_mp4_segmenter();
|
virtual ISrsDvrSegmenter *create_dvr_mp4_segmenter();
|
||||||
virtual ISrsGbMediaTcpConn *create_gb_media_tcp_conn();
|
virtual ISrsGbMediaTcpConn *create_gb_media_tcp_conn();
|
||||||
virtual ISrsGbSession *create_gb_session();
|
virtual ISrsGbSession *create_gb_session();
|
||||||
|
virtual ISrsInitMp4 *create_init_mp4();
|
||||||
|
virtual ISrsFragmentWindow *create_fragment_window();
|
||||||
|
virtual ISrsFragmentedMp4 *create_fragmented_mp4();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Mock ISrsDvrSegmenter for testing SrsDvrPlan
|
// Mock ISrsDvrSegmenter for testing SrsDvrPlan
|
||||||
|
|
|
||||||
|
|
@ -2378,6 +2378,21 @@ ISrsGbSession *MockAppFactoryForGbPublish::create_gb_session()
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ISrsInitMp4 *MockAppFactoryForGbPublish::create_init_mp4()
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsFragmentWindow *MockAppFactoryForGbPublish::create_fragment_window()
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ISrsFragmentedMp4 *MockAppFactoryForGbPublish::create_fragmented_mp4()
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void MockAppFactoryForGbPublish::reset()
|
void MockAppFactoryForGbPublish::reset()
|
||||||
{
|
{
|
||||||
srs_freep(mock_gb_session_);
|
srs_freep(mock_gb_session_);
|
||||||
|
|
@ -3553,7 +3568,8 @@ srs_error_t MockProtocolReadWriterForTcpNetwork::read_fully(void *buf, size_t si
|
||||||
|
|
||||||
memcpy(buf, read_data_.data() + read_pos_, size);
|
memcpy(buf, read_data_.data() + read_pos_, size);
|
||||||
read_pos_ += size;
|
read_pos_ += size;
|
||||||
if (nread) *nread = size;
|
if (nread)
|
||||||
|
*nread = size;
|
||||||
recv_bytes_ += size;
|
recv_bytes_ += size;
|
||||||
|
|
||||||
return srs_success;
|
return srs_success;
|
||||||
|
|
@ -4154,8 +4170,8 @@ VOID TEST(RtcTcpConnTest, ReadPacketSuccess)
|
||||||
// Prepare test packet data: 2-byte length header + packet body
|
// Prepare test packet data: 2-byte length header + packet body
|
||||||
// Length = 100 bytes (0x0064 in big-endian)
|
// Length = 100 bytes (0x0064 in big-endian)
|
||||||
std::string test_data;
|
std::string test_data;
|
||||||
test_data.push_back(0x00); // Length high byte
|
test_data.push_back(0x00); // Length high byte
|
||||||
test_data.push_back(0x64); // Length low byte (100 in decimal)
|
test_data.push_back(0x64); // Length low byte (100 in decimal)
|
||||||
|
|
||||||
// Add 100 bytes of packet data
|
// Add 100 bytes of packet data
|
||||||
for (int i = 0; i < 100; i++) {
|
for (int i = 0; i < 100; i++) {
|
||||||
|
|
@ -4244,8 +4260,8 @@ VOID TEST(RtcTcpConnTest, OnTcpPktRouting)
|
||||||
// RTP packets have version bits (10) in first byte, and payload type < 64
|
// RTP packets have version bits (10) in first byte, and payload type < 64
|
||||||
char rtp_pkt[100];
|
char rtp_pkt[100];
|
||||||
memset(rtp_pkt, 0, sizeof(rtp_pkt));
|
memset(rtp_pkt, 0, sizeof(rtp_pkt));
|
||||||
rtp_pkt[0] = 0x80; // Version 2 (10xxxxxx)
|
rtp_pkt[0] = 0x80; // Version 2 (10xxxxxx)
|
||||||
rtp_pkt[1] = 0x08; // Payload type 8 (PCMA)
|
rtp_pkt[1] = 0x08; // Payload type 8 (PCMA)
|
||||||
|
|
||||||
HELPER_EXPECT_SUCCESS(tcp_conn->on_tcp_pkt(rtp_pkt, 100));
|
HELPER_EXPECT_SUCCESS(tcp_conn->on_tcp_pkt(rtp_pkt, 100));
|
||||||
|
|
||||||
|
|
@ -4253,8 +4269,8 @@ VOID TEST(RtcTcpConnTest, OnTcpPktRouting)
|
||||||
// RTCP packets have version bits (10) and payload type in range [64, 95]
|
// RTCP packets have version bits (10) and payload type in range [64, 95]
|
||||||
char rtcp_pkt[100];
|
char rtcp_pkt[100];
|
||||||
memset(rtcp_pkt, 0, sizeof(rtcp_pkt));
|
memset(rtcp_pkt, 0, sizeof(rtcp_pkt));
|
||||||
rtcp_pkt[0] = 0x80; // Version 2 (10xxxxxx)
|
rtcp_pkt[0] = 0x80; // Version 2 (10xxxxxx)
|
||||||
rtcp_pkt[1] = 0xC8; // Payload type 200 (SR - Sender Report)
|
rtcp_pkt[1] = 0xC8; // Payload type 200 (SR - Sender Report)
|
||||||
|
|
||||||
HELPER_EXPECT_SUCCESS(tcp_conn->on_tcp_pkt(rtcp_pkt, 100));
|
HELPER_EXPECT_SUCCESS(tcp_conn->on_tcp_pkt(rtcp_pkt, 100));
|
||||||
|
|
||||||
|
|
@ -4262,8 +4278,8 @@ VOID TEST(RtcTcpConnTest, OnTcpPktRouting)
|
||||||
// DTLS packets have content type in range [20, 63]
|
// DTLS packets have content type in range [20, 63]
|
||||||
char dtls_pkt[100];
|
char dtls_pkt[100];
|
||||||
memset(dtls_pkt, 0, sizeof(dtls_pkt));
|
memset(dtls_pkt, 0, sizeof(dtls_pkt));
|
||||||
dtls_pkt[0] = 0x16; // Content type: handshake (22)
|
dtls_pkt[0] = 0x16; // Content type: handshake (22)
|
||||||
dtls_pkt[1] = 0xFE; // DTLS version 1.0 (0xFEFF)
|
dtls_pkt[1] = 0xFE; // DTLS version 1.0 (0xFEFF)
|
||||||
dtls_pkt[2] = 0xFF;
|
dtls_pkt[2] = 0xFF;
|
||||||
|
|
||||||
HELPER_EXPECT_SUCCESS(tcp_conn->on_tcp_pkt(dtls_pkt, 100));
|
HELPER_EXPECT_SUCCESS(tcp_conn->on_tcp_pkt(dtls_pkt, 100));
|
||||||
|
|
|
||||||
|
|
@ -600,6 +600,9 @@ public:
|
||||||
virtual SrsDvrMp4Segmenter *create_dvr_mp4_segmenter();
|
virtual SrsDvrMp4Segmenter *create_dvr_mp4_segmenter();
|
||||||
virtual ISrsGbMediaTcpConn *create_gb_media_tcp_conn();
|
virtual ISrsGbMediaTcpConn *create_gb_media_tcp_conn();
|
||||||
virtual ISrsGbSession *create_gb_session();
|
virtual ISrsGbSession *create_gb_session();
|
||||||
|
virtual ISrsInitMp4 *create_init_mp4();
|
||||||
|
virtual ISrsFragmentWindow *create_fragment_window();
|
||||||
|
virtual ISrsFragmentedMp4 *create_fragmented_mp4();
|
||||||
void reset();
|
void reset();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
3405
trunk/src/utest/srs_utest_app15.cpp
Normal file
3405
trunk/src/utest/srs_utest_app15.cpp
Normal file
File diff suppressed because it is too large
Load Diff
452
trunk/src/utest/srs_utest_app15.hpp
Normal file
452
trunk/src/utest/srs_utest_app15.hpp
Normal file
|
|
@ -0,0 +1,452 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2013-2025 The SRS Authors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SRS_UTEST_APP15_HPP
|
||||||
|
#define SRS_UTEST_APP15_HPP
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <srs_utest_app15.hpp>
|
||||||
|
*/
|
||||||
|
#include <srs_utest.hpp>
|
||||||
|
|
||||||
|
#include <srs_app_dash.hpp>
|
||||||
|
#include <srs_app_factory.hpp>
|
||||||
|
#include <srs_app_fragment.hpp>
|
||||||
|
#include <srs_app_rtc_api.hpp>
|
||||||
|
#include <srs_app_server.hpp>
|
||||||
|
#include <srs_app_statistic.hpp>
|
||||||
|
#include <srs_kernel_file.hpp>
|
||||||
|
#include <srs_kernel_mp4.hpp>
|
||||||
|
#include <srs_protocol_http_conn.hpp>
|
||||||
|
#include <srs_protocol_http_stack.hpp>
|
||||||
|
#include <srs_protocol_sdp.hpp>
|
||||||
|
#include <srs_utest_app10.hpp>
|
||||||
|
#include <srs_utest_app11.hpp>
|
||||||
|
#include <srs_utest_app6.hpp>
|
||||||
|
|
||||||
|
// Mock ISrsMpdWriter for testing MPD fragment generation
|
||||||
|
class MockMpdWriter : public ISrsMpdWriter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string file_home_;
|
||||||
|
std::string file_name_;
|
||||||
|
int64_t sequence_number_;
|
||||||
|
bool get_fragment_called_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockMpdWriter();
|
||||||
|
virtual ~MockMpdWriter();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t get_fragment(bool video, std::string &home, std::string &filename, int64_t time, int64_t &sn);
|
||||||
|
|
||||||
|
// Stub implementations for other ISrsMpdWriter methods
|
||||||
|
virtual void dispose() {}
|
||||||
|
virtual srs_error_t initialize(ISrsRequest *r) { return srs_success; }
|
||||||
|
virtual srs_error_t on_publish() { return srs_success; }
|
||||||
|
virtual void on_unpublish() {}
|
||||||
|
virtual srs_error_t write(SrsFormat *format, ISrsFragmentWindow *afragments, ISrsFragmentWindow *vfragments) { return srs_success; }
|
||||||
|
virtual void set_availability_start_time(srs_utime_t t) {}
|
||||||
|
virtual srs_utime_t get_availability_start_time() { return 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock ISrsMp4M2tsSegmentEncoder for testing MP4 encoding
|
||||||
|
class MockMp4SegmentEncoder : public ISrsMp4M2tsSegmentEncoder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool initialize_called_;
|
||||||
|
bool write_sample_called_;
|
||||||
|
bool flush_called_;
|
||||||
|
uint32_t last_sequence_;
|
||||||
|
srs_utime_t last_basetime_;
|
||||||
|
uint32_t last_tid_;
|
||||||
|
SrsMp4HandlerType last_handler_type_;
|
||||||
|
uint32_t last_dts_;
|
||||||
|
uint32_t last_pts_;
|
||||||
|
uint32_t last_sample_size_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockMp4SegmentEncoder();
|
||||||
|
virtual ~MockMp4SegmentEncoder();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t initialize(ISrsWriter *w, uint32_t sequence, srs_utime_t basetime, uint32_t tid);
|
||||||
|
virtual srs_error_t write_sample(SrsMp4HandlerType ht, uint16_t ft, uint32_t dts, uint32_t pts, uint8_t *sample, uint32_t nb_sample);
|
||||||
|
virtual srs_error_t flush(uint64_t &dts);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock ISrsFragment for testing SrsInitMp4 delegation
|
||||||
|
class MockFragment : public ISrsFragment
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string path_;
|
||||||
|
std::string tmppath_;
|
||||||
|
uint64_t number_;
|
||||||
|
srs_utime_t duration_;
|
||||||
|
srs_utime_t start_dts_;
|
||||||
|
|
||||||
|
bool set_path_called_;
|
||||||
|
bool tmppath_called_;
|
||||||
|
bool rename_called_;
|
||||||
|
bool append_called_;
|
||||||
|
bool create_dir_called_;
|
||||||
|
bool set_number_called_;
|
||||||
|
bool number_called_;
|
||||||
|
bool duration_called_;
|
||||||
|
bool unlink_tmpfile_called_;
|
||||||
|
bool get_start_dts_called_;
|
||||||
|
bool unlink_file_called_;
|
||||||
|
|
||||||
|
int64_t append_dts_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockFragment();
|
||||||
|
virtual ~MockFragment();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void set_path(std::string v);
|
||||||
|
virtual std::string tmppath();
|
||||||
|
virtual srs_error_t rename();
|
||||||
|
virtual void append(int64_t dts);
|
||||||
|
virtual srs_error_t create_dir();
|
||||||
|
virtual void set_number(uint64_t n);
|
||||||
|
virtual uint64_t number();
|
||||||
|
virtual srs_utime_t duration();
|
||||||
|
virtual srs_error_t unlink_tmpfile();
|
||||||
|
virtual srs_utime_t get_start_dts();
|
||||||
|
virtual srs_error_t unlink_file();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock ISrsFragmentWindow for testing SrsDashController
|
||||||
|
class MockFragmentWindow : public ISrsFragmentWindow
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool dispose_called_;
|
||||||
|
bool append_called_;
|
||||||
|
bool shrink_called_;
|
||||||
|
bool clear_expired_called_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockFragmentWindow();
|
||||||
|
virtual ~MockFragmentWindow();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void dispose();
|
||||||
|
virtual void append(ISrsFragment *fragment);
|
||||||
|
virtual void shrink(srs_utime_t window);
|
||||||
|
virtual void clear_expired(bool delete_files);
|
||||||
|
virtual srs_utime_t max_duration();
|
||||||
|
virtual bool empty();
|
||||||
|
virtual ISrsFragment *first();
|
||||||
|
virtual int size();
|
||||||
|
virtual ISrsFragment *at(int index);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock ISrsFragmentedMp4 for testing SrsDashController
|
||||||
|
class MockFragmentedMp4 : public ISrsFragmentedMp4
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool initialize_called_;
|
||||||
|
bool write_called_;
|
||||||
|
bool reap_called_;
|
||||||
|
bool unlink_tmpfile_called_;
|
||||||
|
srs_error_t unlink_tmpfile_error_;
|
||||||
|
srs_utime_t duration_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockFragmentedMp4();
|
||||||
|
virtual ~MockFragmentedMp4();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t initialize(ISrsRequest *r, bool video, int64_t time, ISrsMpdWriter *mpd, uint32_t tid);
|
||||||
|
virtual srs_error_t write(SrsMediaPacket *shared_msg, SrsFormat *format);
|
||||||
|
virtual srs_error_t reap(uint64_t &dts);
|
||||||
|
|
||||||
|
public:
|
||||||
|
// ISrsFragment interface implementations
|
||||||
|
virtual void set_path(std::string v);
|
||||||
|
virtual std::string tmppath();
|
||||||
|
virtual srs_error_t rename();
|
||||||
|
virtual void append(int64_t dts);
|
||||||
|
virtual srs_error_t create_dir();
|
||||||
|
virtual void set_number(uint64_t n);
|
||||||
|
virtual uint64_t number();
|
||||||
|
virtual srs_utime_t duration();
|
||||||
|
virtual srs_error_t unlink_tmpfile();
|
||||||
|
virtual srs_utime_t get_start_dts();
|
||||||
|
virtual srs_error_t unlink_file();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Forward declaration
|
||||||
|
class MockDashAppFactory;
|
||||||
|
|
||||||
|
// Mock ISrsInitMp4 for testing SrsDashController refresh_init_mp4
|
||||||
|
class MockInitMp4 : public ISrsInitMp4
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool set_path_called_;
|
||||||
|
bool write_called_;
|
||||||
|
bool rename_called_;
|
||||||
|
std::string path_;
|
||||||
|
bool video_;
|
||||||
|
int tid_;
|
||||||
|
MockDashAppFactory *factory_; // Reference to factory to copy state on destruction
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockInitMp4(MockDashAppFactory *factory);
|
||||||
|
virtual ~MockInitMp4();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t write(SrsFormat *format, bool video, int tid);
|
||||||
|
|
||||||
|
public:
|
||||||
|
// ISrsFragment interface implementations
|
||||||
|
virtual void set_path(std::string v);
|
||||||
|
virtual std::string tmppath();
|
||||||
|
virtual srs_error_t rename();
|
||||||
|
virtual void append(int64_t dts);
|
||||||
|
virtual srs_error_t create_dir();
|
||||||
|
virtual void set_number(uint64_t n);
|
||||||
|
virtual uint64_t number();
|
||||||
|
virtual srs_utime_t duration();
|
||||||
|
virtual srs_error_t unlink_tmpfile();
|
||||||
|
virtual srs_utime_t get_start_dts();
|
||||||
|
virtual srs_error_t unlink_file();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock ISrsAppFactory for testing SrsDashController
|
||||||
|
class MockDashAppFactory : public SrsAppFactory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Track the last created init mp4 state (before it's deleted)
|
||||||
|
bool last_set_path_called_;
|
||||||
|
bool last_write_called_;
|
||||||
|
bool last_rename_called_;
|
||||||
|
std::string last_path_;
|
||||||
|
bool last_video_;
|
||||||
|
int last_tid_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockDashAppFactory();
|
||||||
|
virtual ~MockDashAppFactory();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ISrsInitMp4 *create_init_mp4();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock ISrsDashController for testing SrsDash lifecycle
|
||||||
|
class MockDashController : public ISrsDashController
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool initialize_called_;
|
||||||
|
bool on_publish_called_;
|
||||||
|
bool on_unpublish_called_;
|
||||||
|
bool dispose_called_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockDashController();
|
||||||
|
virtual ~MockDashController();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void dispose();
|
||||||
|
virtual srs_error_t initialize(ISrsRequest *r);
|
||||||
|
virtual srs_error_t on_publish();
|
||||||
|
virtual void on_unpublish();
|
||||||
|
virtual srs_error_t on_audio(SrsMediaPacket *shared_audio, SrsFormat *format);
|
||||||
|
virtual srs_error_t on_video(SrsMediaPacket *shared_video, SrsFormat *format);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock SrsRtcConnection for testing NACK API
|
||||||
|
class MockRtcConnectionForNackApi
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int simulate_nack_drop_value_;
|
||||||
|
bool simulate_nack_drop_called_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockRtcConnectionForNackApi();
|
||||||
|
~MockRtcConnectionForNackApi();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void simulate_nack_drop(int nn);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock ISrsRtcApiServer for testing RTC API
|
||||||
|
class MockRtcApiServer : public ISrsRtcApiServer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool create_session_called_;
|
||||||
|
std::string session_id_;
|
||||||
|
std::string local_sdp_str_;
|
||||||
|
MockRtcConnectionForNackApi *mock_connection_;
|
||||||
|
std::string find_username_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockRtcApiServer();
|
||||||
|
virtual ~MockRtcApiServer();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t create_rtc_session(SrsRtcUserConfig *ruc, SrsSdp &local_sdp, SrsRtcConnection **psession);
|
||||||
|
virtual SrsRtcConnection *find_rtc_session_by_username(const std::string &ufrag);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock ISrsStatistic for testing RTC API
|
||||||
|
class MockStatisticForRtcApi : public ISrsStatistic
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string server_id_;
|
||||||
|
std::string service_id_;
|
||||||
|
std::string service_pid_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockStatisticForRtcApi();
|
||||||
|
virtual ~MockStatisticForRtcApi();
|
||||||
|
|
||||||
|
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);
|
||||||
|
virtual std::string server_id();
|
||||||
|
virtual std::string service_id();
|
||||||
|
virtual std::string service_pid();
|
||||||
|
virtual SrsStatisticVhost *find_vhost_by_id(std::string vid);
|
||||||
|
virtual SrsStatisticStream *find_stream(std::string sid);
|
||||||
|
virtual SrsStatisticClient *find_client(std::string client_id);
|
||||||
|
virtual srs_error_t dumps_vhosts(SrsJsonArray *arr);
|
||||||
|
virtual srs_error_t dumps_streams(SrsJsonArray *arr, int start, int count);
|
||||||
|
virtual srs_error_t dumps_clients(SrsJsonArray *arr, int start, int count);
|
||||||
|
virtual srs_error_t dumps_metrics(int64_t &send_bytes, int64_t &recv_bytes, int64_t &nstreams, int64_t &nclients, int64_t &total_nclients, int64_t &nerrs);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock ISrsHttpMessage for testing RTC API
|
||||||
|
class MockHttpMessageForRtcApi : public SrsHttpMessage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MockHttpConn *mock_conn_;
|
||||||
|
std::string body_content_;
|
||||||
|
std::map<std::string, std::string> query_params_;
|
||||||
|
uint8_t method_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockHttpMessageForRtcApi();
|
||||||
|
virtual ~MockHttpMessageForRtcApi();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t body_read_all(std::string &body);
|
||||||
|
virtual std::string query_get(std::string key);
|
||||||
|
virtual uint8_t method();
|
||||||
|
void set_method(uint8_t method);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock ISrsAppConfig for testing SrsGoApiRtcPlay::serve_http()
|
||||||
|
class MockAppConfigForRtcPlay : public MockAppConfig
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string dtls_role_;
|
||||||
|
std::string dtls_version_;
|
||||||
|
bool rtc_server_enabled_;
|
||||||
|
bool rtc_enabled_;
|
||||||
|
bool vhost_is_edge_;
|
||||||
|
bool rtc_from_rtmp_;
|
||||||
|
bool http_hooks_enabled_;
|
||||||
|
SrsConfDirective *on_play_directive_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockAppConfigForRtcPlay();
|
||||||
|
virtual ~MockAppConfigForRtcPlay();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual std::string get_rtc_dtls_role(std::string vhost);
|
||||||
|
virtual std::string get_rtc_dtls_version(std::string vhost);
|
||||||
|
virtual bool get_rtc_server_enabled();
|
||||||
|
virtual bool get_rtc_enabled(std::string vhost);
|
||||||
|
virtual bool get_vhost_is_edge(std::string vhost);
|
||||||
|
virtual bool get_rtc_from_rtmp(std::string vhost);
|
||||||
|
virtual bool get_vhost_http_hooks_enabled(std::string vhost);
|
||||||
|
virtual SrsConfDirective *get_vhost_on_play(std::string vhost);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock ISrsHttpHooks for testing SrsGoApiRtcPlay::serve_http()
|
||||||
|
class MockHttpHooksForRtcPlay : public ISrsHttpHooks
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int on_play_count_;
|
||||||
|
std::vector<std::pair<std::string, ISrsRequest *> > on_play_calls_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockHttpHooksForRtcPlay();
|
||||||
|
virtual ~MockHttpHooksForRtcPlay();
|
||||||
|
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock ISrsSecurity for testing SrsGoApiRtcPlay::serve_http()
|
||||||
|
class MockSecurityForRtcPlay : public ISrsSecurity
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
srs_error_t check_error_;
|
||||||
|
int check_count_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockSecurityForRtcPlay();
|
||||||
|
virtual ~MockSecurityForRtcPlay();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t check(SrsRtmpConnType type, std::string ip, ISrsRequest *req);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock SrsRtcConnection for testing SrsGoApiRtcPlay::serve_http()
|
||||||
|
class MockRtcConnectionForPlay
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string username_;
|
||||||
|
std::string token_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockRtcConnectionForPlay();
|
||||||
|
~MockRtcConnectionForPlay();
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::string username();
|
||||||
|
std::string token();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock ISrsRtcApiServer for testing SrsGoApiRtcPlay::serve_http()
|
||||||
|
class MockRtcApiServerForPlay : public ISrsRtcApiServer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool create_session_called_;
|
||||||
|
MockRtcConnectionForPlay *mock_connection_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MockRtcApiServerForPlay();
|
||||||
|
virtual ~MockRtcApiServerForPlay();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual srs_error_t create_rtc_session(SrsRtcUserConfig *ruc, SrsSdp &local_sdp, SrsRtcConnection **psession);
|
||||||
|
virtual SrsRtcConnection *find_rtc_session_by_username(const std::string &ufrag);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -2181,6 +2181,8 @@ MockAppConfig::MockAppConfig()
|
||||||
rtc_twcc_enabled_ = true;
|
rtc_twcc_enabled_ = true;
|
||||||
srt_enabled_ = false;
|
srt_enabled_ = false;
|
||||||
rtc_to_rtmp_ = false;
|
rtc_to_rtmp_ = false;
|
||||||
|
dash_dispose_ = 0;
|
||||||
|
dash_enabled_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
MockAppConfig::~MockAppConfig()
|
MockAppConfig::~MockAppConfig()
|
||||||
|
|
@ -2284,6 +2286,16 @@ bool MockAppConfig::get_rtc_stun_strict_check(std::string vhost)
|
||||||
return false; // Default to non-strict mode
|
return false; // Default to non-strict mode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string MockAppConfig::get_rtc_dtls_role(std::string vhost)
|
||||||
|
{
|
||||||
|
return "passive"; // Default DTLS role
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string MockAppConfig::get_rtc_dtls_version(std::string vhost)
|
||||||
|
{
|
||||||
|
return "auto"; // Default DTLS version
|
||||||
|
}
|
||||||
|
|
||||||
SrsConfDirective *MockAppConfig::get_vhost_on_hls(std::string vhost)
|
SrsConfDirective *MockAppConfig::get_vhost_on_hls(std::string vhost)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
||||||
|
|
@ -242,6 +242,8 @@ public:
|
||||||
bool rtc_twcc_enabled_;
|
bool rtc_twcc_enabled_;
|
||||||
bool srt_enabled_;
|
bool srt_enabled_;
|
||||||
bool rtc_to_rtmp_;
|
bool rtc_to_rtmp_;
|
||||||
|
srs_utime_t dash_dispose_;
|
||||||
|
bool dash_enabled_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MockAppConfig();
|
MockAppConfig();
|
||||||
|
|
@ -291,6 +293,7 @@ public:
|
||||||
virtual std::string get_rtc_server_protocol() { return "udp"; }
|
virtual std::string get_rtc_server_protocol() { return "udp"; }
|
||||||
virtual std::vector<std::string> get_rtc_server_listens() { return std::vector<std::string>(); }
|
virtual std::vector<std::string> get_rtc_server_listens() { return std::vector<std::string>(); }
|
||||||
virtual int get_rtc_server_reuseport() { return 1; }
|
virtual int get_rtc_server_reuseport() { return 1; }
|
||||||
|
virtual bool get_rtc_server_encrypt() { return false; }
|
||||||
virtual bool get_rtsp_server_enabled() { return false; }
|
virtual bool get_rtsp_server_enabled() { return false; }
|
||||||
virtual std::vector<std::string> get_rtsp_server_listens() { return std::vector<std::string>(); }
|
virtual std::vector<std::string> get_rtsp_server_listens() { return std::vector<std::string>(); }
|
||||||
virtual std::vector<std::string> get_srt_listens() { return std::vector<std::string>(); }
|
virtual std::vector<std::string> get_srt_listens() { return std::vector<std::string>(); }
|
||||||
|
|
@ -357,6 +360,8 @@ public:
|
||||||
virtual bool get_rtc_to_rtmp(std::string vhost);
|
virtual bool get_rtc_to_rtmp(std::string vhost);
|
||||||
virtual srs_utime_t get_rtc_stun_timeout(std::string vhost);
|
virtual srs_utime_t get_rtc_stun_timeout(std::string vhost);
|
||||||
virtual bool get_rtc_stun_strict_check(std::string vhost);
|
virtual bool get_rtc_stun_strict_check(std::string vhost);
|
||||||
|
virtual std::string get_rtc_dtls_role(std::string vhost);
|
||||||
|
virtual std::string get_rtc_dtls_version(std::string vhost);
|
||||||
virtual SrsConfDirective *get_vhost_on_hls(std::string vhost);
|
virtual SrsConfDirective *get_vhost_on_hls(std::string vhost);
|
||||||
virtual SrsConfDirective *get_vhost_on_hls_notify(std::string vhost);
|
virtual SrsConfDirective *get_vhost_on_hls_notify(std::string vhost);
|
||||||
// HLS methods
|
// HLS methods
|
||||||
|
|
@ -420,6 +425,17 @@ public:
|
||||||
virtual std::string get_vhost_edge_protocol(std::string vhost) { return "rtmp"; }
|
virtual std::string get_vhost_edge_protocol(std::string vhost) { return "rtmp"; }
|
||||||
virtual bool get_vhost_edge_follow_client(std::string vhost) { return false; }
|
virtual bool get_vhost_edge_follow_client(std::string vhost) { return false; }
|
||||||
virtual std::string get_vhost_edge_transform_vhost(std::string vhost) { return ""; }
|
virtual std::string get_vhost_edge_transform_vhost(std::string vhost) { return ""; }
|
||||||
|
// DASH methods
|
||||||
|
virtual bool get_dash_enabled(std::string vhost) { return dash_enabled_; }
|
||||||
|
virtual bool get_dash_enabled(SrsConfDirective *vhost) { return dash_enabled_; }
|
||||||
|
virtual srs_utime_t get_dash_fragment(std::string vhost) { return 30 * SRS_UTIME_SECONDS; }
|
||||||
|
virtual srs_utime_t get_dash_update_period(std::string vhost) { return 30 * SRS_UTIME_SECONDS; }
|
||||||
|
virtual srs_utime_t get_dash_timeshift(std::string vhost) { return 300 * SRS_UTIME_SECONDS; }
|
||||||
|
virtual std::string get_dash_path(std::string vhost) { return "./[vhost]/[app]/[stream]/"; }
|
||||||
|
virtual std::string get_dash_mpd_file(std::string vhost) { return "[stream].mpd"; }
|
||||||
|
virtual int get_dash_window_size(std::string vhost) { return 10; }
|
||||||
|
virtual bool get_dash_cleanup(std::string vhost) { return true; }
|
||||||
|
virtual srs_utime_t get_dash_dispose(std::string vhost) { return dash_dispose_; }
|
||||||
void set_http_hooks_enabled(bool enabled);
|
void set_http_hooks_enabled(bool enabled);
|
||||||
void set_on_stop_urls(const std::vector<std::string> &urls);
|
void set_on_stop_urls(const std::vector<std::string> &urls);
|
||||||
void clear_on_stop_directive();
|
void clear_on_stop_directive();
|
||||||
|
|
|
||||||
|
|
@ -242,6 +242,7 @@ MockAppFactory::MockAppFactory()
|
||||||
real_writer_ = NULL;
|
real_writer_ = NULL;
|
||||||
real_file_ = NULL;
|
real_file_ = NULL;
|
||||||
real_reader_ = NULL;
|
real_reader_ = NULL;
|
||||||
|
real_fragmented_mp4_ = NULL;
|
||||||
create_file_writer_count_ = 0;
|
create_file_writer_count_ = 0;
|
||||||
create_file_reader_count_ = 0;
|
create_file_reader_count_ = 0;
|
||||||
}
|
}
|
||||||
|
|
@ -253,6 +254,8 @@ MockAppFactory::~MockAppFactory()
|
||||||
// real_file_ is also not owned - it's part of real_writer_
|
// real_file_ is also not owned - it's part of real_writer_
|
||||||
// real_reader_ is owned by this factory
|
// real_reader_ is owned by this factory
|
||||||
srs_freep(real_reader_);
|
srs_freep(real_reader_);
|
||||||
|
// Note: real_fragmented_mp4_ is NOT owned by this factory - it's freed by the caller
|
||||||
|
real_fragmented_mp4_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ISrsFileWriter *MockAppFactory::create_file_writer()
|
ISrsFileWriter *MockAppFactory::create_file_writer()
|
||||||
|
|
@ -271,6 +274,15 @@ ISrsFileReader *MockAppFactory::create_file_reader()
|
||||||
return real_reader_;
|
return real_reader_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ISrsFragmentedMp4 *MockAppFactory::create_fragmented_mp4()
|
||||||
|
{
|
||||||
|
// Return the mock fragmented mp4 that was set up for testing
|
||||||
|
// The caller takes ownership of this object
|
||||||
|
ISrsFragmentedMp4 *result = real_fragmented_mp4_;
|
||||||
|
real_fragmented_mp4_ = NULL; // Clear reference after returning
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void MockAppFactory::reset()
|
void MockAppFactory::reset()
|
||||||
{
|
{
|
||||||
create_file_writer_count_ = 0;
|
create_file_writer_count_ = 0;
|
||||||
|
|
@ -280,6 +292,8 @@ void MockAppFactory::reset()
|
||||||
srs_freep(real_file_);
|
srs_freep(real_file_);
|
||||||
real_file_ = NULL;
|
real_file_ = NULL;
|
||||||
// Note: Don't free real_reader_ here as it may still be in use
|
// Note: Don't free real_reader_ here as it may still be in use
|
||||||
|
// Note: real_fragmented_mp4_ should be NULL after being returned by create_fragmented_mp4()
|
||||||
|
real_fragmented_mp4_ = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mock HLS muxer implementation
|
// Mock HLS muxer implementation
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,7 @@ public:
|
||||||
MockSrsFileWriter *real_writer_;
|
MockSrsFileWriter *real_writer_;
|
||||||
MockSrsFile *real_file_;
|
MockSrsFile *real_file_;
|
||||||
MockSrsFileReader *real_reader_;
|
MockSrsFileReader *real_reader_;
|
||||||
|
ISrsFragmentedMp4 *real_fragmented_mp4_;
|
||||||
int create_file_writer_count_;
|
int create_file_writer_count_;
|
||||||
int create_file_reader_count_;
|
int create_file_reader_count_;
|
||||||
|
|
||||||
|
|
@ -109,6 +110,7 @@ public:
|
||||||
virtual ~MockAppFactory();
|
virtual ~MockAppFactory();
|
||||||
virtual ISrsFileWriter *create_file_writer();
|
virtual ISrsFileWriter *create_file_writer();
|
||||||
virtual ISrsFileReader *create_file_reader();
|
virtual ISrsFileReader *create_file_reader();
|
||||||
|
virtual ISrsFragmentedMp4 *create_fragmented_mp4();
|
||||||
void reset();
|
void reset();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1406,7 +1406,7 @@ MockDashForOriginHub::~MockDashForOriginHub()
|
||||||
srs_freep(initialize_error_);
|
srs_freep(initialize_error_);
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t MockDashForOriginHub::initialize(SrsOriginHub *h, ISrsRequest *r)
|
srs_error_t MockDashForOriginHub::initialize(ISrsOriginHub *h, ISrsRequest *r)
|
||||||
{
|
{
|
||||||
initialize_count_++;
|
initialize_count_++;
|
||||||
return srs_error_copy(initialize_error_);
|
return srs_error_copy(initialize_error_);
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,7 @@ public:
|
||||||
public:
|
public:
|
||||||
MockDashForOriginHub();
|
MockDashForOriginHub();
|
||||||
virtual ~MockDashForOriginHub();
|
virtual ~MockDashForOriginHub();
|
||||||
virtual srs_error_t initialize(SrsOriginHub *h, ISrsRequest *r);
|
virtual srs_error_t initialize(ISrsOriginHub *h, ISrsRequest *r);
|
||||||
virtual srs_error_t on_publish();
|
virtual srs_error_t on_publish();
|
||||||
virtual srs_error_t on_audio(SrsMediaPacket *shared_audio, SrsFormat *format);
|
virtual srs_error_t on_audio(SrsMediaPacket *shared_audio, SrsFormat *format);
|
||||||
virtual srs_error_t on_video(SrsMediaPacket *shared_video, SrsFormat *format);
|
virtual srs_error_t on_video(SrsMediaPacket *shared_video, SrsFormat *format);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user