mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
for #179, revert dvr http api. 2.0.128.
This commit is contained in:
parent
4505983944
commit
fb3fced8d0
10 changed files with 7 additions and 932 deletions
|
@ -513,8 +513,6 @@ Supported operating systems and hardware:
|
|||
[#304](https://github.com/winlinvip/simple-rtmp-server/issues/304).
|
||||
1. Support push RTSP to SRS, read
|
||||
[#133](https://github.com/winlinvip/simple-rtmp-server/issues/133).
|
||||
1. Support DVR http api, read
|
||||
[#179](https://github.com/winlinvip/simple-rtmp-server/issues/179).
|
||||
1. [no-plan] Support <500ms latency, FRSC(Fast RTMP-compatible Stream Channel tech).
|
||||
1. [no-plan] Support RTMP 302 redirect [#92](https://github.com/winlinvip/simple-rtmp-server/issues/92).
|
||||
1. [no-plan] Support multiple processes, for both origin and edge
|
||||
|
@ -552,10 +550,9 @@ Supported operating systems and hardware:
|
|||
## History
|
||||
|
||||
### SRS 2.0 history
|
||||
|
||||
* v2.0, 2015-02-24, for [#179](https://github.com/winlinvip/simple-rtmp-server/issues/179), dvr suport vhost/app/stream level control. 2.0.125.
|
||||
* v2.0, 2015-02-24, for [#304](https://github.com/winlinvip/simple-rtmp-server/issues/304), fix hls bug, write pts/dts error. 2.0.124.
|
||||
* v2.0, 2015-02-24, fix [#179](https://github.com/winlinvip/simple-rtmp-server/issues/179), support dvr http api. 2.0.123.
|
||||
.
|
||||
* v2.0, 2015-03-01, for [#179](https://github.com/winlinvip/simple-rtmp-server/issues/179), revert dvr http api. 2.0.128.
|
||||
* v2.0, 2015-02-24, for [#304](https://github.com/winlinvip/simple-rtmp-server/issues/304), fix hls bug, write pts/dts error. 2.0.124
|
||||
* v2.0, 2015-02-19, refine dvr, append file when dvr file exists. 2.0.122.
|
||||
* v2.0, 2015-02-19, refine pithy print to more easyer to use. 2.0.121.
|
||||
* v2.0, 2015-02-18, fix [#133](https://github.com/winlinvip/simple-rtmp-server/issues/133), support push rtsp to srs. 2.0.120.
|
||||
|
|
|
@ -288,52 +288,7 @@ vhost dvr.srs.com {
|
|||
# session reap flv when session end(unpublish).
|
||||
# segment reap flv when flv duration exceed the specified dvr_duration.
|
||||
# append always append to flv file, never reap it.
|
||||
# api reap flv when api required.
|
||||
# about the api plan, the HTTP api to dvr,
|
||||
# http url to control dvr, for example, http://dev:1985/api/v1/dvrs
|
||||
# method=GET
|
||||
# to query dvrs of server.
|
||||
# request params, for example ?vhost=__defaultVhost__&&app=live&&stream=livestream, where:
|
||||
# vhost, <required>, query all dvr of this vhost.
|
||||
# app, [optinal], query all dvr of this app. query all app if not specified.
|
||||
# stream, [optional], query specified dvr stream. query all stream if not specified.
|
||||
# response in json, where:
|
||||
# {code:0, dvrs: [{path_tmpl:"./[15].[04].[05].[999].flv", path_dvr:"./22.7.43.312.flv",
|
||||
# vhost:"__defaultVhost", app:"live", stream:"livestream",
|
||||
# wait_keyframe:true, callback:"http://127.0.0.1:8085/api/v1/dvrs",
|
||||
# status:"stop"|"start"
|
||||
# }]}
|
||||
# method=POST
|
||||
# to start dvr of specified vhost.
|
||||
# request should encode in json, specifies the dvr to create, where:
|
||||
# {path_tmpl:"./[15].[04].[05].[999].flv",
|
||||
# vhost:"__defaultVhost", app:"live", stream:"livestream",
|
||||
# wait_keyframe:true, callback:"http://127.0.0.1:8085/api/v1/dvrs"
|
||||
# }
|
||||
# @remark, the app and stream is required for POST.
|
||||
# response in json, where:
|
||||
# {code:0}
|
||||
# method=DELETE, to stop dvr
|
||||
# to stop dvr of specified vhost.
|
||||
# request params, for example ?vhost=__defaultVhost__, where:
|
||||
# vhost, stop all dvr of this vhost.
|
||||
# response in json, where:
|
||||
# {code:0}
|
||||
# method=PUT, use as RPC(remote process call).
|
||||
# reap_segment, the request params in json, where:
|
||||
# {action:"reap_segment", vhost:"__defaultVhost", app:"live", stream:"livestream",
|
||||
# path_tmpl:"./[15].[04].[05].[999].flv"
|
||||
# }
|
||||
# @remark, the app and stream is optional.
|
||||
# when reap segment, the callback POST request in json:
|
||||
# {action:"on_dvr_reap_segment", client_id:100, vhost:"__defaultVhost__",
|
||||
# app:"live", stream:"livestream", cwd:"/home/winlin/srs", file:"./dvr.flv"
|
||||
# }
|
||||
# for the dvr http callback, @see http_hooks.on_dvr of vhost hooks.callback.srs.com
|
||||
# @read https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_DVR#http-callback
|
||||
# @read https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_DVR#http-callback
|
||||
# default: session
|
||||
# TODO: FIXME: update wiki for the api plan.
|
||||
dvr_plan session;
|
||||
# the dvr output path.
|
||||
# we supports some variables to generate the filename.
|
||||
|
@ -369,27 +324,20 @@ vhost dvr.srs.com {
|
|||
# @see https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_DVR#custom-path
|
||||
# @see https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_DVR#custom-path
|
||||
# segment,session apply it.
|
||||
# api apply before api specified the path.
|
||||
# default: ./objs/nginx/html
|
||||
dvr_path ./objs/nginx/html;
|
||||
# the duration for dvr file, reap if exeed, in seconds.
|
||||
# segment apply it.
|
||||
# session,api ignore.
|
||||
# session,append ignore.
|
||||
# default: 30
|
||||
dvr_duration 30;
|
||||
# whether wait keyframe to reap segment,
|
||||
# if off, reap segment when duration exceed the dvr_duration,
|
||||
# if on, reap segment when duration exceed and got keyframe.
|
||||
# segment apply it.
|
||||
# session,api ignore.
|
||||
# session,append ignore.
|
||||
# default: on
|
||||
dvr_wait_keyframe on;
|
||||
# whether dvr auto start when publish.
|
||||
# if off, dvr wait for api to start it.
|
||||
# api apply it.
|
||||
# segment,session ignore.
|
||||
# default: on
|
||||
dvr_autostart on;
|
||||
# about the stream monotonically increasing:
|
||||
# 1. video timestamp is monotonically increasing,
|
||||
# 2. audio timestamp is monotonically increasing,
|
||||
|
|
|
@ -1418,7 +1418,6 @@ int SrsConfig::check_config()
|
|||
string m = conf->at(j)->name.c_str();
|
||||
if (m != "enabled" && m != "dvr_path" && m != "dvr_plan"
|
||||
&& m != "dvr_duration" && m != "dvr_wait_keyframe" && m != "time_jitter"
|
||||
&& m != "dvr_autostart"
|
||||
) {
|
||||
ret = ERROR_SYSTEM_CONFIG_INVALID;
|
||||
srs_error("unsupported vhost dvr directive %s, ret=%d", m.c_str(), ret);
|
||||
|
@ -1977,41 +1976,6 @@ int SrsConfig::get_stream_caster_rtp_port_max(SrsConfDirective* sc)
|
|||
return ::atoi(conf->arg0().c_str());
|
||||
}
|
||||
|
||||
SrsConfDirective* SrsConfig::create_directive(string vhost, string directive, string sub_directive)
|
||||
{
|
||||
SrsConfDirective* vhost_conf = get_vhost(vhost);
|
||||
|
||||
if (!vhost_conf) {
|
||||
vhost_conf = new SrsConfDirective();
|
||||
vhost_conf->name = vhost;
|
||||
root->directives.push_back(vhost_conf);
|
||||
}
|
||||
|
||||
if (directive.empty()) {
|
||||
return vhost_conf;
|
||||
}
|
||||
|
||||
SrsConfDirective* dir = vhost_conf->get(directive);
|
||||
if (!dir) {
|
||||
dir = new SrsConfDirective();
|
||||
dir->name = directive;
|
||||
vhost_conf->directives.push_back(dir);
|
||||
}
|
||||
|
||||
if (sub_directive.empty()) {
|
||||
return dir;
|
||||
}
|
||||
|
||||
SrsConfDirective* sdir = dir->get(sub_directive);
|
||||
if (!sdir) {
|
||||
sdir = new SrsConfDirective();
|
||||
sdir->name = sub_directive;
|
||||
dir->directives.push_back(sdir);
|
||||
}
|
||||
|
||||
return sdir;
|
||||
}
|
||||
|
||||
SrsConfDirective* SrsConfig::get_vhost(string vhost)
|
||||
{
|
||||
srs_assert(root);
|
||||
|
@ -2355,13 +2319,6 @@ bool SrsConfig::get_vhost_http_hooks_enabled(string vhost)
|
|||
return true;
|
||||
}
|
||||
|
||||
void SrsConfig::set_vhost_http_hooks_enabled(string vhost, bool enabled)
|
||||
{
|
||||
SrsConfDirective* conf = create_directive(vhost, "http_hooks", "enabled");
|
||||
conf->args.clear();
|
||||
conf->args.push_back(enabled? "on":"off");
|
||||
}
|
||||
|
||||
SrsConfDirective* SrsConfig::get_vhost_on_connect(string vhost)
|
||||
{
|
||||
SrsConfDirective* conf = get_vhost_http_hooks(vhost);
|
||||
|
@ -2439,13 +2396,6 @@ SrsConfDirective* SrsConfig::get_vhost_on_dvr(string vhost)
|
|||
return conf->get("on_dvr");
|
||||
}
|
||||
|
||||
void SrsConfig::set_vhost_on_dvr(string vhost, string callback)
|
||||
{
|
||||
SrsConfDirective* conf = create_directive(vhost, "http_hooks", "on_dvr");
|
||||
conf->args.clear();
|
||||
conf->args.push_back(callback);
|
||||
}
|
||||
|
||||
bool SrsConfig::get_bw_check_enabled(string vhost)
|
||||
{
|
||||
SrsConfDirective* conf = get_vhost(vhost);
|
||||
|
@ -3359,13 +3309,6 @@ bool SrsConfig::get_dvr_enabled(string vhost)
|
|||
return false;
|
||||
}
|
||||
|
||||
void SrsConfig::set_dvr_enabled(string vhost, bool enabled)
|
||||
{
|
||||
SrsConfDirective* conf = create_directive(vhost, "dvr", "enabled");
|
||||
conf->args.clear();
|
||||
conf->args.push_back(enabled? "on":"off");
|
||||
}
|
||||
|
||||
string SrsConfig::get_dvr_path(string vhost)
|
||||
{
|
||||
SrsConfDirective* dvr = get_dvr(vhost);
|
||||
|
@ -3383,13 +3326,6 @@ string SrsConfig::get_dvr_path(string vhost)
|
|||
return conf->arg0();
|
||||
}
|
||||
|
||||
void SrsConfig::set_dvr_path(string vhost, string path)
|
||||
{
|
||||
SrsConfDirective* conf = create_directive(vhost, "dvr", "dvr_path");
|
||||
conf->args.clear();
|
||||
conf->args.push_back(path);
|
||||
}
|
||||
|
||||
string SrsConfig::get_dvr_plan(string vhost)
|
||||
{
|
||||
SrsConfDirective* dvr = get_dvr(vhost);
|
||||
|
@ -3407,13 +3343,6 @@ string SrsConfig::get_dvr_plan(string vhost)
|
|||
return conf->arg0();
|
||||
}
|
||||
|
||||
void SrsConfig::set_dvr_plan(string vhost, string plan)
|
||||
{
|
||||
SrsConfDirective* conf = create_directive(vhost, "dvr", "dvr_plan");
|
||||
conf->args.clear();
|
||||
conf->args.push_back(plan);
|
||||
}
|
||||
|
||||
int SrsConfig::get_dvr_duration(string vhost)
|
||||
{
|
||||
SrsConfDirective* dvr = get_dvr(vhost);
|
||||
|
@ -3448,30 +3377,6 @@ bool SrsConfig::get_dvr_wait_keyframe(string vhost)
|
|||
return false;
|
||||
}
|
||||
|
||||
void SrsConfig::set_dvr_wait_keyframe(string vhost, bool wait_keyframe)
|
||||
{
|
||||
SrsConfDirective* conf = create_directive(vhost, "dvr", "dvr_wait_keyframe");
|
||||
conf->args.clear();
|
||||
conf->args.push_back(wait_keyframe? "on":"off");
|
||||
}
|
||||
|
||||
bool SrsConfig::get_dvr_autostart(string vhost)
|
||||
{
|
||||
SrsConfDirective* dvr = get_dvr(vhost);
|
||||
|
||||
if (!dvr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
SrsConfDirective* conf = dvr->get("dvr_autostart");
|
||||
|
||||
if (!conf || conf->arg0() != "off") {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int SrsConfig::get_dvr_time_jitter(string vhost)
|
||||
{
|
||||
SrsConfDirective* dvr = get_dvr(vhost);
|
||||
|
|
|
@ -61,7 +61,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
#define SRS_CONF_DEFAULT_DVR_PLAN_SESSION "session"
|
||||
#define SRS_CONF_DEFAULT_DVR_PLAN_SEGMENT "segment"
|
||||
#define SRS_CONF_DEFAULT_DVR_PLAN_APPEND "append"
|
||||
#define SRS_CONF_DEFAULT_DVR_PLAN_API "api"
|
||||
#define SRS_CONF_DEFAULT_DVR_PLAN SRS_CONF_DEFAULT_DVR_PLAN_SESSION
|
||||
#define SRS_CONF_DEFAULT_DVR_DURATION 30
|
||||
#define SRS_CONF_DEFAULT_TIME_JITTER "full"
|
||||
|
@ -452,14 +451,6 @@ public:
|
|||
* get the max udp port for rtp of stream caster rtsp.
|
||||
*/
|
||||
virtual int get_stream_caster_rtp_port_max(SrsConfDirective* sc);
|
||||
private:
|
||||
/**
|
||||
* create directive under vhost.
|
||||
* @param directive, get the directive of vhost. get vhost if directive is empty.
|
||||
* @param sub_directive, get the sub directive of vhost. get directive if sub-directive is empty.
|
||||
* @return the vhost(empty directive and sub-directive); the directive(empty sub-directive); the sub-directive.
|
||||
*/
|
||||
virtual SrsConfDirective* create_directive(std::string vhost, std::string directive, std::string sub_directive);
|
||||
// vhost specified section
|
||||
public:
|
||||
/**
|
||||
|
@ -596,7 +587,6 @@ public:
|
|||
* @remark, if not enabled, donot callback all http hooks.
|
||||
*/
|
||||
virtual bool get_vhost_http_hooks_enabled(std::string vhost);
|
||||
virtual void set_vhost_http_hooks_enabled(std::string vhost, bool enabled);
|
||||
/**
|
||||
* get the on_connect callbacks of vhost.
|
||||
* @return the on_connect callback directive, the args is the url to callback.
|
||||
|
@ -632,7 +622,6 @@ public:
|
|||
* @return the on_dvr callback directive, the args is the url to callback.
|
||||
*/
|
||||
virtual SrsConfDirective* get_vhost_on_dvr(std::string vhost);
|
||||
virtual void set_vhost_on_dvr(std::string vhost, std::string callback);
|
||||
// bwct(bandwidth check tool) section
|
||||
public:
|
||||
/**
|
||||
|
@ -925,17 +914,14 @@ public:
|
|||
* whether dvr is enabled.
|
||||
*/
|
||||
virtual bool get_dvr_enabled(std::string vhost);
|
||||
virtual void set_dvr_enabled(std::string vhost, bool enabled);
|
||||
/**
|
||||
* get the dvr path, the flv file to save in.
|
||||
*/
|
||||
virtual std::string get_dvr_path(std::string vhost);
|
||||
virtual void set_dvr_path(std::string vhost, std::string path);
|
||||
/**
|
||||
* get the plan of dvr, how to reap the flv file.
|
||||
*/
|
||||
virtual std::string get_dvr_plan(std::string vhost);
|
||||
virtual void set_dvr_plan(std::string vhost, std::string plan);
|
||||
/**
|
||||
* get the duration of dvr flv.
|
||||
*/
|
||||
|
@ -944,11 +930,6 @@ public:
|
|||
* whether wait keyframe to reap segment.
|
||||
*/
|
||||
virtual bool get_dvr_wait_keyframe(std::string vhost);
|
||||
virtual void set_dvr_wait_keyframe(std::string vhost, bool wait_keyframe);
|
||||
/**
|
||||
* whether autostart for dvr. wait api to start dvr if false.
|
||||
*/
|
||||
virtual bool get_dvr_autostart(std::string vhost);
|
||||
/**
|
||||
* get the time_jitter algorithm for dvr.
|
||||
*/
|
||||
|
|
|
@ -785,17 +785,6 @@ SrsDvrPlan* SrsDvrPlan::create_plan(string vhost)
|
|||
return new SrsDvrSessionPlan();
|
||||
} else if (plan == SRS_CONF_DEFAULT_DVR_PLAN_APPEND) {
|
||||
return new SrsDvrAppendPlan();
|
||||
} else if (plan == SRS_CONF_DEFAULT_DVR_PLAN_API) {
|
||||
/**
|
||||
* @remark the api plan maybe create by publish event or http api post create dvr event.
|
||||
* so when we got from pool first when create it.
|
||||
*/
|
||||
SrsApiDvrPool* pool = SrsApiDvrPool::instance();
|
||||
SrsDvrApiPlan* plan = pool->get_dvr(vhost);
|
||||
if (plan) {
|
||||
return plan;
|
||||
}
|
||||
return new SrsDvrApiPlan();
|
||||
} else {
|
||||
srs_error("invalid dvr plan=%s, vhost=%s", plan.c_str(), vhost.c_str());
|
||||
srs_assert(false);
|
||||
|
@ -852,318 +841,6 @@ void SrsDvrSessionPlan::on_unpublish()
|
|||
dvr_enabled = false;
|
||||
}
|
||||
|
||||
SrsDvrApiPlan::SrsDvrApiPlan()
|
||||
{
|
||||
autostart = false;
|
||||
started = false;
|
||||
|
||||
metadata = sh_audio = sh_video = NULL;
|
||||
}
|
||||
|
||||
SrsDvrApiPlan::~SrsDvrApiPlan()
|
||||
{
|
||||
SrsApiDvrPool* pool = SrsApiDvrPool::instance();
|
||||
pool->detach_dvr(this);
|
||||
|
||||
srs_freep(metadata);
|
||||
srs_freep(sh_audio);
|
||||
srs_freep(sh_video);
|
||||
}
|
||||
|
||||
int SrsDvrApiPlan::initialize(SrsRequest* r)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if ((ret = SrsDvrPlan::initialize(r)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsApiDvrPool* pool = SrsApiDvrPool::instance();
|
||||
if ((ret = pool->add_dvr(this)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
autostart = _srs_config->get_dvr_autostart(r->vhost);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsDvrApiPlan::on_publish()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
// support multiple publish.
|
||||
if (dvr_enabled) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!_srs_config->get_dvr_enabled(req->vhost)) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// api disabled dvr when not autostart.
|
||||
bool autostart = _srs_config->get_dvr_autostart(req->vhost);
|
||||
if (!autostart && !started) {
|
||||
srs_warn("dvr: api not start and disabled for not autostart.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
dvr_enabled = true;
|
||||
|
||||
if ((ret = segment->close()) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((ret = segment->open()) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// update sequence header
|
||||
if (metadata && (ret = SrsDvrPlan::on_meta_data(metadata)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if (sh_video && (ret = SrsDvrPlan::on_video(sh_video)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if (sh_audio && (ret = SrsDvrPlan::on_audio(sh_audio)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SrsDvrApiPlan::on_unpublish()
|
||||
{
|
||||
}
|
||||
|
||||
int SrsDvrApiPlan::on_meta_data(SrsSharedPtrMessage* __metadata)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
srs_freep(metadata);
|
||||
metadata = __metadata->copy();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsDvrApiPlan::on_audio(SrsSharedPtrMessage* __audio)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if (SrsFlvCodec::audio_is_sequence_header(__audio->payload, __audio->size)) {
|
||||
srs_freep(sh_audio);
|
||||
sh_audio = __audio->copy();
|
||||
}
|
||||
|
||||
if ((ret = SrsDvrPlan::on_audio(__audio)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsDvrApiPlan::on_video(SrsSharedPtrMessage* __video)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if (SrsFlvCodec::video_is_sequence_header(__video->payload, __video->size)) {
|
||||
srs_freep(sh_video);
|
||||
sh_video = __video->copy();
|
||||
}
|
||||
|
||||
if ((ret = check_user_actions(__video)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((ret = SrsDvrPlan::on_video(__video)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsDvrApiPlan::set_plan()
|
||||
{
|
||||
_srs_config->set_dvr_plan(req->vhost, SRS_CONF_DEFAULT_DVR_PLAN_API);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int SrsDvrApiPlan::set_path_tmpl(string path_tmpl)
|
||||
{
|
||||
_srs_config->set_dvr_path(req->vhost, path_tmpl);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int SrsDvrApiPlan::set_callback(string value)
|
||||
{
|
||||
_srs_config->set_vhost_http_hooks_enabled(req->vhost, true);
|
||||
_srs_config->set_vhost_on_dvr(req->vhost, value);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int SrsDvrApiPlan::set_wait_keyframe(bool wait_keyframe)
|
||||
{
|
||||
_srs_config->set_dvr_wait_keyframe(req->vhost, wait_keyframe);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int SrsDvrApiPlan::start()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if (started) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// enable the config.
|
||||
_srs_config->set_dvr_enabled(req->vhost, true);
|
||||
|
||||
// stop dvr
|
||||
if (dvr_enabled) {
|
||||
// ignore error.
|
||||
int ret = segment->close();
|
||||
if (ret != ERROR_SUCCESS) {
|
||||
srs_warn("ignore flv close error. ret=%d", ret);
|
||||
}
|
||||
|
||||
dvr_enabled = false;
|
||||
}
|
||||
|
||||
// start dvr
|
||||
if ((ret = on_publish()) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
started = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsDvrApiPlan::dumps(stringstream& ss)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
bool wait_keyframe = _srs_config->get_dvr_wait_keyframe(req->vhost);
|
||||
std::string path_template = _srs_config->get_dvr_path(req->vhost);
|
||||
SrsConfDirective* callbacks = _srs_config->get_vhost_on_dvr(req->vhost);
|
||||
|
||||
ss << __SRS_JOBJECT_START
|
||||
<< __SRS_JFIELD_STR("path_tmpl", path_template) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_STR("path_dvr", segment->get_path()) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_BOOL("wait_keyframe", wait_keyframe) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_STR("app", req->app) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_STR("stream", req->stream) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_STR("callback", callbacks->arg0()) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_STR("status", (dvr_enabled? "start":"stop"))
|
||||
<< __SRS_JOBJECT_END;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsDvrApiPlan::stop()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
_srs_config->set_dvr_enabled(req->vhost, false);
|
||||
started = false;
|
||||
|
||||
// stop dvr
|
||||
if (dvr_enabled) {
|
||||
// ignore error.
|
||||
int ret = segment->close();
|
||||
if (ret != ERROR_SUCCESS) {
|
||||
srs_warn("ignore flv close error. ret=%d", ret);
|
||||
}
|
||||
|
||||
dvr_enabled = false;
|
||||
}
|
||||
|
||||
srs_trace("dvr: stop dvr of vhost=%s", req->vhost.c_str());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsDvrApiPlan::rpc(SrsJsonObject* obj)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
SrsJsonAny* prop = NULL;
|
||||
if ((prop = obj->ensure_property_string("action")) == NULL) {
|
||||
ret = ERROR_HTTP_DVR_REQUEST;
|
||||
srs_error("dvr: rpc required action request. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
action = prop->to_str();
|
||||
if (action == SRS_DVR_USER_ACTION_REAP_SEGMENT) {
|
||||
if ((prop = obj->ensure_property_string("path_tmpl")) != NULL) {
|
||||
path_template = prop->to_str();
|
||||
}
|
||||
} else {
|
||||
ret = ERROR_HTTP_DVR_REQUEST;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsDvrApiPlan::check_user_actions(SrsSharedPtrMessage* msg)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
srs_assert(segment);
|
||||
|
||||
if (action == SRS_DVR_USER_ACTION_REAP_SEGMENT) {
|
||||
// when wait keyframe, ignore if no frame arrived.
|
||||
// @see https://github.com/winlinvip/simple-rtmp-server/issues/177
|
||||
if (_srs_config->get_dvr_wait_keyframe(req->vhost)) {
|
||||
if (!msg->is_video()) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
char* payload = msg->payload;
|
||||
int size = msg->size;
|
||||
bool is_key_frame = SrsFlvCodec::video_is_h264(payload, size)
|
||||
&& SrsFlvCodec::video_is_keyframe(payload, size)
|
||||
&& !SrsFlvCodec::video_is_sequence_header(payload, size);
|
||||
if (!is_key_frame) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
// reap segment
|
||||
if ((ret = segment->close()) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// use new path template if user specified.
|
||||
if (!path_template.empty() && (ret = set_path_tmpl(path_template)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// open new flv file
|
||||
if ((ret = segment->open()) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// update sequence header
|
||||
if (metadata && (ret = SrsDvrPlan::on_meta_data(metadata)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if (sh_video && (ret = SrsDvrPlan::on_video(sh_video)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if (sh_audio && (ret = SrsDvrPlan::on_audio(sh_audio)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
// reset rcp params.
|
||||
action = "";
|
||||
path_template = "";
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsDvrAppendPlan::SrsDvrAppendPlan()
|
||||
{
|
||||
last_update_time = 0;
|
||||
|
@ -1420,290 +1097,6 @@ int SrsDvrSegmentPlan::update_duration(SrsSharedPtrMessage* msg)
|
|||
return ret;
|
||||
}
|
||||
|
||||
SrsApiDvrPool* SrsApiDvrPool::_instance = new SrsApiDvrPool();
|
||||
|
||||
SrsApiDvrPool* SrsApiDvrPool::instance()
|
||||
{
|
||||
return SrsApiDvrPool::_instance;
|
||||
}
|
||||
|
||||
SrsApiDvrPool::SrsApiDvrPool()
|
||||
{
|
||||
}
|
||||
|
||||
SrsApiDvrPool::~SrsApiDvrPool()
|
||||
{
|
||||
dvrs.clear();
|
||||
}
|
||||
|
||||
SrsDvrApiPlan* SrsApiDvrPool::get_dvr(string vhost)
|
||||
{
|
||||
std::vector<SrsDvrApiPlan*>::iterator it;
|
||||
for (it = dvrs.begin(); it != dvrs.end(); ++it) {
|
||||
SrsDvrApiPlan* plan = *it;
|
||||
if (plan->req->vhost == vhost) {
|
||||
return plan;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int SrsApiDvrPool::add_dvr(SrsDvrApiPlan* dvr)
|
||||
{
|
||||
dvrs.push_back(dvr);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
void SrsApiDvrPool::detach_dvr(SrsDvrApiPlan* dvr)
|
||||
{
|
||||
std::vector<SrsDvrApiPlan*>::iterator it;
|
||||
it = ::find(dvrs.begin(), dvrs.end(), dvr);
|
||||
|
||||
if (it != dvrs.end()) {
|
||||
dvrs.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
int SrsApiDvrPool::dumps(string vhost, string app, string stream, stringstream& ss)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
ss << __SRS_JARRAY_START;
|
||||
|
||||
std::vector<SrsDvrApiPlan*> plans;
|
||||
for (int i = 0; i < (int)dvrs.size(); i++) {
|
||||
SrsDvrApiPlan* plan = dvrs.at(i);
|
||||
if (!vhost.empty() && plan->req->vhost != vhost) {
|
||||
continue;
|
||||
}
|
||||
if (!app.empty() && plan->req->app != app) {
|
||||
continue;
|
||||
}
|
||||
if (!stream.empty() && plan->req->stream != stream) {
|
||||
continue;
|
||||
}
|
||||
plans.push_back(plan);
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)plans.size(); i++) {
|
||||
SrsDvrApiPlan* plan = plans.at(i);
|
||||
|
||||
if ((ret = plan->dumps(ss)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (i < (int)plans.size() - 1) {
|
||||
ss << __SRS_JFIELD_CONT;
|
||||
}
|
||||
}
|
||||
|
||||
ss << __SRS_JARRAY_END;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsApiDvrPool::create(SrsJsonAny* json)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
srs_assert(json);
|
||||
if (!json->is_object()) {
|
||||
ret = ERROR_HTTP_DVR_CREATE_REQUEST;
|
||||
srs_error("dvr: api create dvr request requires json object. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsJsonObject* obj = json->to_object();
|
||||
SrsJsonAny* prop = NULL;
|
||||
if ((prop = obj->ensure_property_string("vhost")) == NULL) {
|
||||
ret = ERROR_HTTP_DVR_CREATE_REQUEST;
|
||||
srs_error("dvr: api create dvr request requires vhost. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
std::string vhost = prop->to_str();
|
||||
|
||||
if ((prop = obj->ensure_property_string("app")) == NULL) {
|
||||
ret = ERROR_HTTP_DVR_CREATE_REQUEST;
|
||||
srs_error("dvr: api create dvr request requires app. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
std::string app = prop->to_str();
|
||||
|
||||
if ((prop = obj->ensure_property_string("stream")) == NULL) {
|
||||
ret = ERROR_HTTP_DVR_CREATE_REQUEST;
|
||||
srs_error("dvr: api create dvr request requires stream. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
std::string stream = prop->to_str();
|
||||
|
||||
if (vhost.empty() || app.empty() || stream.empty()) {
|
||||
ret = ERROR_HTTP_DVR_CREATE_REQUEST;
|
||||
srs_error("dvr: api create dvr request requires vhost/app/stream. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsDvrApiPlan* dvr = NULL;
|
||||
for (int i = 0; i < (int)dvrs.size(); i++) {
|
||||
SrsDvrApiPlan* plan = dvrs.at(i);
|
||||
if (plan->req->vhost != vhost || plan->req->app != app || plan->req->stream != stream) {
|
||||
continue;
|
||||
}
|
||||
dvr = plan;
|
||||
break;
|
||||
}
|
||||
|
||||
// mock the client request for dvr.
|
||||
SrsRequest* req = new SrsRequest();
|
||||
SrsAutoFree(SrsRequest, req);
|
||||
|
||||
// should notice the source to reload dvr when already publishing.
|
||||
SrsSource* source = NULL;
|
||||
|
||||
// create if not exists
|
||||
if (!dvr) {
|
||||
dvr = new SrsDvrApiPlan();
|
||||
|
||||
req->vhost = vhost;
|
||||
req->app = app;
|
||||
req->stream = stream;
|
||||
req->tcUrl = "rtmp://" + vhost + "/" + app + "/" + stream;
|
||||
|
||||
// fetch source from pool.
|
||||
// NULL, create without source, ignore.
|
||||
// start dvr when already publishing.
|
||||
source = SrsSource::fetch(req);
|
||||
|
||||
// initialize for dvr pool to create it.
|
||||
if ((ret = dvr->initialize(req)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
// update optional parameters for plan.
|
||||
if ((ret = dvr->set_plan()) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if ((prop = obj->ensure_property_string("path_tmpl")) != NULL) {
|
||||
if ((ret = dvr->set_path_tmpl(prop->to_str())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
if ((prop = obj->ensure_property_boolean("wait_keyframe")) != NULL) {
|
||||
if ((ret = dvr->set_wait_keyframe(prop->to_boolean())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
if ((prop = obj->ensure_property_string("callback")) != NULL) {
|
||||
if ((ret = dvr->set_callback(prop->to_str())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if ((ret = dvr->start()) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// do reload for source when already publishing.
|
||||
// when reload, the source will use the request instead.
|
||||
if (source) {
|
||||
if ((ret = source->on_reload_vhost_dvr(vhost)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsApiDvrPool::stop(string vhost, string app, string stream)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
std::vector<SrsDvrApiPlan*> plans;
|
||||
for (int i = 0; i < (int)dvrs.size(); i++) {
|
||||
SrsDvrApiPlan* plan = dvrs.at(i);
|
||||
if (!vhost.empty() && plan->req->vhost != vhost) {
|
||||
continue;
|
||||
}
|
||||
if (!app.empty() && plan->req->app != app) {
|
||||
continue;
|
||||
}
|
||||
if (!stream.empty() && plan->req->stream != stream) {
|
||||
continue;
|
||||
}
|
||||
plans.push_back(plan);
|
||||
}
|
||||
|
||||
if (plans.empty()) {
|
||||
ret = ERROR_HTTP_DVR_NO_TAEGET;
|
||||
srs_error("dvr: stop not found for url=%s/%s/%s, ret=%d", vhost.c_str(), app.c_str(), stream.c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)plans.size(); i++) {
|
||||
SrsDvrApiPlan* plan = plans.at(i);
|
||||
|
||||
if ((ret = plan->stop()) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsApiDvrPool::rpc(SrsJsonAny* json)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
if (!json->is_object()) {
|
||||
ret = ERROR_HTTP_DVR_REQUEST;
|
||||
srs_error("dvr: rpc required object request. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsJsonObject* obj = json->to_object();
|
||||
|
||||
SrsJsonAny* prop = NULL;
|
||||
if ((prop = obj->ensure_property_string("vhost")) == NULL) {
|
||||
ret = ERROR_HTTP_DVR_REQUEST;
|
||||
srs_error("dvr: rpc required vhost request. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
std::string vhost = prop->to_str();
|
||||
std::string app, stream;
|
||||
if ((prop = obj->ensure_property_string("app")) != NULL) {
|
||||
app = prop->to_str();
|
||||
}
|
||||
if ((prop = obj->ensure_property_string("stream")) != NULL) {
|
||||
stream = prop->to_str();
|
||||
}
|
||||
|
||||
std::vector<SrsDvrApiPlan*> plans;
|
||||
for (int i = 0; i < (int)dvrs.size(); i++) {
|
||||
SrsDvrApiPlan* plan = dvrs.at(i);
|
||||
if (!vhost.empty() && plan->req->vhost != vhost) {
|
||||
continue;
|
||||
}
|
||||
plans.push_back(plan);
|
||||
}
|
||||
|
||||
if (plans.empty()) {
|
||||
ret = ERROR_HTTP_DVR_NO_TAEGET;
|
||||
srs_error("dvr: rpc not found for url=%s/%s/%s, ret=%d", vhost.c_str(), app.c_str(), stream.c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)plans.size(); i++) {
|
||||
SrsDvrApiPlan* plan = plans.at(i);
|
||||
|
||||
if ((ret = plan->rpc(obj)) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsDvr::SrsDvr()
|
||||
{
|
||||
source = NULL;
|
||||
|
|
|
@ -276,48 +276,6 @@ public:
|
|||
virtual void on_unpublish();
|
||||
};
|
||||
|
||||
/**
|
||||
* api plan: reap flv by api.
|
||||
* @remark the api plan maybe create by publish event or http api post create dvr event.
|
||||
* so when we got from pool first when create it.
|
||||
*/
|
||||
class SrsDvrApiPlan : public SrsDvrPlan
|
||||
{
|
||||
private:
|
||||
// cache the metadata and sequence header, for new segment maybe opened.
|
||||
SrsSharedPtrMessage* sh_audio;
|
||||
SrsSharedPtrMessage* sh_video;
|
||||
SrsSharedPtrMessage* metadata;
|
||||
private:
|
||||
bool autostart;
|
||||
bool started;
|
||||
private:
|
||||
// user action, reap_segment.
|
||||
std::string action;
|
||||
std::string path_template;
|
||||
public:
|
||||
SrsDvrApiPlan();
|
||||
virtual ~SrsDvrApiPlan();
|
||||
public:
|
||||
virtual int initialize(SrsRequest* r);
|
||||
virtual int on_publish();
|
||||
virtual void on_unpublish();
|
||||
virtual int on_meta_data(SrsSharedPtrMessage* __metadata);
|
||||
virtual int on_audio(SrsSharedPtrMessage* __audio);
|
||||
virtual int on_video(SrsSharedPtrMessage* __video);
|
||||
public:
|
||||
virtual int set_plan();
|
||||
virtual int set_path_tmpl(std::string path_tmpl);
|
||||
virtual int set_callback(std::string value);
|
||||
virtual int set_wait_keyframe(bool wait_keyframe);
|
||||
virtual int start();
|
||||
virtual int dumps(std::stringstream& ss);
|
||||
virtual int stop();
|
||||
virtual int rpc(SrsJsonObject* obj);
|
||||
private:
|
||||
virtual int check_user_actions(SrsSharedPtrMessage* msg);
|
||||
};
|
||||
|
||||
/**
|
||||
* always append to flv file, never reap it.
|
||||
*/
|
||||
|
@ -362,30 +320,6 @@ private:
|
|||
virtual int update_duration(SrsSharedPtrMessage* msg);
|
||||
};
|
||||
|
||||
/**
|
||||
* the api dvr pool.
|
||||
*/
|
||||
class SrsApiDvrPool
|
||||
{
|
||||
private:
|
||||
std::vector<SrsDvrApiPlan*> dvrs;
|
||||
static SrsApiDvrPool* _instance;
|
||||
private:
|
||||
SrsApiDvrPool();
|
||||
public:
|
||||
static SrsApiDvrPool* instance();
|
||||
virtual ~SrsApiDvrPool();
|
||||
public:
|
||||
virtual SrsDvrApiPlan* get_dvr(std::string vhost);
|
||||
virtual int add_dvr(SrsDvrApiPlan* dvr);
|
||||
virtual void detach_dvr(SrsDvrApiPlan* dvr);
|
||||
public:
|
||||
virtual int dumps(std::string vhost, std::string app, std::string stream, std::stringstream& ss);
|
||||
virtual int create(SrsJsonAny* json);
|
||||
virtual int stop(std::string vhost, std::string app, std::string stream);
|
||||
virtual int rpc(SrsJsonAny* json);
|
||||
};
|
||||
|
||||
/**
|
||||
* dvr(digital video recorder) to record RTMP stream to flv file.
|
||||
* TODO: FIXME: add utest for it.
|
||||
|
|
|
@ -108,8 +108,7 @@ int SrsGoApiV1::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r)
|
|||
<< __SRS_JFIELD_STR("authors", "the primary authors and contributors") << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_STR("requests", "the request itself, for http debug") << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_STR("vhosts", "dumps vhost to json") << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_STR("streams", "dumps streams to json") << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_STR("dvrs", "query or control the dvr plan")
|
||||
<< __SRS_JFIELD_STR("streams", "dumps streams to json")
|
||||
<< __SRS_JOBJECT_END
|
||||
<< __SRS_JOBJECT_END;
|
||||
|
||||
|
@ -474,76 +473,6 @@ int SrsGoApiStreams::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r)
|
|||
return srs_go_http_response_json(w, ss.str());
|
||||
}
|
||||
|
||||
SrsGoApiDvrs::SrsGoApiDvrs()
|
||||
{
|
||||
}
|
||||
|
||||
SrsGoApiDvrs::~SrsGoApiDvrs()
|
||||
{
|
||||
}
|
||||
|
||||
int SrsGoApiDvrs::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r)
|
||||
{
|
||||
std::stringstream ss;
|
||||
|
||||
#ifndef SRS_AUTO_DVR
|
||||
ss << __SRS_JOBJECT_START
|
||||
<< __SRS_JFIELD_ERROR(ERROR_HTTP_DVR_DISABLED)
|
||||
<< __SRS_JOBJECT_END;
|
||||
#else
|
||||
SrsApiDvrPool* pool = SrsApiDvrPool::instance();
|
||||
if (r->is_http_get()) {
|
||||
std::stringstream data;
|
||||
int ret = pool->dumps(r->query_get("vhost"), r->query_get("app"), r->query_get("stream"), data);
|
||||
|
||||
ss << __SRS_JOBJECT_START
|
||||
<< __SRS_JFIELD_ERROR(ret) << __SRS_JFIELD_CONT
|
||||
<< __SRS_JFIELD_ORG("dvrs", data.str())
|
||||
<< __SRS_JOBJECT_END;
|
||||
} else if (r->is_http_post()) {
|
||||
std::string body = r->body();
|
||||
SrsJsonAny* json = SrsJsonAny::loads((char*)body.c_str());
|
||||
int ret = ERROR_SUCCESS;
|
||||
if (!json) {
|
||||
ret = ERROR_HTTP_JSON_REQUIRED;
|
||||
} else {
|
||||
SrsAutoFree(SrsJsonAny, json);
|
||||
ret = pool->create(json);
|
||||
}
|
||||
ss << __SRS_JOBJECT_START
|
||||
<< __SRS_JFIELD_ERROR(ret)
|
||||
<< __SRS_JOBJECT_END;
|
||||
} else if (r->is_http_delete()) {
|
||||
int ret = pool->stop(r->query_get("vhost"), r->query_get("app"), r->query_get("stream"));
|
||||
|
||||
ss << __SRS_JOBJECT_START
|
||||
<< __SRS_JFIELD_ERROR(ret)
|
||||
<< __SRS_JOBJECT_END;
|
||||
} else if (r->is_http_put()) {
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
std::string body = r->body();
|
||||
SrsJsonAny* json = SrsJsonAny::loads((char*)body.c_str());
|
||||
if (!json) {
|
||||
ret = ERROR_HTTP_JSON_REQUIRED;
|
||||
} else {
|
||||
SrsAutoFree(SrsJsonAny, json);
|
||||
ret = pool->rpc(json);
|
||||
}
|
||||
|
||||
ss << __SRS_JOBJECT_START
|
||||
<< __SRS_JFIELD_ERROR(ret)
|
||||
<< __SRS_JOBJECT_END;
|
||||
} else {
|
||||
ss << __SRS_JOBJECT_START
|
||||
<< __SRS_JFIELD_ERROR(ERROR_HTTP_DVR_REQUEST)
|
||||
<< __SRS_JOBJECT_END;
|
||||
}
|
||||
#endif
|
||||
|
||||
return srs_go_http_response_json(w, ss.str());
|
||||
}
|
||||
|
||||
SrsHttpApi::SrsHttpApi(SrsServer* svr, st_netfd_t fd, SrsGoHttpServeMux* m)
|
||||
: SrsConnection(svr, fd)
|
||||
{
|
||||
|
|
|
@ -159,15 +159,6 @@ public:
|
|||
virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
};
|
||||
|
||||
class SrsGoApiDvrs : public ISrsGoHttpHandler
|
||||
{
|
||||
public:
|
||||
SrsGoApiDvrs();
|
||||
virtual ~SrsGoApiDvrs();
|
||||
public:
|
||||
virtual int serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r);
|
||||
};
|
||||
|
||||
class SrsHttpApi : public SrsConnection
|
||||
{
|
||||
private:
|
||||
|
|
|
@ -529,9 +529,6 @@ int SrsServer::initialize()
|
|||
if ((ret = http_api_mux->handle("/api/v1/streams", new SrsGoApiStreams())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if ((ret = http_api_mux->handle("/api/v1/dvrs", new SrsGoApiDvrs())) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SRS_AUTO_HTTP_SERVER
|
||||
|
|
|
@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
// current release version
|
||||
#define VERSION_MAJOR 2
|
||||
#define VERSION_MINOR 0
|
||||
#define VERSION_REVISION 127
|
||||
#define VERSION_REVISION 128
|
||||
|
||||
// server info.
|
||||
#define RTMP_SIG_SRS_KEY "SRS"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue