winlin

support on_hls for http hooks. 2.0.152.

@@ -562,6 +562,7 @@ Supported operating systems and hardware: @@ -562,6 +562,7 @@ Supported operating systems and hardware:
562 562
563 ### SRS 2.0 history 563 ### SRS 2.0 history
564 564
  565 +* v2.0, 2015-03-31, support on_hls for http hooks. 2.0.152.
565 * v2.0, 2015-03-31, enhanced hls, support deviation for duration. 2.0.151. 566 * v2.0, 2015-03-31, enhanced hls, support deviation for duration. 2.0.151.
566 * v2.0, 2015-03-30, for [#351](https://github.com/winlinvip/simple-rtmp-server/issues/351), support config the m3u8/ts path for hls. 2.0.149. 567 * v2.0, 2015-03-30, for [#351](https://github.com/winlinvip/simple-rtmp-server/issues/351), support config the m3u8/ts path for hls. 2.0.149.
567 * v2.0, 2015-03-17, for [#155](https://github.com/winlinvip/simple-rtmp-server/issues/155), osx(darwin) support demo with nginx and ffmpeg. 2.0.143. 568 * v2.0, 2015-03-17, for [#155](https://github.com/winlinvip/simple-rtmp-server/issues/155), osx(darwin) support demo with nginx and ffmpeg. 2.0.143.
@@ -174,7 +174,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then @@ -174,7 +174,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then
174 "srs_app_json" "srs_app_ingest" "srs_app_ffmpeg" "srs_app_utility" "srs_app_dvr" "srs_app_edge" 174 "srs_app_json" "srs_app_ingest" "srs_app_ffmpeg" "srs_app_utility" "srs_app_dvr" "srs_app_edge"
175 "srs_app_kbps" "srs_app_heartbeat" "srs_app_empty" "srs_app_http_client" 175 "srs_app_kbps" "srs_app_heartbeat" "srs_app_empty" "srs_app_http_client"
176 "srs_app_recv_thread" "srs_app_security" "srs_app_statistic" "srs_app_hds" 176 "srs_app_recv_thread" "srs_app_security" "srs_app_statistic" "srs_app_hds"
177 - "srs_app_mpegts_udp" "srs_app_rtsp" "srs_app_listener") 177 + "srs_app_mpegts_udp" "srs_app_rtsp" "srs_app_listener" "srs_app_async_call")
178 DEFINES="" 178 DEFINES=""
179 # add each modules for app 179 # add each modules for app
180 for SRS_MODULE in $SRS_MODULES; do 180 for SRS_MODULE in $SRS_MODULES; do
@@ -97,6 +97,7 @@ @@ -97,6 +97,7 @@
97 3C689F9F1AB6AAC800C9CEEE /* sched.c in Sources */ = {isa = PBXBuildFile; fileRef = 3C689F9B1AB6AAC800C9CEEE /* sched.c */; }; 97 3C689F9F1AB6AAC800C9CEEE /* sched.c in Sources */ = {isa = PBXBuildFile; fileRef = 3C689F9B1AB6AAC800C9CEEE /* sched.c */; };
98 3C689FA01AB6AAC800C9CEEE /* stk.c in Sources */ = {isa = PBXBuildFile; fileRef = 3C689F9C1AB6AAC800C9CEEE /* stk.c */; }; 98 3C689FA01AB6AAC800C9CEEE /* stk.c in Sources */ = {isa = PBXBuildFile; fileRef = 3C689F9C1AB6AAC800C9CEEE /* stk.c */; };
99 3C689FA11AB6AAC800C9CEEE /* sync.c in Sources */ = {isa = PBXBuildFile; fileRef = 3C689F9D1AB6AAC800C9CEEE /* sync.c */; }; 99 3C689FA11AB6AAC800C9CEEE /* sync.c in Sources */ = {isa = PBXBuildFile; fileRef = 3C689F9D1AB6AAC800C9CEEE /* sync.c */; };
  100 + 3CD88B3F1ACA9C58000359E0 /* srs_app_async_call.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3CD88B3D1ACA9C58000359E0 /* srs_app_async_call.cpp */; };
