winlin

for #179, support http api to start dvr.

@@ -296,15 +296,14 @@ vhost dvr.srs.com { @@ -296,15 +296,14 @@ vhost dvr.srs.com {
296 # request params, for example ?vhost=__defaultVhost__, where: 296 # request params, for example ?vhost=__defaultVhost__, where:
297 # vhost, query all dvr of this vhost. 297 # vhost, query all dvr of this vhost.
298 # response in json, where: 298 # response in json, where:
299 - # {code:0, dvrs: [{plan:"api", path:"./objs/nginx/html",  
300 - # autostart:true, wait_keyframe:true, jitter:"full" 299 + # {code:0, dvrs: [{path_tmpl:"./[15].[04].[05].[999].flv", path_dvr:"./22.7.43.312.flv",
  300 + # wait_keyframe:true, vhost:"__defaultVhost", callback:"http://dvr/callback"
301 # }]} 301 # }]}
302 # method=POST 302 # method=POST
303 # to start dvr of specified vhost. 303 # to start dvr of specified vhost.
304 # request should encode in json, specifies the dvr to create, where: 304 # request should encode in json, specifies the dvr to create, where:
305 - # {plan:"api", path:"./objs/nginx/html",  
306 - # autostart:true, wait_keyframe:true, jitter:"full",  
307 - # vhost:"__defaultVhost", callback:"http://dvr/callback" 305 + # {path_tmpl:"./[15].[04].[05].[999].flv",
  306 + # wait_keyframe:true, vhost:"__defaultVhost", callback:"http://dvr/callback"
308 # } 307 # }
309 # response in json, where: 308 # response in json, where:
310 # {code:0} 309 # {code:0}
@@ -329,7 +328,7 @@ vhost dvr.srs.com { @@ -329,7 +328,7 @@ vhost dvr.srs.com {
329 # [05], repleace this const to current second. 328 # [05], repleace this const to current second.
330 # [999], repleace this const to current millisecond. 329 # [999], repleace this const to current millisecond.
331 # [timestamp],replace this const to current UNIX timestamp in ms. 330 # [timestamp],replace this const to current UNIX timestamp in ms.
332 - # @remark we use golang time format "2006-01-02 15:04:05.999" 331 + # @remark we use golang time format "2006-01-02 15:04:05.999" as "[2006]-[01]-[02]_[15].[04].[05]_[999]"
333 # for example, for url rtmp://ossrs.net/live/livestream and time 2015-01-03 10:57:30.776 332 # for example, for url rtmp://ossrs.net/live/livestream and time 2015-01-03 10:57:30.776
334 # 1. No variables, the rule of SRS1.0(auto add [stream].[timestamp].flv as filename): 333 # 1. No variables, the rule of SRS1.0(auto add [stream].[timestamp].flv as filename):
335 # dvr_path ./objs/nginx/html; 334 # dvr_path ./objs/nginx/html;
@@ -1977,6 +1977,38 @@ int SrsConfig::get_stream_caster_rtp_port_max(SrsConfDirective* sc) @@ -1977,6 +1977,38 @@ int SrsConfig::get_stream_caster_rtp_port_max(SrsConfDirective* sc)
1977 return ::atoi(conf->arg0().c_str()); 1977 return ::atoi(conf->arg0().c_str());
1978 } 1978 }
1979 1979
  1980 +SrsConfDirective* SrsConfig::create_directive(string vhost, string directive, string sub_directive)
  1981 +{
  1982 + SrsConfDirective* vhost_conf = get_vhost(vhost);
  1983 +
  1984 + if (!vhost_conf) {
  1985 + vhost_conf = new SrsConfDirective();
  1986 + root->directives.push_back(vhost_conf);
  1987 + }
  1988 +
  1989 + if (directive.empty()) {
  1990 + return vhost_conf;
  1991 + }
  1992 +
  1993 + SrsConfDirective* dir = vhost_conf->get(directive);
  1994 + if (!dir) {
  1995 + dir = new SrsConfDirective();
  1996 + vhost_conf->directives.push_back(dir);
  1997 + }
  1998 +
  1999 + if (sub_directive.empty()) {
  2000 + return dir;
  2001 + }
  2002 +
  2003 + SrsConfDirective* sdir = dir->get(sub_directive);
  2004 + if (!sdir) {
  2005 + sdir = new SrsConfDirective();
  2006 + dir->directives.push_back(sdir);
  2007 + }
  2008 +
  2009 + return sdir;
  2010 +}
  2011 +
1980 SrsConfDirective* SrsConfig::get_vhost(string vhost) 2012 SrsConfDirective* SrsConfig::get_vhost(string vhost)
1981 { 2013 {
1982 srs_assert(root); 2014 srs_assert(root);
@@ -3327,6 +3359,13 @@ string SrsConfig::get_dvr_path(string vhost) @@ -3327,6 +3359,13 @@ string SrsConfig::get_dvr_path(string vhost)
3327 return conf->arg0(); 3359 return conf->arg0();
3328 } 3360 }
3329 3361
  3362 +void SrsConfig::set_dvr_path(string vhost, string path)
  3363 +{
  3364 + SrsConfDirective* conf = create_directive(vhost, "dvr", "dvr_path");
  3365 + conf->args.clear();
  3366 + conf->args.push_back(path);
  3367 +}
  3368 +
3330 string SrsConfig::get_dvr_plan(string vhost) 3369 string SrsConfig::get_dvr_plan(string vhost)
3331 { 3370 {
3332 SrsConfDirective* dvr = get_dvr(vhost); 3371 SrsConfDirective* dvr = get_dvr(vhost);
@@ -3378,6 +3417,13 @@ bool SrsConfig::get_dvr_wait_keyframe(string vhost) @@ -3378,6 +3417,13 @@ bool SrsConfig::get_dvr_wait_keyframe(string vhost)
3378 return false; 3417 return false;
3379 } 3418 }
3380 3419
  3420 +void SrsConfig::set_dvr_wait_keyframe(string vhost, bool wait_keyframe)
  3421 +{
  3422 + SrsConfDirective* conf = create_directive(vhost, "dvr", "dvr_wait_keyframe");
  3423 + conf->args.clear();
  3424 + conf->args.push_back(wait_keyframe? "on":"off");
  3425 +}
  3426 +
3381 bool SrsConfig::get_dvr_autostart(string vhost) 3427 bool SrsConfig::get_dvr_autostart(string vhost)
3382 { 3428 {
3383 SrsConfDirective* dvr = get_dvr(vhost); 3429 SrsConfDirective* dvr = get_dvr(vhost);
@@ -452,6 +452,14 @@ public: @@ -452,6 +452,14 @@ public:
452 * get the max udp port for rtp of stream caster rtsp. 452 * get the max udp port for rtp of stream caster rtsp.
453 */ 453 */
454 virtual int get_stream_caster_rtp_port_max(SrsConfDirective* sc); 454 virtual int get_stream_caster_rtp_port_max(SrsConfDirective* sc);
  455 +private:
  456 + /**
  457 + * create directive under vhost.
  458 + * @param directive, get the directive of vhost. get vhost if directive is empty.
  459 + * @param sub_directive, get the sub directive of vhost. get directive if sub-directive is empty.
  460 + * @return the vhost(empty directive and sub-directive); the directive(empty sub-directive); the sub-directive.
  461 + */
  462 + virtual SrsConfDirective* create_directive(std::string vhost, std::string directive, std::string sub_directive);
455 // vhost specified section 463 // vhost specified section
456 public: 464 public:
457 /** 465 /**
@@ -919,6 +927,7 @@ public: @@ -919,6 +927,7 @@ public:
919 * get the dvr path, the flv file to save in. 927 * get the dvr path, the flv file to save in.
920 */ 928 */
921 virtual std::string get_dvr_path(std::string vhost); 929 virtual std::string get_dvr_path(std::string vhost);
  930 + virtual void set_dvr_path(std::string vhost, std::string path);
922 /** 931 /**
923 * get the plan of dvr, how to reap the flv file. 932 * get the plan of dvr, how to reap the flv file.
924 */ 933 */
@@ -931,6 +940,7 @@ public: @@ -931,6 +940,7 @@ public:
931 * whether wait keyframe to reap segment. 940 * whether wait keyframe to reap segment.
932 */ 941 */
933 virtual bool get_dvr_wait_keyframe(std::string vhost); 942 virtual bool get_dvr_wait_keyframe(std::string vhost);
  943 + virtual void set_dvr_wait_keyframe(std::string vhost, bool wait_keyframe);
934 /** 944 /**
935 * whether autostart for dvr. wait api to start dvr if false. 945 * whether autostart for dvr. wait api to start dvr if false.
936 */ 946 */
@@ -194,6 +194,11 @@ int SrsFlvSegment::close() @@ -194,6 +194,11 @@ int SrsFlvSegment::close()
194 return ret; 194 return ret;
195 } 195 }
196 } 196 }
  197 +
  198 + if ((ret = plan->on_reap_segment()) != ERROR_SUCCESS) {
  199 + srs_error("dvr: notify plan to reap segment failed. ret=%d", ret);
  200 + return ret;
  201 + }
