winlin

for #179, refine dvr, support callback when reap dvr segment.

@@ -297,7 +297,8 @@ vhost dvr.srs.com { @@ -297,7 +297,8 @@ vhost dvr.srs.com {
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: [{path_tmpl:"./[15].[04].[05].[999].flv", path_dvr:"./22.7.43.312.flv", 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" 300 + # wait_keyframe:true, vhost:"__defaultVhost", callback:"http://127.0.0.1:8085/api/v1/dvrs",
  301 + # status:"stop"|"start"
301 # }]} 302 # }]}
302 # method=POST 303 # method=POST
303 # to start dvr of specified vhost. 304 # to start dvr of specified vhost.
@@ -313,6 +314,8 @@ vhost dvr.srs.com { @@ -313,6 +314,8 @@ vhost dvr.srs.com {
313 # vhost, stop all dvr of this vhost. 314 # vhost, stop all dvr of this vhost.
314 # response in json, where: 315 # response in json, where:
315 # {code:0} 316 # {code:0}
  317 + # when reap segment, the callback POST request in json:
  318 + # {action:"on_dvr_reap_segment"}
316 # default: session 319 # default: session
317 dvr_plan session; 320 dvr_plan session;
318 # the dvr output path. 321 # the dvr output path.
@@ -253,7 +253,7 @@ class RESTDvrs(object): @@ -253,7 +253,7 @@ class RESTDvrs(object):
253 return json.dumps(dvrs) 253 return json.dumps(dvrs)
254 254
255 ''' 255 '''
256 - for SRS hook: on_dvr 256 + for SRS hook: on_dvr, on_dvr_reap_segment
257 on_dvr: 257 on_dvr:
258 when srs reap a dvr file, call the hook, 258 when srs reap a dvr file, call the hook,
259 the request in the POST data string is a object encode by json: 259 the request in the POST data string is a object encode by json:
@@ -265,6 +265,17 @@ class RESTDvrs(object): @@ -265,6 +265,17 @@ class RESTDvrs(object):
265 "cwd": "/usr/local/srs", 265 "cwd": "/usr/local/srs",
266 "file": "./objs/nginx/html/live/livestream.1420254068776.flv" 266 "file": "./objs/nginx/html/live/livestream.1420254068776.flv"
267 } 267 }
  268 + on_dvr_reap_segment:
  269 + when api dvr specifes the callback when reap flv segment, call the hook,
  270 + the request in the POST data string is a object encode by json:
  271 + {
  272 + "action": "on_dvr_reap_segment",
  273 + "client_id": 1985,
  274 + "vhost": "video.test.com", "app": "live",
  275 + "stream": "livestream",
  276 + "cwd": "/usr/local/srs",
  277 + "file": "./objs/nginx/html/live/livestream.1420254068776.flv"
  278 + }
268 if valid, the hook must return HTTP code 200(Stauts OK) and response 279 if valid, the hook must return HTTP code 200(Stauts OK) and response
269 an int value specifies the error code(0 corresponding to success): 280 an int value specifies the error code(0 corresponding to success):
270 0 281 0
@@ -287,6 +298,8 @@ class RESTDvrs(object): @@ -287,6 +298,8 @@ class RESTDvrs(object):
287 action = json_req["action"] 298 action = json_req["action"]
288 if action == "on_dvr": 299 if action == "on_dvr":
289 code = self.__on_dvr(json_req) 300 code = self.__on_dvr(json_req)
  301 + if action == "on_dvr_reap_segment":
  302 + code = self.__on_dvr_reap_segment(json_req)
290 else: 303 else:
291 trace("invalid request action: %s"%(json_req["action"])) 304 trace("invalid request action: %s"%(json_req["action"]))
292 code = Error.request_invalid_action 305 code = Error.request_invalid_action
@@ -308,6 +321,18 @@ class RESTDvrs(object): @@ -308,6 +321,18 @@ class RESTDvrs(object):
308 321
309 return code 322 return code
310 323
  324 + def __on_dvr_reap_segment(self, req):
  325 + code = Error.success
  326 +
  327 + trace("srs %s: client id=%s, vhost=%s, app=%s, stream=%s, cwd=%s, file=%s"%(
  328 + req["action"], req["client_id"], req["vhost"], req["app"], req["stream"],
  329 + req["cwd"], req["file"]
  330 + ))
  331 +
  332 + # TODO: process the on_dvr event
  333 +
  334 + return code
  335 +
311 ''' 336 '''
312 handle the sessions requests: client play/stop stream 337 handle the sessions requests: client play/stop stream
313 ''' 338 '''
@@ -3342,6 +3342,13 @@ bool SrsConfig::get_dvr_enabled(string vhost) @@ -3342,6 +3342,13 @@ bool SrsConfig::get_dvr_enabled(string vhost)
3342 return false; 3342 return false;
3343 } 3343 }
3344 3344
  3345 +void SrsConfig::set_dvr_enabled(string vhost, bool enabled)
  3346 +{
  3347 + SrsConfDirective* conf = create_directive(vhost, "dvr", "enabled");
  3348 + conf->args.clear();
  3349 + conf->args.push_back(enabled? "on":"off");
  3350 +}
  3351 +
3345 string SrsConfig::get_dvr_path(string vhost) 3352 string SrsConfig::get_dvr_path(string vhost)
3346 { 3353 {
3347 SrsConfDirective* dvr = get_dvr(vhost); 3354 SrsConfDirective* dvr = get_dvr(vhost);
@@ -923,6 +923,7 @@ public: @@ -923,6 +923,7 @@ public:
923 * whether dvr is enabled. 923 * whether dvr is enabled.
924 */ 924 */
925 virtual bool get_dvr_enabled(std::string vhost); 925 virtual bool get_dvr_enabled(std::string vhost);
  926 + virtual void set_dvr_enabled(std::string vhost, bool enabled);
926 /** 927 /**
927 * get the dvr path, the flv file to save in. 928 * get the dvr path, the flv file to save in.
928 */ 929 */
@@ -144,15 +144,15 @@ int SrsFlvSegment::open(bool use_tmp_file) @@ -144,15 +144,15 @@ int SrsFlvSegment::open(bool use_tmp_file)
144 return ret; 144 return ret;
145 } 145 }
146 } 146 }
  147 +
  148 + // initialize the encoder.
  149 + if ((ret = enc->initialize(fs)) != ERROR_SUCCESS) {
  150 + srs_error("initialize enc by fs for file %s failed. ret=%d", path.c_str(), ret);
  151 + return ret;
  152 + }
