winlin

support http hooks: on_connect/close/publish/unpublish/play/stop.

@@ -190,6 +190,7 @@ usr sys idl wai hiq siq| read writ| recv send| in out | int csw @@ -190,6 +190,7 @@ usr sys idl wai hiq siq| read writ| recv send| in out | int csw
190 * nginx v1.5.0: 139524 lines <br/> 190 * nginx v1.5.0: 139524 lines <br/>
191 191
192 ### History 192 ### History
  193 +* v0.8, 2013-12-08, support http hooks: on_connect/close/publish/unpublish/play/stop.
193 * v0.8, 2013-12-08, support multiple http hooks for a event. 194 * v0.8, 2013-12-08, support multiple http hooks for a event.
194 * v0.8, 2013-12-07, support http callback hooks, on_connect. 195 * v0.8, 2013-12-07, support http callback hooks, on_connect.
195 * v0.8, 2013-12-07, support network based cli and json result, add CherryPy 3.2.4. 196 * v0.8, 2013-12-07, support network based cli and json result, add CherryPy 3.2.4.
@@ -139,6 +139,8 @@ vhost hooks.callback.vhost.com { @@ -139,6 +139,8 @@ vhost hooks.callback.vhost.com {
139 # when client connect to vhost/app, call the hook, 139 # when client connect to vhost/app, call the hook,
140 # the request in the POST data string is a object encode by json: 140 # the request in the POST data string is a object encode by json:
141 # { 141 # {
  142 + # "action": "on_connect",
  143 + # "client_id": 1985,
142 # "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live", 144 # "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",
143 # "pageUrl": "http://www.test.com/live.html" 145 # "pageUrl": "http://www.test.com/live.html"
144 # } 146 # }
@@ -148,6 +150,75 @@ vhost hooks.callback.vhost.com { @@ -148,6 +150,75 @@ vhost hooks.callback.vhost.com {
148 # support multiple api hooks, format: 150 # support multiple api hooks, format:
149 # on_connect http://xxx/api0 http://xxx/api1 http://xxx/apiN 151 # on_connect http://xxx/api0 http://xxx/api1 http://xxx/apiN
150 on_connect http://127.0.0.1:8085/api/v1/clients http://localhost:8085/api/v1/clients; 152 on_connect http://127.0.0.1:8085/api/v1/clients http://localhost:8085/api/v1/clients;
  153 + # when client close/disconnect to vhost/app/stream, call the hook,
  154 + # the request in the POST data string is a object encode by json:
  155 + # {
  156 + # "action": "on_close",
  157 + # "client_id": 1985,
  158 + # "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live"
  159 + # }
  160 + # if valid, the hook must return HTTP code 200(Stauts OK) and response
  161 + # an int value specifies the error code(0 corresponding to success):
  162 + # 0
  163 + # support multiple api hooks, format:
  164 + # on_close http://xxx/api0 http://xxx/api1 http://xxx/apiN
  165 + on_close http://127.0.0.1:8085/api/v1/clients http://localhost:8085/api/v1/clients;
  166 + # when client(encoder) publish to vhost/app/stream, call the hook,
  167 + # the request in the POST data string is a object encode by json:
  168 + # {
  169 + # "action": "on_publish",
  170 + # "client_id": 1985,
  171 + # "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",
  172 + # "stream": "livestream"
  173 + # }
  174 + # if valid, the hook must return HTTP code 200(Stauts OK) and response
  175 + # an int value specifies the error code(0 corresponding to success):
  176 + # 0
  177 + # support multiple api hooks, format:
  178 + # on_publish http://xxx/api0 http://xxx/api1 http://xxx/apiN
  179 + on_publish http://127.0.0.1:8085/api/v1/streams http://localhost:8085/api/v1/streams;
  180 + # when client(encoder) stop publish to vhost/app/stream, call the hook,
  181 + # the request in the POST data string is a object encode by json:
  182 + # {
  183 + # "action": "on_unpublish",
  184 + # "client_id": 1985,
  185 + # "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",
  186 + # "stream": "livestream"
  187 + # }
  188 + # if valid, the hook must return HTTP code 200(Stauts OK) and response
  189 + # an int value specifies the error code(0 corresponding to success):
  190 + # 0
  191 + # support multiple api hooks, format:
  192 + # on_unpublish http://xxx/api0 http://xxx/api1 http://xxx/apiN
  193 + on_unpublish http://127.0.0.1:8085/api/v1/streams http://localhost:8085/api/v1/streams;
  194 + # when client start to play vhost/app/stream, call the hook,
  195 + # the request in the POST data string is a object encode by json:
  196 + # {
  197 + # "action": "on_play",
  198 + # "client_id": 1985,
  199 + # "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",
  200 + # "stream": "livestream"
  201 + # }
  202 + # if valid, the hook must return HTTP code 200(Stauts OK) and response
  203 + # an int value specifies the error code(0 corresponding to success):
  204 + # 0
  205 + # support multiple api hooks, format:
  206 + # on_play http://xxx/api0 http://xxx/api1 http://xxx/apiN
  207 + on_play http://127.0.0.1:8085/api/v1/sessions http://localhost:8085/api/v1/sessions;
  208 + # when client stop to play vhost/app/stream, call the hook,
  209 + # the request in the POST data string is a object encode by json:
  210 + # {
  211 + # "action": "on_stop",
  212 + # "client_id": 1985,
  213 + # "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",
  214 + # "stream": "livestream"
  215 + # }
  216 + # if valid, the hook must return HTTP code 200(Stauts OK) and response
  217 + # an int value specifies the error code(0 corresponding to success):
  218 + # 0
  219 + # support multiple api hooks, format:
  220 + # on_stop http://xxx/api0 http://xxx/api1 http://xxx/apiN
  221 + on_stop http://127.0.0.1:8085/api/v1/sessions http://localhost:8085/api/v1/sessions;
151 } 222 }
152 } 223 }
153 # the mirror filter of ffmpeg, @see: http://ffmpeg.org/ffmpeg-filters.html#Filtering-Introduction 224 # the mirror filter of ffmpeg, @see: http://ffmpeg.org/ffmpeg-filters.html#Filtering-Introduction
@@ -57,10 +57,11 @@ class Error: @@ -57,10 +57,11 @@ class Error:
57 success = 0 57 success = 0
58 # error when parse json 58 # error when parse json
59 system_parse_json = 100 59 system_parse_json = 100
  60 + # request action invalid
  61 + request_invalid_action = 200