197 202
198 #ifdef SRS_AUTO_HTTP_CALLBACK 203 #ifdef SRS_AUTO_HTTP_CALLBACK
199 if (_srs_config->get_vhost_http_hooks_enabled(req->vhost)) { 204 if (_srs_config->get_vhost_http_hooks_enabled(req->vhost)) {
@@ -405,6 +410,11 @@ int SrsFlvSegment::update_flv_metadata() @@ -405,6 +410,11 @@ int SrsFlvSegment::update_flv_metadata()
405 return ret; 410 return ret;
406 } 411 }
407 412
  413 +string SrsFlvSegment::get_path()
  414 +{
  415 + return path;
  416 +}
  417 +
408 string SrsFlvSegment::generate_path() 418 string SrsFlvSegment::generate_path()
409 { 419 {
410 // the path in config, for example, 420 // the path in config, for example,
@@ -657,6 +667,11 @@ int SrsDvrPlan::on_video(SrsSharedPtrMessage* __video) @@ -657,6 +667,11 @@ int SrsDvrPlan::on_video(SrsSharedPtrMessage* __video)
657 return ret; 667 return ret;
658 } 668 }
659 669
  670 +int SrsDvrPlan::on_reap_segment()
  671 +{
  672 + return ERROR_SUCCESS;
  673 +}
  674 +