147 153
148 // when exists, donot write flv header. 154 // when exists, donot write flv header.
149 if (fresh_flv_file) { 155 if (fresh_flv_file) {
150 - // initialize the encoder.  
151 - if ((ret = enc->initialize(fs)) != ERROR_SUCCESS) {  
152 - srs_error("initialize enc by fs for file %s failed. ret=%d", path.c_str(), ret);  
153 - return ret;  
154 - }  
155 -  
156 // write the flv header to writer. 156 // write the flv header to writer.
157 if ((ret = enc->write_header()) != ERROR_SUCCESS) { 157 if ((ret = enc->write_header()) != ERROR_SUCCESS) {
158 srs_error("write flv header failed. ret=%d", ret); 158 srs_error("write flv header failed. ret=%d", ret);
@@ -195,6 +195,8 @@ int SrsFlvSegment::close() @@ -195,6 +195,8 @@ int SrsFlvSegment::close()
195 } 195 }
196 } 196 }
197 197
  198 + // TODO: FIXME: the http callback is async, which will trigger thread switch,
  199 + // so the on_video maybe invoked during the http callback, and error.
198 if ((ret = plan->on_reap_segment()) != ERROR_SUCCESS) { 200 if ((ret = plan->on_reap_segment()) != ERROR_SUCCESS) {
199 srs_error("dvr: notify plan to reap segment failed. ret=%d", ret); 201 srs_error("dvr: notify plan to reap segment failed. ret=%d", ret);
200 return ret; 202 return ret;
@@ -743,10 +745,15 @@ SrsDvrApiPlan::SrsDvrApiPlan() @@ -743,10 +745,15 @@ SrsDvrApiPlan::SrsDvrApiPlan()
743 { 745 {
744 autostart = false; 746 autostart = false;
745 started = false; 747 started = false;
  748 +
  749 + metadata = sh_audio = sh_video = NULL;
746 } 750 }
747 751
748 SrsDvrApiPlan::~SrsDvrApiPlan() 752 SrsDvrApiPlan::~SrsDvrApiPlan()
749 { 753 {
  754 + srs_freep(metadata);
  755 + srs_freep(sh_audio);
  756 + srs_freep(sh_video);
750 } 757 }
751 758
752 int SrsDvrApiPlan::initialize(SrsSource* s, SrsRequest* r) 759 int SrsDvrApiPlan::initialize(SrsSource* s, SrsRequest* r)
@@ -787,6 +794,8 @@ int SrsDvrApiPlan::on_publish() @@ -787,6 +794,8 @@ int SrsDvrApiPlan::on_publish()
787 return ret; 794 return ret;
788 } 795 }
789 796
  797 + dvr_enabled = true;
  798 +