60 62
61 ''' 63 '''
62 -handle the clients requests:  
63 -POST: create new client, handle the SRS on_connect callback. 64 +handle the clients requests: connect/disconnect vhost/app.
64 ''' 65 '''
65 class RESTClients(object): 66 class RESTClients(object):
66 exposed = True 67 exposed = True
@@ -72,13 +73,24 @@ class RESTClients(object): @@ -72,13 +73,24 @@ class RESTClients(object):
72 return json.dumps(clients) 73 return json.dumps(clients)
73 74
74 ''' 75 '''
75 - for SRS hook: on_connect  
76 - when client connect to vhost/app, call the hook,  
77 - the request in the POST data string is a object encode by json:  
78 - {  
79 - "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",  
80 - "pageUrl": "http://www.test.com/live.html"  
81 - } 76 + for SRS hook: on_connect/on_close
  77 + on_connect:
  78 + when client connect to vhost/app, call the hook,
  79 + the request in the POST data string is a object encode by json:
  80 + {
  81 + "action": "on_connect",
  82 + "client_id": 1985,
  83 + "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",
  84 + "pageUrl": "http://www.test.com/live.html"
  85 + }
  86 + on_close:
  87 + when client close/disconnect to vhost/app/stream, call the hook,
  88 + the request in the POST data string is a object encode by json:
  89 + {
  90 + "action": "on_close",
  91 + "client_id": 1985,
  92 + "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live"
  93 + }
82 if valid, the hook must return HTTP code 200(Stauts OK) and response 94 if valid, the hook must return HTTP code 200(Stauts OK) and response
83 an int value specifies the error code(0 corresponding to success): 95 an int value specifies the error code(0 corresponding to success):
84 0 96 0
@@ -87,29 +99,227 @@ class RESTClients(object): @@ -87,29 +99,227 @@ class RESTClients(object):
87 enable_crossdomain() 99 enable_crossdomain()
88 100
89 # return the error code in str 101 # return the error code in str
90 - ret = Error.success 102 + code = Error.success
91 103
92 req = cherrypy.request.body.read() 104 req = cherrypy.request.body.read()
93 trace("post to clients, req=%s"%(req)) 105 trace("post to clients, req=%s"%(req))
94 try: 106 try:
95 json_req = json.loads(req) 107 json_req = json.loads(req)
96 except Exception, ex: 108 except Exception, ex:
97 - ret = Error.system_parse_json  
98 - trace("parse the request to json failed, req=%s, ex=%s, ret=%s"%(req, ex, ret))  
99 - return str(ret) 109 + code = Error.system_parse_json
  110 + trace("parse the request to json failed, req=%s, ex=%s, code=%s"%(req, ex, code))
  111 + return str(code)
100 112
101 - trace("srs on_connect: client ip=%s, vhost=%s, app=%s, pageUrl=%s"%(  
102 - json_req["ip"], json_req["vhost"], json_req["app"], json_req["pageUrl"] 113 + action = json_req["action"]
  114 + if action == "on_connect":
  115 + code = self.__on_connect(json_req)
  116 + elif action == "on_close":
  117 + code = self.__on_close(json_req)
  118 + else:
  119 + trace("invalid request action: %s"%(json_req["action"]))
  120 + code = Error.request_invalid_action
  121 +
  122 + return str(code)
  123 +
  124 + def OPTIONS(self):
  125 + enable_crossdomain()
  126 +
  127 + def __on_connect(self, req):
  128 + code = Error.success
  129 +
  130 + trace("srs %s: client id=%s, ip=%s, vhost=%s, app=%s, pageUrl=%s"%(
  131 + req["action"], req["client_id"], req["ip"], req["vhost"], req["app"], req["pageUrl"]
  132 + ))
  133 +
  134 + # TODO: process the on_connect event
  135 +
  136 + return code
  137 +
  138 + def __on_close(self, req):
  139 + code = Error.success
  140 +
  141 + trace("srs %s: client id=%s, ip=%s, vhost=%s, app=%s"%(
  142 + req["action"], req["client_id"], req["ip"], req["vhost"], req["app"]
  143 + ))
  144 +
  145 + # TODO: process the on_close event
  146 +
  147 + return code
  148 +
  149 +'''
  150 +handle the streams requests: publish/unpublish stream.
  151 +'''
  152 +class RESTStreams(object):
  153 + exposed = True
  154 +
  155 + def GET(self):
  156 + enable_crossdomain()
  157 +
  158 + streams = {}
  159 + return json.dumps(streams)
  160 +
  161 + '''
  162 + for SRS hook: on_publish/on_unpublish
  163 + on_publish:
  164 + when client(encoder) publish to vhost/app/stream, call the hook,
  165 + the request in the POST data string is a object encode by json:
  166 + {
  167 + "action": "on_publish",
  168 + "client_id": 1985,
  169 + "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",
  170 + "stream": "livestream"
  171 + }
  172 + on_unpublish:
  173 + when client(encoder) stop publish to vhost/app/stream, call the hook,
  174 + the request in the POST data string is a object encode by json:
  175 + {
  176 + "action": "on_unpublish",
  177 + "client_id": 1985,
  178 + "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",
  179 + "stream": "livestream"
  180 + }
  181 + if valid, the hook must return HTTP code 200(Stauts OK) and response
  182 + an int value specifies the error code(0 corresponding to success):
  183 + 0
  184 + '''
  185 + def POST(self):
  186 + enable_crossdomain()
  187 +
  188 + # return the error code in str
  189 + code = Error.success
  190 +
  191 + req = cherrypy.request.body.read()
  192 + trace("post to streams, req=%s"%(req))
  193 + try:
  194 + json_req = json.loads(req)
  195 + except Exception, ex:
  196 + code = Error.system_parse_json
  197 + trace("parse the request to json failed, req=%s, ex=%s, code=%s"%(req, ex, code))
  198 + return str(code)
  199 +
  200 + action = json_req["action"]
  201 + if action == "on_publish":
  202 + code = self.__on_publish(json_req)
  203 + elif action == "on_unpublish":
  204 + code = self.__on_unpublish(json_req)
  205 + else:
  206 + trace("invalid request action: %s"%(json_req["action"]))
  207 + code = Error.request_invalid_action
  208 +
  209 + return str(code)
  210 +
  211 + def OPTIONS(self):
  212 + enable_crossdomain()
  213 +
  214 + def __on_publish(self, req):
  215 + code = Error.success
  216 +
  217 + trace("srs %s: client id=%s, ip=%s, vhost=%s, app=%s, stream=%s"%(
  218 + req["action"], req["client_id"], req["ip"], req["vhost"], req["app"], req["stream"]
103 )) 219 ))
104 220
105 - # TODO: valid the client. 221 + # TODO: process the on_publish event
  222 +
  223 + return code
  224 +
  225 + def __on_unpublish(self, req):
  226 + code = Error.success
  227 +
  228 + trace("srs %s: client id=%s, ip=%s, vhost=%s, app=%s, stream=%s"%(
  229 + req["action"], req["client_id"], req["ip"], req["vhost"], req["app"], req["stream"]
  230 + ))
  231 +
  232 + # TODO: process the on_unpublish event
  233 +
  234 + return code
  235 +
  236 +'''
  237 +handle the sessions requests: client play/stop stream
  238 +'''
  239 +class RESTSessions(object):
  240 + exposed = True
  241 +
  242 + def GET(self):
  243 + enable_crossdomain()
  244 +
  245 + sessions = {}
  246 + return json.dumps(sessions)
  247 +
  248 + '''
  249 + for SRS hook: on_play/on_stop
  250 + on_play:
  251 + when client(encoder) publish to vhost/app/stream, call the hook,
  252 + the request in the POST data string is a object encode by json:
  253 + {
  254 + "action": "on_play",
  255 + "client_id": 1985,
  256 + "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",
  257 + "stream": "livestream"
  258 + }
  259 + on_stop:
  260 + when client(encoder) stop publish to vhost/app/stream, call the hook,
  261 + the request in the POST data string is a object encode by json:
  262 + {
  263 + "action": "on_stop",
  264 + "client_id": 1985,
  265 + "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",
  266 + "stream": "livestream"
  267 + }
  268 + 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):
  270 + 0
  271 + '''
  272 + def POST(self):
  273 + enable_crossdomain()
  274 +
  275 + # return the error code in str
  276 + code = Error.success
  277 +
  278 + req = cherrypy.request.body.read()
  279 + trace("post to sessions, req=%s"%(req))
  280 + try:
  281 + json_req = json.loads(req)
  282 + except Exception, ex:
  283 + code = Error.system_parse_json
  284 + trace("parse the request to json failed, req=%s, ex=%s, code=%s"%(req, ex, code))
  285 + return str(code)
  286 +
  287 + action = json_req["action"]
  288 + if action == "on_play":
  289 + code = self.__on_play(json_req)
  290 + elif action == "on_stop":
  291 + code = self.__on_stop(json_req)
  292 + else:
  293 + trace("invalid request action: %s"%(json_req["action"]))
  294 + code = Error.request_invalid_action
