winlin

Merge branch '2.0release' into develop

@@ -566,6 +566,8 @@ Supported operating systems and hardware: @@ -566,6 +566,8 @@ Supported operating systems and hardware:
566 566
567 ### SRS 2.0 history 567 ### SRS 2.0 history
568 568
  569 +* v2.0, 2015-04-10, enhanced on_hls_notify, support HTTP GET when reap ts.
  570 +* v2.0, 2015-04-10, refine the hls deviation for floor algorithm.
569 * v2.0, 2015-04-08, for [#375](https://github.com/winlinvip/simple-rtmp-server/issues/375), fix hls bug, keep cc continous between ts files. 2.0.159. 571 * v2.0, 2015-04-08, for [#375](https://github.com/winlinvip/simple-rtmp-server/issues/375), fix hls bug, keep cc continous between ts files. 2.0.159.
570 * v2.0, 2015-04-04, for [#304](https://github.com/winlinvip/simple-rtmp-server/issues/304), rewrite annexb mux for ts, refer to apple sample. 2.0.157. 572 * v2.0, 2015-04-04, for [#304](https://github.com/winlinvip/simple-rtmp-server/issues/304), rewrite annexb mux for ts, refer to apple sample. 2.0.157.
571 * v2.0, 2015-04-03, enhanced avc decode, parse the sps get width+height. 2.0.156. 573 * v2.0, 2015-04-03, enhanced avc decode, parse the sps get width+height. 2.0.156.
@@ -618,6 +618,15 @@ vhost with-hls.srs.com { @@ -618,6 +618,15 @@ vhost with-hls.srs.com {
618 # for the hls http callback, @see http_hooks.on_hls of vhost hooks.callback.srs.com 618 # for the hls http callback, @see http_hooks.on_hls of vhost hooks.callback.srs.com
619 # @read https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_DeliveryHLS#http-callback 619 # @read https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_DeliveryHLS#http-callback
620 # @read https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_DeliveryHLS#http-callback 620 # @read https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_DeliveryHLS#http-callback
  621 +
  622 + # on_hls_notify, never config in here, should config in http_hooks.
  623 + # we support the variables to generate the notify url:
  624 + # [app], replace with the app.
  625 + # [stream], replace with the stream.
  626 + # [ts_url], replace with the ts url.
  627 + # for the hls http callback, @see http_hooks.on_hls_notify of vhost hooks.callback.srs.com
  628 + # @read https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_DeliveryHLS#on-hls-notify
  629 + # @read https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_DeliveryHLS#on-hls-notify
621 } 630 }
622 } 631 }
623 # the vhost with hls disabled. 632 # the vhost with hls disabled.
@@ -768,6 +777,14 @@ vhost hooks.callback.srs.com { @@ -768,6 +777,14 @@ vhost hooks.callback.srs.com {
768 # an int value specifies the error code(0 corresponding to success): 777 # an int value specifies the error code(0 corresponding to success):
769 # 0 778 # 0
770 on_hls http://127.0.0.1:8085/api/v1/hls http://localhost:8085/api/v1/hls; 779 on_hls http://127.0.0.1:8085/api/v1/hls http://localhost:8085/api/v1/hls;
  780 + # when srs reap a ts file of hls, call this hook,
  781 + # used to push file to cdn network, by get the ts file from cdn network.
  782 + # so we use HTTP GET and use the variable following:
  783 + # [app], replace with the app.
  784 + # [stream], replace with the stream.
  785 + # [ts_url], replace with the ts url.
  786 + # ignore any return data of server.
  787 + on_hls_notify http://127.0.0.1:8085/api/v1/hls/[app]/[stream][ts_url];
771 } 788 }
772 } 789 }
773 790
@@ -314,10 +314,24 @@ handle the hls requests: hls stream. @@ -314,10 +314,24 @@ handle the hls requests: hls stream.
314 class RESTHls(object): 314 class RESTHls(object):
315 exposed = True 315 exposed = True
316 316
317 - def GET(self): 317 + '''
  318 + for SRS hook: on_hls_notify
  319 + on_hls_notify:
  320 + when srs reap a ts file of hls, call this hook,
  321 + used to push file to cdn network, by get the ts file from cdn network.
  322 + so we use HTTP GET and use the variable following:
  323 + [app], replace with the app.
  324 + [stream], replace with the stream.
  325 + [ts_url], replace with the ts url.
  326 + ignore any return data of server.
  327 + '''
  328 + def GET(self, *args, **kwargs):