790 if ((ret = segment->close()) != ERROR_SUCCESS) { 799 if ((ret = segment->close()) != ERROR_SUCCESS) {
791 return ret; 800 return ret;
792 } 801 }
@@ -794,8 +803,17 @@ int SrsDvrApiPlan::on_publish() @@ -794,8 +803,17 @@ int SrsDvrApiPlan::on_publish()
794 if ((ret = segment->open()) != ERROR_SUCCESS) { 803 if ((ret = segment->open()) != ERROR_SUCCESS) {
795 return ret; 804 return ret;
796 } 805 }
797 -  
798 - dvr_enabled = true; 806 +
  807 + // update sequence header
  808 + if (metadata && (ret = SrsDvrPlan::on_meta_data(metadata)) != ERROR_SUCCESS) {
  809 + return ret;
  810 + }
  811 + if (sh_video && (ret = SrsDvrPlan::on_video(sh_video)) != ERROR_SUCCESS) {
  812 + return ret;
  813 + }
  814 + if (sh_audio && (ret = SrsDvrPlan::on_audio(sh_audio)) != ERROR_SUCCESS) {
  815 + return ret;
  816 + }
799 817
800 return ret; 818 return ret;
801 } 819 }
@@ -804,6 +822,48 @@ void SrsDvrApiPlan::on_unpublish() @@ -804,6 +822,48 @@ void SrsDvrApiPlan::on_unpublish()
804 { 822 {
805 } 823 }
806 824
  825 +int SrsDvrApiPlan::on_meta_data(SrsSharedPtrMessage* __metadata)
  826 +{
  827 + int ret = ERROR_SUCCESS;
  828 +
  829 + srs_freep(metadata);
  830 + metadata = __metadata->copy();
  831 +
  832 + return ret;
  833 +}
  834 +
  835 +int SrsDvrApiPlan::on_audio(SrsSharedPtrMessage* __audio)
  836 +{
  837 + int ret = ERROR_SUCCESS;
  838 +
  839 + if (SrsFlvCodec::audio_is_sequence_header(__audio->payload, __audio->size)) {
  840 + srs_freep(sh_audio);
  841 + sh_audio = __audio->copy();
  842 + }
  843 +
  844 + if ((ret = SrsDvrPlan::on_audio(__audio)) != ERROR_SUCCESS) {
  845 + return ret;
  846 + }
  847 +
  848 + return ret;
  849 +}
  850 +
  851 +int SrsDvrApiPlan::on_video(SrsSharedPtrMessage* __video)
  852 +{
  853 + int ret = ERROR_SUCCESS;
  854 +
  855 + if (SrsFlvCodec::video_is_sequence_header(__video->payload, __video->size)) {
  856 + srs_freep(sh_video);
  857 + sh_video = __video->copy();
  858 + }
  859 +
  860 + if ((ret = SrsDvrPlan::on_video(__video)) != ERROR_SUCCESS) {
  861 + return ret;
  862 + }
  863 +
  864 + return ret;
  865 +}
  866 +
807 int SrsDvrApiPlan::set_path_tmpl(string path_tmpl) 867 int SrsDvrApiPlan::set_path_tmpl(string path_tmpl)
808 { 868 {
809 _srs_config->set_dvr_path(req->vhost, path_tmpl); 869 _srs_config->set_dvr_path(req->vhost, path_tmpl);
@@ -830,6 +890,9 @@ int SrsDvrApiPlan::start() @@ -830,6 +890,9 @@ int SrsDvrApiPlan::start()
830 return ret; 890 return ret;
831 } 891 }
832 892
  893 + // enable the config.
  894 + _srs_config->set_dvr_enabled(req->vhost, true);
  895 +