106 295
107 - trace("valid clients post request success.")  
108 - return str(ret) 296 + return str(code)
109 297
110 def OPTIONS(self): 298 def OPTIONS(self):
111 enable_crossdomain() 299 enable_crossdomain()
112 300
  301 + def __on_play(self, req):
  302 + code = Error.success
  303 +
  304 + trace("srs %s: client id=%s, ip=%s, vhost=%s, app=%s, stream=%s"%(
  305 + req["action"], req["client_id"], req["ip"], req["vhost"], req["app"], req["stream"]
  306 + ))
  307 +
  308 + # TODO: process the on_play event
  309 +
  310 + return code
  311 +
  312 + def __on_stop(self, req):
  313 + code = Error.success
  314 +
  315 + trace("srs %s: client id=%s, ip=%s, vhost=%s, app=%s, stream=%s"%(
  316 + req["action"], req["client_id"], req["ip"], req["vhost"], req["app"], req["stream"]
  317 + ))
  318 +
  319 + # TODO: process the on_stop event
  320 +
  321 + return code
  322 +
113 # HTTP RESTful path. 323 # HTTP RESTful path.
114 class Root(object): 324 class Root(object):
115 def __init__(self): 325 def __init__(self):
@@ -123,6 +333,8 @@ class Api(object): @@ -123,6 +333,8 @@ class Api(object):
123 class V1(object): 333 class V1(object):
124 def __init__(self): 334 def __init__(self):
125 self.clients = RESTClients() 335 self.clients = RESTClients()
  336 + self.streams = RESTStreams()
  337 + self.sessions = RESTSessions()
126 338
127 ''' 339 '''
128 main code start. 340 main code start.
@@ -108,12 +108,16 @@ int SrsClient::do_cycle() @@ -108,12 +108,16 @@ int SrsClient::do_cycle()
108 req->schema.c_str(), req->vhost.c_str(), req->port.c_str(), 108 req->schema.c_str(), req->vhost.c_str(), req->port.c_str(),
109 req->app.c_str()); 109 req->app.c_str());
110 110
111 - if ((ret = refer->check(req->pageUrl, config->get_refer(req->vhost))) != ERROR_SUCCESS) {  
112 - srs_error("check refer failed. ret=%d", ret);  
113 - return ret;  
114 - }  
115 - srs_verbose("check refer success.");  
116 - 111 + ret = service_cycle();
  112 + on_close();
  113 +
  114 + return ret;
  115 +}
  116 +
  117 +int SrsClient::service_cycle()
  118 +{
  119 + int ret = ERROR_SUCCESS;
  120 +
117 if ((ret = rtmp->set_window_ack_size(2.5 * 1000 * 1000)) != ERROR_SUCCESS) { 121 if ((ret = rtmp->set_window_ack_size(2.5 * 1000 * 1000)) != ERROR_SUCCESS) {
118 srs_error("set window acknowledgement size failed. ret=%d", ret); 122 srs_error("set window acknowledgement size failed. ret=%d", ret);
119 return ret; 123 return ret;
@@ -188,8 +192,14 @@ int SrsClient::do_cycle() @@ -188,8 +192,14 @@ int SrsClient::do_cycle()
188 srs_error("start to play stream failed. ret=%d", ret); 192 srs_error("start to play stream failed. ret=%d", ret);
189 return ret; 193 return ret;
190 } 194 }
  195 + if ((ret = on_play()) != ERROR_SUCCESS) {
  196 + srs_error("http hook on_play failed. ret=%d", ret);
  197 + return ret;
  198 + }
191 srs_info("start to play stream %s success", req->stream.c_str()); 199 srs_info("start to play stream %s success", req->stream.c_str());
192 - return playing(source); 200 + ret = playing(source);
  201 + on_stop();
  202 + return ret;
193 } 203 }
194 case SrsClientFMLEPublish: { 204 case SrsClientFMLEPublish: {
195 srs_verbose("FMLE start to publish stream %s.", req->stream.c_str()); 205 srs_verbose("FMLE start to publish stream %s.", req->stream.c_str());
@@ -198,9 +208,14 @@ int SrsClient::do_cycle() @@ -198,9 +208,14 @@ int SrsClient::do_cycle()
198 srs_error("start to publish stream failed. ret=%d", ret); 208 srs_error("start to publish stream failed. ret=%d", ret);
199 return ret; 209 return ret;
200 } 210 }
  211 + if ((ret = on_publish()) != ERROR_SUCCESS) {
  212 + srs_error("http hook on_publish failed. ret=%d", ret);
  213 + return ret;
  214 + }
201 srs_info("start to publish stream %s success", req->stream.c_str()); 215 srs_info("start to publish stream %s success", req->stream.c_str());
202 ret = publish(source, true); 216 ret = publish(source, true);
203 source->on_unpublish(); 217 source->on_unpublish();
  218 + on_unpublish();
204 return ret; 219 return ret;
205 } 220 }
206 case SrsClientFlashPublish: { 221 case SrsClientFlashPublish: {
@@ -210,9 +225,14 @@ int SrsClient::do_cycle() @@ -210,9 +225,14 @@ int SrsClient::do_cycle()
210 srs_error("flash start to publish stream failed. ret=%d", ret); 225 srs_error("flash start to publish stream failed. ret=%d", ret);
211 return ret; 226 return ret;
212 } 227 }
  228 + if ((ret = on_publish()) != ERROR_SUCCESS) {
  229 + srs_error("http hook on_publish failed. ret=%d", ret);
  230 + return ret;
  231 + }