100 /* End PBXBuildFile section */ 101 /* End PBXBuildFile section */
101 102
102 /* Begin PBXCopyFilesBuildPhase section */ 103 /* Begin PBXCopyFilesBuildPhase section */
@@ -337,6 +338,8 @@ @@ -337,6 +338,8 @@
337 3C689F9B1AB6AAC800C9CEEE /* sched.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sched.c; path = "../../objs/st-1.9/sched.c"; sourceTree = "<group>"; }; 338 3C689F9B1AB6AAC800C9CEEE /* sched.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sched.c; path = "../../objs/st-1.9/sched.c"; sourceTree = "<group>"; };
338 3C689F9C1AB6AAC800C9CEEE /* stk.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = stk.c; path = "../../objs/st-1.9/stk.c"; sourceTree = "<group>"; }; 339 3C689F9C1AB6AAC800C9CEEE /* stk.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = stk.c; path = "../../objs/st-1.9/stk.c"; sourceTree = "<group>"; };
339 3C689F9D1AB6AAC800C9CEEE /* sync.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sync.c; path = "../../objs/st-1.9/sync.c"; sourceTree = "<group>"; }; 340 3C689F9D1AB6AAC800C9CEEE /* sync.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sync.c; path = "../../objs/st-1.9/sync.c"; sourceTree = "<group>"; };
  341 + 3CD88B3D1ACA9C58000359E0 /* srs_app_async_call.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = srs_app_async_call.cpp; path = ../../../src/app/srs_app_async_call.cpp; sourceTree = "<group>"; };
  342 + 3CD88B3E1ACA9C58000359E0 /* srs_app_async_call.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = srs_app_async_call.hpp; path = ../../../src/app/srs_app_async_call.hpp; sourceTree = "<group>"; };
340 /* End PBXFileReference section */ 343 /* End PBXFileReference section */
341 344
342 /* Begin PBXFrameworksBuildPhase section */ 345 /* Begin PBXFrameworksBuildPhase section */
@@ -483,6 +486,8 @@ @@ -483,6 +486,8 @@
483 3C12324B1AAE81CE00CE8F6C /* app */ = { 486 3C12324B1AAE81CE00CE8F6C /* app */ = {
484 isa = PBXGroup; 487 isa = PBXGroup;
485 children = ( 488 children = (
  489 + 3CD88B3D1ACA9C58000359E0 /* srs_app_async_call.cpp */,
  490 + 3CD88B3E1ACA9C58000359E0 /* srs_app_async_call.hpp */,
486 3C12324C1AAE81D900CE8F6C /* srs_app_bandwidth.cpp */, 491 3C12324C1AAE81D900CE8F6C /* srs_app_bandwidth.cpp */,
487 3C12324D1AAE81D900CE8F6C /* srs_app_bandwidth.hpp */, 492 3C12324D1AAE81D900CE8F6C /* srs_app_bandwidth.hpp */,
488 3C12324E1AAE81D900CE8F6C /* srs_app_config.cpp */, 493 3C12324E1AAE81D900CE8F6C /* srs_app_config.cpp */,
@@ -789,6 +794,7 @@ @@ -789,6 +794,7 @@
789 3C1232951AAE81D900CE8F6C /* srs_app_config.cpp in Sources */, 794 3C1232951AAE81D900CE8F6C /* srs_app_config.cpp in Sources */,
790 3C663F0F1AB0155100286D8B /* srs_aac_raw_publish.c in Sources */, 795 3C663F0F1AB0155100286D8B /* srs_aac_raw_publish.c in Sources */,
791 3C689FA01AB6AAC800C9CEEE /* stk.c in Sources */, 796 3C689FA01AB6AAC800C9CEEE /* stk.c in Sources */,
  797 + 3CD88B3F1ACA9C58000359E0 /* srs_app_async_call.cpp in Sources */,
792 3C1232961AAE81D900CE8F6C /* srs_app_conn.cpp in Sources */, 798 3C1232961AAE81D900CE8F6C /* srs_app_conn.cpp in Sources */,
793 3C12322A1AAE814D00CE8F6C /* srs_kernel_ts.cpp in Sources */, 799 3C12322A1AAE814D00CE8F6C /* srs_kernel_ts.cpp in Sources */,
794 3C12329E1AAE81D900CE8F6C /* srs_app_hls.cpp in Sources */, 800 3C12329E1AAE81D900CE8F6C /* srs_app_hls.cpp in Sources */,
@@ -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
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,17 +265,6 @@ class RESTDvrs(object): @@ -265,17 +265,6 @@ 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 - }  
279 if valid, the hook must return HTTP code 200(Stauts OK) and response 268 if valid, the hook must return HTTP code 200(Stauts OK) and response
280 an int value specifies the error code(0 corresponding to success): 269 an int value specifies the error code(0 corresponding to success):
281 0 270 0
@@ -298,8 +287,6 @@ class RESTDvrs(object): @@ -298,8 +287,6 @@ class RESTDvrs(object):
298 action = json_req["action"] 287 action = json_req["action"]
299 if action == "on_dvr": 288 if action == "on_dvr":
300 code = self.__on_dvr(json_req) 289 code = self.__on_dvr(json_req)
301 - if action == "on_dvr_reap_segment":  
302 - code = self.__on_dvr_reap_segment(json_req)  
303 else: 290 else:
304 trace("invalid request action: %s"%(json_req["action"])) 291 trace("invalid request action: %s"%(json_req["action"]))
305 code = Error.request_invalid_action 292 code = Error.request_invalid_action
@@ -321,18 +308,6 @@ class RESTDvrs(object): @@ -321,18 +308,6 @@ class RESTDvrs(object):
321 308
322 return code 309 return code
323 310
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 -  
336 ''' 311 '''
337 handle the hls requests: hls stream. 312 handle the hls requests: hls stream.
338 ''' 313 '''
@@ -346,8 +321,8 @@ class RESTHls(object): @@ -346,8 +321,8 @@ class RESTHls(object):
346 return json.dumps(hls) 321 return json.dumps(hls)
347 322
348 ''' 323 '''
349 - for SRS hook: on, on_dvr_reap_segment  
350 - on_dvr: 324 + for SRS hook: on_hls
  325 + on_hls:
351 when srs reap a dvr file, call the hook, 326 when srs reap a dvr file, call the hook,
352 the request in the POST data string is a object encode by json: 327 the request in the POST data string is a object encode by json:
353 { 328 {
@@ -356,18 +331,8 @@ class RESTHls(object): @@ -356,18 +331,8 @@ class RESTHls(object):
356 "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live", 331 "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",
357 "stream": "livestream", 332 "stream": "livestream",
358 "cwd": "/usr/local/srs", 333 "cwd": "/usr/local/srs",
359 - "file": "./objs/nginx/html/live/livestream.1420254068776.flv"  
360 - }  
361 - on_dvr_reap_segment:  
362 - when api dvr specifes the callback when reap flv segment, call the hook,  
363 - the request in the POST data string is a object encode by json:  
364 - {  
365 - "action": "on_dvr_reap_segment",  
366 - "client_id": 1985,  
367 - "vhost": "video.test.com", "app": "live",  
368 - "stream": "livestream",  
369 - "cwd": "/usr/local/srs",  
370 - "file": "./objs/nginx/html/live/livestream.1420254068776.flv" 334 + "file": "./objs/nginx/html/live/livestream.1420254068776-100.ts",
  335 + "seq_no": 100
371 } 336 }
372 if valid, the hook must return HTTP code 200(Stauts OK) and response 337 if valid, the hook must return HTTP code 200(Stauts OK) and response
373 an int value specifies the error code(0 corresponding to success): 338 an int value specifies the error code(0 corresponding to success):
@@ -380,7 +345,7 @@ class RESTHls(object): @@ -380,7 +345,7 @@ class RESTHls(object):
380 code = Error.success 345 code = Error.success
381 346
382 req = cherrypy.request.body.read() 347 req = cherrypy.request.body.read()
383 - trace("post to dvrs, req=%s"%(req)) 348 + trace("post to hls, req=%s"%(req))
384 try: 349 try:
385 json_req = json.loads(req) 350 json_req = json.loads(req)
386 except Exception, ex: 351 except Exception, ex:
@@ -389,10 +354,8 @@ class RESTHls(object): @@ -389,10 +354,8 @@ class RESTHls(object):
389 return str(code) 354 return str(code)
390 355
391 action = json_req["action"] 356 action = json_req["action"]
392 - if action == "on_dvr":  
393 - code = self.__on_dvr(json_req)  
394 - if action == "on_dvr_reap_segment":  
395 - code = self.__on_dvr_reap_segment(json_req) 357 + if action == "on_hls":
  358 + code = self.__on_hls(json_req)
396 else: 359 else:
397 trace("invalid request action: %s"%(json_req["action"])) 360 trace("invalid request action: %s"%(json_req["action"]))
398 code = Error.request_invalid_action 361 code = Error.request_invalid_action
@@ -402,27 +365,15 @@ class RESTHls(object): @@ -402,27 +365,15 @@ class RESTHls(object):
402 def OPTIONS(self, *args, **kwargs): 365 def OPTIONS(self, *args, **kwargs):
403 enable_crossdomain() 366 enable_crossdomain()
404 367
405 - def __on_dvr(self, req): 368 + def __on_hls(self, req):
406 code = Error.success 369 code = Error.success
407 370
408 - trace("srs %s: client id=%s, ip=%s, vhost=%s, app=%s, stream=%s, cwd=%s, file=%s"%( 371 + trace("srs %s: client id=%s, ip=%s, vhost=%s, app=%s, stream=%s, cwd=%s, file=%s, seq_no=%s"%(
409 req["action"], req["client_id"], req["ip"], req["vhost"], req["app"], req["stream"], 372 req["action"], req["client_id"], req["ip"], req["vhost"], req["app"], req["stream"],
410 - req["cwd"], req["file"] 373 + req["cwd"], req["file"], req["seq_no"]
411 )) 374 ))
412 375
413 - # TODO: process the on_dvr event  
414 -  
415 - return code  
416 -  
417 - def __on_dvr_reap_segment(self, req):  
418 - code = Error.success  
419 -  
420 - trace("srs %s: client id=%s, vhost=%s, app=%s, stream=%s, cwd=%s, file=%s"%(  
421 - req["action"], req["client_id"], req["vhost"], req["app"], req["stream"],  
422 - req["cwd"], req["file"]  
423 - ))  
424 -  
425 - # TODO: process the on_dvr event 376 + # TODO: process the on_hls event
426 377
427 return code 378 return code
428 379
  1 +/*
  2 +The MIT License (MIT)
  3 +
  4 +Copyright (c) 2013-2015 winlin
  5 +
  6 +Permission is hereby granted, free of charge, to any person obtaining a copy of
  7 +this software and associated documentation files (the "Software"), to deal in
  8 +the Software without restriction, including without limitation the rights to
  9 +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  10 +the Software, and to permit persons to whom the Software is furnished to do so,
  11 +subject to the following conditions:
  12 +
  13 +The above copyright notice and this permission notice shall be included in all
  14 +copies or substantial portions of the Software.
  15 +
  16 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  18 +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  19 +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  20 +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21 +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22 +*/
  23 +
  24 +#include <srs_app_async_call.hpp>
  25 +
  26 +using namespace std;
  27 +
  28 +#include <srs_kernel_error.hpp>
  29 +#include <srs_kernel_log.hpp>
  30 +
  31 +// the sleep interval for http async callback.
  32 +#define SRS_AUTO_ASYNC_CALLBACL_SLEEP_US 300000
  33 +
  34 +ISrsDvrAsyncCall::ISrsDvrAsyncCall()
  35 +{
  36 +}
  37 +
  38 +ISrsDvrAsyncCall::~ISrsDvrAsyncCall()
  39 +{
  40 +}
  41 +
  42 +SrsDvrAsyncCallThread::SrsDvrAsyncCallThread()
  43 +{
  44 + pthread = new SrsThread("async", this, SRS_AUTO_ASYNC_CALLBACL_SLEEP_US, true);
  45 +}
  46 +
  47 +SrsDvrAsyncCallThread::~SrsDvrAsyncCallThread()
  48 +{
  49 + stop();
  50 + srs_freep(pthread);
  51 +
  52 + std::vector<ISrsDvrAsyncCall*>::iterator it;
  53 + for (it = callbacks.begin(); it != callbacks.end(); ++it) {
  54 + ISrsDvrAsyncCall* call = *it;
  55 + srs_freep(call);
  56 + }
  57 + callbacks.clear();
  58 +}
  59 +
  60 +int SrsDvrAsyncCallThread::call(ISrsDvrAsyncCall* c)
  61 +{
  62 + int ret = ERROR_SUCCESS;
  63 +
  64 + callbacks.push_back(c);
  65 +
  66 + return ret;
  67 +}
  68 +
  69 +int SrsDvrAsyncCallThread::start()
  70 +{
  71 + return pthread->start();
  72 +}
  73 +
  74 +void SrsDvrAsyncCallThread::stop()
  75 +{
  76 + pthread->stop();
  77 +}
  78 +
  79 +int SrsDvrAsyncCallThread::cycle()
  80 +{
  81 + int ret = ERROR_SUCCESS;
  82 +
  83 + std::vector<ISrsDvrAsyncCall*> copies = callbacks;
  84 + callbacks.clear();
  85 +
  86 + std::vector<ISrsDvrAsyncCall*>::iterator it;
  87 + for (it = copies.begin(); it != copies.end(); ++it) {
  88 + ISrsDvrAsyncCall* call = *it;
  89 + if ((ret = call->call()) != ERROR_SUCCESS) {
  90 + srs_warn("dvr: ignore callback %s, ret=%d", call->to_string().c_str(), ret);
  91 + }
  92 + srs_freep(call);
  93 + }
  94 +
  95 + return ret;
  96 +}
  97 +
  98 +
  1 +/*
  2 +The MIT License (MIT)
  3 +
  4 +Copyright (c) 2013-2015 winlin
  5 +
  6 +Permission is hereby granted, free of charge, to any person obtaining a copy of
  7 +this software and associated documentation files (the "Software"), to deal in
  8 +the Software without restriction, including without limitation the rights to
  9 +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  10 +the Software, and to permit persons to whom the Software is furnished to do so,
  11 +subject to the following conditions:
  12 +
  13 +The above copyright notice and this permission notice shall be included in all
  14 +copies or substantial portions of the Software.
  15 +
  16 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  18 +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  19 +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  20 +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21 +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22 +*/
  23 +
  24 +#ifndef SRS_APP_ASYNC_CALL_HPP
  25 +#define SRS_APP_ASYNC_CALL_HPP
  26 +
  27 +/*
  28 +#include <srs_app_async_call.hpp>
  29 +*/
  30 +#include <srs_core.hpp>
  31 +
  32 +#include <string>
  33 +#include <vector>
  34 +
  35 +#include <srs_app_thread.hpp>
  36 +
  37 +/**
  38 + * the async call for http hooks,
  39 + * for the http hooks will switch st-thread,
  40 + * so we must use isolate thread to avoid the thread corrupt,
  41 + * for example, when dvr call http hooks, the video receive thread got
  42 + * a video and pass it to the dvr again.
  43 + * futhurmore, the aync call never block the main worker thread.
  44 + */
  45 +class ISrsDvrAsyncCall
  46 +{
  47 +public:
  48 + ISrsDvrAsyncCall();
  49 + virtual ~ISrsDvrAsyncCall();
  50 +public:
  51 + virtual int call() = 0;
  52 + virtual std::string to_string() = 0;
  53 +};
  54 +
  55 +/**
  56 +* the async callback for dvr.
  57 +*/
  58 +class SrsDvrAsyncCallThread : public ISrsThreadHandler
  59 +{
  60 +private:
  61 + SrsThread* pthread;
  62 + std::vector<ISrsDvrAsyncCall*> callbacks;
  63 +public:
  64 + SrsDvrAsyncCallThread();
  65 + virtual ~SrsDvrAsyncCallThread();
  66 +public:
  67 + virtual int call(ISrsDvrAsyncCall* c);
  68 +public:
  69 + virtual int start();
  70 + virtual void stop();
  71 + virtual int cycle();
  72 +};
  73 +
  74 +#endif
  75 +
@@ -1494,7 +1494,7 @@ int SrsConfig::check_config() @@ -1494,7 +1494,7 @@ int SrsConfig::check_config()
1494 string m = conf->at(j)->name.c_str(); 1494 string m = conf->at(j)->name.c_str();
1495 if (m != "enabled" && m != "on_connect" && m != "on_close" && m != "on_publish" 1495 if (m != "enabled" && m != "on_connect" && m != "on_close" && m != "on_publish"
1496 && m != "on_unpublish" && m != "on_play" && m != "on_stop" 1496 && m != "on_unpublish" && m != "on_play" && m != "on_stop"
1497 - && m != "on_dvr" 1497 + && m != "on_dvr" && m != "on_hls"
1498 ) { 1498 ) {
1499 ret = ERROR_SYSTEM_CONFIG_INVALID; 1499 ret = ERROR_SYSTEM_CONFIG_INVALID;
1500 srs_error("unsupported vhost http_hooks directive %s, ret=%d", m.c_str(), ret); 1500 srs_error("unsupported vhost http_hooks directive %s, ret=%d", m.c_str(), ret);
@@ -2403,14 +2403,25 @@ SrsConfDirective* SrsConfig::get_vhost_on_stop(string vhost) @@ -2403,14 +2403,25 @@ SrsConfDirective* SrsConfig::get_vhost_on_stop(string vhost)
2403 SrsConfDirective* SrsConfig::get_vhost_on_dvr(string vhost) 2403 SrsConfDirective* SrsConfig::get_vhost_on_dvr(string vhost)
2404 { 2404 {
2405 SrsConfDirective* conf = get_vhost_http_hooks(vhost); 2405 SrsConfDirective* conf = get_vhost_http_hooks(vhost);
2406 -  
2407 - if (!conf) { 2406 +
  2407 + if (!conf) {
2408 return NULL; 2408 return NULL;
2409 } 2409 }
2410 2410
2411 return conf->get("on_dvr"); 2411 return conf->get("on_dvr");
2412 } 2412 }
2413 2413
  2414 +SrsConfDirective* SrsConfig::get_vhost_on_hls(string vhost)
  2415 +{
  2416 + SrsConfDirective* conf = get_vhost_http_hooks(vhost);
  2417 +
  2418 + if (!conf) {
  2419 + return NULL;
  2420 + }
  2421 +
  2422 + return conf->get("on_hls");
  2423 +}
  2424 +
2414 bool SrsConfig::get_bw_check_enabled(string vhost) 2425 bool SrsConfig::get_bw_check_enabled(string vhost)
2415 { 2426 {
2416 SrsConfDirective* conf = get_vhost(vhost); 2427 SrsConfDirective* conf = get_vhost(vhost);
@@ -627,10 +627,15 @@ public: @@ -627,10 +627,15 @@ public:
627 */ 627 */
628 virtual SrsConfDirective* get_vhost_on_stop(std::string vhost); 628 virtual SrsConfDirective* get_vhost_on_stop(std::string vhost);
629 /** 629 /**
630 - * get the on_dvr callbacks of vhost.  
631 - * @return the on_dvr callback directive, the args is the url to callback.  
632 - */ 630 + * get the on_dvr callbacks of vhost.
  631 + * @return the on_dvr callback directive, the args is the url to callback.
  632 + */
633 virtual SrsConfDirective* get_vhost_on_dvr(std::string vhost); 633 virtual SrsConfDirective* get_vhost_on_dvr(std::string vhost);
  634 + /**
  635 + * get the on_hls callbacks of vhost.
  636 + * @return the on_hls callback directive, the args is the url to callback.
  637 + */
  638 + virtual SrsConfDirective* get_vhost_on_hls(std::string vhost);
634 // bwct(bandwidth check tool) section 639 // bwct(bandwidth check tool) section
635 public: 640 public:
636 /** 641 /**
@@ -46,12 +46,6 @@ using namespace std; @@ -46,12 +46,6 @@ using namespace std;
46 // update the flv duration and filesize every this interval in ms. 46 // update the flv duration and filesize every this interval in ms.
47 #define SRS_DVR_UPDATE_DURATION_INTERVAL 60000 47 #define SRS_DVR_UPDATE_DURATION_INTERVAL 60000
48 48
49 -// the sleep interval for http async callback.  
50 -#define SRS_AUTO_ASYNC_CALLBACL_SLEEP_US 300000  
51 -  
52 -// the use raction for dvr rpc.  
53 -#define SRS_DVR_USER_ACTION_REAP_SEGMENT "reap_segment"  
54 -  
55 SrsFlvSegment::SrsFlvSegment(SrsDvrPlan* p) 49 SrsFlvSegment::SrsFlvSegment(SrsDvrPlan* p)
56 { 50 {
57 req = NULL; 51 req = NULL;
@@ -502,14 +496,6 @@ int SrsFlvSegment::on_reload_vhost_dvr(std::string /*vhost*/) @@ -502,14 +496,6 @@ int SrsFlvSegment::on_reload_vhost_dvr(std::string /*vhost*/)
502 return ret; 496 return ret;
503 } 497 }
504 498
505 -ISrsDvrAsyncCall::ISrsDvrAsyncCall()  
506 -{  
507 -}  
508 -  
509 -ISrsDvrAsyncCall::~ISrsDvrAsyncCall()  
510 -{  
511 -}  
512 -  
513 SrsDvrAsyncCallOnDvr::SrsDvrAsyncCallOnDvr(SrsRequest* r, string p) 499 SrsDvrAsyncCallOnDvr::SrsDvrAsyncCallOnDvr(SrsRequest* r, string p)
514 { 500 {
515 req = r; 501 req = r;
@@ -558,62 +544,6 @@ string SrsDvrAsyncCallOnDvr::to_string() @@ -558,62 +544,6 @@ string SrsDvrAsyncCallOnDvr::to_string()
558 return ss.str(); 544 return ss.str();
559 } 545 }
560 546
561 -SrsDvrAsyncCallThread::SrsDvrAsyncCallThread()  
562 -{  
563 - pthread = new SrsThread("async", this, SRS_AUTO_ASYNC_CALLBACL_SLEEP_US, true);  
564 -}  
565 -  
566 -SrsDvrAsyncCallThread::~SrsDvrAsyncCallThread()  
567 -{  
568 - stop();  
569 - srs_freep(pthread);  
570 -  
571 - std::vector<ISrsDvrAsyncCall*>::iterator it;  
572 - for (it = callbacks.begin(); it != callbacks.end(); ++it) {  
573 - ISrsDvrAsyncCall* call = *it;  
574 - srs_freep(call);  
575 - }  
576 - callbacks.clear();  
577 -}  
578 -  
579 -int SrsDvrAsyncCallThread::call(ISrsDvrAsyncCall* c)  
580 -{  
581 - int ret = ERROR_SUCCESS;  
582 -  
583 - callbacks.push_back(c);  
584 -  
585 - return ret;  
586 -}  
587 -  
588 -int SrsDvrAsyncCallThread::start()  
589 -{  
590 - return pthread->start();  
591 -}  
592 -  
593 -void SrsDvrAsyncCallThread::stop()  
594 -{  
595 - pthread->stop();  
596 -}  
597 -  
598 -int SrsDvrAsyncCallThread::cycle()  
599 -{  
600 - int ret = ERROR_SUCCESS;  
601 -  
602 - std::vector<ISrsDvrAsyncCall*> copies = callbacks;  
603 - callbacks.clear();  
604 -  
605 - std::vector<ISrsDvrAsyncCall*>::iterator it;  
606 - for (it = copies.begin(); it != copies.end(); ++it) {  
607 - ISrsDvrAsyncCall* call = *it;  
608 - if ((ret = call->call()) != ERROR_SUCCESS) {  
609 - srs_warn("dvr: ignore callback %s, ret=%d", call->to_string().c_str(), ret);  
610 - }  
611 - srs_freep(call);  
612 - }  
613 -  
614 - return ret;  
615 -}  
616 -  
617 SrsDvrPlan::SrsDvrPlan() 547 SrsDvrPlan::SrsDvrPlan()
618 { 548 {
619 req = NULL; 549 req = NULL;
@@ -49,7 +49,7 @@ class SrsThread; @@ -49,7 +49,7 @@ class SrsThread;
49 49
50 #include <srs_app_source.hpp> 50 #include <srs_app_source.hpp>
51 #include <srs_app_reload.hpp> 51 #include <srs_app_reload.hpp>
52 -#include <srs_app_thread.hpp> 52 +#include <srs_app_async_call.hpp>
53 53
54 /** 54 /**
55 * a piece of flv segment. 55 * a piece of flv segment.
@@ -178,15 +178,6 @@ public: @@ -178,15 +178,6 @@ public:
178 /** 178 /**
179 * the dvr async call. 179 * the dvr async call.
180 */ 180 */
181 -class ISrsDvrAsyncCall  
182 -{  
183 -public:  
184 - ISrsDvrAsyncCall();  
185 - virtual ~ISrsDvrAsyncCall();  
186 -public:  
187 - virtual int call() = 0;  
188 - virtual std::string to_string() = 0;  
189 -};  
190 class SrsDvrAsyncCallOnDvr : public ISrsDvrAsyncCall 181 class SrsDvrAsyncCallOnDvr : public ISrsDvrAsyncCall
191 { 182 {
192 private: 183 private:
@@ -201,25 +192,6 @@ public: @@ -201,25 +192,6 @@ public:
201 }; 192 };
202 193
203 /** 194 /**
204 -* the async callback for dvr.  
205 -*/  
206 -class SrsDvrAsyncCallThread : public ISrsThreadHandler  
207 -{  
208 -private:  
209 - SrsThread* pthread;  
210 - std::vector<ISrsDvrAsyncCall*> callbacks;  
211 -public:  
212 - SrsDvrAsyncCallThread();  
213 - virtual ~SrsDvrAsyncCallThread();  
214 -public:  
215 - virtual int call(ISrsDvrAsyncCall* c);  
216 -public:  
217 - virtual int start();  
218 - virtual void stop();  
219 - virtual int cycle();  
220 -};  
221 -  
222 -/**  
223 * the plan for dvr. 195 * the plan for dvr.
224 * use to control the following dvr params: 196 * use to control the following dvr params:
225 * 1. filename: the filename for record file. 197 * 1. filename: the filename for record file.
@@ -54,6 +54,7 @@ using namespace std; @@ -54,6 +54,7 @@ using namespace std;
54 #include <srs_rtmp_buffer.hpp> 54 #include <srs_rtmp_buffer.hpp>
55 #include <srs_kernel_ts.hpp> 55 #include <srs_kernel_ts.hpp>
56 #include <srs_app_utility.hpp> 56 #include <srs_app_utility.hpp>
  57 +#include <srs_app_http_hooks.hpp>
57 58
58 // drop the segment when duration of ts too small. 59 // drop the segment when duration of ts too small.
59 #define SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS 100 60 #define SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS 100
@@ -169,6 +170,55 @@ void SrsHlsSegment::update_duration(int64_t current_frame_dts) @@ -169,6 +170,55 @@ void SrsHlsSegment::update_duration(int64_t current_frame_dts)
169 return; 170 return;
170 } 171 }
171 172
  173 +SrsDvrAsyncCallOnHls::SrsDvrAsyncCallOnHls(SrsRequest* r, string p, int s)
  174 +{
  175 + req = r;
  176 + path = p;
  177 + seq_no = s;
  178 +}
  179 +
  180 +SrsDvrAsyncCallOnHls::~SrsDvrAsyncCallOnHls()
  181 +{
  182 +}
  183 +
  184 +int SrsDvrAsyncCallOnHls::call()
  185 +{
  186 + int ret = ERROR_SUCCESS;
  187 +
  188 +#ifdef SRS_AUTO_HTTP_CALLBACK
  189 + // http callback for on_hls in config.
  190 + if (_srs_config->get_vhost_http_hooks_enabled(req->vhost)) {
  191 + // HTTP: on_hls
  192 + SrsConfDirective* on_hls = _srs_config->get_vhost_on_hls(req->vhost);
  193 + if (!on_hls) {
  194 + srs_info("ignore the empty http callback: on_hls");
  195 + return ret;
  196 + }
  197 +
  198 + int connection_id = _srs_context->get_id();
  199 + std::string cwd = _srs_config->cwd();
  200 + std::string file = path;
  201 + int sn = seq_no;
  202 + for (int i = 0; i < (int)on_hls->args.size(); i++) {
  203 + std::string url = on_hls->args.at(i);
  204 + if ((ret = SrsHttpHooks::on_hls(url, connection_id, req, cwd, file, sn)) != ERROR_SUCCESS) {
  205 + srs_error("hook client on_hls failed. url=%s, ret=%d", url.c_str(), ret);
  206 + return ret;
  207 + }
  208 + }
  209 + }
  210 +#endif
  211 +
  212 + return ret;
  213 +}
  214 +
  215 +string SrsDvrAsyncCallOnHls::to_string()
  216 +{
  217 + std::stringstream ss;
  218 + ss << "vhost=" << req->vhost << ", file=" << path;
  219 + return ss.str();
  220 +}
  221 +
172 SrsHlsMuxer::SrsHlsMuxer() 222 SrsHlsMuxer::SrsHlsMuxer()
173 { 223 {
174 req = NULL; 224 req = NULL;
@@ -185,6 +235,7 @@ SrsHlsMuxer::SrsHlsMuxer() @@ -185,6 +235,7 @@ SrsHlsMuxer::SrsHlsMuxer()
185 acodec = SrsCodecAudioReserved1; 235 acodec = SrsCodecAudioReserved1;
186 should_write_cache = false; 236 should_write_cache = false;
187 should_write_file = true; 237 should_write_file = true;
  238 + async = new SrsDvrAsyncCallThread();
188 } 239 }
189 240
190 SrsHlsMuxer::~SrsHlsMuxer() 241 SrsHlsMuxer::~SrsHlsMuxer()
@@ -198,6 +249,7 @@ SrsHlsMuxer::~SrsHlsMuxer() @@ -198,6 +249,7 @@ SrsHlsMuxer::~SrsHlsMuxer()
198 249
199 srs_freep(current); 250 srs_freep(current);
200 srs_freep(req); 251 srs_freep(req);
  252 + srs_freep(async);
201 } 253 }
202 254
203 int SrsHlsMuxer::initialize(ISrsHlsHandler* h) 255 int SrsHlsMuxer::initialize(ISrsHlsHandler* h)
@@ -205,6 +257,10 @@ int SrsHlsMuxer::initialize(ISrsHlsHandler* h) @@ -205,6 +257,10 @@ int SrsHlsMuxer::initialize(ISrsHlsHandler* h)
205 int ret = ERROR_SUCCESS; 257 int ret = ERROR_SUCCESS;
206 258
207 handler = h; 259 handler = h;
  260 +
  261 + if ((ret = async->start()) != ERROR_SUCCESS) {
  262 + return ret;
  263 + }
208 264
209 return ret; 265 return ret;
210 } 266 }
@@ -523,6 +579,11 @@ int SrsHlsMuxer::segment_close(string log_desc) @@ -523,6 +579,11 @@ int SrsHlsMuxer::segment_close(string log_desc)
523 if (hls_ts_floor) { 579 if (hls_ts_floor) {
524 hls_fragment_deviation += (double)(hls_fragment - current->duration); 580 hls_fragment_deviation += (double)(hls_fragment - current->duration);
525 } 581 }
  582 +
  583 + // use async to call the http hooks, for it will cause thread switch.
  584 + if ((ret = async->call(new SrsDvrAsyncCallOnHls(req, current->full_path, current->sequence_no))) != ERROR_SUCCESS) {
  585 + return ret;
  586 + }
526 587
527 srs_info("%s reap ts segment, sequence_no=%d, uri=%s, duration=%.2f, start=%"PRId64", deviation=%.2f", 588 srs_info("%s reap ts segment, sequence_no=%d, uri=%s, duration=%.2f, start=%"PRId64", deviation=%.2f",
528 log_desc.c_str(), current->sequence_no, current->uri.c_str(), current->duration, 589 log_desc.c_str(), current->sequence_no, current->uri.c_str(), current->duration,
@@ -39,6 +39,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -39,6 +39,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
39 39
40 #include <srs_kernel_codec.hpp> 40 #include <srs_kernel_codec.hpp>
41 #include <srs_kernel_file.hpp> 41 #include <srs_kernel_file.hpp>
  42 +#include <srs_app_async_call.hpp>
42 43
43 class SrsSharedPtrMessage; 44 class SrsSharedPtrMessage;
44 class SrsCodecSample; 45 class SrsCodecSample;
@@ -155,6 +156,23 @@ public: @@ -155,6 +156,23 @@ public:
155 }; 156 };
156 157
157 /** 158 /**
  159 + * the dvr async call.
  160 + */
  161 +class SrsDvrAsyncCallOnHls : public ISrsDvrAsyncCall
  162 +{
  163 +private:
  164 + std::string path;
  165 + int seq_no;
  166 + SrsRequest* req;
  167 +public:
  168 + SrsDvrAsyncCallOnHls(SrsRequest* r, std::string p, int s);
  169 + virtual ~SrsDvrAsyncCallOnHls();
  170 +public:
  171 + virtual int call();
  172 + virtual std::string to_string();
  173 +};
  174 +
  175 +/**
158 * muxer the HLS stream(m3u8 and ts files). 176 * muxer the HLS stream(m3u8 and ts files).
159 * generally, the m3u8 muxer only provides methods to open/close segments, 177 * generally, the m3u8 muxer only provides methods to open/close segments,
160 * to flush video/audio, without any mechenisms. 178 * to flush video/audio, without any mechenisms.
@@ -174,6 +192,7 @@ private: @@ -174,6 +192,7 @@ private:
174 double hls_aof_ratio; 192 double hls_aof_ratio;
175 double hls_fragment; 193 double hls_fragment;
176 double hls_window; 194 double hls_window;
  195 + SrsDvrAsyncCallThread* async;
177 private: 196 private:
178 // whether use floor algorithm for timestamp. 197 // whether use floor algorithm for timestamp.
179 bool hls_ts_floor; 198 bool hls_ts_floor;
@@ -271,32 +271,34 @@ int SrsHttpHooks::on_dvr(string url, int client_id, string ip, SrsRequest* req, @@ -271,32 +271,34 @@ int SrsHttpHooks::on_dvr(string url, int client_id, string ip, SrsRequest* req,
271 return ret; 271 return ret;
272 } 272 }
273 273
274 -int SrsHttpHooks::on_dvr_reap_segment(string url, int client_id, SrsRequest* req, string cwd, string file) 274 +int SrsHttpHooks::on_hls(string url, int client_id, SrsRequest* req, string cwd, string file, int sn)
275 { 275 {
276 int ret = ERROR_SUCCESS; 276 int ret = ERROR_SUCCESS;
277 277
278 std::stringstream ss; 278 std::stringstream ss;
279 ss << SRS_JOBJECT_START 279 ss << SRS_JOBJECT_START
280 - << SRS_JFIELD_STR("action", "on_dvr_reap_segment") << SRS_JFIELD_CONT 280 + << SRS_JFIELD_STR("action", "on_hls") << SRS_JFIELD_CONT
281 << SRS_JFIELD_ORG("client_id", client_id) << SRS_JFIELD_CONT 281 << SRS_JFIELD_ORG("client_id", client_id) << SRS_JFIELD_CONT
  282 + << SRS_JFIELD_STR("ip", req->ip) << SRS_JFIELD_CONT
282 << SRS_JFIELD_STR("vhost", req->vhost) << SRS_JFIELD_CONT 283 << SRS_JFIELD_STR("vhost", req->vhost) << SRS_JFIELD_CONT
283 << SRS_JFIELD_STR("app", req->app) << SRS_JFIELD_CONT 284 << SRS_JFIELD_STR("app", req->app) << SRS_JFIELD_CONT
284 << SRS_JFIELD_STR("stream", req->stream) << SRS_JFIELD_CONT 285 << SRS_JFIELD_STR("stream", req->stream) << SRS_JFIELD_CONT
285 << SRS_JFIELD_STR("cwd", cwd) << SRS_JFIELD_CONT 286 << SRS_JFIELD_STR("cwd", cwd) << SRS_JFIELD_CONT
286 - << SRS_JFIELD_STR("file", file) 287 + << SRS_JFIELD_STR("file", file) << SRS_JFIELD_CONT
  288 + << SRS_JFIELD_ORG("seq_no", sn)
287 << SRS_JOBJECT_END; 289 << SRS_JOBJECT_END;
288 290
289 std::string data = ss.str(); 291 std::string data = ss.str();
290 std::string res; 292 std::string res;
291 int status_code; 293 int status_code;
292 if ((ret = do_post(url, data, status_code, res)) != ERROR_SUCCESS) { 294 if ((ret = do_post(url, data, status_code, res)) != ERROR_SUCCESS) {
293 - srs_error("http post on_dvr_reap_segment uri failed, ignored. " 295 + srs_error("http post on_hls uri failed, ignored. "
294 "client_id=%d, url=%s, request=%s, response=%s, code=%d, ret=%d", 296 "client_id=%d, url=%s, request=%s, response=%s, code=%d, ret=%d",
295 client_id, url.c_str(), data.c_str(), res.c_str(), status_code, ret); 297 client_id, url.c_str(), data.c_str(), res.c_str(), status_code, ret);
296 return ret; 298 return ret;
297 } 299 }
298 300
299 - srs_trace("http hook on_dvr_reap_segment success. " 301 + srs_trace("http hook on_hls success. "
300 "client_id=%d, url=%s, request=%s, response=%s, ret=%d", 302 "client_id=%d, url=%s, request=%s, response=%s, ret=%d",
301 client_id, url.c_str(), data.c_str(), res.c_str(), ret); 303 client_id, url.c_str(), data.c_str(), res.c_str(), ret);
302 304
@@ -105,14 +105,15 @@ public: @@ -105,14 +105,15 @@ public:
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 /** 107 /**
108 - * when dvr reap segment, callback. 108 + * when hls reap segment, callback.
109 * @param client_id the id of client on server. 109 * @param client_id the id of client on server.
110 * @param url the api server url, to process the event. 110 * @param url the api server url, to process the event.
111 * ignore if empty. 111 * ignore if empty.
112 * @param cwd the current work directory, used to resolve the reltive file path. 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. 113 + * @param file the ts file path, can be relative or absolute path.
  114 + * @param sn the seq_no, the sequence number of ts in hls/m3u8.
114 */ 115 */
115 - static int on_dvr_reap_segment(std::string url, int client_id, SrsRequest* req, std::string cwd, std::string file); 116 + static int on_hls(std::string url, int client_id, SrsRequest* req, std::string cwd, std::string file, int sn);
116 private: 117 private:
117 static int do_post(std::string url, std::string req, int& code, std::string& res); 118 static int do_post(std::string url, std::string req, int& code, std::string& res);
118 }; 119 };
@@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 // current release version 31 // current release version
32 #define VERSION_MAJOR 2 32 #define VERSION_MAJOR 2
33 #define VERSION_MINOR 0 33 #define VERSION_MINOR 0
34 -#define VERSION_REVISION 151 34 +#define VERSION_REVISION 152
35 35
36 // server info. 36 // server info.
37 #define RTMP_SIG_SRS_KEY "SRS" 37 #define RTMP_SIG_SRS_KEY "SRS"