mirror of
https://github.com/ossrs/srs.git
synced 2025-02-12 11:21:52 +00:00
support on_hls for http hooks. 2.0.152.
This commit is contained in:
parent
97442c56b6
commit
c49bc0628e
15 changed files with 308 additions and 176 deletions
|
@ -562,6 +562,7 @@ Supported operating systems and hardware:
|
|||
|
||||
### SRS 2.0 history
|
||||
|
||||
* v2.0, 2015-03-31, support on_hls for http hooks. 2.0.152.
|
||||
* v2.0, 2015-03-31, enhanced hls, support deviation for duration. 2.0.151.
|
||||
* 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.
|
||||
* 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.
|
||||
|
|
2
trunk/configure
vendored
2
trunk/configure
vendored
|
@ -174,7 +174,7 @@ if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then
|
|||
"srs_app_json" "srs_app_ingest" "srs_app_ffmpeg" "srs_app_utility" "srs_app_dvr" "srs_app_edge"
|
||||
"srs_app_kbps" "srs_app_heartbeat" "srs_app_empty" "srs_app_http_client"
|
||||
"srs_app_recv_thread" "srs_app_security" "srs_app_statistic" "srs_app_hds"
|
||||
"srs_app_mpegts_udp" "srs_app_rtsp" "srs_app_listener")
|
||||
"srs_app_mpegts_udp" "srs_app_rtsp" "srs_app_listener" "srs_app_async_call")
|
||||
DEFINES=""
|
||||
# add each modules for app
|
||||
for SRS_MODULE in $SRS_MODULES; do
|
||||
|
|
|
@ -97,6 +97,7 @@
|
|||
3C689F9F1AB6AAC800C9CEEE /* sched.c in Sources */ = {isa = PBXBuildFile; fileRef = 3C689F9B1AB6AAC800C9CEEE /* sched.c */; };
|
||||
3C689FA01AB6AAC800C9CEEE /* stk.c in Sources */ = {isa = PBXBuildFile; fileRef = 3C689F9C1AB6AAC800C9CEEE /* stk.c */; };
|
||||
3C689FA11AB6AAC800C9CEEE /* sync.c in Sources */ = {isa = PBXBuildFile; fileRef = 3C689F9D1AB6AAC800C9CEEE /* sync.c */; };
|
||||
3CD88B3F1ACA9C58000359E0 /* srs_app_async_call.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3CD88B3D1ACA9C58000359E0 /* srs_app_async_call.cpp */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
|
@ -337,6 +338,8 @@
|
|||
3C689F9B1AB6AAC800C9CEEE /* sched.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sched.c; path = "../../objs/st-1.9/sched.c"; sourceTree = "<group>"; };
|
||||
3C689F9C1AB6AAC800C9CEEE /* stk.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = stk.c; path = "../../objs/st-1.9/stk.c"; sourceTree = "<group>"; };
|
||||
3C689F9D1AB6AAC800C9CEEE /* sync.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sync.c; path = "../../objs/st-1.9/sync.c"; sourceTree = "<group>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
@ -483,6 +486,8 @@
|
|||
3C12324B1AAE81CE00CE8F6C /* app */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3CD88B3D1ACA9C58000359E0 /* srs_app_async_call.cpp */,
|
||||
3CD88B3E1ACA9C58000359E0 /* srs_app_async_call.hpp */,
|
||||
3C12324C1AAE81D900CE8F6C /* srs_app_bandwidth.cpp */,
|
||||
3C12324D1AAE81D900CE8F6C /* srs_app_bandwidth.hpp */,
|
||||
3C12324E1AAE81D900CE8F6C /* srs_app_config.cpp */,
|
||||
|
@ -789,6 +794,7 @@
|
|||
3C1232951AAE81D900CE8F6C /* srs_app_config.cpp in Sources */,
|
||||
3C663F0F1AB0155100286D8B /* srs_aac_raw_publish.c in Sources */,
|
||||
3C689FA01AB6AAC800C9CEEE /* stk.c in Sources */,
|
||||
3CD88B3F1ACA9C58000359E0 /* srs_app_async_call.cpp in Sources */,
|
||||
3C1232961AAE81D900CE8F6C /* srs_app_conn.cpp in Sources */,
|
||||
3C12322A1AAE814D00CE8F6C /* srs_kernel_ts.cpp in Sources */,
|
||||
3C12329E1AAE81D900CE8F6C /* srs_app_hls.cpp in Sources */,
|
||||
|
|
|
@ -253,7 +253,7 @@ class RESTDvrs(object):
|
|||
return json.dumps(dvrs)
|
||||
|
||||
'''
|
||||
for SRS hook: on_dvr,
|
||||
for SRS hook: on_dvr
|
||||
on_dvr:
|
||||
when srs reap a dvr file, call the hook,
|
||||
the request in the POST data string is a object encode by json:
|
||||
|
@ -265,17 +265,6 @@ class RESTDvrs(object):
|
|||
"cwd": "/usr/local/srs",
|
||||
"file": "./objs/nginx/html/live/livestream.1420254068776.flv"
|
||||
}
|
||||
on_dvr_reap_segment:
|
||||
when api dvr specifes the callback when reap flv segment, call the hook,
|
||||
the request in the POST data string is a object encode by json:
|
||||
{
|
||||
"action": "on_dvr_reap_segment",
|
||||
"client_id": 1985,
|
||||
"vhost": "video.test.com", "app": "live",
|
||||
"stream": "livestream",
|
||||
"cwd": "/usr/local/srs",
|
||||
"file": "./objs/nginx/html/live/livestream.1420254068776.flv"
|
||||
}
|
||||
if valid, the hook must return HTTP code 200(Stauts OK) and response
|
||||
an int value specifies the error code(0 corresponding to success):
|
||||
0
|
||||
|
@ -298,8 +287,6 @@ class RESTDvrs(object):
|
|||
action = json_req["action"]
|
||||
if action == "on_dvr":
|
||||
code = self.__on_dvr(json_req)
|
||||
if action == "on_dvr_reap_segment":
|
||||
code = self.__on_dvr_reap_segment(json_req)
|
||||
else:
|
||||
trace("invalid request action: %s"%(json_req["action"]))
|
||||
code = Error.request_invalid_action
|
||||
|
@ -321,18 +308,6 @@ class RESTDvrs(object):
|
|||
|
||||
return code
|
||||
|
||||
def __on_dvr_reap_segment(self, req):
|
||||
code = Error.success
|
||||
|
||||
trace("srs %s: client id=%s, vhost=%s, app=%s, stream=%s, cwd=%s, file=%s"%(
|
||||
req["action"], req["client_id"], req["vhost"], req["app"], req["stream"],
|
||||
req["cwd"], req["file"]
|
||||
))
|
||||
|
||||
# TODO: process the on_dvr event
|
||||
|
||||
return code
|
||||
|
||||
'''
|
||||
handle the hls requests: hls stream.
|
||||
'''
|
||||
|
@ -346,8 +321,8 @@ class RESTHls(object):
|
|||
return json.dumps(hls)
|
||||
|
||||
'''
|
||||
for SRS hook: on, on_dvr_reap_segment
|
||||
on_dvr:
|
||||
for SRS hook: on_hls
|
||||
on_hls:
|
||||
when srs reap a dvr file, call the hook,
|
||||
the request in the POST data string is a object encode by json:
|
||||
{
|
||||
|
@ -356,18 +331,8 @@ class RESTHls(object):
|
|||
"ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",
|
||||
"stream": "livestream",
|
||||
"cwd": "/usr/local/srs",
|
||||
"file": "./objs/nginx/html/live/livestream.1420254068776.flv"
|
||||
}
|
||||
on_dvr_reap_segment:
|
||||
when api dvr specifes the callback when reap flv segment, call the hook,
|
||||
the request in the POST data string is a object encode by json:
|
||||
{
|
||||
"action": "on_dvr_reap_segment",
|
||||
"client_id": 1985,
|
||||
"vhost": "video.test.com", "app": "live",
|
||||
"stream": "livestream",
|
||||
"cwd": "/usr/local/srs",
|
||||
"file": "./objs/nginx/html/live/livestream.1420254068776.flv"
|
||||
"file": "./objs/nginx/html/live/livestream.1420254068776-100.ts",
|
||||
"seq_no": 100
|
||||
}
|
||||
if valid, the hook must return HTTP code 200(Stauts OK) and response
|
||||
an int value specifies the error code(0 corresponding to success):
|
||||
|
@ -380,7 +345,7 @@ class RESTHls(object):
|
|||
code = Error.success
|
||||
|
||||
req = cherrypy.request.body.read()
|
||||
trace("post to dvrs, req=%s"%(req))
|
||||
trace("post to hls, req=%s"%(req))
|
||||
try:
|
||||
json_req = json.loads(req)
|
||||
except Exception, ex:
|
||||
|
@ -389,10 +354,8 @@ class RESTHls(object):
|
|||
return str(code)
|
||||
|
||||
action = json_req["action"]
|
||||
if action == "on_dvr":
|
||||
code = self.__on_dvr(json_req)
|
||||
if action == "on_dvr_reap_segment":
|
||||
code = self.__on_dvr_reap_segment(json_req)
|
||||
if action == "on_hls":
|
||||
code = self.__on_hls(json_req)
|
||||
else:
|
||||
trace("invalid request action: %s"%(json_req["action"]))
|
||||
code = Error.request_invalid_action
|
||||
|
@ -402,27 +365,15 @@ class RESTHls(object):
|
|||
def OPTIONS(self, *args, **kwargs):
|
||||
enable_crossdomain()
|
||||
|
||||
def __on_dvr(self, req):
|
||||
def __on_hls(self, req):
|
||||
code = Error.success
|
||||
|
||||
trace("srs %s: client id=%s, ip=%s, vhost=%s, app=%s, stream=%s, cwd=%s, file=%s"%(
|
||||
trace("srs %s: client id=%s, ip=%s, vhost=%s, app=%s, stream=%s, cwd=%s, file=%s, seq_no=%s"%(
|
||||
req["action"], req["client_id"], req["ip"], req["vhost"], req["app"], req["stream"],
|
||||
req["cwd"], req["file"]
|
||||
req["cwd"], req["file"], req["seq_no"]
|
||||
))
|
||||
|
||||
# TODO: process the on_dvr event
|
||||
|
||||
return code
|
||||
|
||||
def __on_dvr_reap_segment(self, req):
|
||||
code = Error.success
|
||||
|
||||
trace("srs %s: client id=%s, vhost=%s, app=%s, stream=%s, cwd=%s, file=%s"%(
|
||||
req["action"], req["client_id"], req["vhost"], req["app"], req["stream"],
|
||||
req["cwd"], req["file"]
|
||||
))
|
||||
|
||||
# TODO: process the on_dvr event
|
||||
# TODO: process the on_hls event
|
||||
|
||||
return code
|
||||
|
||||
|
|
98
trunk/src/app/srs_app_async_call.cpp
Normal file
98
trunk/src/app/srs_app_async_call.cpp
Normal file
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2015 winlin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <srs_app_async_call.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include <srs_kernel_error.hpp>
|
||||
#include <srs_kernel_log.hpp>
|
||||
|
||||
// the sleep interval for http async callback.
|
||||
#define SRS_AUTO_ASYNC_CALLBACL_SLEEP_US 300000
|
||||
|
||||
ISrsDvrAsyncCall::ISrsDvrAsyncCall()
|
||||
{
|
||||
}
|
||||
|
||||
ISrsDvrAsyncCall::~ISrsDvrAsyncCall()
|
||||
{
|
||||
}
|
||||
|
||||
SrsDvrAsyncCallThread::SrsDvrAsyncCallThread()
|
||||
{
|
||||
pthread = new SrsThread("async", this, SRS_AUTO_ASYNC_CALLBACL_SLEEP_US, true);
|
||||
}
|
||||
|
||||
SrsDvrAsyncCallThread::~SrsDvrAsyncCallThread()
|
||||
{
|
||||
stop();
|
||||
srs_freep(pthread);
|
||||
|
||||
std::vector<ISrsDvrAsyncCall*>::iterator it;
|
||||
for (it = callbacks.begin(); it != callbacks.end(); ++it) {
|
||||
ISrsDvrAsyncCall* call = *it;
|
||||
srs_freep(call);
|
||||
}
|
||||
callbacks.clear();
|
||||
}
|
||||
|
||||
int SrsDvrAsyncCallThread::call(ISrsDvrAsyncCall* c)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
callbacks.push_back(c);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsDvrAsyncCallThread::start()
|
||||
{
|
||||
return pthread->start();
|
||||
}
|
||||
|
||||
void SrsDvrAsyncCallThread::stop()
|
||||
{
|
||||
pthread->stop();
|
||||
}
|
||||
|
||||
int SrsDvrAsyncCallThread::cycle()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
std::vector<ISrsDvrAsyncCall*> copies = callbacks;
|
||||
callbacks.clear();
|
||||
|
||||
std::vector<ISrsDvrAsyncCall*>::iterator it;
|
||||
for (it = copies.begin(); it != copies.end(); ++it) {
|
||||
ISrsDvrAsyncCall* call = *it;
|
||||
if ((ret = call->call()) != ERROR_SUCCESS) {
|
||||
srs_warn("dvr: ignore callback %s, ret=%d", call->to_string().c_str(), ret);
|
||||
}
|
||||
srs_freep(call);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
75
trunk/src/app/srs_app_async_call.hpp
Normal file
75
trunk/src/app/srs_app_async_call.hpp
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2015 winlin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef SRS_APP_ASYNC_CALL_HPP
|
||||
#define SRS_APP_ASYNC_CALL_HPP
|
||||
|
||||
/*
|
||||
#include <srs_app_async_call.hpp>
|
||||
*/
|
||||
#include <srs_core.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <srs_app_thread.hpp>
|
||||
|
||||
/**
|
||||
* the async call for http hooks,
|
||||
* for the http hooks will switch st-thread,
|
||||
* so we must use isolate thread to avoid the thread corrupt,
|
||||
* for example, when dvr call http hooks, the video receive thread got
|
||||
* a video and pass it to the dvr again.
|
||||
* futhurmore, the aync call never block the main worker thread.
|
||||
*/
|
||||
class ISrsDvrAsyncCall
|
||||
{
|
||||
public:
|
||||
ISrsDvrAsyncCall();
|
||||
virtual ~ISrsDvrAsyncCall();
|
||||
public:
|
||||
virtual int call() = 0;
|
||||
virtual std::string to_string() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* the async callback for dvr.
|
||||
*/
|
||||
class SrsDvrAsyncCallThread : public ISrsThreadHandler
|
||||
{
|
||||
private:
|
||||
SrsThread* pthread;
|
||||
std::vector<ISrsDvrAsyncCall*> callbacks;
|
||||
public:
|
||||
SrsDvrAsyncCallThread();
|
||||
virtual ~SrsDvrAsyncCallThread();
|
||||
public:
|
||||
virtual int call(ISrsDvrAsyncCall* c);
|
||||
public:
|
||||
virtual int start();
|
||||
virtual void stop();
|
||||
virtual int cycle();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1494,7 +1494,7 @@ int SrsConfig::check_config()
|
|||
string m = conf->at(j)->name.c_str();
|
||||
if (m != "enabled" && m != "on_connect" && m != "on_close" && m != "on_publish"
|
||||
&& m != "on_unpublish" && m != "on_play" && m != "on_stop"
|
||||
&& m != "on_dvr"
|
||||
&& m != "on_dvr" && m != "on_hls"
|
||||
) {
|
||||
ret = ERROR_SYSTEM_CONFIG_INVALID;
|
||||
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)
|
|||
SrsConfDirective* SrsConfig::get_vhost_on_dvr(string vhost)
|
||||
{
|
||||
SrsConfDirective* conf = get_vhost_http_hooks(vhost);
|
||||
|
||||
if (!conf) {
|
||||
|
||||
if (!conf) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return conf->get("on_dvr");
|
||||
}
|
||||
|
||||
SrsConfDirective* SrsConfig::get_vhost_on_hls(string vhost)
|
||||
{
|
||||
SrsConfDirective* conf = get_vhost_http_hooks(vhost);
|
||||
|
||||
if (!conf) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return conf->get("on_hls");
|
||||
}
|
||||
|
||||
bool SrsConfig::get_bw_check_enabled(string vhost)
|
||||
{
|
||||
SrsConfDirective* conf = get_vhost(vhost);
|
||||
|
|
|
@ -627,10 +627,15 @@ public:
|
|||
*/
|
||||
virtual SrsConfDirective* get_vhost_on_stop(std::string vhost);
|
||||
/**
|
||||
* get the on_dvr callbacks of vhost.
|
||||
* @return the on_dvr callback directive, the args is the url to callback.
|
||||
*/
|
||||
* get the on_dvr callbacks of vhost.
|
||||
* @return the on_dvr callback directive, the args is the url to callback.
|
||||
*/
|
||||
virtual SrsConfDirective* get_vhost_on_dvr(std::string vhost);
|
||||
/**
|
||||
* get the on_hls callbacks of vhost.
|
||||
* @return the on_hls callback directive, the args is the url to callback.
|
||||
*/
|
||||
virtual SrsConfDirective* get_vhost_on_hls(std::string vhost);
|
||||
// bwct(bandwidth check tool) section
|
||||
public:
|
||||
/**
|
||||
|
|
|
@ -46,12 +46,6 @@ using namespace std;
|
|||
// update the flv duration and filesize every this interval in ms.
|
||||
#define SRS_DVR_UPDATE_DURATION_INTERVAL 60000
|
||||
|
||||
// the sleep interval for http async callback.
|
||||
#define SRS_AUTO_ASYNC_CALLBACL_SLEEP_US 300000
|
||||
|
||||
// the use raction for dvr rpc.
|
||||
#define SRS_DVR_USER_ACTION_REAP_SEGMENT "reap_segment"
|
||||
|
||||
SrsFlvSegment::SrsFlvSegment(SrsDvrPlan* p)
|
||||
{
|
||||
req = NULL;
|
||||
|
@ -502,14 +496,6 @@ int SrsFlvSegment::on_reload_vhost_dvr(std::string /*vhost*/)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ISrsDvrAsyncCall::ISrsDvrAsyncCall()
|
||||
{
|
||||
}
|
||||
|
||||
ISrsDvrAsyncCall::~ISrsDvrAsyncCall()
|
||||
{
|
||||
}
|
||||
|
||||
SrsDvrAsyncCallOnDvr::SrsDvrAsyncCallOnDvr(SrsRequest* r, string p)
|
||||
{
|
||||
req = r;
|
||||
|
@ -558,62 +544,6 @@ string SrsDvrAsyncCallOnDvr::to_string()
|
|||
return ss.str();
|
||||
}
|
||||
|
||||
SrsDvrAsyncCallThread::SrsDvrAsyncCallThread()
|
||||
{
|
||||
pthread = new SrsThread("async", this, SRS_AUTO_ASYNC_CALLBACL_SLEEP_US, true);
|
||||
}
|
||||
|
||||
SrsDvrAsyncCallThread::~SrsDvrAsyncCallThread()
|
||||
{
|
||||
stop();
|
||||
srs_freep(pthread);
|
||||
|
||||
std::vector<ISrsDvrAsyncCall*>::iterator it;
|
||||
for (it = callbacks.begin(); it != callbacks.end(); ++it) {
|
||||
ISrsDvrAsyncCall* call = *it;
|
||||
srs_freep(call);
|
||||
}
|
||||
callbacks.clear();
|
||||
}
|
||||
|
||||
int SrsDvrAsyncCallThread::call(ISrsDvrAsyncCall* c)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
callbacks.push_back(c);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsDvrAsyncCallThread::start()
|
||||
{
|
||||
return pthread->start();
|
||||
}
|
||||
|
||||
void SrsDvrAsyncCallThread::stop()
|
||||
{
|
||||
pthread->stop();
|
||||
}
|
||||
|
||||
int SrsDvrAsyncCallThread::cycle()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
std::vector<ISrsDvrAsyncCall*> copies = callbacks;
|
||||
callbacks.clear();
|
||||
|
||||
std::vector<ISrsDvrAsyncCall*>::iterator it;
|
||||
for (it = copies.begin(); it != copies.end(); ++it) {
|
||||
ISrsDvrAsyncCall* call = *it;
|
||||
if ((ret = call->call()) != ERROR_SUCCESS) {
|
||||
srs_warn("dvr: ignore callback %s, ret=%d", call->to_string().c_str(), ret);
|
||||
}
|
||||
srs_freep(call);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsDvrPlan::SrsDvrPlan()
|
||||
{
|
||||
req = NULL;
|
||||
|
|
|
@ -49,7 +49,7 @@ class SrsThread;
|
|||
|
||||
#include <srs_app_source.hpp>
|
||||
#include <srs_app_reload.hpp>
|
||||
#include <srs_app_thread.hpp>
|
||||
#include <srs_app_async_call.hpp>
|
||||
|
||||
/**
|
||||
* a piece of flv segment.
|
||||
|
@ -178,15 +178,6 @@ public:
|
|||
/**
|
||||
* the dvr async call.
|
||||
*/
|
||||
class ISrsDvrAsyncCall
|
||||
{
|
||||
public:
|
||||
ISrsDvrAsyncCall();
|
||||
virtual ~ISrsDvrAsyncCall();
|
||||
public:
|
||||
virtual int call() = 0;
|
||||
virtual std::string to_string() = 0;
|
||||
};
|
||||
class SrsDvrAsyncCallOnDvr : public ISrsDvrAsyncCall
|
||||
{
|
||||
private:
|
||||
|
@ -200,25 +191,6 @@ public:
|
|||
virtual std::string to_string();
|
||||
};
|
||||
|
||||
/**
|
||||
* the async callback for dvr.
|
||||
*/
|
||||
class SrsDvrAsyncCallThread : public ISrsThreadHandler
|
||||
{
|
||||
private:
|
||||
SrsThread* pthread;
|
||||
std::vector<ISrsDvrAsyncCall*> callbacks;
|
||||
public:
|
||||
SrsDvrAsyncCallThread();
|
||||
virtual ~SrsDvrAsyncCallThread();
|
||||
public:
|
||||
virtual int call(ISrsDvrAsyncCall* c);
|
||||
public:
|
||||
virtual int start();
|
||||
virtual void stop();
|
||||
virtual int cycle();
|
||||
};
|
||||
|
||||
/**
|
||||
* the plan for dvr.
|
||||
* use to control the following dvr params:
|
||||
|
|
|
@ -54,6 +54,7 @@ using namespace std;
|
|||
#include <srs_rtmp_buffer.hpp>
|
||||
#include <srs_kernel_ts.hpp>
|
||||
#include <srs_app_utility.hpp>
|
||||
#include <srs_app_http_hooks.hpp>
|
||||
|
||||
// drop the segment when duration of ts too small.
|
||||
#define SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS 100
|
||||
|
@ -169,6 +170,55 @@ void SrsHlsSegment::update_duration(int64_t current_frame_dts)
|
|||
return;
|
||||
}
|
||||
|
||||
SrsDvrAsyncCallOnHls::SrsDvrAsyncCallOnHls(SrsRequest* r, string p, int s)
|
||||
{
|
||||
req = r;
|
||||
path = p;
|
||||
seq_no = s;
|
||||
}
|
||||
|
||||
SrsDvrAsyncCallOnHls::~SrsDvrAsyncCallOnHls()
|
||||
{
|
||||
}
|
||||
|
||||
int SrsDvrAsyncCallOnHls::call()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
#ifdef SRS_AUTO_HTTP_CALLBACK
|
||||
// http callback for on_hls in config.
|
||||
if (_srs_config->get_vhost_http_hooks_enabled(req->vhost)) {
|
||||
// HTTP: on_hls
|
||||
SrsConfDirective* on_hls = _srs_config->get_vhost_on_hls(req->vhost);
|
||||
if (!on_hls) {
|
||||
srs_info("ignore the empty http callback: on_hls");
|
||||
return ret;
|
||||
}
|
||||
|
||||
int connection_id = _srs_context->get_id();
|
||||
std::string cwd = _srs_config->cwd();
|
||||
std::string file = path;
|
||||
int sn = seq_no;
|
||||
for (int i = 0; i < (int)on_hls->args.size(); i++) {
|
||||
std::string url = on_hls->args.at(i);
|
||||
if ((ret = SrsHttpHooks::on_hls(url, connection_id, req, cwd, file, sn)) != ERROR_SUCCESS) {
|
||||
srs_error("hook client on_hls failed. url=%s, ret=%d", url.c_str(), ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
string SrsDvrAsyncCallOnHls::to_string()
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "vhost=" << req->vhost << ", file=" << path;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
SrsHlsMuxer::SrsHlsMuxer()
|
||||
{
|
||||
req = NULL;
|
||||
|
@ -185,6 +235,7 @@ SrsHlsMuxer::SrsHlsMuxer()
|
|||
acodec = SrsCodecAudioReserved1;
|
||||
should_write_cache = false;
|
||||
should_write_file = true;
|
||||
async = new SrsDvrAsyncCallThread();
|
||||
}
|
||||
|
||||
SrsHlsMuxer::~SrsHlsMuxer()
|
||||
|
@ -198,6 +249,7 @@ SrsHlsMuxer::~SrsHlsMuxer()
|
|||
|
||||
srs_freep(current);
|
||||
srs_freep(req);
|
||||
srs_freep(async);
|
||||
}
|
||||
|
||||
int SrsHlsMuxer::initialize(ISrsHlsHandler* h)
|
||||
|
@ -205,6 +257,10 @@ int SrsHlsMuxer::initialize(ISrsHlsHandler* h)
|
|||
int ret = ERROR_SUCCESS;
|
||||
|
||||
handler = h;
|
||||
|
||||
if ((ret = async->start()) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -523,6 +579,11 @@ int SrsHlsMuxer::segment_close(string log_desc)
|
|||
if (hls_ts_floor) {
|
||||
hls_fragment_deviation += (double)(hls_fragment - current->duration);
|
||||
}
|
||||
|
||||
// use async to call the http hooks, for it will cause thread switch.
|
||||
if ((ret = async->call(new SrsDvrAsyncCallOnHls(req, current->full_path, current->sequence_no))) != ERROR_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
srs_info("%s reap ts segment, sequence_no=%d, uri=%s, duration=%.2f, start=%"PRId64", deviation=%.2f",
|
||||
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.
|
|||
|
||||
#include <srs_kernel_codec.hpp>
|
||||
#include <srs_kernel_file.hpp>
|
||||
#include <srs_app_async_call.hpp>
|
||||
|
||||
class SrsSharedPtrMessage;
|
||||
class SrsCodecSample;
|
||||
|
@ -154,6 +155,23 @@ public:
|
|||
virtual void update_duration(int64_t current_frame_dts);
|
||||
};
|
||||
|
||||
/**
|
||||
* the dvr async call.
|
||||
*/
|
||||
class SrsDvrAsyncCallOnHls : public ISrsDvrAsyncCall
|
||||
{
|
||||
private:
|
||||
std::string path;
|
||||
int seq_no;
|
||||
SrsRequest* req;
|
||||
public:
|
||||
SrsDvrAsyncCallOnHls(SrsRequest* r, std::string p, int s);
|
||||
virtual ~SrsDvrAsyncCallOnHls();
|
||||
public:
|
||||
virtual int call();
|
||||
virtual std::string to_string();
|
||||
};
|
||||
|
||||
/**
|
||||
* muxer the HLS stream(m3u8 and ts files).
|
||||
* generally, the m3u8 muxer only provides methods to open/close segments,
|
||||
|
@ -174,6 +192,7 @@ private:
|
|||
double hls_aof_ratio;
|
||||
double hls_fragment;
|
||||
double hls_window;
|
||||
SrsDvrAsyncCallThread* async;
|
||||
private:
|
||||
// whether use floor algorithm for timestamp.
|
||||
bool hls_ts_floor;
|
||||
|
|
|
@ -271,32 +271,34 @@ int SrsHttpHooks::on_dvr(string url, int client_id, string ip, SrsRequest* req,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int SrsHttpHooks::on_dvr_reap_segment(string url, int client_id, SrsRequest* req, string cwd, string file)
|
||||
int SrsHttpHooks::on_hls(string url, int client_id, SrsRequest* req, string cwd, string file, int sn)
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
std::stringstream ss;
|
||||
ss << SRS_JOBJECT_START
|
||||
<< SRS_JFIELD_STR("action", "on_dvr_reap_segment") << SRS_JFIELD_CONT
|
||||
<< SRS_JFIELD_STR("action", "on_hls") << SRS_JFIELD_CONT
|
||||
<< SRS_JFIELD_ORG("client_id", client_id) << SRS_JFIELD_CONT
|
||||
<< SRS_JFIELD_STR("ip", req->ip) << 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("cwd", cwd) << SRS_JFIELD_CONT
|
||||
<< SRS_JFIELD_STR("file", file)
|
||||
<< SRS_JFIELD_STR("file", file) << SRS_JFIELD_CONT
|
||||
<< SRS_JFIELD_ORG("seq_no", sn)
|
||||
<< SRS_JOBJECT_END;
|
||||
|
||||
std::string data = ss.str();
|
||||
std::string res;
|
||||
int status_code;
|
||||
if ((ret = do_post(url, data, status_code, res)) != ERROR_SUCCESS) {
|
||||
srs_error("http post on_dvr_reap_segment uri failed, ignored. "
|
||||
srs_error("http post on_hls uri failed, ignored. "
|
||||
"client_id=%d, url=%s, request=%s, response=%s, code=%d, ret=%d",
|
||||
client_id, url.c_str(), data.c_str(), res.c_str(), status_code, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
srs_trace("http hook on_dvr_reap_segment success. "
|
||||
srs_trace("http hook on_hls success. "
|
||||
"client_id=%d, url=%s, request=%s, response=%s, ret=%d",
|
||||
client_id, url.c_str(), data.c_str(), res.c_str(), ret);
|
||||
|
||||
|
|
|
@ -105,14 +105,15 @@ public:
|
|||
*/
|
||||
static int on_dvr(std::string url, int client_id, std::string ip, SrsRequest* req, std::string cwd, std::string file);
|
||||
/**
|
||||
* when dvr reap segment, callback.
|
||||
* when hls reap segment, callback.
|
||||
* @param client_id the id of client on server.
|
||||
* @param url the api server url, to process the event.
|
||||
* ignore if empty.
|
||||
* @param cwd the current work directory, used to resolve the reltive file path.
|
||||
* @param file the file path, can be relative or absolute path.
|
||||
* @param file the ts file path, can be relative or absolute path.
|
||||
* @param sn the seq_no, the sequence number of ts in hls/m3u8.
|
||||
*/
|
||||
static int on_dvr_reap_segment(std::string url, int client_id, SrsRequest* req, std::string cwd, std::string file);
|
||||
static int on_hls(std::string url, int client_id, SrsRequest* req, std::string cwd, std::string file, int sn);
|
||||
private:
|
||||
static int do_post(std::string url, std::string req, int& code, std::string& res);
|
||||
};
|
||||
|
|
|
@ -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 151
|
||||
#define VERSION_REVISION 152
|
||||
|
||||
// server info.
|
||||
#define RTMP_SIG_SRS_KEY "SRS"
|
||||
|
|
Loading…
Reference in a new issue