318 enable_crossdomain() 329 enable_crossdomain()
319 330
320 - hls = {} 331 + hls = {
  332 + "args": args,
  333 + "kwargs": kwargs
  334 + }
321 return json.dumps(hls) 335 return json.dumps(hls)
322 336
323 ''' 337 '''
@@ -1499,7 +1499,7 @@ int SrsConfig::check_config() @@ -1499,7 +1499,7 @@ int SrsConfig::check_config()
1499 string m = conf->at(j)->name.c_str(); 1499 string m = conf->at(j)->name.c_str();
1500 if (m != "enabled" && m != "on_connect" && m != "on_close" && m != "on_publish" 1500 if (m != "enabled" && m != "on_connect" && m != "on_close" && m != "on_publish"
1501 && m != "on_unpublish" && m != "on_play" && m != "on_stop" 1501 && m != "on_unpublish" && m != "on_play" && m != "on_stop"
1502 - && m != "on_dvr" && m != "on_hls" 1502 + && m != "on_dvr" && m != "on_hls" && m != "on_hls_notify"
1503 ) { 1503 ) {
1504 ret = ERROR_SYSTEM_CONFIG_INVALID; 1504 ret = ERROR_SYSTEM_CONFIG_INVALID;
1505 srs_error("unsupported vhost http_hooks directive %s, ret=%d", m.c_str(), ret); 1505 srs_error("unsupported vhost http_hooks directive %s, ret=%d", m.c_str(), ret);
@@ -2429,6 +2429,17 @@ SrsConfDirective* SrsConfig::get_vhost_on_hls(string vhost) @@ -2429,6 +2429,17 @@ SrsConfDirective* SrsConfig::get_vhost_on_hls(string vhost)
2429 return conf->get("on_hls"); 2429 return conf->get("on_hls");
2430 } 2430 }
2431 2431
  2432 +SrsConfDirective* SrsConfig::get_vhost_on_hls_notify(string vhost)
  2433 +{
  2434 + SrsConfDirective* conf = get_vhost_http_hooks(vhost);
  2435 +
  2436 + if (!conf) {
  2437 + return NULL;
  2438 + }
  2439 +
  2440 + return conf->get("on_hls_notify");
  2441 +}
  2442 +