213 srs_info("flash start to publish stream %s success", req->stream.c_str()); 232 srs_info("flash start to publish stream %s success", req->stream.c_str());
214 ret = publish(source, false); 233 ret = publish(source, false);
215 source->on_unpublish(); 234 source->on_unpublish();
  235 + on_unpublish();
216 return ret; 236 return ret;
217 } 237 }
218 default: { 238 default: {
@@ -249,22 +269,15 @@ int SrsClient::check_vhost() @@ -249,22 +269,15 @@ int SrsClient::check_vhost()
249 req->vhost = vhost->arg0(); 269 req->vhost = vhost->arg0();
250 } 270 }
251 271
252 -#ifdef SRS_HTTP  
253 - // HTTP: on_connect  
254 - SrsConfDirective* on_connect = config->get_vhost_on_connect(req->vhost);  
255 - if (!on_connect) {  
256 - srs_info("ignore the empty http callback: on_connect"); 272 + if ((ret = refer->check(req->pageUrl, config->get_refer(req->vhost))) != ERROR_SUCCESS) {
  273 + srs_error("check refer failed. ret=%d", ret);
257 return ret; 274 return ret;
258 } 275 }
  276 + srs_verbose("check refer success.");
259 277
260 - for (int i = 0; i < (int)on_connect->args.size(); i++) {  
261 - std::string url = on_connect->args.at(i);  
262 - if ((ret = http_hooks->on_connect(url, ip, req)) != ERROR_SUCCESS) {  
263 - srs_error("hook client failed. url=%s, ret=%d", url.c_str(), ret);  
264 - return ret;  
265 - } 278 + if ((ret = on_connect()) != ERROR_SUCCESS) {
  279 + return ret;
266 } 280 }
267 -#endif  
268 281
269 return ret; 282 return ret;
270 } 283 }
@@ -545,3 +558,129 @@ int SrsClient::process_play_control_msg(SrsConsumer* consumer, SrsCommonMessage* @@ -545,3 +558,129 @@ int SrsClient::process_play_control_msg(SrsConsumer* consumer, SrsCommonMessage*
545 return ret; 558 return ret;
546 } 559 }
547 560
  561 +int SrsClient::on_connect()
  562 +{
  563 + int ret = ERROR_SUCCESS;
  564 +
  565 +#ifdef SRS_HTTP
  566 + // HTTP: on_connect
  567 + SrsConfDirective* on_connect = config->get_vhost_on_connect(req->vhost);
  568 + if (!on_connect) {
  569 + srs_info("ignore the empty http callback: on_connect");
  570 + return ret;
  571 + }
  572 +
  573 + for (int i = 0; i < (int)on_connect->args.size(); i++) {
  574 + std::string url = on_connect->args.at(i);
  575 + if ((ret = http_hooks->on_connect(url, connection_id, ip, req)) != ERROR_SUCCESS) {
  576 + srs_error("hook client on_connect failed. url=%s, ret=%d", url.c_str(), ret);
  577 + return ret;
  578 + }
  579 + }
  580 +#endif
  581 +
  582 + return ret;
  583 +}
  584 +
  585 +void SrsClient::on_close()
  586 +{
  587 +#ifdef SRS_HTTP
  588 + // whatever the ret code, notify the api hooks.
  589 + // HTTP: on_close
  590 + SrsConfDirective* on_close = config->get_vhost_on_close(req->vhost);
  591 + if (!on_close) {
  592 + srs_info("ignore the empty http callback: on_close");
  593 + return;
  594 + }
  595 +
  596 + for (int i = 0; i < (int)on_close->args.size(); i++) {
  597 + std::string url = on_close->args.at(i);
  598 + http_hooks->on_close(url, connection_id, ip, req);
  599 + }
  600 +#endif
  601 +}
  602 +
  603 +int SrsClient::on_publish()
  604 +{
  605 + int ret = ERROR_SUCCESS;
  606 +
  607 +#ifdef SRS_HTTP
  608 + // HTTP: on_publish
  609 + SrsConfDirective* on_publish = config->get_vhost_on_publish(req->vhost);
  610 + if (!on_publish) {
  611 + srs_info("ignore the empty http callback: on_publish");
  612 + return ret;
  613 + }
  614 +
  615 + for (int i = 0; i < (int)on_publish->args.size(); i++) {
  616 + std::string url = on_publish->args.at(i);
  617 + if ((ret = http_hooks->on_publish(url, connection_id, ip, req)) != ERROR_SUCCESS) {
  618 + srs_error("hook client on_publish failed. url=%s, ret=%d", url.c_str(), ret);
  619 + return ret;
  620 + }
  621 + }
  622 +#endif
  623 +
  624 + return ret;
  625 +}
  626 +
  627 +void SrsClient::on_unpublish()
  628 +{
  629 +#ifdef SRS_HTTP
  630 + // whatever the ret code, notify the api hooks.
  631 + // HTTP: on_unpublish
  632 + SrsConfDirective* on_unpublish = config->get_vhost_on_unpublish(req->vhost);
  633 + if (!on_unpublish) {
  634 + srs_info("ignore the empty http callback: on_unpublish");
  635 + return;
  636 + }
  637 +
  638 + for (int i = 0; i < (int)on_unpublish->args.size(); i++) {
  639 + std::string url = on_unpublish->args.at(i);
  640 + http_hooks->on_unpublish(url, connection_id, ip, req);
  641 + }
  642 +#endif
  643 +}
  644 +
  645 +int SrsClient::on_play()
  646 +{
  647 + int ret = ERROR_SUCCESS;
  648 +
  649 +#ifdef SRS_HTTP
  650 + // HTTP: on_play
  651 + SrsConfDirective* on_play = config->get_vhost_on_play(req->vhost);
  652 + if (!on_play) {
  653 + srs_info("ignore the empty http callback: on_play");
  654 + return ret;
  655 + }
  656 +
  657 + for (int i = 0; i < (int)on_play->args.size(); i++) {
  658 + std::string url = on_play->args.at(i);
  659 + if ((ret = http_hooks->on_play(url, connection_id, ip, req)) != ERROR_SUCCESS) {
  660 + srs_error("hook client on_play failed. url=%s, ret=%d", url.c_str(), ret);
  661 + return ret;
  662 + }
  663 + }
  664 +#endif
  665 +
  666 + return ret;
  667 +}
  668 +
  669 +void SrsClient::on_stop()
  670 +{
  671 +#ifdef SRS_HTTP
  672 + // whatever the ret code, notify the api hooks.
  673 + // HTTP: on_stop
  674 + SrsConfDirective* on_stop = config->get_vhost_on_stop(req->vhost);
  675 + if (!on_stop) {
  676 + srs_info("ignore the empty http callback: on_stop");
  677 + return;
  678 + }
  679 +
  680 + for (int i = 0; i < (int)on_stop->args.size(); i++) {
  681 + std::string url = on_stop->args.at(i);
  682 + http_hooks->on_stop(url, connection_id, ip, req);
  683 + }
  684 +#endif
  685 +}
  686 +
