diff --git a/README.md b/README.md index 49b89d8861..6289691ada 100755 --- a/README.md +++ b/README.md @@ -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. diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index d4e3f35ae4..76b7966c46 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -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, , 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, diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 2341e21bff..c7416c84d4 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -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); diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index 6b7fb4982c..e79f333edc 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -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 @@ class SrsConfig * 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 @@ class SrsConfig * @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 @@ class SrsConfig * @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 @@ class SrsConfig * 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 @@ class SrsConfig * 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. */ diff --git a/trunk/src/app/srs_app_dvr.cpp b/trunk/src/app/srs_app_dvr.cpp index b218d9e4c1..ef4b759bab 100644 --- a/trunk/src/app/srs_app_dvr.cpp +++ b/trunk/src/app/srs_app_dvr.cpp @@ -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::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::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 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 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 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; diff --git a/trunk/src/app/srs_app_dvr.hpp b/trunk/src/app/srs_app_dvr.hpp index e6bf334340..a29a25081e 100644 --- a/trunk/src/app/srs_app_dvr.hpp +++ b/trunk/src/app/srs_app_dvr.hpp @@ -276,48 +276,6 @@ class SrsDvrSessionPlan : public SrsDvrPlan 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 @@ class SrsDvrSegmentPlan : public SrsDvrPlan virtual int update_duration(SrsSharedPtrMessage* msg); }; -/** -* the api dvr pool. -*/ -class SrsApiDvrPool -{ -private: - std::vector 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. diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index cb02f890f0..06de700d3d 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -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) { diff --git a/trunk/src/app/srs_app_http_api.hpp b/trunk/src/app/srs_app_http_api.hpp index 067047cdab..dbc61e846d 100644 --- a/trunk/src/app/srs_app_http_api.hpp +++ b/trunk/src/app/srs_app_http_api.hpp @@ -159,15 +159,6 @@ class SrsGoApiStreams : public ISrsGoHttpHandler 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: diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp index 7d2481ea5f..8be3609f1b 100644 --- a/trunk/src/app/srs_app_server.cpp +++ b/trunk/src/app/srs_app_server.cpp @@ -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 diff --git a/trunk/src/core/srs_core.hpp b/trunk/src/core/srs_core.hpp index d7e74657bd..7bef924159 100644 --- a/trunk/src/core/srs_core.hpp +++ b/trunk/src/core/srs_core.hpp @@ -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"