660 SrsDvrPlan* SrsDvrPlan::create_plan(string vhost) 675 SrsDvrPlan* SrsDvrPlan::create_plan(string vhost)
661 { 676 {
662 std::string plan = _srs_config->get_dvr_plan(vhost); 677 std::string plan = _srs_config->get_dvr_plan(vhost);
@@ -726,12 +741,32 @@ void SrsDvrSessionPlan::on_unpublish() @@ -726,12 +741,32 @@ void SrsDvrSessionPlan::on_unpublish()
726 741
727 SrsDvrApiPlan::SrsDvrApiPlan() 742 SrsDvrApiPlan::SrsDvrApiPlan()
728 { 743 {
  744 + autostart = false;
  745 + started = false;
729 } 746 }
730 747
731 SrsDvrApiPlan::~SrsDvrApiPlan() 748 SrsDvrApiPlan::~SrsDvrApiPlan()
732 { 749 {
733 } 750 }
734 751
  752 +int SrsDvrApiPlan::initialize(SrsSource* s, SrsRequest* r)
  753 +{
  754 + int ret = ERROR_SUCCESS;
  755 +
  756 + if ((ret = SrsDvrPlan::initialize(s, r)) != ERROR_SUCCESS) {
  757 + return ret;
  758 + }
  759 +
  760 + SrsApiDvrPool* pool = SrsApiDvrPool::instance();
  761 + if ((ret = pool->add_dvr(this)) != ERROR_SUCCESS) {
  762 + return ret;
  763 + }
  764 +
  765 + autostart = _srs_config->get_dvr_autostart(r->vhost);
  766 +
  767 + return ret;
  768 +}
  769 +
735 int SrsDvrApiPlan::on_publish() 770 int SrsDvrApiPlan::on_publish()
736 { 771 {
737 int ret = ERROR_SUCCESS; 772 int ret = ERROR_SUCCESS;
@@ -745,6 +780,13 @@ int SrsDvrApiPlan::on_publish() @@ -745,6 +780,13 @@ int SrsDvrApiPlan::on_publish()
745 return ret; 780 return ret;
746 } 781 }
747 782
  783 + // api disabled dvr when not autostart.
  784 + bool autostart = _srs_config->get_dvr_autostart(req->vhost);
  785 + if (!autostart && !started) {
  786 + srs_warn("dvr: api not start and disabled for not autostart.");
  787 + return ret;
  788 + }
  789 +
748 if ((ret = segment->close()) != ERROR_SUCCESS) { 790 if ((ret = segment->close()) != ERROR_SUCCESS) {
749 return ret; 791 return ret;
750 } 792 }
@@ -760,18 +802,76 @@ int SrsDvrApiPlan::on_publish() @@ -760,18 +802,76 @@ int SrsDvrApiPlan::on_publish()
760 802
761 void SrsDvrApiPlan::on_unpublish() 803 void SrsDvrApiPlan::on_unpublish()
762 { 804 {
763 - // support multiple publish.  
764 - if (!dvr_enabled) {  
765 - return; 805 +}
  806 +
  807 +int SrsDvrApiPlan::set_path_tmpl(string path_tmpl)
  808 +{
  809 + _srs_config->set_dvr_path(req->vhost, path_tmpl);
  810 + return ERROR_SUCCESS;
  811 +}
  812 +
  813 +int SrsDvrApiPlan::set_callback(string value)
  814 +{
  815 + callback = value;
  816 + return ERROR_SUCCESS;
  817 +}
  818 +
  819 +int SrsDvrApiPlan::set_wait_keyframe(bool wait_keyframe)
  820 +{
  821 + _srs_config->set_dvr_wait_keyframe(req->vhost, wait_keyframe);
  822 + return ERROR_SUCCESS;
  823 +}
  824 +
  825 +int SrsDvrApiPlan::start()
  826 +{
  827 + int ret = ERROR_SUCCESS;
  828 +
  829 + if (started) {
  830 + return ret;
766 } 831 }
  832 +
  833 + // stop dvr
  834 + if (dvr_enabled) {
  835 + // ignore error.
  836 + int ret = segment->close();
  837 + if (ret != ERROR_SUCCESS) {
  838 + srs_warn("ignore flv close error. ret=%d", ret);
  839 + }
767 840
768 - // ignore error.  
769 - int ret = segment->close();  
770 - if (ret != ERROR_SUCCESS) {  
771 - srs_warn("ignore flv close error. ret=%d", ret); 841 + dvr_enabled = false;
772 } 842 }
773 -  
774 - dvr_enabled = false; 843 +
  844 + // start dvr
  845 + if ((ret = on_publish()) != ERROR_SUCCESS) {
  846 + return ret;
  847 + }
  848 +
  849 + started = true;
  850 + return ret;
  851 +}
  852 +
  853 +int SrsDvrApiPlan::dumps(stringstream& ss)
  854 +{
  855 + int ret = ERROR_SUCCESS;
  856 +
  857 + bool wait_keyframe = _srs_config->get_dvr_wait_keyframe(req->vhost);
  858 + std::string path_template = _srs_config->get_dvr_path(req->vhost);
  859 +
  860 + ss << __SRS_JOBJECT_START
  861 + << __SRS_JFIELD_STR("path_tmpl", path_template) << __SRS_JFIELD_CONT
  862 + << __SRS_JFIELD_STR("path_dvr", segment->get_path()) << __SRS_JFIELD_CONT
  863 + << __SRS_JFIELD_BOOL("wait_keyframe", wait_keyframe) << __SRS_JFIELD_CONT
  864 + << __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT
  865 + << __SRS_JFIELD_STR("callback", callback)
  866 + << __SRS_JOBJECT_END;
  867 +
  868 + return ret;
  869 +}
  870 +
  871 +int SrsDvrApiPlan::on_reap_segment()
  872 +{
  873 + // TODO: FIXME: implements it.
  874 + return ERROR_SUCCESS;
775 } 875 }
776 876
777 SrsDvrAppendPlan::SrsDvrAppendPlan() 877 SrsDvrAppendPlan::SrsDvrAppendPlan()
@@ -1043,16 +1143,103 @@ SrsApiDvrPool::SrsApiDvrPool() @@ -1043,16 +1143,103 @@ SrsApiDvrPool::SrsApiDvrPool()
1043 1143
1044 SrsApiDvrPool::~SrsApiDvrPool() 1144 SrsApiDvrPool::~SrsApiDvrPool()
1045 { 1145 {
  1146 + dvrs.clear();
1046 } 1147 }
1047 1148
1048 -int SrsApiDvrPool::dumps(stringstream& ss) 1149 +int SrsApiDvrPool::add_dvr(SrsDvrApiPlan* dvr)
  1150 +{
  1151 + dvrs.push_back(dvr);
  1152 + return ERROR_SUCCESS;
  1153 +}
  1154 +
  1155 +int SrsApiDvrPool::dumps(string vhost, stringstream& ss)
1049 { 1156 {
1050 int ret = ERROR_SUCCESS; 1157 int ret = ERROR_SUCCESS;
1051 - ss << __SRS_JARRAY_START  
1052 - << __SRS_JARRAY_END; 1158 +
  1159 + ss << __SRS_JARRAY_START;
  1160 +
  1161 + std::vector<SrsDvrApiPlan*> plans;
  1162 + for (int i = 0; i < (int)dvrs.size(); i++) {
  1163 + SrsDvrApiPlan* plan = dvrs.at(i);
  1164 + if (!vhost.empty() && plan->req->vhost != vhost) {
  1165 + continue;
  1166 + }
  1167 + plans.push_back(plan);
  1168 + }
  1169 +
  1170 + for (int i = 0; i < (int)plans.size(); i++) {
  1171 + SrsDvrApiPlan* plan = plans.at(i);
  1172 +
  1173 + if ((ret = plan->dumps(ss)) != ERROR_SUCCESS) {
  1174 + return ret;
  1175 + }
  1176 +
  1177 + if (i < (int)dvrs.size() - 1) {
  1178 + ss << __SRS_JFIELD_CONT;
  1179 + }
  1180 + }
  1181 +
  1182 + ss << __SRS_JARRAY_END;
  1183 +
1053 return ret; 1184 return ret;
1054 } 1185 }
1055 1186
  1187 +int SrsApiDvrPool::create(SrsJsonAny* json)
  1188 +{
  1189 + int ret = ERROR_SUCCESS;
  1190 +
  1191 + srs_assert(json);
  1192 + if (!json->is_object()) {
  1193 + ret = ERROR_HTTP_DVR_CREATE_REQUEST;
  1194 + srs_error("dvr: api create dvr request requires json object. ret=%d", ret);
  1195 + return ret;
  1196 + }
  1197 +
  1198 + SrsJsonObject* obj = json->to_object();
  1199 + SrsJsonAny* prop = NULL;
  1200 + if ((prop = obj->ensure_property_string("vhost")) == NULL) {
  1201 + ret = ERROR_HTTP_DVR_CREATE_REQUEST;
  1202 + srs_error("dvr: api create dvr request requires vhost. ret=%d", ret);
  1203 + return ret;
  1204 + }
  1205 +
  1206 + std::string vhost = prop->to_str();
  1207 + SrsDvrApiPlan* dvr = NULL;
  1208 + for (int i = 0; i < (int)dvrs.size(); i++) {
  1209 + SrsDvrApiPlan* plan = dvrs.at(i);
  1210 + if (!vhost.empty() && plan->req->vhost != vhost) {
  1211 + continue;
  1212 + }
  1213 + dvr = plan;
  1214 + break;
  1215 + }
  1216 +
  1217 + if (!dvr) {
  1218 + ret = ERROR_HTTP_DVR_CREATE_REQUEST;
  1219 + srs_error("dvr: api create dvr request vhost invalid. vhost=%s. ret=%d", vhost.c_str(), ret);
  1220 + return ret;
  1221 + }
  1222 +
  1223 + // update optional parameters for plan.
  1224 + if ((prop = obj->ensure_property_string("path_tmpl")) != NULL) {
  1225 + if ((ret = dvr->set_path_tmpl(prop->to_str())) != ERROR_SUCCESS) {
  1226 + return ret;
  1227 + }
  1228 + }
  1229 + if ((prop = obj->ensure_property_boolean("wait_keyframe")) != NULL) {
  1230 + if ((ret = dvr->set_wait_keyframe(prop->to_boolean())) != ERROR_SUCCESS) {
  1231 + return ret;
  1232 + }
  1233 + }
  1234 + if ((prop = obj->ensure_property_string("callback")) != NULL) {
  1235 + if ((ret = dvr->set_callback(prop->to_str())) != ERROR_SUCCESS) {
  1236 + return ret;
  1237 + }
  1238 + }
  1239 +
  1240 + return dvr->start();
  1241 +}
  1242 +
1056 SrsDvr::SrsDvr(SrsSource* s) 1243 SrsDvr::SrsDvr(SrsSource* s)
1057 { 1244 {
1058 source = s; 1245 source = s;
@@ -43,6 +43,7 @@ class SrsSharedPtrMessage; @@ -43,6 +43,7 @@ class SrsSharedPtrMessage;
43 class SrsFileWriter; 43 class SrsFileWriter;
44 class SrsFlvEncoder; 44 class SrsFlvEncoder;
45 class SrsDvrPlan; 45 class SrsDvrPlan;
  46 +class SrsJsonAny;
46 47
47 #include <srs_app_source.hpp> 48 #include <srs_app_source.hpp>
48 #include <srs_app_reload.hpp> 49 #include <srs_app_reload.hpp>
@@ -149,6 +150,10 @@ public: @@ -149,6 +150,10 @@ public:
149 * update the flv metadata. 150 * update the flv metadata.
150 */ 151 */
151 virtual int update_flv_metadata(); 152 virtual int update_flv_metadata();
  153 + /**
  154 + * get the current dvr path.
  155 + */
  156 + virtual std::string get_path();
152 private: 157 private:
153 /** 158 /**
154 * generate the flv segment path. 159 * generate the flv segment path.
@@ -179,9 +184,10 @@ class SrsDvrPlan @@ -179,9 +184,10 @@ class SrsDvrPlan
179 { 184 {
180 public: 185 public:
181 friend class SrsFlvSegment; 186 friend class SrsFlvSegment;
  187 +public:
  188 + SrsRequest* req;
182 protected: 189 protected:
183 SrsSource* source; 190 SrsSource* source;
184 - SrsRequest* req;  
185 SrsFlvSegment* segment; 191 SrsFlvSegment* segment;
186 bool dvr_enabled; 192 bool dvr_enabled;
187 public: 193 public:
@@ -204,6 +210,7 @@ public: @@ -204,6 +210,7 @@ public:
204 */ 210 */
205 virtual int on_video(SrsSharedPtrMessage* __video); 211 virtual int on_video(SrsSharedPtrMessage* __video);
206 protected: 212 protected:
  213 + virtual int on_reap_segment();
207 virtual int on_dvr_request_sh(); 214 virtual int on_dvr_request_sh();
208 virtual int on_video_keyframe(); 215 virtual int on_video_keyframe();
209 virtual int64_t filter_timestamp(int64_t timestamp); 216 virtual int64_t filter_timestamp(int64_t timestamp);
@@ -229,12 +236,25 @@ public: @@ -229,12 +236,25 @@ public:
229 */ 236 */
230 class SrsDvrApiPlan : public SrsDvrPlan 237 class SrsDvrApiPlan : public SrsDvrPlan
231 { 238 {
  239 +private:
  240 + std::string callback;
  241 + bool autostart;
  242 + bool started;
232 public: 243 public:
233 SrsDvrApiPlan(); 244 SrsDvrApiPlan();
234 virtual ~SrsDvrApiPlan(); 245 virtual ~SrsDvrApiPlan();
235 public: 246 public:
  247 + virtual int initialize(SrsSource* s, SrsRequest* r);
236 virtual int on_publish(); 248 virtual int on_publish();
237 virtual void on_unpublish(); 249 virtual void on_unpublish();
  250 +public:
  251 + virtual int set_path_tmpl(std::string path_tmpl);
  252 + virtual int set_callback(std::string value);
  253 + virtual int set_wait_keyframe(bool wait_keyframe);
  254 + virtual int start();
  255 + virtual int dumps(std::stringstream& ss);
  256 +protected:
  257 + virtual int on_reap_segment();
238 }; 258 };
239 259
240 /** 260 /**
@@ -302,6 +322,7 @@ private: @@ -302,6 +322,7 @@ private:
302 class SrsApiDvrPool 322 class SrsApiDvrPool
303 { 323 {
304 private: 324 private:
  325 + std::vector<SrsDvrApiPlan*> dvrs;
305 static SrsApiDvrPool* _instance; 326 static SrsApiDvrPool* _instance;
306 private: 327 private:
307 SrsApiDvrPool(); 328 SrsApiDvrPool();
@@ -309,7 +330,10 @@ public: @@ -309,7 +330,10 @@ public:
309 static SrsApiDvrPool* instance(); 330 static SrsApiDvrPool* instance();
310 virtual ~SrsApiDvrPool(); 331 virtual ~SrsApiDvrPool();
311 public: 332 public:
312 - virtual int dumps(std::stringstream& ss); 333 + virtual int add_dvr(SrsDvrApiPlan* dvr);
  334 +public:
  335 + virtual int dumps(std::string vhost, std::stringstream& ss);
  336 + virtual int create(SrsJsonAny* json);
313 }; 337 };
314 338
315 /** 339 /**
@@ -494,12 +494,25 @@ int SrsGoApiDvrs::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r) @@ -494,12 +494,25 @@ int SrsGoApiDvrs::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r)
494 SrsApiDvrPool* pool = SrsApiDvrPool::instance(); 494 SrsApiDvrPool* pool = SrsApiDvrPool::instance();
495 if (r->is_http_get()) { 495 if (r->is_http_get()) {
496 std::stringstream data; 496 std::stringstream data;
497 - int ret = pool->dumps(data); 497 + int ret = pool->dumps(r->query_get("vhost"), data);
498 498
499 ss << __SRS_JOBJECT_START 499 ss << __SRS_JOBJECT_START
500 << __SRS_JFIELD_ERROR(ret) << __SRS_JFIELD_CONT 500 << __SRS_JFIELD_ERROR(ret) << __SRS_JFIELD_CONT
501 << __SRS_JFIELD_ORG("dvrs", data.str()) 501 << __SRS_JFIELD_ORG("dvrs", data.str())
502 << __SRS_JOBJECT_END; 502 << __SRS_JOBJECT_END;
  503 + } else if (r->is_http_post()) {
  504 + char* body = (char*)r->body().c_str();
  505 + SrsJsonAny* json = SrsJsonAny::loads(body);
  506 + int ret = ERROR_SUCCESS;
  507 + if (!json) {
  508 + ret = ERROR_HTTP_JSON_REQUIRED;
  509 + } else {
  510 + SrsAutoFree(SrsJsonAny, json);
  511 + ret = pool->create(json);
  512 + }
  513 + ss << __SRS_JOBJECT_START
  514 + << __SRS_JFIELD_ERROR(ret)
  515 + << __SRS_JOBJECT_END;
503 } else { 516 } else {
504 ss << __SRS_JOBJECT_START 517 ss << __SRS_JOBJECT_START
505 << __SRS_JFIELD_ERROR(ERROR_HTTP_DVR_REQUEST) 518 << __SRS_JFIELD_ERROR(ERROR_HTTP_DVR_REQUEST)
@@ -457,6 +457,21 @@ SrsJsonAny* SrsJsonObject::ensure_property_string(string name) @@ -457,6 +457,21 @@ SrsJsonAny* SrsJsonObject::ensure_property_string(string name)
457 return prop; 457 return prop;
458 } 458 }
459 459
  460 +SrsJsonAny* SrsJsonObject::ensure_property_boolean(string name)
  461 +{
  462 + SrsJsonAny* prop = get_property(name);
  463 +
  464 + if (!prop) {
  465 + return NULL;
  466 + }
  467 +
  468 + if (!prop->is_boolean()) {
  469 + return NULL;
  470 + }
  471 +
  472 + return prop;
  473 +}
  474 +
460 SrsJsonArray::SrsJsonArray() 475 SrsJsonArray::SrsJsonArray()
461 { 476 {
462 marker = SRS_JSON_Array; 477 marker = SRS_JSON_Array;
@@ -123,6 +123,7 @@ public: @@ -123,6 +123,7 @@ public:
123 public: 123 public:
124 /** 124 /**
125 * read json tree from str:char* 125 * read json tree from str:char*
  126 + * @return json object. NULL if error.
126 */ 127 */
127 static SrsJsonAny* loads(char* str); 128 static SrsJsonAny* loads(char* str);
128 }; 129 };
@@ -148,6 +149,7 @@ public: @@ -148,6 +149,7 @@ public:
148 virtual void set(std::string key, SrsJsonAny* value); 149 virtual void set(std::string key, SrsJsonAny* value);
149 virtual SrsJsonAny* get_property(std::string name); 150 virtual SrsJsonAny* get_property(std::string name);
150 virtual SrsJsonAny* ensure_property_string(std::string name); 151 virtual SrsJsonAny* ensure_property_string(std::string name);
  152 + virtual SrsJsonAny* ensure_property_boolean(std::string name);
151 }; 153 };
152 154
153 class SrsJsonArray : public SrsJsonAny 155 class SrsJsonArray : public SrsJsonAny
@@ -214,6 +216,7 @@ that is: @@ -214,6 +216,7 @@ that is:
214 #define __SRS_JFIELD_NAME(k) "\"" << k << "\":" 216 #define __SRS_JFIELD_NAME(k) "\"" << k << "\":"
215 #define __SRS_JFIELD_STR(k, v) "\"" << k << "\":\"" << v << "\"" 217 #define __SRS_JFIELD_STR(k, v) "\"" << k << "\":\"" << v << "\""
216 #define __SRS_JFIELD_ORG(k, v) "\"" << k << "\":" << std::dec << v 218 #define __SRS_JFIELD_ORG(k, v) "\"" << k << "\":" << std::dec << v
  219 +#define __SRS_JFIELD_BOOL(k, v) __SRS_JFIELD_ORG(k, (v? "true":"false"))
217 #define __SRS_JFIELD_ERROR(ret) "\"" << "code" << "\":" << ret 220 #define __SRS_JFIELD_ERROR(ret) "\"" << "code" << "\":" << ret
218 #define __SRS_JFIELD_CONT "," 221 #define __SRS_JFIELD_CONT ","
219 #define __SRS_JOBJECT_END "}" 222 #define __SRS_JOBJECT_END "}"
@@ -211,6 +211,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -211,6 +211,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
211 #define ERROR_HLS_TRY_MP3 3049 211 #define ERROR_HLS_TRY_MP3 3049
212 #define ERROR_HTTP_DVR_DISABLED 3050 212 #define ERROR_HTTP_DVR_DISABLED 3050
213 #define ERROR_HTTP_DVR_REQUEST 3051 213 #define ERROR_HTTP_DVR_REQUEST 3051
  214 +#define ERROR_HTTP_JSON_REQUIRED 3052
  215 +#define ERROR_HTTP_DVR_CREATE_REQUEST 3053
214 216
215 /////////////////////////////////////////////////////// 217 ///////////////////////////////////////////////////////
216 // HTTP/StreamCaster protocol error. 218 // HTTP/StreamCaster protocol error.