2432 bool SrsConfig::get_bw_check_enabled(string vhost) 2443 bool SrsConfig::get_bw_check_enabled(string vhost)
2433 { 2444 {
2434 SrsConfDirective* conf = get_vhost(vhost); 2445 SrsConfDirective* conf = get_vhost(vhost);
@@ -646,6 +646,11 @@ public: @@ -646,6 +646,11 @@ public:
646 * @return the on_hls callback directive, the args is the url to callback. 646 * @return the on_hls callback directive, the args is the url to callback.
647 */ 647 */
648 virtual SrsConfDirective* get_vhost_on_hls(std::string vhost); 648 virtual SrsConfDirective* get_vhost_on_hls(std::string vhost);
  649 + /**
  650 + * get the on_hls_notify callbacks of vhost.
  651 + * @return the on_hls_notify callback directive, the args is the url to callback.
  652 + */
  653 + virtual SrsConfDirective* get_vhost_on_hls_notify(std::string vhost);
649 // bwct(bandwidth check tool) section 654 // bwct(bandwidth check tool) section
650 public: 655 public:
651 /** 656 /**
@@ -59,10 +59,10 @@ using namespace std; @@ -59,10 +59,10 @@ using namespace std;
59 // drop the segment when duration of ts too small. 59 // drop the segment when duration of ts too small.
60 #define SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS 100 60 #define SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS 100
61 61
62 -// startup piece, the first piece, fragment percent to reap.  
63 -#define SRS_HLS_FLOOR_STARTUP_PERCENT 0.1  
64 // fragment plus the deviation percent. 62 // fragment plus the deviation percent.
65 #define SRS_HLS_FLOOR_REAP_PERCENT 0.2 63 #define SRS_HLS_FLOOR_REAP_PERCENT 0.2
  64 +// reset the piece id when deviation overflow this.
  65 +#define SRS_JUMP_WHEN_PIECE_DEVIATION 10
66 66
67 ISrsHlsHandler::ISrsHlsHandler() 67 ISrsHlsHandler::ISrsHlsHandler()
68 { 68 {
@@ -213,9 +213,49 @@ int SrsDvrAsyncCallOnHls::call() @@ -213,9 +213,49 @@ int SrsDvrAsyncCallOnHls::call()
213 213
214 string SrsDvrAsyncCallOnHls::to_string() 214 string SrsDvrAsyncCallOnHls::to_string()
215 { 215 {
216 - std::stringstream ss;  
217 - ss << "vhost=" << req->vhost << ", file=" << path;  
218 - return ss.str(); 216 + return "on_hls: " + path;
  217 +}
  218 +
  219 +SrsDvrAsyncCallOnHlsNotify::SrsDvrAsyncCallOnHlsNotify(SrsRequest* r, string u)
  220 +{
  221 + req = r;
  222 + ts_url = u;
  223 +}
  224 +
  225 +SrsDvrAsyncCallOnHlsNotify::~SrsDvrAsyncCallOnHlsNotify()
  226 +{
  227 +}
  228 +
  229 +int SrsDvrAsyncCallOnHlsNotify::call()
  230 +{
  231 + int ret = ERROR_SUCCESS;
  232 +
  233 +#ifdef SRS_AUTO_HTTP_CALLBACK
  234 + // http callback for on_hls_notify in config.
  235 + if (_srs_config->get_vhost_http_hooks_enabled(req->vhost)) {
  236 + // HTTP: on_hls
  237 + SrsConfDirective* on_hls = _srs_config->get_vhost_on_hls_notify(req->vhost);
  238 + if (!on_hls) {
  239 + srs_info("ignore the empty http callback: on_hls_notify");
  240 + return ret;
  241 + }
  242 +
  243 + for (int i = 0; i < (int)on_hls->args.size(); i++) {
  244 + std::string url = on_hls->args.at(i);
  245 + if ((ret = SrsHttpHooks::on_hls_notify(url, req, ts_url)) != ERROR_SUCCESS) {
  246 + srs_error("hook client on_hls_notify failed. url=%s, ret=%d", url.c_str(), ret);
  247 + return ret;
  248 + }
  249 + }
  250 + }
  251 +#endif
  252 +
  253 + return ret;
  254 +}
  255 +
  256 +string SrsDvrAsyncCallOnHlsNotify::to_string()
  257 +{
  258 + return "on_hls_notify: " + ts_url;
219 } 259 }
220 260
221 SrsHlsMuxer::SrsHlsMuxer() 261 SrsHlsMuxer::SrsHlsMuxer()
@@ -224,7 +264,7 @@ SrsHlsMuxer::SrsHlsMuxer() @@ -224,7 +264,7 @@ SrsHlsMuxer::SrsHlsMuxer()
224 handler = NULL; 264 handler = NULL;
225 hls_fragment = hls_window = 0; 265 hls_fragment = hls_window = 0;
226 hls_aof_ratio = 1.0; 266 hls_aof_ratio = 1.0;
227 - hls_fragment_deviation = 0; 267 + deviation_ts = 0;
228 hls_cleanup = true; 268 hls_cleanup = true;
229 previous_floor_ts = 0; 269 previous_floor_ts = 0;
230 accept_floor_ts = 0; 270 accept_floor_ts = 0;
@@ -269,26 +309,14 @@ double SrsHlsMuxer::duration() @@ -269,26 +309,14 @@ double SrsHlsMuxer::duration()
269 return current? current->duration:0; 309 return current? current->duration:0;
270 } 310 }
271 311
272 -double SrsHlsMuxer::deviation() 312 +int SrsHlsMuxer::deviation()
273 { 313 {
274 // no floor, no deviation. 314 // no floor, no deviation.
275 if (!hls_ts_floor) { 315 if (!hls_ts_floor) {
276 return 0; 316 return 0;
277 } 317 }
278 318
279 - return hls_fragment_deviation;  
280 -}  
281 -  
282 -int SrsHlsMuxer::absolute_deviation()  
283 -{  
284 - // no floor, no deviation.  
285 - if (!hls_ts_floor) {  
286 - return 0;  
287 - }  
288 -  
289 - // accept the floor ts for the first piece.  
290 - int64_t floor_ts = (int64_t)(srs_get_system_time_ms() / (1000 * hls_fragment));  
291 - return (int)(accept_floor_ts - (floor_ts - 1)); 319 + return deviation_ts;
292 } 320 }
293 321
294 int SrsHlsMuxer::initialize(ISrsHlsHandler* h) 322 int SrsHlsMuxer::initialize(ISrsHlsHandler* h)
@@ -323,9 +351,7 @@ int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix, @@ -323,9 +351,7 @@ int SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix,
323 previous_floor_ts = 0; 351 previous_floor_ts = 0;
324 accept_floor_ts = 0; 352 accept_floor_ts = 0;
325 hls_window = window; 353 hls_window = window;
326 - // for the first time, we set to -N% of fragment,  
327 - // that is, the first piece always smaller.  
328 - hls_fragment_deviation = -1 * (fragment * SRS_HLS_FLOOR_STARTUP_PERCENT); 354 + deviation_ts = 0;
329 355
330 // generate the m3u8 dir and path. 356 // generate the m3u8 dir and path.
331 m3u8 = path + "/" + m3u8_file; 357 m3u8 = path + "/" + m3u8_file;
@@ -412,26 +438,39 @@ int SrsHlsMuxer::segment_open(int64_t segment_start_dts) @@ -412,26 +438,39 @@ int SrsHlsMuxer::segment_open(int64_t segment_start_dts)
412 ts_file = srs_path_build_stream(ts_file, req->vhost, req->app, req->stream); 438 ts_file = srs_path_build_stream(ts_file, req->vhost, req->app, req->stream);
413 if (hls_ts_floor) { 439 if (hls_ts_floor) {
414 // accept the floor ts for the first piece. 440 // accept the floor ts for the first piece.
415 - int64_t floor_ts = (int64_t)(srs_get_system_time_ms() / (1000 * hls_fragment)); 441 + int64_t current_floor_ts = (int64_t)(srs_get_system_time_ms() / (1000 * hls_fragment));
416 if (!accept_floor_ts) { 442 if (!accept_floor_ts) {
417 - accept_floor_ts = floor_ts - 1; 443 + accept_floor_ts = current_floor_ts - 1;
418 } else { 444 } else {
419 accept_floor_ts++; 445 accept_floor_ts++;
420 } 446 }
421 447
  448 + // jump when deviation more than 10p
  449 + if (accept_floor_ts - current_floor_ts > SRS_JUMP_WHEN_PIECE_DEVIATION) {
  450 + srs_warn("hls: jmp for ts deviation, current=%"PRId64", accept=%"PRId64, current_floor_ts, accept_floor_ts);
  451 + accept_floor_ts = current_floor_ts - 1;
  452 + }
  453 +
  454 + // when reap ts, adjust the deviation.
  455 + deviation_ts = (int)(accept_floor_ts - current_floor_ts);
  456 +
  457 + // dup/jmp detect for ts in floor mode.
  458 + if (previous_floor_ts && previous_floor_ts != current_floor_ts - 1) {
  459 + srs_warn("hls: dup or jmp for floor ts, previous=%"PRId64", current=%"PRId64", accept=%"PRId64", deviation=%d",
  460 + previous_floor_ts, current_floor_ts, accept_floor_ts, deviation_ts);
  461 + }
  462 + previous_floor_ts = current_floor_ts;
  463 +
422 // we always ensure the piece is increase one by one. 464 // we always ensure the piece is increase one by one.
423 std::stringstream ts_floor; 465 std::stringstream ts_floor;
424 ts_floor << accept_floor_ts; 466 ts_floor << accept_floor_ts;
425 ts_file = srs_string_replace(ts_file, "[timestamp]", ts_floor.str()); 467 ts_file = srs_string_replace(ts_file, "[timestamp]", ts_floor.str());
426 468
427 - // dup/jmp detect for ts in floor mode.  
428 - if (previous_floor_ts && previous_floor_ts != floor_ts - 1) {  
429 - srs_warn("hls: dup or jmp for floor ts, previous=%"PRId64", current=%"PRId64", ts=%s, deviation=%.2f",  
430 - previous_floor_ts, floor_ts, ts_file.c_str(), hls_fragment_deviation);  
431 - }  
432 - previous_floor_ts = floor_ts;  
433 - } 469 + // TODO: FIMXE: we must use the accept ts floor time to generate the hour variable.
  470 + ts_file = srs_path_build_timestamp(ts_file);
  471 + } else {
434 ts_file = srs_path_build_timestamp(ts_file); 472 ts_file = srs_path_build_timestamp(ts_file);
  473 + }
435 if (true) { 474 if (true) {
436 std::stringstream ss; 475 std::stringstream ss;
437 ss << current->sequence_no; 476 ss << current->sequence_no;
@@ -497,7 +536,7 @@ bool SrsHlsMuxer::is_segment_overflow() @@ -497,7 +536,7 @@ bool SrsHlsMuxer::is_segment_overflow()
497 srs_assert(current); 536 srs_assert(current);
498 537
499 // use N% deviation, to smoother. 538 // use N% deviation, to smoother.
500 - double deviation = hls_ts_floor? SRS_HLS_FLOOR_REAP_PERCENT * hls_fragment_deviation : 0.0; 539 + double deviation = hls_ts_floor? SRS_HLS_FLOOR_REAP_PERCENT * deviation_ts * hls_fragment : 0.0;
501 540
502 return current->duration >= hls_fragment + deviation; 541 return current->duration >= hls_fragment + deviation;
503 } 542 }
@@ -594,19 +633,19 @@ int SrsHlsMuxer::segment_close(string log_desc) @@ -594,19 +633,19 @@ int SrsHlsMuxer::segment_close(string log_desc)
594 if (current->duration * 1000 >= SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS) { 633 if (current->duration * 1000 >= SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS) {
595 segments.push_back(current); 634 segments.push_back(current);
596 635
597 - // when reap ts, adjust the deviation.  
598 - if (hls_ts_floor) {  
599 - hls_fragment_deviation += (double)(hls_fragment - current->duration); 636 + // use async to call the http hooks, for it will cause thread switch.
  637 + if ((ret = async->call(new SrsDvrAsyncCallOnHls(req, current->full_path, current->sequence_no, current->duration))) != ERROR_SUCCESS) {
  638 + return ret;
600 } 639 }
601 640
602 // use async to call the http hooks, for it will cause thread switch. 641 // use async to call the http hooks, for it will cause thread switch.
603 - if ((ret = async->call(new SrsDvrAsyncCallOnHls(req, current->full_path, current->sequence_no, current->duration))) != ERROR_SUCCESS) { 642 + if ((ret = async->call(new SrsDvrAsyncCallOnHlsNotify(req, current->uri))) != ERROR_SUCCESS) {
604 return ret; 643 return ret;
605 } 644 }
606 645
607 - srs_info("%s reap ts segment, sequence_no=%d, uri=%s, duration=%.2f, start=%"PRId64", deviation=%.2f", 646 + srs_info("%s reap ts segment, sequence_no=%d, uri=%s, duration=%.2f, start=%"PRId64,
608 log_desc.c_str(), current->sequence_no, current->uri.c_str(), current->duration, 647 log_desc.c_str(), current->sequence_no, current->uri.c_str(), current->duration,
609 - current->segment_start_dts, hls_fragment_deviation); 648 + current->segment_start_dts);
610 649
611 // notify handler for update ts. 650 // notify handler for update ts.
612 srs_assert(current->writer); 651 srs_assert(current->writer);
@@ -1222,9 +1261,9 @@ void SrsHls::hls_show_mux_log() @@ -1222,9 +1261,9 @@ void SrsHls::hls_show_mux_log()
1222 // the run time is not equals to stream time, 1261 // the run time is not equals to stream time,
1223 // @see: https://github.com/winlinvip/simple-rtmp-server/issues/81#issuecomment-48100994 1262 // @see: https://github.com/winlinvip/simple-rtmp-server/issues/81#issuecomment-48100994
1224 // it's ok. 1263 // it's ok.
1225 - srs_trace("-> "SRS_CONSTS_LOG_HLS" time=%"PRId64", stream dts=%"PRId64"(%"PRId64"ms), sno=%d, ts=%s, dur=%.2f, dva=%.2fs/%dp", 1264 + srs_trace("-> "SRS_CONSTS_LOG_HLS" time=%"PRId64", stream dts=%"PRId64"(%"PRId64"ms), sno=%d, ts=%s, dur=%.2f, dva=%dp",
1226 pprint->age(), stream_dts, stream_dts / 90, muxer->sequence_no(), muxer->ts_url().c_str(), 1265 pprint->age(), stream_dts, stream_dts / 90, muxer->sequence_no(), muxer->ts_url().c_str(),
1227 - muxer->duration(), muxer->deviation(), muxer->absolute_deviation()); 1266 + muxer->duration(), muxer->deviation());
1228 } 1267 }
1229 } 1268 }
1230 1269
@@ -157,7 +157,7 @@ public: @@ -157,7 +157,7 @@ public:
157 }; 157 };
158 158
159 /** 159 /**
160 - * the dvr async call. 160 + * the hls async call: on_hls
161 */ 161 */
162 class SrsDvrAsyncCallOnHls : public ISrsDvrAsyncCall 162 class SrsDvrAsyncCallOnHls : public ISrsDvrAsyncCall
163 { 163 {
@@ -175,6 +175,22 @@ public: @@ -175,6 +175,22 @@ public:
175 }; 175 };
176 176
177 /** 177 /**
  178 + * the hls async call: on_hls_notify
  179 + */
  180 +class SrsDvrAsyncCallOnHlsNotify : public ISrsDvrAsyncCall
  181 +{
  182 +private:
  183 + std::string ts_url;
  184 + SrsRequest* req;
  185 +public:
  186 + SrsDvrAsyncCallOnHlsNotify(SrsRequest* r, std::string u);
  187 + virtual ~SrsDvrAsyncCallOnHlsNotify();
  188 +public:
  189 + virtual int call();
  190 + virtual std::string to_string();
  191 +};
  192 +
  193 +/**
178 * muxer the HLS stream(m3u8 and ts files). 194 * muxer the HLS stream(m3u8 and ts files).
179 * generally, the m3u8 muxer only provides methods to open/close segments, 195 * generally, the m3u8 muxer only provides methods to open/close segments,
180 * to flush video/audio, without any mechenisms. 196 * to flush video/audio, without any mechenisms.
@@ -199,9 +215,9 @@ private: @@ -199,9 +215,9 @@ private:
199 private: 215 private:
200 // whether use floor algorithm for timestamp. 216 // whether use floor algorithm for timestamp.
201 bool hls_ts_floor; 217 bool hls_ts_floor;
202 - // the deviation in seconds to adjust the fragment to be more 218 + // the deviation in piece to adjust the fragment to be more
203 // bigger or smaller. 219 // bigger or smaller.
204 - double hls_fragment_deviation; 220 + int deviation_ts;
205 // the previous reap floor timestamp, 221 // the previous reap floor timestamp,
206 // used to detect the dup or jmp or ts. 222 // used to detect the dup or jmp or ts.
207 int64_t accept_floor_ts; 223 int64_t accept_floor_ts;
@@ -242,8 +258,7 @@ public: @@ -242,8 +258,7 @@ public:
242 virtual int sequence_no(); 258 virtual int sequence_no();
243 virtual std::string ts_url(); 259 virtual std::string ts_url();
244 virtual double duration(); 260 virtual double duration();
245 - virtual double deviation();  
246 - virtual int absolute_deviation(); 261 + virtual int deviation();
247 public: 262 public:
248 /** 263 /**
249 * initialize the hls muxer. 264 * initialize the hls muxer.
@@ -37,6 +37,7 @@ using namespace std; @@ -37,6 +37,7 @@ using namespace std;
37 #include <srs_app_http_client.hpp> 37 #include <srs_app_http_client.hpp>
38 #include <srs_core_autofree.hpp> 38 #include <srs_core_autofree.hpp>
39 #include <srs_app_config.hpp> 39 #include <srs_app_config.hpp>
  40 +#include <srs_kernel_utility.hpp>
40 41
41 #define SRS_HTTP_RESPONSE_OK SRS_XSTR(ERROR_SUCCESS) 42 #define SRS_HTTP_RESPONSE_OK SRS_XSTR(ERROR_SUCCESS)
42 43
@@ -325,6 +326,55 @@ int SrsHttpHooks::on_hls(string url, SrsRequest* req, string file, int sn, doubl @@ -325,6 +326,55 @@ int SrsHttpHooks::on_hls(string url, SrsRequest* req, string file, int sn, doubl
325 return ret; 326 return ret;
326 } 327 }
327 328
  329 +int SrsHttpHooks::on_hls_notify(std::string url, SrsRequest* req, std::string ts_url)
  330 +{
  331 + int ret = ERROR_SUCCESS;
  332 +
  333 + int client_id = _srs_context->get_id();
  334 + std::string cwd = _srs_config->cwd();
  335 +
  336 + if (srs_string_starts_with(ts_url, "http://") || srs_string_starts_with(ts_url, "https://")) {
  337 + url = ts_url;
  338 + }
  339 +
  340 + url = srs_string_replace(url, "[app]", req->app);
  341 + url = srs_string_replace(url, "[stream]", req->stream);
  342 + url = srs_string_replace(url, "[ts_url]", ts_url);
  343 +
  344 + SrsHttpUri uri;
  345 + if ((ret = uri.initialize(url)) != ERROR_SUCCESS) {
  346 + srs_error("http: post failed. url=%s, ret=%d", url.c_str(), ret);
  347 + return ret;
  348 + }
  349 +
  350 + SrsHttpClient http;
  351 + if ((ret = http.initialize(uri.get_host(), uri.get_port())) != ERROR_SUCCESS) {
  352 + return ret;
  353 + }
  354 +
  355 + SrsHttpMessage* msg = NULL;
  356 + if ((ret = http.get(uri.get_path(), "", &msg)) != ERROR_SUCCESS) {
  357 + return ret;
  358 + }
  359 + SrsAutoFree(SrsHttpMessage, msg);
  360 +
  361 + ISrsHttpResponseReader* br = msg->body_reader();
  362 + while (!br->eof()) {
  363 + std::string data;
  364 + if ((ret = br->read(data)) != ERROR_SUCCESS) {
  365 + break;
  366 + }
  367 + }
  368 +
  369 + srs_trace("http hook on_hls_notify success. client_id=%d, url=%s, code=%d, ret=%d",
  370 + client_id, url.c_str(), msg->status_code(), ret);
  371 +
  372 + // ignore any error for on_hls_notify.
  373 + ret = ERROR_SUCCESS;
  374 +
  375 + return ret;
  376 +}
  377 +
328 int SrsHttpHooks::do_post(std::string url, std::string req, int& code, string& res) 378 int SrsHttpHooks::do_post(std::string url, std::string req, int& code, string& res)
329 { 379 {
330 int ret = ERROR_SUCCESS; 380 int ret = ERROR_SUCCESS;
@@ -105,6 +105,13 @@ public: @@ -105,6 +105,13 @@ public:
105 * @param duration the segment duration in seconds. 105 * @param duration the segment duration in seconds.
106 */ 106 */
107 static int on_hls(std::string url, SrsRequest* req, std::string file, int sn, double duration); 107 static int on_hls(std::string url, SrsRequest* req, std::string file, int sn, double duration);
  108 + /**
  109 + * when hls reap segment, callback.
  110 + * @param url the api server url, to process the event.
  111 + * ignore if empty.
  112 + * @param ts_url the ts uri, used to replace the variable [ts_url] in url.
  113 + */
  114 + static int on_hls_notify(std::string url, SrsRequest* req, std::string ts_url);
108 private: 115 private:
109 static int do_post(std::string url, std::string req, int& code, std::string& res); 116 static int do_post(std::string url, std::string req, int& code, std::string& res);
110 }; 117 };