@@ -63,12 +63,21 @@ public: @@ -63,12 +63,21 @@ public:
63 protected: 63 protected:
64 virtual int do_cycle(); 64 virtual int do_cycle();
65 private: 65 private:
  66 + // when valid and connected to vhost/app, service the client.
  67 + virtual int service_cycle();
66 virtual int check_vhost(); 68 virtual int check_vhost();
67 virtual int playing(SrsSource* source); 69 virtual int playing(SrsSource* source);
68 virtual int publish(SrsSource* source, bool is_fmle); 70 virtual int publish(SrsSource* source, bool is_fmle);
69 virtual int process_publish_message(SrsSource* source, SrsCommonMessage* msg, bool is_fmle); 71 virtual int process_publish_message(SrsSource* source, SrsCommonMessage* msg, bool is_fmle);
70 virtual int get_peer_ip(); 72 virtual int get_peer_ip();
71 virtual int process_play_control_msg(SrsConsumer* consumer, SrsCommonMessage* msg); 73 virtual int process_play_control_msg(SrsConsumer* consumer, SrsCommonMessage* msg);
  74 +private:
  75 + virtual int on_connect();
  76 + virtual void on_close();
  77 + virtual int on_publish();
  78 + virtual void on_unpublish();
  79 + virtual int on_play();
  80 + virtual void on_stop();
72 }; 81 };
73 82
74 #endif 83 #endif
@@ -578,6 +578,86 @@ SrsConfDirective* SrsConfig::get_vhost_on_connect(std::string vhost) @@ -578,6 +578,86 @@ SrsConfDirective* SrsConfig::get_vhost_on_connect(std::string vhost)
578 return conf->get("on_connect"); 578 return conf->get("on_connect");
579 } 579 }
580 580
  581 +SrsConfDirective* SrsConfig::get_vhost_on_close(std::string vhost)
  582 +{
  583 + SrsConfDirective* conf = get_vhost(vhost);
  584 +
  585 + if (!conf) {
  586 + return NULL;
  587 + }
  588 +
  589 + conf = conf->get("http_hooks");
  590 + if (!conf) {
  591 + return NULL;
  592 + }
  593 +
  594 + return conf->get("on_close");
  595 +}
  596 +
  597 +SrsConfDirective* SrsConfig::get_vhost_on_publish(std::string vhost)
  598 +{
  599 + SrsConfDirective* conf = get_vhost(vhost);
  600 +
  601 + if (!conf) {
  602 + return NULL;
  603 + }
  604 +
  605 + conf = conf->get("http_hooks");
  606 + if (!conf) {
  607 + return NULL;
  608 + }
  609 +
  610 + return conf->get("on_publish");
  611 +}
  612 +
  613 +SrsConfDirective* SrsConfig::get_vhost_on_unpublish(std::string vhost)
  614 +{
  615 + SrsConfDirective* conf = get_vhost(vhost);
  616 +
  617 + if (!conf) {
  618 + return NULL;
  619 + }
  620 +
  621 + conf = conf->get("http_hooks");
  622 + if (!conf) {
  623 + return NULL;
  624 + }
  625 +
  626 + return conf->get("on_unpublish");
  627 +}
  628 +
  629 +SrsConfDirective* SrsConfig::get_vhost_on_play(std::string vhost)
  630 +{
  631 + SrsConfDirective* conf = get_vhost(vhost);
  632 +
  633 + if (!conf) {
  634 + return NULL;
  635 + }
  636 +
  637 + conf = conf->get("http_hooks");
  638 + if (!conf) {
  639 + return NULL;
  640 + }
  641 +
  642 + return conf->get("on_play");
  643 +}
  644 +
  645 +SrsConfDirective* SrsConfig::get_vhost_on_stop(std::string vhost)
  646 +{
  647 + SrsConfDirective* conf = get_vhost(vhost);
  648 +
  649 + if (!conf) {
  650 + return NULL;
  651 + }
  652 +
  653 + conf = conf->get("http_hooks");
  654 + if (!conf) {
  655 + return NULL;
  656 + }
  657 +
  658 + return conf->get("on_stop");
  659 +}
  660 +