833 // stop dvr 896 // stop dvr
834 if (dvr_enabled) { 897 if (dvr_enabled) {
835 // ignore error. 898 // ignore error.
@@ -862,16 +925,58 @@ int SrsDvrApiPlan::dumps(stringstream& ss) @@ -862,16 +925,58 @@ int SrsDvrApiPlan::dumps(stringstream& ss)
862 << __SRS_JFIELD_STR("path_dvr", segment->get_path()) << __SRS_JFIELD_CONT 925 << __SRS_JFIELD_STR("path_dvr", segment->get_path()) << __SRS_JFIELD_CONT
863 << __SRS_JFIELD_BOOL("wait_keyframe", wait_keyframe) << __SRS_JFIELD_CONT 926 << __SRS_JFIELD_BOOL("wait_keyframe", wait_keyframe) << __SRS_JFIELD_CONT
864 << __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT 927 << __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT
865 - << __SRS_JFIELD_STR("callback", callback) 928 + << __SRS_JFIELD_STR("callback", callback) << __SRS_JFIELD_CONT
  929 + << __SRS_JFIELD_STR("status", (dvr_enabled? "start":"stop"))
866 << __SRS_JOBJECT_END; 930 << __SRS_JOBJECT_END;
867 931
868 return ret; 932 return ret;
869 } 933 }
870 934
  935 +int SrsDvrApiPlan::stop()
  936 +{
  937 + int ret = ERROR_SUCCESS;
  938 +
  939 + _srs_config->set_dvr_enabled(req->vhost, false);
  940 + started = false;
  941 +
  942 + // stop dvr
  943 + if (dvr_enabled) {
  944 + // ignore error.
  945 + int ret = segment->close();
  946 + if (ret != ERROR_SUCCESS) {
  947 + srs_warn("ignore flv close error. ret=%d", ret);
  948 + }
  949 +
  950 + dvr_enabled = false;
  951 + }
  952 +
  953 + srs_trace("dvr: stop dvr of vhost=%s", req->vhost.c_str());
  954 +
  955 + return ret;
  956 +}
  957 +
