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_protocol3" "srs_utest_app" "srs_utest_app2" "srs_utest_app3" "srs_utest_app4"
|
||||
"srs_utest_app5" "srs_utest_app6" "srs_utest_app7" "srs_utest_app8" "srs_utest_app9"
|
||||
"srs_utest_app10" "srs_utest_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
|
||||
MODULE_FILES+=("srs_utest_srt")
|
||||
if [[ $SRS_GB28181 == YES ]]; then
|
||||
|
|
|
|||
|
|
@ -344,6 +344,7 @@ public:
|
|||
virtual std::string get_rtc_server_protocol() = 0;
|
||||
virtual std::vector<std::string> get_rtc_server_listens() = 0;
|
||||
virtual int get_rtc_server_reuseport() = 0;
|
||||
virtual bool get_rtc_server_encrypt() = 0;
|
||||
|
||||
public:
|
||||
// RTSP config
|
||||
|
|
@ -453,6 +454,8 @@ public:
|
|||
virtual bool get_rtc_to_rtmp(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 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_notify(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_ts_ctx_enabled(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 SrsConfDirective *get_forwards(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_config.hpp>
|
||||
#include <srs_app_factory.hpp>
|
||||
#include <srs_app_rtmp_source.hpp>
|
||||
#include <srs_app_utility.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);
|
||||
}
|
||||
|
||||
ISrsInitMp4::ISrsInitMp4()
|
||||
{
|
||||
}
|
||||
|
||||
ISrsInitMp4::~ISrsInitMp4()
|
||||
{
|
||||
}
|
||||
|
||||
SrsInitMp4::SrsInitMp4()
|
||||
{
|
||||
fw_ = new SrsFileWriter();
|
||||
init_ = new SrsMp4M2tsInitEncoder();
|
||||
fragment_ = new SrsFragment();
|
||||
}
|
||||
|
||||
SrsInitMp4::~SrsInitMp4()
|
||||
{
|
||||
srs_freep(init_);
|
||||
srs_freep(fw_);
|
||||
srs_freep(fragment_);
|
||||
}
|
||||
|
||||
srs_error_t SrsInitMp4::write(SrsFormat *format, bool video, int tid)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
string path_tmp = tmppath();
|
||||
string path_tmp = fragment_->tmppath();
|
||||
if ((err = fw_->open(path_tmp)) != srs_success) {
|
||||
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;
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
fw_ = new SrsFileWriter();
|
||||
enc_ = new SrsMp4M2tsSegmentEncoder();
|
||||
fragment_ = new SrsFragment();
|
||||
|
||||
config_ = _srs_config;
|
||||
}
|
||||
|
||||
SrsFragmentedMp4::~SrsFragmentedMp4()
|
||||
{
|
||||
srs_freep(enc_);
|
||||
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;
|
||||
|
||||
|
|
@ -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());
|
||||
}
|
||||
|
||||
string home = _srs_config->get_dash_path(r->vhost_);
|
||||
set_path(home + "/" + file_home + "/" + file_name);
|
||||
string home = config_->get_dash_path(r->vhost_);
|
||||
fragment_->set_path(home + "/" + file_home + "/" + file_name);
|
||||
// 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");
|
||||
}
|
||||
|
||||
string path_tmp = tmppath();
|
||||
string path_tmp = fragment_->tmppath();
|
||||
if ((err = fw_->open(path_tmp)) != srs_success) {
|
||||
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;
|
||||
}
|
||||
|
||||
append(shared_msg->timestamp_);
|
||||
fragment_->append(shared_msg->timestamp_);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
@ -151,13 +231,76 @@ srs_error_t SrsFragmentedMp4::reap(uint64_t &dts)
|
|||
|
||||
srs_freep(fw_);
|
||||
|
||||
if ((err = rename()) != srs_success) {
|
||||
if ((err = fragment_->rename()) != srs_success) {
|
||||
return srs_error_wrap(err, "rename");
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
req_ = NULL;
|
||||
|
|
@ -168,10 +311,15 @@ SrsMpdWriter::SrsMpdWriter()
|
|||
|
||||
video_number_ = 0;
|
||||
audio_number_ = 0;
|
||||
|
||||
config_ = _srs_config;
|
||||
app_factory_ = _srs_app_factory;
|
||||
}
|
||||
|
||||
SrsMpdWriter::~SrsMpdWriter()
|
||||
{
|
||||
config_ = NULL;
|
||||
app_factory_ = NULL;
|
||||
}
|
||||
|
||||
void SrsMpdWriter::dispose()
|
||||
|
|
@ -204,16 +352,16 @@ srs_error_t SrsMpdWriter::on_publish()
|
|||
{
|
||||
ISrsRequest *r = req_;
|
||||
|
||||
fragment_ = _srs_config->get_dash_fragment(r->vhost_);
|
||||
update_period_ = _srs_config->get_dash_update_period(r->vhost_);
|
||||
timeshit_ = _srs_config->get_dash_timeshift(r->vhost_);
|
||||
home_ = _srs_config->get_dash_path(r->vhost_);
|
||||
mpd_file_ = _srs_config->get_dash_mpd_file(r->vhost_);
|
||||
fragment_ = config_->get_dash_fragment(r->vhost_);
|
||||
update_period_ = config_->get_dash_update_period(r->vhost_);
|
||||
timeshit_ = config_->get_dash_timeshift(r->vhost_);
|
||||
home_ = config_->get_dash_path(r->vhost_);
|
||||
mpd_file_ = config_->get_dash_mpd_file(r->vhost_);
|
||||
|
||||
SrsPath path;
|
||||
string mpd_path = srs_path_build_stream(mpd_file_, req_->vhost_, req_->app_, 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",
|
||||
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;
|
||||
|
||||
|
|
@ -305,7 +453,7 @@ srs_error_t SrsMpdWriter::write(SrsFormat *format, SrsFragmentWindow *afragments
|
|||
ss << " </Period>" << endl;
|
||||
ss << "</MPD>" << endl;
|
||||
|
||||
SrsUniquePtr<SrsFileWriter> fw(new SrsFileWriter());
|
||||
SrsUniquePtr<ISrsFileWriter> fw(app_factory_->create_file_writer());
|
||||
|
||||
string full_path_tmp = full_path + ".tmp";
|
||||
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_;
|
||||
}
|
||||
|
||||
ISrsDashController::ISrsDashController()
|
||||
{
|
||||
}
|
||||
|
||||
ISrsDashController::~ISrsDashController()
|
||||
{
|
||||
}
|
||||
|
||||
SrsDashController::SrsDashController()
|
||||
{
|
||||
req_ = NULL;
|
||||
|
|
@ -372,6 +528,9 @@ SrsDashController::SrsDashController()
|
|||
first_dts_ = -1;
|
||||
video_reaped_ = false;
|
||||
fragment_ = 0;
|
||||
|
||||
app_factory_ = _srs_app_factory;
|
||||
config_ = _srs_config;
|
||||
}
|
||||
|
||||
SrsDashController::~SrsDashController()
|
||||
|
|
@ -381,6 +540,9 @@ SrsDashController::~SrsDashController()
|
|||
srs_freep(acurrent_);
|
||||
srs_freep(vfragments_);
|
||||
srs_freep(afragments_);
|
||||
|
||||
app_factory_ = NULL;
|
||||
config_ = NULL;
|
||||
}
|
||||
|
||||
void SrsDashController::dispose()
|
||||
|
|
@ -430,8 +592,8 @@ srs_error_t SrsDashController::on_publish()
|
|||
|
||||
ISrsRequest *r = req_;
|
||||
|
||||
fragment_ = _srs_config->get_dash_fragment(r->vhost_);
|
||||
home_ = _srs_config->get_dash_path(r->vhost_);
|
||||
fragment_ = config_->get_dash_fragment(r->vhost_);
|
||||
home_ = config_->get_dash_path(r->vhost_);
|
||||
|
||||
if ((err = mpd_->on_publish()) != srs_success) {
|
||||
return srs_error_wrap(err, "mpd");
|
||||
|
|
@ -439,11 +601,11 @@ srs_error_t SrsDashController::on_publish()
|
|||
|
||||
srs_freep(vcurrent_);
|
||||
srs_freep(vfragments_);
|
||||
vfragments_ = new SrsFragmentWindow();
|
||||
vfragments_ = app_factory_->create_fragment_window();
|
||||
|
||||
srs_freep(acurrent_);
|
||||
srs_freep(afragments_);
|
||||
afragments_ = new SrsFragmentWindow();
|
||||
afragments_ = app_factory_->create_fragment_window();
|
||||
|
||||
audio_dts_ = 0;
|
||||
video_dts_ = 0;
|
||||
|
|
@ -498,7 +660,7 @@ srs_error_t SrsDashController::on_audio(SrsMediaPacket *shared_audio, SrsFormat
|
|||
audio_dts_ = shared_audio->timestamp_;
|
||||
|
||||
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) {
|
||||
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_);
|
||||
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) {
|
||||
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");
|
||||
}
|
||||
|
||||
srs_utime_t fragment = _srs_config->get_dash_fragment(req_->vhost_);
|
||||
int window_size = _srs_config->get_dash_window_size(req_->vhost_);
|
||||
srs_utime_t fragment = config_->get_dash_fragment(req_->vhost_);
|
||||
int window_size = config_->get_dash_window_size(req_->vhost_);
|
||||
int dash_window = 2 * window_size * fragment;
|
||||
if (afragments_->size() > window_size) {
|
||||
int w = 0;
|
||||
|
|
@ -550,7 +712,7 @@ srs_error_t SrsDashController::on_audio(SrsMediaPacket *shared_audio, SrsFormat
|
|||
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.
|
||||
afragments_->clear_expired(dash_cleanup);
|
||||
|
||||
|
|
@ -570,7 +732,7 @@ srs_error_t SrsDashController::on_video(SrsMediaPacket *shared_video, SrsFormat
|
|||
video_dts_ = shared_video->timestamp_;
|
||||
|
||||
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) {
|
||||
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;
|
||||
|
||||
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) {
|
||||
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");
|
||||
}
|
||||
|
||||
srs_utime_t fragment = _srs_config->get_dash_fragment(req_->vhost_);
|
||||
int window_size = _srs_config->get_dash_window_size(req_->vhost_);
|
||||
srs_utime_t fragment = config_->get_dash_fragment(req_->vhost_);
|
||||
int window_size = config_->get_dash_window_size(req_->vhost_);
|
||||
int dash_window = 2 * window_size * fragment;
|
||||
if (vfragments_->size() > window_size) {
|
||||
int w = 0;
|
||||
|
|
@ -623,7 +785,7 @@ srs_error_t SrsDashController::on_video(SrsMediaPacket *shared_video, SrsFormat
|
|||
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.
|
||||
vfragments_->clear_expired(dash_cleanup);
|
||||
|
||||
|
|
@ -668,7 +830,7 @@ srs_error_t SrsDashController::refresh_init_mp4(SrsMediaPacket *msg, SrsFormat *
|
|||
path += "/audio-init.mp4";
|
||||
}
|
||||
|
||||
SrsUniquePtr<SrsInitMp4> init_mp4(new SrsInitMp4());
|
||||
SrsUniquePtr<ISrsInitMp4> init_mp4(app_factory_->create_init_mp4());
|
||||
|
||||
init_mp4->set_path(path);
|
||||
|
||||
|
|
@ -703,11 +865,15 @@ SrsDash::SrsDash()
|
|||
enabled_ = false;
|
||||
disposable_ = false;
|
||||
last_update_time_ = 0;
|
||||
|
||||
config_ = _srs_config;
|
||||
}
|
||||
|
||||
SrsDash::~SrsDash()
|
||||
{
|
||||
srs_freep(controller_);
|
||||
|
||||
config_ = NULL;
|
||||
}
|
||||
|
||||
void SrsDash::dispose()
|
||||
|
|
@ -717,7 +883,7 @@ void SrsDash::dispose()
|
|||
}
|
||||
|
||||
// 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) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -737,7 +903,7 @@ srs_error_t SrsDash::cycle()
|
|||
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) {
|
||||
return err;
|
||||
}
|
||||
|
|
@ -760,7 +926,7 @@ srs_error_t SrsDash::cycle()
|
|||
srs_utime_t SrsDash::cleanup_delay()
|
||||
{
|
||||
// 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
|
||||
|
|
@ -769,7 +935,7 @@ srs_utime_t SrsDash::cleanup_delay()
|
|||
// 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
|
||||
// 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;
|
||||
|
||||
|
|
@ -792,7 +958,7 @@ srs_error_t SrsDash::on_publish()
|
|||
return err;
|
||||
}
|
||||
|
||||
if (!_srs_config->get_dash_enabled(req_->vhost_)) {
|
||||
if (!config_->get_dash_enabled(req_->vhost_)) {
|
||||
return err;
|
||||
}
|
||||
enabled_ = true;
|
||||
|
|
|
|||
|
|
@ -16,19 +16,43 @@
|
|||
|
||||
class ISrsRequest;
|
||||
class SrsOriginHub;
|
||||
class ISrsOriginHub;
|
||||
class SrsMediaPacket;
|
||||
class SrsFormat;
|
||||
class SrsFileWriter;
|
||||
class ISrsFileWriter;
|
||||
class SrsMpdWriter;
|
||||
class ISrsMpdWriter;
|
||||
class SrsMp4M2tsInitEncoder;
|
||||
class ISrsMp4M2tsInitEncoder;
|
||||
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.
|
||||
class SrsInitMp4 : public SrsFragment
|
||||
class SrsInitMp4 : public ISrsInitMp4
|
||||
{
|
||||
private:
|
||||
SrsFileWriter *fw_;
|
||||
SrsMp4M2tsInitEncoder *init_;
|
||||
ISrsFileWriter *fw_;
|
||||
ISrsMp4M2tsInitEncoder *init_;
|
||||
ISrsFragment *fragment_;
|
||||
|
||||
public:
|
||||
SrsInitMp4();
|
||||
|
|
@ -37,14 +61,48 @@ public:
|
|||
public:
|
||||
// Write the init mp4 file, with the tid(track id).
|
||||
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.
|
||||
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:
|
||||
SrsFileWriter *fw_;
|
||||
SrsMp4M2tsSegmentEncoder *enc_;
|
||||
ISrsAppConfig *config_;
|
||||
|
||||
private:
|
||||
ISrsFileWriter *fw_;
|
||||
ISrsMp4M2tsSegmentEncoder *enc_;
|
||||
ISrsFragment *fragment_;
|
||||
|
||||
public:
|
||||
SrsFragmentedMp4();
|
||||
|
|
@ -52,16 +110,60 @@ public:
|
|||
|
||||
public:
|
||||
// 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.
|
||||
virtual srs_error_t write(SrsMediaPacket *shared_msg, SrsFormat *format);
|
||||
// Reap the fragment, close the fd and rename tmp to official file.
|
||||
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.
|
||||
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:
|
||||
ISrsRequest *req_;
|
||||
|
||||
|
|
@ -101,7 +203,7 @@ public:
|
|||
virtual srs_error_t on_publish();
|
||||
virtual void on_unpublish();
|
||||
// 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:
|
||||
// Get the fragment relative home and filename.
|
||||
|
|
@ -112,19 +214,41 @@ public:
|
|||
virtual srs_utime_t get_availability_start_time();
|
||||
};
|
||||
|
||||
// The controller for DASH, control the MPD and FMP4 generating system.
|
||||
class SrsDashController
|
||||
// The DASH controller interface.
|
||||
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:
|
||||
ISrsRequest *req_;
|
||||
SrsFormat *format_;
|
||||
SrsMpdWriter *mpd_;
|
||||
ISrsMpdWriter *mpd_;
|
||||
|
||||
private:
|
||||
SrsFragmentedMp4 *vcurrent_;
|
||||
SrsFragmentWindow *vfragments_;
|
||||
SrsFragmentedMp4 *acurrent_;
|
||||
SrsFragmentWindow *afragments_;
|
||||
ISrsFragmentedMp4 *vcurrent_;
|
||||
ISrsFragmentWindow *vfragments_;
|
||||
ISrsFragmentedMp4 *acurrent_;
|
||||
ISrsFragmentWindow *afragments_;
|
||||
// Current audio dts.
|
||||
uint64_t audio_dts_;
|
||||
// Current video dts.
|
||||
|
|
@ -175,7 +299,7 @@ public:
|
|||
virtual srs_utime_t cleanup_delay() = 0;
|
||||
|
||||
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_audio(SrsMediaPacket *shared_audio, 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.
|
||||
class SrsDash : public ISrsDash
|
||||
{
|
||||
private:
|
||||
ISrsAppConfig *config_;
|
||||
|
||||
private:
|
||||
bool enabled_;
|
||||
bool disposable_;
|
||||
|
|
@ -192,8 +319,8 @@ private:
|
|||
|
||||
private:
|
||||
ISrsRequest *req_;
|
||||
SrsOriginHub *hub_;
|
||||
SrsDashController *controller_;
|
||||
ISrsOriginHub *hub_;
|
||||
ISrsDashController *controller_;
|
||||
|
||||
public:
|
||||
SrsDash();
|
||||
|
|
@ -206,7 +333,7 @@ public:
|
|||
|
||||
public:
|
||||
// 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.
|
||||
virtual srs_error_t on_publish();
|
||||
// When got an shared audio message.
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@
|
|||
|
||||
#include <srs_app_caster_flv.hpp>
|
||||
#include <srs_app_config.hpp>
|
||||
#include <srs_app_dash.hpp>
|
||||
#include <srs_app_dvr.hpp>
|
||||
#include <srs_app_fragment.hpp>
|
||||
#include <srs_app_gb28181.hpp>
|
||||
#include <srs_app_rtmp_conn.hpp>
|
||||
#include <srs_app_rtmp_source.hpp>
|
||||
|
|
@ -140,6 +142,21 @@ ISrsGbSession *SrsAppFactory::create_gb_session()
|
|||
}
|
||||
#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()
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,10 @@ class ISrsMp4Encoder;
|
|||
class ISrsDvrSegmenter;
|
||||
class ISrsGbMediaTcpConn;
|
||||
class ISrsGbSession;
|
||||
class ISrsFragment;
|
||||
class ISrsInitMp4;
|
||||
class ISrsFragmentWindow;
|
||||
class ISrsFragmentedMp4;
|
||||
|
||||
// The factory to create app objects.
|
||||
class ISrsAppFactory
|
||||
|
|
@ -63,6 +67,9 @@ public:
|
|||
virtual ISrsGbMediaTcpConn *create_gb_media_tcp_conn() = 0;
|
||||
virtual ISrsGbSession *create_gb_session() = 0;
|
||||
#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.
|
||||
|
|
@ -96,6 +103,9 @@ public:
|
|||
virtual ISrsGbMediaTcpConn *create_gb_media_tcp_conn();
|
||||
virtual ISrsGbSession *create_gb_session();
|
||||
#endif
|
||||
virtual ISrsInitMp4 *create_init_mp4();
|
||||
virtual ISrsFragmentWindow *create_fragment_window();
|
||||
virtual ISrsFragmentedMp4 *create_fragmented_mp4();
|
||||
};
|
||||
|
||||
extern ISrsAppFactory *_srs_app_factory;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,14 @@
|
|||
#include <unistd.h>
|
||||
using namespace std;
|
||||
|
||||
ISrsFragment::ISrsFragment()
|
||||
{
|
||||
}
|
||||
|
||||
ISrsFragment::~ISrsFragment()
|
||||
{
|
||||
}
|
||||
|
||||
SrsFragment::SrsFragment()
|
||||
{
|
||||
dur_ = 0;
|
||||
|
|
@ -155,22 +163,30 @@ uint64_t SrsFragment::number()
|
|||
return number_;
|
||||
}
|
||||
|
||||
ISrsFragmentWindow::ISrsFragmentWindow()
|
||||
{
|
||||
}
|
||||
|
||||
ISrsFragmentWindow::~ISrsFragmentWindow()
|
||||
{
|
||||
}
|
||||
|
||||
SrsFragmentWindow::SrsFragmentWindow()
|
||||
{
|
||||
}
|
||||
|
||||
SrsFragmentWindow::~SrsFragmentWindow()
|
||||
{
|
||||
vector<SrsFragment *>::iterator it;
|
||||
vector<ISrsFragment *>::iterator it;
|
||||
|
||||
for (it = fragments_.begin(); it != fragments_.end(); ++it) {
|
||||
SrsFragment *fragment = *it;
|
||||
ISrsFragment *fragment = *it;
|
||||
srs_freep(fragment);
|
||||
}
|
||||
fragments_.clear();
|
||||
|
||||
for (it = expired_fragments_.begin(); it != expired_fragments_.end(); ++it) {
|
||||
SrsFragment *fragment = *it;
|
||||
ISrsFragment *fragment = *it;
|
||||
srs_freep(fragment);
|
||||
}
|
||||
expired_fragments_.clear();
|
||||
|
|
@ -180,10 +196,10 @@ void SrsFragmentWindow::dispose()
|
|||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
std::vector<SrsFragment *>::iterator it;
|
||||
std::vector<ISrsFragment *>::iterator it;
|
||||
|
||||
for (it = fragments_.begin(); it != fragments_.end(); ++it) {
|
||||
SrsFragment *fragment = *it;
|
||||
ISrsFragment *fragment = *it;
|
||||
if ((err = fragment->unlink_file()) != srs_success) {
|
||||
srs_warn("Unlink ts failed %s", srs_error_desc(err).c_str());
|
||||
srs_freep(err);
|
||||
|
|
@ -193,7 +209,7 @@ void SrsFragmentWindow::dispose()
|
|||
fragments_.clear();
|
||||
|
||||
for (it = expired_fragments_.begin(); it != expired_fragments_.end(); ++it) {
|
||||
SrsFragment *fragment = *it;
|
||||
ISrsFragment *fragment = *it;
|
||||
if ((err = fragment->unlink_file()) != srs_success) {
|
||||
srs_warn("Unlink ts failed %s", srs_error_desc(err).c_str());
|
||||
srs_freep(err);
|
||||
|
|
@ -203,7 +219,7 @@ void SrsFragmentWindow::dispose()
|
|||
expired_fragments_.clear();
|
||||
}
|
||||
|
||||
void SrsFragmentWindow::append(SrsFragment *fragment)
|
||||
void SrsFragmentWindow::append(ISrsFragment *fragment)
|
||||
{
|
||||
fragments_.push_back(fragment);
|
||||
}
|
||||
|
|
@ -215,7 +231,7 @@ void SrsFragmentWindow::shrink(srs_utime_t window)
|
|||
int remove_index = -1;
|
||||
|
||||
for (int i = (int)fragments_.size() - 1; i >= 0; i--) {
|
||||
SrsFragment *fragment = fragments_[i];
|
||||
ISrsFragment *fragment = fragments_[i];
|
||||
duration += fragment->duration();
|
||||
|
||||
if (duration > window) {
|
||||
|
|
@ -225,7 +241,7 @@ void SrsFragmentWindow::shrink(srs_utime_t window)
|
|||
}
|
||||
|
||||
for (int i = 0; i < remove_index && !fragments_.empty(); i++) {
|
||||
SrsFragment *fragment = *fragments_.begin();
|
||||
ISrsFragment *fragment = *fragments_.begin();
|
||||
fragments_.erase(fragments_.begin());
|
||||
expired_fragments_.push_back(fragment);
|
||||
}
|
||||
|
|
@ -235,10 +251,10 @@ void SrsFragmentWindow::clear_expired(bool delete_files)
|
|||
{
|
||||
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) {
|
||||
SrsFragment *fragment = *it;
|
||||
ISrsFragment *fragment = *it;
|
||||
if (delete_files && (err = fragment->unlink_file()) != srs_success) {
|
||||
srs_warn("Unlink ts failed, %s", srs_error_desc(err).c_str());
|
||||
srs_freep(err);
|
||||
|
|
@ -253,10 +269,10 @@ srs_utime_t SrsFragmentWindow::max_duration()
|
|||
{
|
||||
srs_utime_t v = 0;
|
||||
|
||||
std::vector<SrsFragment *>::iterator it;
|
||||
std::vector<ISrsFragment *>::iterator it;
|
||||
|
||||
for (it = fragments_.begin(); it != fragments_.end(); ++it) {
|
||||
SrsFragment *fragment = *it;
|
||||
ISrsFragment *fragment = *it;
|
||||
v = srs_max(v, fragment->duration());
|
||||
}
|
||||
|
||||
|
|
@ -268,7 +284,7 @@ bool SrsFragmentWindow::empty()
|
|||
return fragments_.empty();
|
||||
}
|
||||
|
||||
SrsFragment *SrsFragmentWindow::first()
|
||||
ISrsFragment *SrsFragmentWindow::first()
|
||||
{
|
||||
return fragments_.at(0);
|
||||
}
|
||||
|
|
@ -278,7 +294,7 @@ int SrsFragmentWindow::size()
|
|||
return (int)fragments_.size();
|
||||
}
|
||||
|
||||
SrsFragment *SrsFragmentWindow::at(int index)
|
||||
ISrsFragment *SrsFragmentWindow::at(int index)
|
||||
{
|
||||
return fragments_.at(index);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,9 +12,44 @@
|
|||
#include <string>
|
||||
#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.
|
||||
// It's a media file, for example FLV or MP4, with duration.
|
||||
class SrsFragment
|
||||
class SrsFragment : public ISrsFragment
|
||||
{
|
||||
private:
|
||||
// The duration in srs_utime_t.
|
||||
|
|
@ -68,13 +103,39 @@ public:
|
|||
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.
|
||||
class SrsFragmentWindow
|
||||
class SrsFragmentWindow : public ISrsFragmentWindow
|
||||
{
|
||||
private:
|
||||
std::vector<SrsFragment *> fragments_;
|
||||
std::vector<ISrsFragment *> fragments_;
|
||||
// The expired fragments, need to be free in future.
|
||||
std::vector<SrsFragment *> expired_fragments_;
|
||||
std::vector<ISrsFragment *> expired_fragments_;
|
||||
|
||||
public:
|
||||
SrsFragmentWindow();
|
||||
|
|
@ -84,7 +145,7 @@ public:
|
|||
// Dispose all fragments, delete the files.
|
||||
virtual void dispose();
|
||||
// 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.
|
||||
virtual void shrink(srs_utime_t window);
|
||||
// Clear the expired fragments.
|
||||
|
|
@ -94,9 +155,9 @@ public:
|
|||
|
||||
public:
|
||||
virtual bool empty();
|
||||
virtual SrsFragment *first();
|
||||
virtual ISrsFragment *first();
|
||||
virtual int size();
|
||||
virtual SrsFragment *at(int index);
|
||||
virtual ISrsFragment *at(int index);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -328,7 +328,7 @@ SrsGbListener::SrsGbListener()
|
|||
media_listener_ = new SrsTcpListener(this);
|
||||
|
||||
config_ = _srs_config;
|
||||
api_server_owner_ = _srs_server;
|
||||
api_server_owner_ = NULL;
|
||||
gb_manager_ = _srs_gb_manager;
|
||||
app_factory_ = _srs_app_factory;
|
||||
}
|
||||
|
|
@ -348,6 +348,12 @@ srs_error_t SrsGbListener::initialize(SrsConfDirective *conf)
|
|||
{
|
||||
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_);
|
||||
conf_ = conf->copy();
|
||||
|
||||
|
|
@ -381,6 +387,10 @@ srs_error_t SrsGbListener::listen_api()
|
|||
srs_error_t err = srs_success;
|
||||
|
||||
ISrsHttpServeMux *mux = api_server_owner_->api_server();
|
||||
if (!mux) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((err = mux->handle("/gb/v1/publish/", new SrsGoApiGbPublish(conf_))) != srs_success) {
|
||||
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.
|
||||
#define SRS_ICE_PWD_MAX 32
|
||||
|
||||
SrsGoApiRtcPlay::SrsGoApiRtcPlay(SrsServer *server)
|
||||
SrsGoApiRtcPlay::SrsGoApiRtcPlay(ISrsRtcApiServer *server)
|
||||
{
|
||||
server_ = server;
|
||||
security_ = new SrsSecurity();
|
||||
|
||||
config_ = _srs_config;
|
||||
stat_ = _srs_stat;
|
||||
rtc_sources_ = _srs_rtc_sources;
|
||||
live_sources_ = _srs_sources;
|
||||
hooks_ = _srs_hooks;
|
||||
}
|
||||
|
||||
SrsGoApiRtcPlay::~SrsGoApiRtcPlay()
|
||||
{
|
||||
srs_freep(security_);
|
||||
|
||||
config_ = NULL;
|
||||
stat_ = NULL;
|
||||
rtc_sources_ = NULL;
|
||||
live_sources_ = NULL;
|
||||
hooks_ = NULL;
|
||||
}
|
||||
|
||||
// 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_);
|
||||
|
||||
// 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) {
|
||||
ruc.req_->vhost_ = parsed_vhost->arg0();
|
||||
}
|
||||
|
|
@ -162,7 +174,7 @@ srs_error_t SrsGoApiRtcPlay::do_serve_http(ISrsHttpResponseWriter *w, ISrsHttpMe
|
|||
ruc.dtls_ = (dtls != "false");
|
||||
|
||||
if (srtp.empty()) {
|
||||
ruc.srtp_ = _srs_config->get_rtc_server_encrypt();
|
||||
ruc.srtp_ = config_->get_rtc_server_encrypt();
|
||||
} else {
|
||||
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("server", SrsJsonAny::str(_srs_stat->server_id().c_str()));
|
||||
res->set("service", SrsJsonAny::str(_srs_stat->service_id().c_str()));
|
||||
res->set("pid", SrsJsonAny::str(_srs_stat->service_pid().c_str()));
|
||||
res->set("server", SrsJsonAny::str(stat_->server_id().c_str()));
|
||||
res->set("service", SrsJsonAny::str(stat_->service_id().c_str()));
|
||||
res->set("pid", SrsJsonAny::str(stat_->service_pid().c_str()));
|
||||
|
||||
// TODO: add candidates in response json?
|
||||
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;
|
||||
|
||||
// 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_version_ = _srs_config->get_rtc_dtls_version(ruc->req_->vhost_);
|
||||
local_sdp.session_config_.dtls_role_ = config_->get_rtc_dtls_role(ruc->req_->vhost_);
|
||||
local_sdp.session_config_.dtls_version_ = config_->get_rtc_dtls_version(ruc->req_->vhost_);
|
||||
|
||||
// Whether enabled.
|
||||
bool server_enabled = _srs_config->get_rtc_server_enabled();
|
||||
bool rtc_enabled = _srs_config->get_rtc_enabled(ruc->req_->vhost_);
|
||||
bool edge = _srs_config->get_vhost_is_edge(ruc->req_->vhost_);
|
||||
bool server_enabled = config_->get_rtc_server_enabled();
|
||||
bool rtc_enabled = config_->get_rtc_enabled(ruc->req_->vhost_);
|
||||
bool edge = config_->get_vhost_is_edge(ruc->req_->vhost_);
|
||||
|
||||
if (rtc_enabled && edge) {
|
||||
rtc_enabled = false;
|
||||
|
|
@ -224,19 +236,19 @@ srs_error_t SrsGoApiRtcPlay::serve_http(ISrsHttpResponseWriter *w, ISrsHttpMessa
|
|||
// Whether RTC stream is active.
|
||||
bool is_rtc_stream_active = false;
|
||||
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());
|
||||
}
|
||||
|
||||
// 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) {
|
||||
rtmp_to_rtc = false;
|
||||
srs_warn("disable RTMP to WebRTC for edge vhost=%s", ruc->req_->vhost_.c_str());
|
||||
}
|
||||
|
||||
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()) {
|
||||
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;
|
||||
|
||||
if (!_srs_config->get_vhost_http_hooks_enabled(req->vhost_)) {
|
||||
if (!config_->get_vhost_http_hooks_enabled(req->vhost_)) {
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -320,7 +332,7 @@ srs_error_t SrsGoApiRtcPlay::http_hooks_on_play(ISrsRequest *req)
|
|||
vector<string> hooks;
|
||||
|
||||
if (true) {
|
||||
SrsConfDirective *conf = _srs_config->get_vhost_on_play(req->vhost_);
|
||||
SrsConfDirective *conf = config_->get_vhost_on_play(req->vhost_);
|
||||
|
||||
if (!conf) {
|
||||
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++) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
|
@ -339,15 +351,23 @@ srs_error_t SrsGoApiRtcPlay::http_hooks_on_play(ISrsRequest *req)
|
|||
return err;
|
||||
}
|
||||
|
||||
SrsGoApiRtcPublish::SrsGoApiRtcPublish(SrsServer *server)
|
||||
SrsGoApiRtcPublish::SrsGoApiRtcPublish(ISrsRtcApiServer *server)
|
||||
{
|
||||
server_ = server;
|
||||
security_ = new SrsSecurity();
|
||||
|
||||
config_ = _srs_config;
|
||||
stat_ = _srs_stat;
|
||||
hooks_ = _srs_hooks;
|
||||
}
|
||||
|
||||
SrsGoApiRtcPublish::~SrsGoApiRtcPublish()
|
||||
{
|
||||
srs_freep(security_);
|
||||
|
||||
config_ = NULL;
|
||||
stat_ = NULL;
|
||||
hooks_ = NULL;
|
||||
}
|
||||
|
||||
// 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", "&");
|
||||
|
||||
// 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) {
|
||||
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("server", SrsJsonAny::str(_srs_stat->server_id().c_str()));
|
||||
res->set("service", SrsJsonAny::str(_srs_stat->service_id().c_str()));
|
||||
res->set("pid", SrsJsonAny::str(_srs_stat->service_pid().c_str()));
|
||||
res->set("server", SrsJsonAny::str(stat_->server_id().c_str()));
|
||||
res->set("service", SrsJsonAny::str(stat_->service_id().c_str()));
|
||||
res->set("pid", SrsJsonAny::str(stat_->service_pid().c_str()));
|
||||
|
||||
// TODO: add candidates in response json?
|
||||
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.
|
||||
// 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_version_ = _srs_config->get_rtc_dtls_version(ruc->req_->vhost_);
|
||||
local_sdp.session_config_.dtls_role_ = config_->get_rtc_dtls_role(ruc->req_->vhost_);
|
||||
local_sdp.session_config_.dtls_version_ = config_->get_rtc_dtls_version(ruc->req_->vhost_);
|
||||
|
||||
// Whether enabled.
|
||||
bool server_enabled = _srs_config->get_rtc_server_enabled();
|
||||
bool rtc_enabled = _srs_config->get_rtc_enabled(ruc->req_->vhost_);
|
||||
bool edge = _srs_config->get_vhost_is_edge(ruc->req_->vhost_);
|
||||
bool server_enabled = config_->get_rtc_server_enabled();
|
||||
bool rtc_enabled = config_->get_rtc_enabled(ruc->req_->vhost_);
|
||||
bool edge = config_->get_vhost_is_edge(ruc->req_->vhost_);
|
||||
|
||||
if (rtc_enabled && edge) {
|
||||
rtc_enabled = false;
|
||||
|
|
@ -592,7 +612,7 @@ srs_error_t SrsGoApiRtcPublish::http_hooks_on_publish(ISrsRequest *req)
|
|||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -602,7 +622,7 @@ srs_error_t SrsGoApiRtcPublish::http_hooks_on_publish(ISrsRequest *req)
|
|||
vector<string> hooks;
|
||||
|
||||
if (true) {
|
||||
SrsConfDirective *conf = _srs_config->get_vhost_on_publish(req->vhost_);
|
||||
SrsConfDirective *conf = config_->get_vhost_on_publish(req->vhost_);
|
||||
if (!conf) {
|
||||
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++) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
|
@ -619,17 +639,21 @@ srs_error_t SrsGoApiRtcPublish::http_hooks_on_publish(ISrsRequest *req)
|
|||
return err;
|
||||
}
|
||||
|
||||
SrsGoApiRtcWhip::SrsGoApiRtcWhip(SrsServer *server)
|
||||
SrsGoApiRtcWhip::SrsGoApiRtcWhip(ISrsRtcApiServer *server)
|
||||
{
|
||||
server_ = server;
|
||||
publish_ = new SrsGoApiRtcPublish(server);
|
||||
play_ = new SrsGoApiRtcPlay(server);
|
||||
|
||||
config_ = _srs_config;
|
||||
}
|
||||
|
||||
SrsGoApiRtcWhip::~SrsGoApiRtcWhip()
|
||||
{
|
||||
srs_freep(publish_);
|
||||
srs_freep(play_);
|
||||
|
||||
config_ = NULL;
|
||||
}
|
||||
|
||||
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
|
||||
SrsConfDirective *parsed_vhost = _srs_config->get_vhost(ruc->req_->vhost_);
|
||||
SrsConfDirective *parsed_vhost = config_->get_vhost(ruc->req_->vhost_);
|
||||
if (parsed_vhost) {
|
||||
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.
|
||||
ruc->dtls_ = (dtls != "false");
|
||||
if (srtp.empty()) {
|
||||
ruc->srtp_ = _srs_config->get_rtc_server_encrypt();
|
||||
ruc->srtp_ = config_->get_rtc_server_encrypt();
|
||||
} else {
|
||||
ruc->srtp_ = (srtp != "false");
|
||||
}
|
||||
|
|
@ -780,7 +804,7 @@ srs_error_t SrsGoApiRtcWhip::do_serve_http(ISrsHttpResponseWriter *w, ISrsHttpMe
|
|||
return err;
|
||||
}
|
||||
|
||||
SrsGoApiRtcNACK::SrsGoApiRtcNACK(SrsServer *server)
|
||||
SrsGoApiRtcNACK::SrsGoApiRtcNACK(ISrsRtcApiServer *server)
|
||||
{
|
||||
server_ = server;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,15 +15,29 @@ class SrsServer;
|
|||
class ISrsRequest;
|
||||
class SrsSdp;
|
||||
class SrsRtcUserConfig;
|
||||
class ISrsRtcApiServer;
|
||||
class ISrsSecurity;
|
||||
class ISrsAppConfig;
|
||||
class ISrsStatistic;
|
||||
class ISrsRtcSourceManager;
|
||||
class ISrsLiveSourceManager;
|
||||
class ISrsHttpHooks;
|
||||
|
||||
class SrsGoApiRtcPlay : public ISrsHttpHandler
|
||||
{
|
||||
private:
|
||||
SrsServer *server_;
|
||||
SrsSecurity *security_;
|
||||
ISrsAppConfig *config_;
|
||||
ISrsStatistic *stat_;
|
||||
ISrsRtcSourceManager *rtc_sources_;
|
||||
ISrsLiveSourceManager *live_sources_;
|
||||
ISrsHttpHooks *hooks_;
|
||||
|
||||
private:
|
||||
ISrsRtcApiServer *server_;
|
||||
ISrsSecurity *security_;
|
||||
|
||||
public:
|
||||
SrsGoApiRtcPlay(SrsServer *server);
|
||||
SrsGoApiRtcPlay(ISrsRtcApiServer *server);
|
||||
virtual ~SrsGoApiRtcPlay();
|
||||
|
||||
public:
|
||||
|
|
@ -45,11 +59,16 @@ private:
|
|||
class SrsGoApiRtcPublish : public ISrsHttpHandler
|
||||
{
|
||||
private:
|
||||
SrsServer *server_;
|
||||
SrsSecurity *security_;
|
||||
ISrsAppConfig *config_;
|
||||
ISrsStatistic *stat_;
|
||||
ISrsHttpHooks *hooks_;
|
||||
|
||||
private:
|
||||
ISrsRtcApiServer *server_;
|
||||
ISrsSecurity *security_;
|
||||
|
||||
public:
|
||||
SrsGoApiRtcPublish(SrsServer *server);
|
||||
SrsGoApiRtcPublish(ISrsRtcApiServer *server);
|
||||
virtual ~SrsGoApiRtcPublish();
|
||||
|
||||
public:
|
||||
|
|
@ -72,12 +91,15 @@ private:
|
|||
class SrsGoApiRtcWhip : public ISrsHttpHandler
|
||||
{
|
||||
private:
|
||||
SrsServer *server_;
|
||||
ISrsAppConfig *config_;
|
||||
|
||||
private:
|
||||
ISrsRtcApiServer *server_;
|
||||
SrsGoApiRtcPublish *publish_;
|
||||
SrsGoApiRtcPlay *play_;
|
||||
|
||||
public:
|
||||
SrsGoApiRtcWhip(SrsServer *server);
|
||||
SrsGoApiRtcWhip(ISrsRtcApiServer *server);
|
||||
virtual ~SrsGoApiRtcWhip();
|
||||
|
||||
public:
|
||||
|
|
@ -90,10 +112,10 @@ private:
|
|||
class SrsGoApiRtcNACK : public ISrsHttpHandler
|
||||
{
|
||||
private:
|
||||
SrsServer *server_;
|
||||
ISrsRtcApiServer *server_;
|
||||
|
||||
public:
|
||||
SrsGoApiRtcNACK(SrsServer *server);
|
||||
SrsGoApiRtcNACK(ISrsRtcApiServer *server);
|
||||
virtual ~SrsGoApiRtcNACK();
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -158,6 +158,14 @@ ISrsApiServerOwner::~ISrsApiServerOwner()
|
|||
{
|
||||
}
|
||||
|
||||
ISrsRtcApiServer::ISrsRtcApiServer()
|
||||
{
|
||||
}
|
||||
|
||||
ISrsRtcApiServer::~ISrsRtcApiServer()
|
||||
{
|
||||
}
|
||||
|
||||
SrsServer::SrsServer()
|
||||
{
|
||||
signal_reload_ = false;
|
||||
|
|
|
|||
|
|
@ -95,6 +95,18 @@ public:
|
|||
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
|
||||
// streaming media server functionality. It serves as the central orchestrator for all streaming
|
||||
// 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 ISrsUdpMuxHandler,
|
||||
public ISrsSignalHandler,
|
||||
public ISrsApiServerOwner
|
||||
public ISrsApiServerOwner,
|
||||
public ISrsRtcApiServer
|
||||
{
|
||||
private:
|
||||
ISrsAppConfig *config_;
|
||||
|
|
|
|||
|
|
@ -6990,6 +6990,14 @@ SrsMp4ObjectType SrsMp4Encoder::get_audio_object_type()
|
|||
}
|
||||
}
|
||||
|
||||
ISrsMp4M2tsInitEncoder::ISrsMp4M2tsInitEncoder()
|
||||
{
|
||||
}
|
||||
|
||||
ISrsMp4M2tsInitEncoder::~ISrsMp4M2tsInitEncoder()
|
||||
{
|
||||
}
|
||||
|
||||
SrsMp4M2tsInitEncoder::SrsMp4M2tsInitEncoder()
|
||||
{
|
||||
writer_ = NULL;
|
||||
|
|
@ -7580,6 +7588,14 @@ srs_error_t SrsMp4M2tsInitEncoder::config_sample_description_encryption(SrsMp4Sa
|
|||
return err;
|
||||
}
|
||||
|
||||
ISrsMp4M2tsSegmentEncoder::ISrsMp4M2tsSegmentEncoder()
|
||||
{
|
||||
}
|
||||
|
||||
ISrsMp4M2tsSegmentEncoder::~ISrsMp4M2tsSegmentEncoder()
|
||||
{
|
||||
}
|
||||
|
||||
SrsMp4M2tsSegmentEncoder::SrsMp4M2tsSegmentEncoder()
|
||||
{
|
||||
writer_ = NULL;
|
||||
|
|
|
|||
|
|
@ -2721,9 +2721,23 @@ private:
|
|||
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.
|
||||
// TODO: What the M2ts short for?
|
||||
class SrsMp4M2tsInitEncoder
|
||||
class SrsMp4M2tsInitEncoder : public ISrsMp4M2tsInitEncoder
|
||||
{
|
||||
private:
|
||||
ISrsWriter *writer_;
|
||||
|
|
@ -2781,10 +2795,34 @@ private:
|
|||
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
|
||||
// trun box before mdat.
|
||||
// TODO: fmp4 support package more than one tracks.
|
||||
class SrsMp4M2tsSegmentEncoder
|
||||
class SrsMp4M2tsSegmentEncoder : public ISrsMp4M2tsSegmentEncoder
|
||||
{
|
||||
private:
|
||||
ISrsWriter *writer_;
|
||||
|
|
|
|||
|
|
@ -3219,6 +3219,21 @@ ISrsGbSession *MockDvrAppFactory::create_gb_session()
|
|||
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)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
|
|
|||
|
|
@ -637,6 +637,9 @@ public:
|
|||
virtual ISrsDvrSegmenter *create_dvr_mp4_segmenter();
|
||||
virtual ISrsGbMediaTcpConn *create_gb_media_tcp_conn();
|
||||
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
|
||||
|
|
|
|||
|
|
@ -2378,6 +2378,21 @@ ISrsGbSession *MockAppFactoryForGbPublish::create_gb_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()
|
||||
{
|
||||
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);
|
||||
read_pos_ += size;
|
||||
if (nread) *nread = size;
|
||||
if (nread)
|
||||
*nread = size;
|
||||
recv_bytes_ += size;
|
||||
|
||||
return srs_success;
|
||||
|
|
@ -4154,8 +4170,8 @@ VOID TEST(RtcTcpConnTest, ReadPacketSuccess)
|
|||
// Prepare test packet data: 2-byte length header + packet body
|
||||
// Length = 100 bytes (0x0064 in big-endian)
|
||||
std::string test_data;
|
||||
test_data.push_back(0x00); // Length high byte
|
||||
test_data.push_back(0x64); // Length low byte (100 in decimal)
|
||||
test_data.push_back(0x00); // Length high byte
|
||||
test_data.push_back(0x64); // Length low byte (100 in decimal)
|
||||
|
||||
// Add 100 bytes of packet data
|
||||
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
|
||||
char rtp_pkt[100];
|
||||
memset(rtp_pkt, 0, sizeof(rtp_pkt));
|
||||
rtp_pkt[0] = 0x80; // Version 2 (10xxxxxx)
|
||||
rtp_pkt[1] = 0x08; // Payload type 8 (PCMA)
|
||||
rtp_pkt[0] = 0x80; // Version 2 (10xxxxxx)
|
||||
rtp_pkt[1] = 0x08; // Payload type 8 (PCMA)
|
||||
|
||||
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]
|
||||
char rtcp_pkt[100];
|
||||
memset(rtcp_pkt, 0, sizeof(rtcp_pkt));
|
||||
rtcp_pkt[0] = 0x80; // Version 2 (10xxxxxx)
|
||||
rtcp_pkt[1] = 0xC8; // Payload type 200 (SR - Sender Report)
|
||||
rtcp_pkt[0] = 0x80; // Version 2 (10xxxxxx)
|
||||
rtcp_pkt[1] = 0xC8; // Payload type 200 (SR - Sender Report)
|
||||
|
||||
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]
|
||||
char dtls_pkt[100];
|
||||
memset(dtls_pkt, 0, sizeof(dtls_pkt));
|
||||
dtls_pkt[0] = 0x16; // Content type: handshake (22)
|
||||
dtls_pkt[1] = 0xFE; // DTLS version 1.0 (0xFEFF)
|
||||
dtls_pkt[0] = 0x16; // Content type: handshake (22)
|
||||
dtls_pkt[1] = 0xFE; // DTLS version 1.0 (0xFEFF)
|
||||
dtls_pkt[2] = 0xFF;
|
||||
|
||||
HELPER_EXPECT_SUCCESS(tcp_conn->on_tcp_pkt(dtls_pkt, 100));
|
||||
|
|
|
|||
|
|
@ -600,6 +600,9 @@ public:
|
|||
virtual SrsDvrMp4Segmenter *create_dvr_mp4_segmenter();
|
||||
virtual ISrsGbMediaTcpConn *create_gb_media_tcp_conn();
|
||||
virtual ISrsGbSession *create_gb_session();
|
||||
virtual ISrsInitMp4 *create_init_mp4();
|
||||
virtual ISrsFragmentWindow *create_fragment_window();
|
||||
virtual ISrsFragmentedMp4 *create_fragmented_mp4();
|
||||
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;
|
||||
srt_enabled_ = false;
|
||||
rtc_to_rtmp_ = false;
|
||||
dash_dispose_ = 0;
|
||||
dash_enabled_ = false;
|
||||
}
|
||||
|
||||
MockAppConfig::~MockAppConfig()
|
||||
|
|
@ -2284,6 +2286,16 @@ bool MockAppConfig::get_rtc_stun_strict_check(std::string vhost)
|
|||
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)
|
||||
{
|
||||
return NULL;
|
||||
|
|
|
|||
|
|
@ -242,6 +242,8 @@ public:
|
|||
bool rtc_twcc_enabled_;
|
||||
bool srt_enabled_;
|
||||
bool rtc_to_rtmp_;
|
||||
srs_utime_t dash_dispose_;
|
||||
bool dash_enabled_;
|
||||
|
||||
public:
|
||||
MockAppConfig();
|
||||
|
|
@ -291,6 +293,7 @@ public:
|
|||
virtual std::string get_rtc_server_protocol() { return "udp"; }
|
||||
virtual std::vector<std::string> get_rtc_server_listens() { return std::vector<std::string>(); }
|
||||
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 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>(); }
|
||||
|
|
@ -357,6 +360,8 @@ public:
|
|||
virtual bool get_rtc_to_rtmp(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 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_notify(std::string vhost);
|
||||
// HLS methods
|
||||
|
|
@ -420,6 +425,17 @@ public:
|
|||
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 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_on_stop_urls(const std::vector<std::string> &urls);
|
||||
void clear_on_stop_directive();
|
||||
|
|
|
|||
|
|
@ -242,6 +242,7 @@ MockAppFactory::MockAppFactory()
|
|||
real_writer_ = NULL;
|
||||
real_file_ = NULL;
|
||||
real_reader_ = NULL;
|
||||
real_fragmented_mp4_ = NULL;
|
||||
create_file_writer_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_reader_ is owned by this factory
|
||||
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()
|
||||
|
|
@ -271,6 +274,15 @@ ISrsFileReader *MockAppFactory::create_file_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()
|
||||
{
|
||||
create_file_writer_count_ = 0;
|
||||
|
|
@ -280,6 +292,8 @@ void MockAppFactory::reset()
|
|||
srs_freep(real_file_);
|
||||
real_file_ = NULL;
|
||||
// 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
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ public:
|
|||
MockSrsFileWriter *real_writer_;
|
||||
MockSrsFile *real_file_;
|
||||
MockSrsFileReader *real_reader_;
|
||||
ISrsFragmentedMp4 *real_fragmented_mp4_;
|
||||
int create_file_writer_count_;
|
||||
int create_file_reader_count_;
|
||||
|
||||
|
|
@ -109,6 +110,7 @@ public:
|
|||
virtual ~MockAppFactory();
|
||||
virtual ISrsFileWriter *create_file_writer();
|
||||
virtual ISrsFileReader *create_file_reader();
|
||||
virtual ISrsFragmentedMp4 *create_fragmented_mp4();
|
||||
void reset();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1406,7 +1406,7 @@ MockDashForOriginHub::~MockDashForOriginHub()
|
|||
srs_freep(initialize_error_);
|
||||
}
|
||||
|
||||
srs_error_t MockDashForOriginHub::initialize(SrsOriginHub *h, ISrsRequest *r)
|
||||
srs_error_t MockDashForOriginHub::initialize(ISrsOriginHub *h, ISrsRequest *r)
|
||||
{
|
||||
initialize_count_++;
|
||||
return srs_error_copy(initialize_error_);
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ public:
|
|||
public:
|
||||
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_audio(SrsMediaPacket *shared_audio, SrsFormat *format);
|
||||
virtual srs_error_t on_video(SrsMediaPacket *shared_video, SrsFormat *format);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user