581 bool SrsConfig::get_vhost_enabled(std::string vhost) 661 bool SrsConfig::get_vhost_enabled(std::string vhost)
582 { 662 {
583 SrsConfDirective* vhost_conf = get_vhost(vhost); 663 SrsConfDirective* vhost_conf = get_vhost(vhost);
@@ -120,6 +120,11 @@ public: @@ -120,6 +120,11 @@ public:
120 virtual SrsConfDirective* get_vhost(std::string vhost); 120 virtual SrsConfDirective* get_vhost(std::string vhost);
121 virtual bool get_vhost_enabled(std::string vhost); 121 virtual bool get_vhost_enabled(std::string vhost);
122 virtual SrsConfDirective* get_vhost_on_connect(std::string vhost); 122 virtual SrsConfDirective* get_vhost_on_connect(std::string vhost);
  123 + virtual SrsConfDirective* get_vhost_on_close(std::string vhost);
  124 + virtual SrsConfDirective* get_vhost_on_publish(std::string vhost);
  125 + virtual SrsConfDirective* get_vhost_on_unpublish(std::string vhost);
  126 + virtual SrsConfDirective* get_vhost_on_play(std::string vhost);
  127 + virtual SrsConfDirective* get_vhost_on_stop(std::string vhost);
123 virtual SrsConfDirective* get_transcode(std::string vhost, std::string scope); 128 virtual SrsConfDirective* get_transcode(std::string vhost, std::string scope);
124 virtual bool get_transcode_enabled(SrsConfDirective* transcode); 129 virtual bool get_transcode_enabled(SrsConfDirective* transcode);
125 virtual std::string get_transcode_ffmpeg(SrsConfDirective* transcode); 130 virtual std::string get_transcode_ffmpeg(SrsConfDirective* transcode);
@@ -31,6 +31,7 @@ SrsConnection::SrsConnection(SrsServer* srs_server, st_netfd_t client_stfd) @@ -31,6 +31,7 @@ SrsConnection::SrsConnection(SrsServer* srs_server, st_netfd_t client_stfd)
31 { 31 {
32 server = srs_server; 32 server = srs_server;
33 stfd = client_stfd; 33 stfd = client_stfd;
  34 + connection_id = 0;
34 } 35 }
35 36
36 SrsConnection::~SrsConnection() 37 SrsConnection::~SrsConnection()
@@ -65,6 +66,8 @@ void SrsConnection::cycle() @@ -65,6 +66,8 @@ void SrsConnection::cycle()
65 int ret = ERROR_SUCCESS; 66 int ret = ERROR_SUCCESS;
66 67
67 log_context->generate_id(); 68 log_context->generate_id();
  69 + connection_id = log_context->get_id();
  70 +
68 ret = do_cycle(); 71 ret = do_cycle();
69 72
70 // if socket io error, set to closed. 73 // if socket io error, set to closed.
@@ -38,6 +38,7 @@ class SrsConnection @@ -38,6 +38,7 @@ class SrsConnection
38 protected: 38 protected:
39 SrsServer* server; 39 SrsServer* server;
40 st_netfd_t stfd; 40 st_netfd_t stfd;
  41 + int connection_id;
41 public: 42 public:
42 SrsConnection(SrsServer* srs_server, st_netfd_t client_stfd); 43 SrsConnection(SrsServer* srs_server, st_netfd_t client_stfd);
43 virtual ~SrsConnection(); 44 virtual ~SrsConnection();
@@ -400,25 +400,35 @@ SrsHttpHooks::~SrsHttpHooks() @@ -400,25 +400,35 @@ SrsHttpHooks::~SrsHttpHooks()
400 { 400 {
401 } 401 }
402 402
403 -int SrsHttpHooks::on_connect(std::string url, std::string ip, SrsRequest* req) 403 +int SrsHttpHooks::on_connect(std::string url, int client_id, std::string ip, SrsRequest* req)
404 { 404 {
405 int ret = ERROR_SUCCESS; 405 int ret = ERROR_SUCCESS;
406 406
407 SrsHttpUri uri; 407 SrsHttpUri uri;
408 if ((ret = uri.initialize(url)) != ERROR_SUCCESS) { 408 if ((ret = uri.initialize(url)) != ERROR_SUCCESS) {
409 - srs_error("http uri parse url failed. "  
410 - "url=%s, ret=%d", url.c_str(), ret); 409 + srs_error("http uri parse on_connect url failed. "
  410 + "client_id=%d, url=%s, ret=%d", client_id, url.c_str(), ret);
411 return ret; 411 return ret;
412 } 412 }
413 413
414 /** 414 /**
415 { 415 {
  416 + "action": "on_connect",
  417 + "client_id": 1985,
416 "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live", 418 "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",
417 "pageUrl": "http://www.test.com/live.html" 419 "pageUrl": "http://www.test.com/live.html"
418 } 420 }
419 */ 421 */
420 std::stringstream ss; 422 std::stringstream ss;
421 ss << "{" 423 ss << "{"
  424 + // action
  425 + << '"' << "action" << '"' << ':'
  426 + << '"' << "on_connect" << '"'
  427 + << ','
  428 + // client_id
  429 + << '"' << "client_id" << '"' << ':'
  430 + << std::dec << client_id
  431 + << ','
422 // ip 432 // ip
423 << '"' << "ip" << '"' << ':' 433 << '"' << "ip" << '"' << ':'
424 << '"' << ip << '"' 434 << '"' << ip << '"'
@@ -441,24 +451,375 @@ int SrsHttpHooks::on_connect(std::string url, std::string ip, SrsRequest* req) @@ -441,24 +451,375 @@ int SrsHttpHooks::on_connect(std::string url, std::string ip, SrsRequest* req)
441 451
442 SrsHttpClient http; 452 SrsHttpClient http;
443 if ((ret = http.post(&uri, data, res)) != ERROR_SUCCESS) { 453 if ((ret = http.post(&uri, data, res)) != ERROR_SUCCESS) {
444 - srs_error("http post uri failed. "  
445 - "url=%s, request=%s, response=%s, ret=%d",  
446 - url.c_str(), data.c_str(), res.c_str(), ret); 454 + srs_error("http post on_connect uri failed. "
  455 + "client_id=%d, url=%s, request=%s, response=%s, ret=%d",
  456 + client_id, url.c_str(), data.c_str(), res.c_str(), ret);
447 return ret; 457 return ret;
448 } 458 }
449 459
450 if (res.empty() || res != SRS_HTTP_RESPONSE_OK) { 460 if (res.empty() || res != SRS_HTTP_RESPONSE_OK) {
451 ret = ERROR_HTTP_DATA_INVLIAD; 461 ret = ERROR_HTTP_DATA_INVLIAD;
452 - srs_error("http hook validate failed. "  
453 - "res=%s, ret=%d", res.c_str(), ret); 462 + srs_error("http hook on_connect validate failed. "
  463 + "client_id=%d, res=%s, ret=%d", client_id, res.c_str(), ret);
454 return ret; 464 return ret;
455 } 465 }
456 466
457 srs_trace("http hook on_connect success. " 467 srs_trace("http hook on_connect success. "
458 - "url=%s, request=%s, response=%s, ret=%d",  
459 - url.c_str(), data.c_str(), res.c_str(), ret); 468 + "client_id=%d, url=%s, request=%s, response=%s, ret=%d",
  469 + client_id, url.c_str(), data.c_str(), res.c_str(), ret);
460 470
461 return ret; 471 return ret;
462 } 472 }
463 473
  474 +void SrsHttpHooks::on_close(std::string url, int client_id, std::string ip, SrsRequest* req)
  475 +{
  476 + int ret = ERROR_SUCCESS;
  477 +
  478 + SrsHttpUri uri;
  479 + if ((ret = uri.initialize(url)) != ERROR_SUCCESS) {
  480 + srs_warn("http uri parse on_close url failed, ignored. "
  481 + "client_id=%d, url=%s, ret=%d", client_id, url.c_str(), ret);
  482 + return;
  483 + }
  484 +
  485 + /**
  486 + {
  487 + "action": "on_close",
  488 + "client_id": 1985,
  489 + "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",
  490 + "stream": "livestream"
  491 + }
  492 + */
  493 + std::stringstream ss;
  494 + ss << "{"
  495 + // action
  496 + << '"' << "action" << '"' << ':'
  497 + << '"' << "on_close" << '"'
  498 + << ','
  499 + // client_id
  500 + << '"' << "client_id" << '"' << ':'
  501 + << std::dec << client_id
  502 + << ','
  503 + // ip
  504 + << '"' << "ip" << '"' << ':'
  505 + << '"' << ip << '"'
  506 + << ','
  507 + // vhost
  508 + << '"' << "vhost" << '"' << ':'
  509 + << '"' << req->vhost << '"'
  510 + << ','
  511 + // app
  512 + << '"' << "app" << '"' << ':'
  513 + << '"' << req->app << '"'
  514 + //<< ','
  515 + << "}";
  516 + std::string data = ss.str();
  517 + std::string res;
  518 +
  519 + SrsHttpClient http;
  520 + if ((ret = http.post(&uri, data, res)) != ERROR_SUCCESS) {
  521 + srs_warn("http post on_close uri failed, ignored. "
  522 + "client_id=%d, url=%s, request=%s, response=%s, ret=%d",
  523 + client_id, url.c_str(), data.c_str(), res.c_str(), ret);
  524 + return;
  525 + }
  526 +
  527 + if (res.empty() || res != SRS_HTTP_RESPONSE_OK) {
  528 + ret = ERROR_HTTP_DATA_INVLIAD;
  529 + srs_warn("http hook on_close validate failed, ignored. "
  530 + "client_id=%d, res=%s, ret=%d", client_id, res.c_str(), ret);
  531 + return;
  532 + }
  533 +
  534 + srs_trace("http hook on_close success. "
  535 + "client_id=%d, url=%s, request=%s, response=%s, ret=%d",
  536 + client_id, url.c_str(), data.c_str(), res.c_str(), ret);
  537 +
  538 + return;
  539 +}
  540 +
  541 +int SrsHttpHooks::on_publish(std::string url, int client_id, std::string ip, SrsRequest* req)
  542 +{
  543 + int ret = ERROR_SUCCESS;
  544 +
  545 + SrsHttpUri uri;
  546 + if ((ret = uri.initialize(url)) != ERROR_SUCCESS) {
  547 + srs_error("http uri parse on_publish url failed. "
  548 + "client_id=%d, url=%s, ret=%d", client_id, url.c_str(), ret);
  549 + return ret;
  550 + }
  551 +
  552 + /**
  553 + {
  554 + "action": "on_publish",
  555 + "client_id": 1985,
  556 + "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",
  557 + "stream": "livestream"
  558 + }
  559 + */
  560 + std::stringstream ss;
  561 + ss << "{"
  562 + // action
  563 + << '"' << "action" << '"' << ':'
  564 + << '"' << "on_publish" << '"'
  565 + << ','
  566 + // client_id
  567 + << '"' << "client_id" << '"' << ':'
  568 + << std::dec << client_id
  569 + << ','
  570 + // ip
  571 + << '"' << "ip" << '"' << ':'
  572 + << '"' << ip << '"'
  573 + << ','
  574 + // vhost
  575 + << '"' << "vhost" << '"' << ':'
  576 + << '"' << req->vhost << '"'
  577 + << ','
  578 + // app
  579 + << '"' << "app" << '"' << ':'
  580 + << '"' << req->app << '"'
  581 + << ','
  582 + // stream
  583 + << '"' << "stream" << '"' << ':'
  584 + << '"' << req->stream << '"'
  585 + //<< ','
  586 + << "}";
  587 + std::string data = ss.str();
  588 + std::string res;
  589 +
  590 + SrsHttpClient http;
  591 + if ((ret = http.post(&uri, data, res)) != ERROR_SUCCESS) {
  592 + srs_error("http post on_publish uri failed. "
  593 + "client_id=%d, url=%s, request=%s, response=%s, ret=%d",
  594 + client_id, url.c_str(), data.c_str(), res.c_str(), ret);
  595 + return ret;
  596 + }
  597 +
  598 + if (res.empty() || res != SRS_HTTP_RESPONSE_OK) {
  599 + ret = ERROR_HTTP_DATA_INVLIAD;
  600 + srs_error("http hook on_publish validate failed. "
  601 + "client_id=%d, res=%s, ret=%d", client_id, res.c_str(), ret);
  602 + return ret;
  603 + }
  604 +
  605 + srs_trace("http hook on_publish success. "
  606 + "client_id=%d, url=%s, request=%s, response=%s, ret=%d",
  607 + client_id, url.c_str(), data.c_str(), res.c_str(), ret);
  608 +
  609 + return ret;
  610 +}
  611 +
  612 +void SrsHttpHooks::on_unpublish(std::string url, int client_id, std::string ip, SrsRequest* req)
  613 +{
  614 + int ret = ERROR_SUCCESS;
  615 +
  616 + SrsHttpUri uri;
  617 + if ((ret = uri.initialize(url)) != ERROR_SUCCESS) {
  618 + srs_warn("http uri parse on_unpublish url failed, ignored. "
  619 + "client_id=%d, url=%s, ret=%d", client_id, url.c_str(), ret);
  620 + return;
  621 + }
  622 +
  623 + /**
  624 + {
  625 + "action": "on_unpublish",
  626 + "client_id": 1985,
  627 + "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",
  628 + "stream": "livestream"
  629 + }
  630 + */
  631 + std::stringstream ss;
  632 + ss << "{"
  633 + // action
  634 + << '"' << "action" << '"' << ':'
  635 + << '"' << "on_unpublish" << '"'
  636 + << ','
  637 + // client_id
  638 + << '"' << "client_id" << '"' << ':'
  639 + << std::dec << client_id
  640 + << ','
  641 + // ip
  642 + << '"' << "ip" << '"' << ':'
  643 + << '"' << ip << '"'
  644 + << ','
  645 + // vhost
  646 + << '"' << "vhost" << '"' << ':'
  647 + << '"' << req->vhost << '"'
  648 + << ','
  649 + // app
  650 + << '"' << "app" << '"' << ':'
  651 + << '"' << req->app << '"'
  652 + << ','
  653 + // stream
  654 + << '"' << "stream" << '"' << ':'
  655 + << '"' << req->stream << '"'
  656 + //<< ','
  657 + << "}";
  658 + std::string data = ss.str();
  659 + std::string res;
  660 +
  661 + SrsHttpClient http;
  662 + if ((ret = http.post(&uri, data, res)) != ERROR_SUCCESS) {
  663 + srs_warn("http post on_unpublish uri failed, ignored. "
  664 + "client_id=%d, url=%s, request=%s, response=%s, ret=%d",
  665 + client_id, url.c_str(), data.c_str(), res.c_str(), ret);
  666 + return;
  667 + }
  668 +
  669 + if (res.empty() || res != SRS_HTTP_RESPONSE_OK) {
  670 + ret = ERROR_HTTP_DATA_INVLIAD;
  671 + srs_warn("http hook on_unpublish validate failed, ignored. "
  672 + "client_id=%d, res=%s, ret=%d", client_id, res.c_str(), ret);
  673 + return;
  674 + }
  675 +
  676 + srs_trace("http hook on_unpublish success. "
  677 + "client_id=%d, url=%s, request=%s, response=%s, ret=%d",
  678 + client_id, url.c_str(), data.c_str(), res.c_str(), ret);
  679 +
  680 + return;
  681 +}
  682 +
  683 +int SrsHttpHooks::on_play(std::string url, int client_id, std::string ip, SrsRequest* req)
  684 +{
  685 + int ret = ERROR_SUCCESS;
  686 +
  687 + SrsHttpUri uri;
  688 + if ((ret = uri.initialize(url)) != ERROR_SUCCESS) {
  689 + srs_error("http uri parse on_play url failed. "
  690 + "client_id=%d, url=%s, ret=%d", client_id, url.c_str(), ret);
  691 + return ret;
  692 + }
  693 +
  694 + /**
  695 + {
  696 + "action": "on_play",
  697 + "client_id": 1985,
  698 + "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",
  699 + "stream": "livestream"
  700 + }
  701 + */
  702 + std::stringstream ss;
  703 + ss << "{"
  704 + // action
  705 + << '"' << "action" << '"' << ':'
  706 + << '"' << "on_play" << '"'
  707 + << ','
  708 + // client_id
  709 + << '"' << "client_id" << '"' << ':'
  710 + << std::dec << client_id
  711 + << ','
  712 + // ip
  713 + << '"' << "ip" << '"' << ':'
  714 + << '"' << ip << '"'
  715 + << ','
  716 + // vhost
  717 + << '"' << "vhost" << '"' << ':'
  718 + << '"' << req->vhost << '"'
  719 + << ','
  720 + // app
  721 + << '"' << "app" << '"' << ':'
  722 + << '"' << req->app << '"'
  723 + << ','
  724 + // stream
  725 + << '"' << "stream" << '"' << ':'
  726 + << '"' << req->stream << '"'
  727 + //<< ','
  728 + << "}";
  729 + std::string data = ss.str();
  730 + std::string res;
  731 +
  732 + SrsHttpClient http;
  733 + if ((ret = http.post(&uri, data, res)) != ERROR_SUCCESS) {
  734 + srs_error("http post on_play uri failed. "
  735 + "client_id=%d, url=%s, request=%s, response=%s, ret=%d",
  736 + client_id, url.c_str(), data.c_str(), res.c_str(), ret);
  737 + return ret;
  738 + }
  739 +
  740 + if (res.empty() || res != SRS_HTTP_RESPONSE_OK) {
  741 + ret = ERROR_HTTP_DATA_INVLIAD;
  742 + srs_error("http hook on_play validate failed. "
  743 + "client_id=%d, res=%s, ret=%d", client_id, res.c_str(), ret);
  744 + return ret;
  745 + }
  746 +
  747 + srs_trace("http hook on_play success. "
  748 + "client_id=%d, url=%s, request=%s, response=%s, ret=%d",
  749 + client_id, url.c_str(), data.c_str(), res.c_str(), ret);
  750 +
  751 + return ret;
  752 +}
  753 +
  754 +void SrsHttpHooks::on_stop(std::string url, int client_id, std::string ip, SrsRequest* req)
  755 +{
  756 + int ret = ERROR_SUCCESS;
  757 +
  758 + SrsHttpUri uri;
  759 + if ((ret = uri.initialize(url)) != ERROR_SUCCESS) {
  760 + srs_warn("http uri parse on_stop url failed, ignored. "
  761 + "client_id=%d, url=%s, ret=%d", client_id, url.c_str(), ret);
  762 + return;
  763 + }
  764 +
  765 + /**
  766 + {
  767 + "action": "on_stop",
  768 + "client_id": 1985,
  769 + "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live",
  770 + "stream": "livestream"
  771 + }
  772 + */
  773 + std::stringstream ss;
  774 + ss << "{"
  775 + // action
  776 + << '"' << "action" << '"' << ':'
  777 + << '"' << "on_stop" << '"'
  778 + << ','
  779 + // client_id
  780 + << '"' << "client_id" << '"' << ':'
  781 + << std::dec << client_id
  782 + << ','
  783 + // ip
  784 + << '"' << "ip" << '"' << ':'
  785 + << '"' << ip << '"'
  786 + << ','
  787 + // vhost
  788 + << '"' << "vhost" << '"' << ':'
  789 + << '"' << req->vhost << '"'
  790 + << ','
  791 + // app
  792 + << '"' << "app" << '"' << ':'
  793 + << '"' << req->app << '"'
  794 + << ','
  795 + // stream
  796 + << '"' << "stream" << '"' << ':'
  797 + << '"' << req->stream << '"'
  798 + //<< ','
  799 + << "}";
  800 + std::string data = ss.str();
  801 + std::string res;
  802 +
  803 + SrsHttpClient http;
  804 + if ((ret = http.post(&uri, data, res)) != ERROR_SUCCESS) {
  805 + srs_warn("http post on_stop uri failed, ignored. "
  806 + "client_id=%d, url=%s, request=%s, response=%s, ret=%d",
  807 + client_id, url.c_str(), data.c_str(), res.c_str(), ret);
  808 + return;
  809 + }
  810 +
  811 + if (res.empty() || res != SRS_HTTP_RESPONSE_OK) {
  812 + ret = ERROR_HTTP_DATA_INVLIAD;
  813 + srs_warn("http hook on_stop validate failed, ignored. "
  814 + "client_id=%d, res=%s, ret=%d", client_id, res.c_str(), ret);
  815 + return;
  816 + }
  817 +
  818 + srs_trace("http hook on_stop success. "
  819 + "client_id=%d, url=%s, request=%s, response=%s, ret=%d",
  820 + client_id, url.c_str(), data.c_str(), res.c_str(), ret);
  821 +
  822 + return;
  823 +}
  824 +
464 #endif 825 #endif
@@ -120,12 +120,50 @@ public: @@ -120,12 +120,50 @@ public:
120 virtual ~SrsHttpHooks(); 120 virtual ~SrsHttpHooks();
121 public: 121 public:
122 /** 122 /**
123 - * on_connect hook, 123 + * on_connect hook, when client connect to srs.
  124 + * @param client_id the id of client on server.
124 * @param url the api server url, to valid the client. 125 * @param url the api server url, to valid the client.
125 * ignore if empty. 126 * ignore if empty.
126 * @return valid failed or connect to the url failed. 127 * @return valid failed or connect to the url failed.
127 */ 128 */
128 - virtual int on_connect(std::string url, std::string ip, SrsRequest* req); 129 + virtual int on_connect(std::string url, int client_id, std::string ip, SrsRequest* req);
  130 + /**
  131 + * on_close hook, when client disconnect to srs, where client is valid by on_connect.
  132 + * @param client_id the id of client on server.
  133 + * @param url the api server url, to process the event.
  134 + * ignore if empty.
  135 + */
  136 + virtual void on_close(std::string url, int client_id, std::string ip, SrsRequest* req);
  137 + /**
  138 + * on_publish hook, when client(encoder) start to publish stream
  139 + * @param client_id the id of client on server.
  140 + * @param url the api server url, to valid the client.
  141 + * ignore if empty.
  142 + * @return valid failed or connect to the url failed.
  143 + */
  144 + virtual int on_publish(std::string url, int client_id, std::string ip, SrsRequest* req);
  145 + /**
  146 + * on_unpublish hook, when client(encoder) stop publish stream.
  147 + * @param client_id the id of client on server.
  148 + * @param url the api server url, to process the event.
  149 + * ignore if empty.
  150 + */
  151 + virtual void on_unpublish(std::string url, int client_id, std::string ip, SrsRequest* req);
  152 + /**
  153 + * on_play hook, when client start to play stream.
  154 + * @param client_id the id of client on server.
  155 + * @param url the api server url, to valid the client.
  156 + * ignore if empty.
  157 + * @return valid failed or connect to the url failed.
  158 + */
  159 + virtual int on_play(std::string url, int client_id, std::string ip, SrsRequest* req);
  160 + /**
  161 + * on_stop hook, when client stop to play the stream.
  162 + * @param client_id the id of client on server.
  163 + * @param url the api server url, to process the event.
  164 + * ignore if empty.
  165 + */
  166 + virtual void on_stop(std::string url, int client_id, std::string ip, SrsRequest* req);
129 }; 167 };
130 168
131 #endif 169 #endif