871 int SrsDvrApiPlan::on_reap_segment() 958 int SrsDvrApiPlan::on_reap_segment()
872 { 959 {
873 - // TODO: FIXME: implements it.  
874 - return ERROR_SUCCESS; 960 + int ret = ERROR_SUCCESS;
  961 +
  962 +#ifdef SRS_AUTO_HTTP_CALLBACK
  963 + // HTTP: callback
  964 + if (callback.empty()) {
  965 + srs_warn("dvr: ignore for callback empty, vhost=%s", req->vhost.c_str());
  966 + return ret;
  967 + }
  968 +
  969 + int connection_id = _srs_context->get_id();
  970 + std::string cwd = _srs_config->cwd();
  971 + std::string file = segment->get_path();
  972 + std::string url = callback;
  973 + if ((ret = SrsHttpHooks::on_dvr_reap_segment(url, connection_id, req, cwd, file)) != ERROR_SUCCESS) {
  974 + srs_error("hook client on_dvr_reap_segment failed. url=%s, ret=%d", url.c_str(), ret);
  975 + return ret;
  976 + }
  977 +#endif
  978 +
  979 + return ret;
875 } 980 }
876 981
877 SrsDvrAppendPlan::SrsDvrAppendPlan() 982 SrsDvrAppendPlan::SrsDvrAppendPlan()
@@ -909,30 +1014,30 @@ void SrsDvrAppendPlan::on_unpublish() @@ -909,30 +1014,30 @@ void SrsDvrAppendPlan::on_unpublish()
909 { 1014 {
910 } 1015 }
911 1016
912 -int SrsDvrAppendPlan::on_audio(SrsSharedPtrMessage* audio) 1017 +int SrsDvrAppendPlan::on_audio(SrsSharedPtrMessage* __audio)
913 { 1018 {
914 int ret = ERROR_SUCCESS; 1019 int ret = ERROR_SUCCESS;
915 1020
916 - if ((ret = update_duration(audio)) != ERROR_SUCCESS) { 1021 + if ((ret = update_duration(__audio)) != ERROR_SUCCESS) {
917 return ret; 1022 return ret;
918 } 1023 }
919 1024
920 - if ((ret = SrsDvrPlan::on_audio(audio)) != ERROR_SUCCESS) { 1025 + if ((ret = SrsDvrPlan::on_audio(__audio)) != ERROR_SUCCESS) {
921 return ret; 1026 return ret;
922 } 1027 }
923 1028
924 return ret; 1029 return ret;
925 } 1030 }
926 1031
927 -int SrsDvrAppendPlan::on_video(SrsSharedPtrMessage* video) 1032 +int SrsDvrAppendPlan::on_video(SrsSharedPtrMessage* __video)
928 { 1033 {
929 int ret = ERROR_SUCCESS; 1034 int ret = ERROR_SUCCESS;
930 1035
931 - if ((ret = update_duration(video)) != ERROR_SUCCESS) { 1036 + if ((ret = update_duration(__video)) != ERROR_SUCCESS) {
932 return ret; 1037 return ret;
933 } 1038 }
934 1039
935 - if ((ret = SrsDvrPlan::on_video(video)) != ERROR_SUCCESS) { 1040 + if ((ret = SrsDvrPlan::on_video(__video)) != ERROR_SUCCESS) {
936 return ret; 1041 return ret;
937 } 1042 }
938 1043
@@ -1038,40 +1143,40 @@ int SrsDvrSegmentPlan::on_meta_data(SrsSharedPtrMessage* __metadata) @@ -1038,40 +1143,40 @@ int SrsDvrSegmentPlan::on_meta_data(SrsSharedPtrMessage* __metadata)
1038 return ret; 1143 return ret;
1039 } 1144 }
1040 1145
1041 -int SrsDvrSegmentPlan::on_audio(SrsSharedPtrMessage* audio) 1146 +int SrsDvrSegmentPlan::on_audio(SrsSharedPtrMessage* __audio)
1042 { 1147 {
1043 int ret = ERROR_SUCCESS; 1148 int ret = ERROR_SUCCESS;
1044 1149
1045 - if (SrsFlvCodec::audio_is_sequence_header(audio->payload, audio->size)) { 1150 + if (SrsFlvCodec::audio_is_sequence_header(__audio->payload, __audio->size)) {
1046 srs_freep(sh_audio); 1151 srs_freep(sh_audio);
1047 - sh_audio = audio->copy(); 1152 + sh_audio = __audio->copy();
1048 } 1153 }
1049 1154
1050 - if ((ret = update_duration(audio)) != ERROR_SUCCESS) { 1155 + if ((ret = update_duration(__audio)) != ERROR_SUCCESS) {
1051 return ret; 1156 return ret;
1052 } 1157 }
1053 1158
1054 - if ((ret = SrsDvrPlan::on_audio(audio)) != ERROR_SUCCESS) { 1159 + if ((ret = SrsDvrPlan::on_audio(__audio)) != ERROR_SUCCESS) {
1055 return ret; 1160 return ret;
1056 } 1161 }
1057 1162
1058 return ret; 1163 return ret;
1059 } 1164 }
1060 1165
1061 -int SrsDvrSegmentPlan::on_video(SrsSharedPtrMessage* video) 1166 +int SrsDvrSegmentPlan::on_video(SrsSharedPtrMessage* __video)
1062 { 1167 {
1063 int ret = ERROR_SUCCESS; 1168 int ret = ERROR_SUCCESS;
1064 1169
1065 - if (SrsFlvCodec::video_is_sequence_header(video->payload, video->size)) { 1170 + if (SrsFlvCodec::video_is_sequence_header(__video->payload, __video->size)) {
1066 srs_freep(sh_video); 1171 srs_freep(sh_video);
1067 - sh_video = video->copy(); 1172 + sh_video = __video->copy();
1068 } 1173 }
1069 1174
1070 - if ((ret = update_duration(video)) != ERROR_SUCCESS) { 1175 + if ((ret = update_duration(__video)) != ERROR_SUCCESS) {
1071 return ret; 1176 return ret;
1072 } 1177 }
1073 1178
1074 - if ((ret = SrsDvrPlan::on_video(video)) != ERROR_SUCCESS) { 1179 + if ((ret = SrsDvrPlan::on_video(__video)) != ERROR_SUCCESS) {
1075 return ret; 1180 return ret;
1076 } 1181 }
1077 1182
@@ -1240,6 +1345,30 @@ int SrsApiDvrPool::create(SrsJsonAny* json) @@ -1240,6 +1345,30 @@ int SrsApiDvrPool::create(SrsJsonAny* json)
1240 return dvr->start(); 1345 return dvr->start();
1241 } 1346 }
1242 1347
  1348 +int SrsApiDvrPool::stop(string vhost)
  1349 +{
  1350 + int ret = ERROR_SUCCESS;
  1351 +
  1352 + std::vector<SrsDvrApiPlan*> plans;
  1353 + for (int i = 0; i < (int)dvrs.size(); i++) {
  1354 + SrsDvrApiPlan* plan = dvrs.at(i);
  1355 + if (!vhost.empty() && plan->req->vhost != vhost) {
  1356 + continue;
  1357 + }
  1358 + plans.push_back(plan);
  1359 + }
  1360 +
  1361 + for (int i = 0; i < (int)plans.size(); i++) {
  1362 + SrsDvrApiPlan* plan = plans.at(i);
  1363 +
  1364 + if ((ret = plan->stop()) != ERROR_SUCCESS) {
  1365 + return ret;
  1366 + }
  1367 + }
  1368 +
  1369 + return ret;
  1370 +}
  1371 +
1243 SrsDvr::SrsDvr(SrsSource* s) 1372 SrsDvr::SrsDvr(SrsSource* s)
1244 { 1373 {
1245 source = s; 1374 source = s;
@@ -237,6 +237,11 @@ public: @@ -237,6 +237,11 @@ public:
237 class SrsDvrApiPlan : public SrsDvrPlan 237 class SrsDvrApiPlan : public SrsDvrPlan
238 { 238 {
239 private: 239 private:
  240 + // cache the metadata and sequence header, for new segment maybe opened.
  241 + SrsSharedPtrMessage* sh_audio;
  242 + SrsSharedPtrMessage* sh_video;
  243 + SrsSharedPtrMessage* metadata;
  244 +private:
240 std::string callback; 245 std::string callback;
241 bool autostart; 246 bool autostart;
242 bool started; 247 bool started;
@@ -247,12 +252,16 @@ public: @@ -247,12 +252,16 @@ public:
247 virtual int initialize(SrsSource* s, SrsRequest* r); 252 virtual int initialize(SrsSource* s, SrsRequest* r);
248 virtual int on_publish(); 253 virtual int on_publish();
249 virtual void on_unpublish(); 254 virtual void on_unpublish();
  255 + virtual int on_meta_data(SrsSharedPtrMessage* __metadata);
  256 + virtual int on_audio(SrsSharedPtrMessage* __audio);
  257 + virtual int on_video(SrsSharedPtrMessage* __video);
250 public: 258 public:
251 virtual int set_path_tmpl(std::string path_tmpl); 259 virtual int set_path_tmpl(std::string path_tmpl);
252 virtual int set_callback(std::string value); 260 virtual int set_callback(std::string value);
253 virtual int set_wait_keyframe(bool wait_keyframe); 261 virtual int set_wait_keyframe(bool wait_keyframe);
254 virtual int start(); 262 virtual int start();
255 virtual int dumps(std::stringstream& ss); 263 virtual int dumps(std::stringstream& ss);
  264 + virtual int stop();
256 protected: 265 protected:
257 virtual int on_reap_segment(); 266 virtual int on_reap_segment();
258 }; 267 };
@@ -270,14 +279,8 @@ public: @@ -270,14 +279,8 @@ public:
270 public: 279 public:
271 virtual int on_publish(); 280 virtual int on_publish();
272 virtual void on_unpublish(); 281 virtual void on_unpublish();
273 - /**  
274 - * @param audio, directly ptr, copy it if need to save it.  
275 - */  
276 - virtual int on_audio(SrsSharedPtrMessage* audio);  
277 - /**  
278 - * @param video, directly ptr, copy it if need to save it.  
279 - */  
280 - virtual int on_video(SrsSharedPtrMessage* video); 282 + virtual int on_audio(SrsSharedPtrMessage* __audio);
  283 + virtual int on_video(SrsSharedPtrMessage* __video);
281 private: 284 private:
282 virtual int update_duration(SrsSharedPtrMessage* msg); 285 virtual int update_duration(SrsSharedPtrMessage* msg);
283 }; 286 };
@@ -300,18 +303,9 @@ public: @@ -300,18 +303,9 @@ public:
300 virtual int initialize(SrsSource* source, SrsRequest* req); 303 virtual int initialize(SrsSource* source, SrsRequest* req);
301 virtual int on_publish(); 304 virtual int on_publish();
302 virtual void on_unpublish(); 305 virtual void on_unpublish();
303 - /**  
304 - * when got metadata.  
305 - */  
306 virtual int on_meta_data(SrsSharedPtrMessage* __metadata); 306 virtual int on_meta_data(SrsSharedPtrMessage* __metadata);
307 - /**  
308 - * @param audio, directly ptr, copy it if need to save it.  
309 - */  
310 - virtual int on_audio(SrsSharedPtrMessage* audio);  
311 - /**  
312 - * @param video, directly ptr, copy it if need to save it.  
313 - */  
314 - virtual int on_video(SrsSharedPtrMessage* video); 307 + virtual int on_audio(SrsSharedPtrMessage* __audio);
  308 + virtual int on_video(SrsSharedPtrMessage* __video);
315 private: 309 private:
316 virtual int update_duration(SrsSharedPtrMessage* msg); 310 virtual int update_duration(SrsSharedPtrMessage* msg);
317 }; 311 };
@@ -334,6 +328,7 @@ public: @@ -334,6 +328,7 @@ public:
334 public: 328 public:
335 virtual int dumps(std::string vhost, std::stringstream& ss); 329 virtual int dumps(std::string vhost, std::stringstream& ss);
336 virtual int create(SrsJsonAny* json); 330 virtual int create(SrsJsonAny* json);
  331 + virtual int stop(std::string vhost);
337 }; 332 };
338 333
339 /** 334 /**
@@ -501,8 +501,8 @@ int SrsGoApiDvrs::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r) @@ -501,8 +501,8 @@ int SrsGoApiDvrs::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r)
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()) { 503 } else if (r->is_http_post()) {
504 - char* body = (char*)r->body().c_str();  
505 - SrsJsonAny* json = SrsJsonAny::loads(body); 504 + std::string body = r->body();
  505 + SrsJsonAny* json = SrsJsonAny::loads((char*)body.c_str());
506 int ret = ERROR_SUCCESS; 506 int ret = ERROR_SUCCESS;
507 if (!json) { 507 if (!json) {
508 ret = ERROR_HTTP_JSON_REQUIRED; 508 ret = ERROR_HTTP_JSON_REQUIRED;
@@ -513,6 +513,12 @@ int SrsGoApiDvrs::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r) @@ -513,6 +513,12 @@ int SrsGoApiDvrs::serve_http(ISrsGoHttpResponseWriter* w, SrsHttpMessage* r)
513 ss << __SRS_JOBJECT_START 513 ss << __SRS_JOBJECT_START
514 << __SRS_JFIELD_ERROR(ret) 514 << __SRS_JFIELD_ERROR(ret)
515 << __SRS_JOBJECT_END; 515 << __SRS_JOBJECT_END;
  516 + } else if (r->is_http_delete()) {
  517 + int ret = pool->stop(r->query_get("vhost"));
  518 +
  519 + ss << __SRS_JOBJECT_START
  520 + << __SRS_JFIELD_ERROR(ret)
  521 + << __SRS_JOBJECT_END;
516 } else { 522 } else {
517 ss << __SRS_JOBJECT_START 523 ss << __SRS_JOBJECT_START
518 << __SRS_JFIELD_ERROR(ERROR_HTTP_DVR_REQUEST) 524 << __SRS_JFIELD_ERROR(ERROR_HTTP_DVR_REQUEST)
@@ -436,4 +436,60 @@ int SrsHttpHooks::on_dvr(string url, int client_id, string ip, SrsRequest* req, @@ -436,4 +436,60 @@ int SrsHttpHooks::on_dvr(string url, int client_id, string ip, SrsRequest* req,
436 return ret; 436 return ret;
437 } 437 }
438 438
  439 +int SrsHttpHooks::on_dvr_reap_segment(string url, int client_id, SrsRequest* req, string cwd, string file)
  440 +{
  441 + int ret = ERROR_SUCCESS;
  442 +
  443 + SrsHttpUri uri;
  444 + if ((ret = uri.initialize(url)) != ERROR_SUCCESS) {
  445 + srs_error("http uri parse on_dvr_reap_segment url failed, ignored. "
  446 + "client_id=%d, url=%s, ret=%d", client_id, url.c_str(), ret);
  447 + return ret;
  448 + }
  449 +
  450 + std::stringstream ss;
  451 + ss << __SRS_JOBJECT_START
  452 + << __SRS_JFIELD_STR("action", "on_dvr_reap_segment") << __SRS_JFIELD_CONT
  453 + << __SRS_JFIELD_ORG("client_id", client_id) << __SRS_JFIELD_CONT
  454 + << __SRS_JFIELD_STR("vhost", req->vhost) << __SRS_JFIELD_CONT
  455 + << __SRS_JFIELD_STR("app", req->app) << __SRS_JFIELD_CONT
  456 + << __SRS_JFIELD_STR("stream", req->stream) << __SRS_JFIELD_CONT
  457 + << __SRS_JFIELD_STR("cwd", cwd) << __SRS_JFIELD_CONT
  458 + << __SRS_JFIELD_STR("file", file)
  459 + << __SRS_JOBJECT_END;
  460 + std::string data = ss.str();
  461 + std::string res;
  462 + int status_code;
  463 +
  464 + SrsHttpClient http;
  465 + if ((ret = http.post(&uri, data, status_code, res)) != ERROR_SUCCESS) {
  466 + srs_error("http post on_dvr_reap_segment uri failed, ignored. "
  467 + "client_id=%d, url=%s, request=%s, response=%s, ret=%d",
  468 + client_id, url.c_str(), data.c_str(), res.c_str(), ret);
  469 + return ret;
  470 + }
  471 +
  472 + // ensure the http status is ok.
  473 + // https://github.com/winlinvip/simple-rtmp-server/issues/158
  474 + if (status_code != SRS_CONSTS_HTTP_OK) {
  475 + ret = ERROR_HTTP_STATUS_INVLIAD;
  476 + srs_error("http hook on_dvr_reap_segment status failed. "
  477 + "client_id=%d, code=%d, ret=%d", client_id, status_code, ret);
  478 + return ret;
  479 + }
  480 +
  481 + if (res.empty() || res != SRS_HTTP_RESPONSE_OK) {
  482 + ret = ERROR_HTTP_DATA_INVLIAD;
  483 + srs_warn("http hook on_dvr_reap_segment validate failed, ignored. "
  484 + "client_id=%d, res=%s, ret=%d", client_id, res.c_str(), ret);
  485 + return ret;
  486 + }
  487 +
  488 + srs_trace("http hook on_dvr_reap_segment success. "
  489 + "client_id=%d, url=%s, request=%s, response=%s, ret=%d",
  490 + client_id, url.c_str(), data.c_str(), res.c_str(), ret);
  491 +
  492 + return ret;
  493 +}
  494 +
439 #endif 495 #endif
@@ -104,6 +104,15 @@ public: @@ -104,6 +104,15 @@ public:
104 * @param file the file path, can be relative or absolute path. 104 * @param file the file path, can be relative or absolute path.
105 */ 105 */
106 static int on_dvr(std::string url, int client_id, std::string ip, SrsRequest* req, std::string cwd, std::string file); 106 static int on_dvr(std::string url, int client_id, std::string ip, SrsRequest* req, std::string cwd, std::string file);
  107 + /**
  108 + * when dvr reap segment, callback.
  109 + * @param client_id the id of client on server.
  110 + * @param url the api server url, to process the event.
  111 + * ignore if empty.
  112 + * @param cwd the current work directory, used to resolve the reltive file path.
  113 + * @param file the file path, can be relative or absolute path.
  114 + */
  115 + static int on_dvr_reap_segment(std::string url, int client_id, SrsRequest* req, std::string cwd, std::string file);
107 }; 116 };
108 117
109 #endif 118 #endif