diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 18067353fd..2da52a1447 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -1199,7 +1199,8 @@ vhost hooks.callback.srs.com { # "action": "on_publish", # "client_id": "9308h583", # "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live", - # "stream": "livestream", "param":"?token=xxx&salt=yyy", "server_id": "vid-werty" + # "stream": "livestream", "param":"?token=xxx&salt=yyy", "server_id": "vid-werty", + # "stream_url": "video.test.com/live/livestream", "stream_id": "vid-124q9y3" # } # if valid, the hook must return HTTP code 200(Status OK) and response # an int value specifies the error code(0 corresponding to success): @@ -1215,7 +1216,8 @@ vhost hooks.callback.srs.com { # "action": "on_unpublish", # "client_id": "9308h583", # "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live", - # "stream": "livestream", "param":"?token=xxx&salt=yyy", "server_id": "vid-werty" + # "stream": "livestream", "param":"?token=xxx&salt=yyy", "server_id": "vid-werty", + # "stream_url": "video.test.com/live/livestream", "stream_id": "vid-124q9y3" # } # if valid, the hook must return HTTP code 200(Status OK) and response # an int value specifies the error code(0 corresponding to success): @@ -1232,7 +1234,8 @@ vhost hooks.callback.srs.com { # "client_id": "9308h583", # "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live", # "stream": "livestream", "param":"?token=xxx&salt=yyy", - # "pageUrl": "http://www.test.com/live.html", "server_id": "vid-werty" + # "pageUrl": "http://www.test.com/live.html", "server_id": "vid-werty", + # "stream_url": "video.test.com/live/livestream", "stream_id": "vid-124q9y3" # } # if valid, the hook must return HTTP code 200(Status OK) and response # an int value specifies the error code(0 corresponding to success): @@ -1248,7 +1251,8 @@ vhost hooks.callback.srs.com { # "action": "on_stop", # "client_id": "9308h583", # "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live", - # "stream": "livestream", "param":"?token=xxx&salt=yyy", "server_id": "vid-werty" + # "stream": "livestream", "param":"?token=xxx&salt=yyy", "server_id": "vid-werty", + # "stream_url": "video.test.com/live/livestream", "stream_id": "vid-124q9y3" # } # if valid, the hook must return HTTP code 200(Status OK) and response # an int value specifies the error code(0 corresponding to success): @@ -1266,7 +1270,8 @@ vhost hooks.callback.srs.com { # "ip": "192.168.1.10", "vhost": "video.test.com", "app": "live", # "stream": "livestream", "param":"?token=xxx&salt=yyy", # "cwd": "/usr/local/srs", - # "file": "./objs/nginx/html/live/livestream.1420254068776.flv", "server_id": "vid-werty" + # "file": "./objs/nginx/html/live/livestream.1420254068776.flv", "server_id": "vid-werty", + # "stream_url": "video.test.com/live/livestream", "stream_id": "vid-124q9y3" # } # if valid, the hook must return HTTP code 200(Status OK) and response # an int value specifies the error code(0 corresponding to success): @@ -1285,7 +1290,8 @@ vhost hooks.callback.srs.com { # "url": "live/livestream/2015-04-23/01/476584165.ts", # "m3u8": "./objs/nginx/html/live/livestream/live.m3u8", # "m3u8_url": "live/livestream/live.m3u8", - # "seq_no": 100, "server_id": "vid-werty" + # "seq_no": 100, "server_id": "vid-werty", + # "stream_url": "video.test.com/live/livestream", "stream_id": "vid-124q9y3" # } # if valid, the hook must return HTTP code 200(Status OK) and response # an int value specifies the error code(0 corresponding to success): diff --git a/trunk/doc/CHANGELOG.md b/trunk/doc/CHANGELOG.md index b76f54c11e..aa5b7d9625 100644 --- a/trunk/doc/CHANGELOG.md +++ b/trunk/doc/CHANGELOG.md @@ -7,6 +7,7 @@ The changelog for SRS. ## SRS 5.0 Changelog +* v5.0, 2022-08-30, Fix [#2837](https://github.com/ossrs/srs/issues/2837): Callback: Support stream_url and stream_id. v5.0.55 * v5.0, 2022-08-30, STAT: Refine tcUrl for SRT/RTC. v5.0.54 * v5.0, 2022-08-30, Refactor: Extract SrsNetworkKbps from SrsKbps. v5.0.53 * v5.0, 2022-08-30, Remove bandwidth check because falsh is disabled. v5.0.52 diff --git a/trunk/src/app/srs_app_http_conn.cpp b/trunk/src/app/srs_app_http_conn.cpp index 7e22233bb5..6860a6f0ce 100644 --- a/trunk/src/app/srs_app_http_conn.cpp +++ b/trunk/src/app/srs_app_http_conn.cpp @@ -292,6 +292,7 @@ SrsHttpxConn::SrsHttpxConn(bool https, ISrsResourceManager* cm, srs_netfd_t fd, manager = cm; skt = new SrsTcpConnection(fd); + enable_stat_ = false; if (https) { ssl = new SrsSslConnection(skt); @@ -313,6 +314,11 @@ SrsHttpxConn::~SrsHttpxConn() srs_freep(skt); } +void SrsHttpxConn::set_enable_stat(bool v) +{ + enable_stat_ = v; +} + srs_error_t SrsHttpxConn::pop_message(ISrsHttpMessage** preq) { srs_error_t err = srs_success; @@ -399,9 +405,8 @@ srs_error_t SrsHttpxConn::on_message_done(ISrsHttpMessage* r, SrsHttpResponseWri srs_error_t SrsHttpxConn::on_conn_done(srs_error_t r0) { // Only stat the HTTP streaming clients, ignore all API clients. - bool exists = false; - SrsStatistic::instance()->on_disconnect(get_id().c_str(), &exists); - if (exists) { + if (enable_stat_) { + SrsStatistic::instance()->on_disconnect(get_id().c_str()); SrsStatistic::instance()->kbps_add_delta(get_id().c_str(), conn->delta()); } diff --git a/trunk/src/app/srs_app_http_conn.hpp b/trunk/src/app/srs_app_http_conn.hpp index 3cc143ed33..5970cd9ee1 100644 --- a/trunk/src/app/srs_app_http_conn.hpp +++ b/trunk/src/app/srs_app_http_conn.hpp @@ -131,10 +131,14 @@ class SrsHttpxConn : public ISrsConnection, public ISrsStartable, public ISrsHtt SrsTcpConnection* skt; SrsSslConnection* ssl; SrsHttpConn* conn; + // We should never enable the stat, unless HTTP stream connection requires. + bool enable_stat_; public: SrsHttpxConn(bool https, ISrsResourceManager* cm, srs_netfd_t fd, ISrsHttpServeMux* m, std::string cip, int port); virtual ~SrsHttpxConn(); public: + // Require statistic about HTTP connection, for HTTP streaming clients only. + void set_enable_stat(bool v); // Directly read a HTTP request message. // It's exported for HTTP stream, such as HTTP FLV, only need to write to client when // serving it, but we need to start a thread to read message to detect whether FD is closed. diff --git a/trunk/src/app/srs_app_http_hooks.cpp b/trunk/src/app/srs_app_http_hooks.cpp index 34f3fbe1ee..ccbcb91845 100644 --- a/trunk/src/app/srs_app_http_hooks.cpp +++ b/trunk/src/app/srs_app_http_hooks.cpp @@ -127,7 +127,7 @@ srs_error_t SrsHttpHooks::on_publish(string url, SrsRequest* req) SrsJsonObject* obj = SrsJsonAny::object(); SrsAutoFree(SrsJsonObject, obj); - + obj->set("server_id", SrsJsonAny::str(stat->server_id().c_str())); obj->set("action", SrsJsonAny::str("on_publish")); obj->set("client_id", SrsJsonAny::str(cid.c_str())); @@ -137,6 +137,12 @@ srs_error_t SrsHttpHooks::on_publish(string url, SrsRequest* req) obj->set("tcUrl", SrsJsonAny::str(req->tcUrl.c_str())); obj->set("stream", SrsJsonAny::str(req->stream.c_str())); obj->set("param", SrsJsonAny::str(req->param.c_str())); + + obj->set("stream_url", SrsJsonAny::str(req->get_stream_url().c_str())); + SrsStatisticStream* stream = stat->find_stream_by_url(req->get_stream_url()); + if (stream) { + obj->set("stream_id", SrsJsonAny::str(stream->id.c_str())); + } std::string data = obj->dumps(); std::string res; @@ -171,8 +177,15 @@ void SrsHttpHooks::on_unpublish(string url, SrsRequest* req) obj->set("ip", SrsJsonAny::str(req->ip.c_str())); obj->set("vhost", SrsJsonAny::str(req->vhost.c_str())); obj->set("app", SrsJsonAny::str(req->app.c_str())); + obj->set("tcUrl", SrsJsonAny::str(req->tcUrl.c_str())); obj->set("stream", SrsJsonAny::str(req->stream.c_str())); obj->set("param", SrsJsonAny::str(req->param.c_str())); + + obj->set("stream_url", SrsJsonAny::str(req->get_stream_url().c_str())); + SrsStatisticStream* stream = stat->find_stream_by_url(req->get_stream_url()); + if (stream) { + obj->set("stream_id", SrsJsonAny::str(stream->id.c_str())); + } std::string data = obj->dumps(); std::string res; @@ -211,8 +224,15 @@ srs_error_t SrsHttpHooks::on_play(string url, SrsRequest* req) obj->set("vhost", SrsJsonAny::str(req->vhost.c_str())); obj->set("app", SrsJsonAny::str(req->app.c_str())); obj->set("stream", SrsJsonAny::str(req->stream.c_str())); + obj->set("tcUrl", SrsJsonAny::str(req->tcUrl.c_str())); obj->set("param", SrsJsonAny::str(req->param.c_str())); obj->set("pageUrl", SrsJsonAny::str(req->pageUrl.c_str())); + + obj->set("stream_url", SrsJsonAny::str(req->get_stream_url().c_str())); + SrsStatisticStream* stream = stat->find_stream_by_url(req->get_stream_url()); + if (stream) { + obj->set("stream_id", SrsJsonAny::str(stream->id.c_str())); + } std::string data = obj->dumps(); std::string res; @@ -247,8 +267,15 @@ void SrsHttpHooks::on_stop(string url, SrsRequest* req) obj->set("ip", SrsJsonAny::str(req->ip.c_str())); obj->set("vhost", SrsJsonAny::str(req->vhost.c_str())); obj->set("app", SrsJsonAny::str(req->app.c_str())); + obj->set("tcUrl", SrsJsonAny::str(req->tcUrl.c_str())); obj->set("stream", SrsJsonAny::str(req->stream.c_str())); obj->set("param", SrsJsonAny::str(req->param.c_str())); + + obj->set("stream_url", SrsJsonAny::str(req->get_stream_url().c_str())); + SrsStatisticStream* stream = stat->find_stream_by_url(req->get_stream_url()); + if (stream) { + obj->set("stream_id", SrsJsonAny::str(stream->id.c_str())); + } std::string data = obj->dumps(); std::string res; @@ -287,10 +314,17 @@ srs_error_t SrsHttpHooks::on_dvr(SrsContextId c, string url, SrsRequest* req, st obj->set("ip", SrsJsonAny::str(req->ip.c_str())); obj->set("vhost", SrsJsonAny::str(req->vhost.c_str())); obj->set("app", SrsJsonAny::str(req->app.c_str())); + obj->set("tcUrl", SrsJsonAny::str(req->tcUrl.c_str())); obj->set("stream", SrsJsonAny::str(req->stream.c_str())); obj->set("param", SrsJsonAny::str(req->param.c_str())); obj->set("cwd", SrsJsonAny::str(cwd.c_str())); obj->set("file", SrsJsonAny::str(file.c_str())); + + obj->set("stream_url", SrsJsonAny::str(req->get_stream_url().c_str())); + SrsStatisticStream* stream = stat->find_stream_by_url(req->get_stream_url()); + if (stream) { + obj->set("stream_id", SrsJsonAny::str(stream->id.c_str())); + } std::string data = obj->dumps(); std::string res; @@ -332,6 +366,7 @@ srs_error_t SrsHttpHooks::on_hls(SrsContextId c, string url, SrsRequest* req, st obj->set("ip", SrsJsonAny::str(req->ip.c_str())); obj->set("vhost", SrsJsonAny::str(req->vhost.c_str())); obj->set("app", SrsJsonAny::str(req->app.c_str())); + obj->set("tcUrl", SrsJsonAny::str(req->tcUrl.c_str())); obj->set("stream", SrsJsonAny::str(req->stream.c_str())); obj->set("param", SrsJsonAny::str(req->param.c_str())); obj->set("duration", SrsJsonAny::number(srsu2ms(duration)/1000.0)); @@ -341,6 +376,12 @@ srs_error_t SrsHttpHooks::on_hls(SrsContextId c, string url, SrsRequest* req, st obj->set("m3u8", SrsJsonAny::str(m3u8.c_str())); obj->set("m3u8_url", SrsJsonAny::str(m3u8_url.c_str())); obj->set("seq_no", SrsJsonAny::integer(sn)); + + obj->set("stream_url", SrsJsonAny::str(req->get_stream_url().c_str())); + SrsStatisticStream* stream = stat->find_stream_by_url(req->get_stream_url()); + if (stream) { + obj->set("stream_id", SrsJsonAny::str(stream->id.c_str())); + } std::string data = obj->dumps(); std::string res; diff --git a/trunk/src/app/srs_app_http_static.cpp b/trunk/src/app/srs_app_http_static.cpp index b9e3d5a2fb..930d0bfdca 100644 --- a/trunk/src/app/srs_app_http_static.cpp +++ b/trunk/src/app/srs_app_http_static.cpp @@ -128,6 +128,13 @@ srs_error_t SrsHlsStream::serve_new_session(ISrsHttpResponseWriter* w, ISrsHttpM SrsContextRestore(_srs_context->get_id()); _srs_context->set_id(SrsContextId().set_value(ctx)); + // We must do stat the client before hooks, because hooks depends on it. + SrsStatistic* stat = SrsStatistic::instance(); + if ((err = stat->on_client(ctx, req, NULL, SrsHlsPlay)) != srs_success) { + return srs_error_wrap(err, "stat on client"); + } + + // We must do hook after stat, because depends on it. if ((err = http_hooks_on_play(req)) != srs_success) { return srs_error_wrap(err, "HLS: http_hooks_on_play"); } @@ -155,12 +162,6 @@ srs_error_t SrsHlsStream::serve_new_session(ISrsHttpResponseWriter* w, ISrsHttpM return srs_error_wrap(err, "final request"); } - // update the statistic when source disconveried. - SrsStatistic* stat = SrsStatistic::instance(); - if ((err = stat->on_client(ctx, req, NULL, SrsHlsPlay)) != srs_success) { - return srs_error_wrap(err, "stat on client"); - } - return err; } @@ -497,6 +498,13 @@ srs_error_t SrsVodStream::serve_ts_ctx(ISrsHttpResponseWriter * w, ISrsHttpMessa // SrsServer also stat all HTTP connections including this one, but it should be ignored because the id is not // matched to any exists client. And we will do stat for the HLS streaming by session in hls_ctx. + SrsHttpMessage* hr = dynamic_cast(r); + SrsHttpConn* hc = dynamic_cast(hr->connection()); + SrsHttpxConn* hxc = dynamic_cast(hc->handler()); + + // Note that we never enable the stat for the HTTP connection, because we always stat the pseudo HLS streaming + // session identified by hls_ctx, which served by an SrsHlsStream object. + hxc->set_enable_stat(false); // Serve by default HLS handler. err = SrsHttpFileServer::serve_ts_ctx(w, r, fullpath); diff --git a/trunk/src/app/srs_app_http_stream.cpp b/trunk/src/app/srs_app_http_stream.cpp index 246f54b1e5..b143124caa 100755 --- a/trunk/src/app/srs_app_http_stream.cpp +++ b/trunk/src/app/srs_app_http_stream.cpp @@ -524,10 +524,28 @@ srs_error_t SrsLiveStream::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage { srs_error_t err = srs_success; + SrsHttpMessage* hr = dynamic_cast(r); + SrsHttpConn* hc = dynamic_cast(hr->connection()); + SrsHttpxConn* hxc = dynamic_cast(hc->handler()); + + // Note that we should enable stat for HTTP streaming client, because each HTTP streaming connection is a real + // session that should have statistics for itself. + hxc->set_enable_stat(true); + // Correct the app and stream by path, which is created from template. // @remark Be careful that the stream has extension now, might cause identify fail. req->stream = srs_path_basename(r->path()); - + + // update client ip + req->ip = hc->remote_ip(); + + // We must do stat the client before hooks, because hooks depends on it. + SrsStatistic* stat = SrsStatistic::instance(); + if ((err = stat->on_client(_srs_context->get_id().c_str(), req, hc, SrsFlvPlay)) != srs_success) { + return srs_error_wrap(err, "stat on client"); + } + + // We must do hook after stat, because depends on it. if ((err = http_hooks_on_play(r)) != srs_success) { return srs_error_wrap(err, "http hook"); } @@ -591,15 +609,6 @@ srs_error_t SrsLiveStream::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMess SrsHttpMessage* hr = dynamic_cast(r); SrsHttpConn* hc = dynamic_cast(hr->connection()); - // update client ip - req->ip = hc->remote_ip(); - - // update the statistic when source disconveried. - SrsStatistic* stat = SrsStatistic::instance(); - if ((err = stat->on_client(_srs_context->get_id().c_str(), req, hc, SrsFlvPlay)) != srs_success) { - return srs_error_wrap(err, "stat on client"); - } - // the memory writer. SrsBufferWriter writer(w); if ((err = enc->initialize(&writer, cache)) != srs_success) { @@ -616,25 +625,25 @@ srs_error_t SrsLiveStream::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMess // Try to use fast flv encoder, remember that it maybe NULL. SrsFlvStreamEncoder* ffe = dynamic_cast(enc); - // Note that the handler of hc now is rohc. - SrsHttpxConn* rohc = dynamic_cast(hc->handler()); - srs_assert(rohc); + // Note that the handler of hc now is hxc. + SrsHttpxConn* hxc = dynamic_cast(hc->handler()); + srs_assert(hxc); // Set the socket options for transport. bool tcp_nodelay = _srs_config->get_tcp_nodelay(req->vhost); if (tcp_nodelay) { - if ((err = rohc->set_tcp_nodelay(tcp_nodelay)) != srs_success) { + if ((err = hxc->set_tcp_nodelay(tcp_nodelay)) != srs_success) { return srs_error_wrap(err, "set tcp nodelay"); } } srs_utime_t mw_sleep = _srs_config->get_mw_sleep(req->vhost); - if ((err = rohc->set_socket_buffer(mw_sleep)) != srs_success) { + if ((err = hxc->set_socket_buffer(mw_sleep)) != srs_success) { return srs_error_wrap(err, "set mw_sleep %" PRId64, mw_sleep); } // Start a thread to receive all messages from client, then drop them. - SrsHttpRecvThread* trd = new SrsHttpRecvThread(rohc); + SrsHttpRecvThread* trd = new SrsHttpRecvThread(hxc); SrsAutoFree(SrsHttpRecvThread, trd); if ((err = trd->start()) != srs_success) { diff --git a/trunk/src/app/srs_app_rtc_api.cpp b/trunk/src/app/srs_app_rtc_api.cpp index fc698b7ef4..5ae6b31b7d 100644 --- a/trunk/src/app/srs_app_rtc_api.cpp +++ b/trunk/src/app/srs_app_rtc_api.cpp @@ -130,10 +130,6 @@ srs_error_t SrsGoApiRtcPlay::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMe ruc.req_->vhost = parsed_vhost->arg0(); } - if ((err = http_hooks_on_play(ruc.req_)) != srs_success) { - return srs_error_wrap(err, "RTC: http_hooks_on_play"); - } - // For client to specifies the candidate(EIP) of server. string eip = r->query_get("eip"); if (eip.empty()) { @@ -202,11 +198,17 @@ srs_error_t SrsGoApiRtcPlay::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMe } // TODO: FIXME: When server enabled, but vhost disabled, should report error. + // We must do stat the client before hooks, because hooks depends on it. SrsRtcConnection* session = NULL; if ((err = server_->create_session(&ruc, local_sdp, &session)) != srs_success) { return srs_error_wrap(err, "create session, dtls=%u, srtp=%u, eip=%s", ruc.dtls_, ruc.srtp_, eip.c_str()); } + // We must do hook after stat, because depends on it. + if ((err = http_hooks_on_play(ruc.req_)) != srs_success) { + return srs_error_wrap(err, "RTC: http_hooks_on_play"); + } + ostringstream os; if ((err = local_sdp.encode(os)) != srs_success) { return srs_error_wrap(err, "encode sdp"); @@ -406,10 +408,6 @@ srs_error_t SrsGoApiRtcPublish::do_serve_http(ISrsHttpResponseWriter* w, ISrsHtt ruc.req_->vhost = parsed_vhost->arg0(); } - if ((err = http_hooks_on_publish(ruc.req_)) != srs_success) { - return srs_error_wrap(err, "RTC: http_hooks_on_publish"); - } - // For client to specifies the candidate(EIP) of server. string eip = r->query_get("eip"); if (eip.empty()) { @@ -455,11 +453,17 @@ srs_error_t SrsGoApiRtcPublish::do_serve_http(ISrsHttpResponseWriter* w, ISrsHtt } // TODO: FIXME: When server enabled, but vhost disabled, should report error. + // We must do stat the client before hooks, because hooks depends on it. SrsRtcConnection* session = NULL; if ((err = server_->create_session(&ruc, local_sdp, &session)) != srs_success) { return srs_error_wrap(err, "create session"); } + // We must do hook after stat, because depends on it. + if ((err = http_hooks_on_publish(ruc.req_)) != srs_success) { + return srs_error_wrap(err, "RTC: http_hooks_on_publish"); + } + ostringstream os; if ((err = local_sdp.encode(os)) != srs_success) { return srs_error_wrap(err, "encode sdp"); diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp index 712fa09b0a..908be90bd4 100644 --- a/trunk/src/app/srs_app_rtc_conn.cpp +++ b/trunk/src/app/srs_app_rtc_conn.cpp @@ -471,6 +471,12 @@ srs_error_t SrsRtcPlayStream::initialize(SrsRequest* req, std::mapcopy(); + // We must do stat the client before hooks, because hooks depends on it. + SrsStatistic* stat = SrsStatistic::instance(); + if ((err = stat->on_client(cid_.c_str(), req_, session_, SrsRtcConnPlay)) != srs_success) { + return srs_error_wrap(err, "rtc: stat client"); + } + if ((err = _srs_rtc_sources->fetch_or_create(req_, &source_)) != srs_success) { return srs_error_wrap(err, "rtc fetch source failed"); } @@ -588,12 +594,6 @@ srs_error_t SrsRtcPlayStream::start() return srs_error_wrap(err, "on start play"); } } - - // update the statistic when client discoveried. - SrsStatistic* stat = SrsStatistic::instance(); - if ((err = stat->on_client(cid_.c_str(), req_, session_, SrsRtcConnPlay)) != srs_success) { - return srs_error_wrap(err, "rtc: stat client"); - } is_started = true; @@ -1130,6 +1130,12 @@ srs_error_t SrsRtcPublishStream::initialize(SrsRequest* r, SrsRtcSourceDescripti req_ = r->copy(); + // We must do stat the client before hooks, because hooks depends on it. + SrsStatistic* stat = SrsStatistic::instance(); + if ((err = stat->on_client(cid_.c_str(), req_, session_, SrsRtcConnPublish)) != srs_success) { + return srs_error_wrap(err, "rtc: stat client"); + } + if (stream_desc->audio_track_desc_) { audio_tracks_.push_back(new SrsRtcAudioRecvTrack(session_, stream_desc->audio_track_desc_)); } @@ -1236,12 +1242,6 @@ srs_error_t SrsRtcPublishStream::start() return srs_error_wrap(err, "on start publish"); } } - - // update the statistic when client discoveried. - SrsStatistic* stat = SrsStatistic::instance(); - if ((err = stat->on_client(cid_.c_str(), req_, session_, SrsRtcConnPublish)) != srs_success) { - return srs_error_wrap(err, "rtc: stat client"); - } is_started = true; diff --git a/trunk/src/app/srs_app_rtmp_conn.cpp b/trunk/src/app/srs_app_rtmp_conn.cpp index 65bd81482f..023a90fd1e 100644 --- a/trunk/src/app/srs_app_rtmp_conn.cpp +++ b/trunk/src/app/srs_app_rtmp_conn.cpp @@ -524,6 +524,14 @@ srs_error_t SrsRtmpConn::stream_service_cycle() if ((err = rtmp->start_play(info->res->stream_id)) != srs_success) { return srs_error_wrap(err, "rtmp: start play"); } + + // We must do stat the client before hooks, because hooks depends on it. + SrsStatistic* stat = SrsStatistic::instance(); + if ((err = stat->on_client(_srs_context->get_id().c_str(), req, this, info->type)) != srs_success) { + return srs_error_wrap(err, "rtmp: stat client"); + } + + // We must do hook after stat, because depends on it. if ((err = http_hooks_on_play()) != srs_success) { return srs_error_wrap(err, "rtmp: callback on play"); } @@ -690,12 +698,6 @@ srs_error_t SrsRtmpConn::do_playing(SrsLiveSource* source, SrsLiveConsumer* cons SrsRequest* req = info->req; srs_assert(req); srs_assert(consumer); - - // update the statistic when source disconveried. - SrsStatistic* stat = SrsStatistic::instance(); - if ((err = stat->on_client(_srs_context->get_id().c_str(), req, this, info->type)) != srs_success) { - return srs_error_wrap(err, "rtmp: stat client"); - } // initialize other components SrsPithyPrint* pprint = SrsPithyPrint::create_rtmp_play(); @@ -824,7 +826,14 @@ srs_error_t SrsRtmpConn::publishing(SrsLiveSource* source) return srs_error_wrap(err, "rtmp: referer check"); } } - + + // We must do stat the client before hooks, because hooks depends on it. + SrsStatistic* stat = SrsStatistic::instance(); + if ((err = stat->on_client(_srs_context->get_id().c_str(), req, this, info->type)) != srs_success) { + return srs_error_wrap(err, "rtmp: stat client"); + } + + // We must do hook after stat, because depends on it. if ((err = http_hooks_on_publish()) != srs_success) { return srs_error_wrap(err, "rtmp: callback on publish"); } @@ -860,12 +869,6 @@ srs_error_t SrsRtmpConn::do_publishing(SrsLiveSource* source, SrsPublishRecvThre SrsPithyPrint* pprint = SrsPithyPrint::create_rtmp_publish(); SrsAutoFree(SrsPithyPrint, pprint); - // update the statistic when source disconveried. - SrsStatistic* stat = SrsStatistic::instance(); - if ((err = stat->on_client(_srs_context->get_id().c_str(), req, this, info->type)) != srs_success) { - return srs_error_wrap(err, "rtmp: stat client"); - } - // start isolate recv thread. // TODO: FIXME: Pass the callback here. if ((err = rtrd->start()) != srs_success) { diff --git a/trunk/src/app/srs_app_srt_conn.cpp b/trunk/src/app/srs_app_srt_conn.cpp index a6bedb312c..97c35d96dd 100644 --- a/trunk/src/app/srs_app_srt_conn.cpp +++ b/trunk/src/app/srs_app_srt_conn.cpp @@ -302,7 +302,14 @@ srs_error_t SrsMpegtsSrtConn::do_cycle() srs_error_t SrsMpegtsSrtConn::publishing() { srs_error_t err = srs_success; - + + // We must do stat the client before hooks, because hooks depends on it. + SrsStatistic* stat = SrsStatistic::instance(); + if ((err = stat->on_client(_srs_context->get_id().c_str(), req_, this, SrsSrtConnPublish)) != srs_success) { + return srs_error_wrap(err, "srt: stat client"); + } + + // We must do hook after stat, because depends on it. if ((err = http_hooks_on_publish()) != srs_success) { return srs_error_wrap(err, "srt: callback on publish"); } @@ -321,14 +328,16 @@ srs_error_t SrsMpegtsSrtConn::playing() { srs_error_t err = srs_success; - if ((err = http_hooks_on_play()) != srs_success) { - return srs_error_wrap(err, "rtmp: callback on play"); - } - + // We must do stat the client before hooks, because hooks depends on it. SrsStatistic* stat = SrsStatistic::instance(); if ((err = stat->on_client(_srs_context->get_id().c_str(), req_, this, SrsSrtConnPlay)) != srs_success) { return srs_error_wrap(err, "rtmp: stat client"); } + + // We must do hook after stat, because depends on it. + if ((err = http_hooks_on_play()) != srs_success) { + return srs_error_wrap(err, "rtmp: callback on play"); + } err = do_playing(); http_hooks_on_stop(); @@ -385,11 +394,6 @@ srs_error_t SrsMpegtsSrtConn::do_publishing() SrsPithyPrint* pprint = SrsPithyPrint::create_srt_publish(); SrsAutoFree(SrsPithyPrint, pprint); - SrsStatistic* stat = SrsStatistic::instance(); - if ((err = stat->on_client(_srs_context->get_id().c_str(), req_, this, SrsSrtConnPublish)) != srs_success) { - return srs_error_wrap(err, "srt: stat client"); - } - int nb_packets = 0; // Max udp packet size equal to 1500. diff --git a/trunk/src/app/srs_app_statistic.cpp b/trunk/src/app/srs_app_statistic.cpp index dd37df89a1..e156ba442c 100644 --- a/trunk/src/app/srs_app_statistic.cpp +++ b/trunk/src/app/srs_app_statistic.cpp @@ -114,6 +114,8 @@ srs_error_t SrsStatisticStream::dumps(SrsJsonObject* obj) obj->set("name", SrsJsonAny::str(stream.c_str())); obj->set("vhost", SrsJsonAny::str(vhost->id.c_str())); obj->set("app", SrsJsonAny::str(app.c_str())); + obj->set("tcUrl", SrsJsonAny::str(tcUrl.c_str())); + obj->set("url", SrsJsonAny::str(url.c_str())); obj->set("live_ms", SrsJsonAny::integer(srsu2ms(srs_get_system_time()))); obj->set("clients", SrsJsonAny::integer(nb_clients)); obj->set("frames", SrsJsonAny::integer(frames->sugar)); @@ -218,6 +220,7 @@ srs_error_t SrsStatisticClient::dumps(SrsJsonObject* obj) obj->set("swfUrl", SrsJsonAny::str(req->swfUrl.c_str())); obj->set("tcUrl", SrsJsonAny::str(req->tcUrl.c_str())); obj->set("url", SrsJsonAny::str(req->get_stream_url().c_str())); + obj->set("name", SrsJsonAny::str(req->stream.c_str())); obj->set("type", SrsJsonAny::str(srs_client_type_string(type).c_str())); obj->set("publish", SrsJsonAny::boolean(srs_client_type_is_publish(type))); obj->set("alive", SrsJsonAny::number(srsu2ms(srs_get_system_time() - create) / 1000.0)); @@ -311,6 +314,15 @@ SrsStatisticStream* SrsStatistic::find_stream(string sid) return NULL; } +SrsStatisticStream* SrsStatistic::find_stream_by_url(string url) +{ + std::map::iterator it; + if ((it = rstreams.find(url)) != rstreams.end()) { + return it->second; + } + return NULL; +} + SrsStatisticClient* SrsStatistic::find_client(string client_id) { std::map::iterator it; @@ -413,10 +425,9 @@ srs_error_t SrsStatistic::on_client(std::string id, SrsRequest* req, ISrsExpire* return err; } -void SrsStatistic::on_disconnect(std::string id, bool* exists) +void SrsStatistic::on_disconnect(std::string id) { std::map::iterator it = clients.find(id); - if (exists) *exists = (it != clients.end()); if (it == clients.end()) return; SrsStatisticClient* client = it->second; @@ -683,7 +694,12 @@ SrsStatisticVhost* SrsStatistic::create_vhost(SrsRequest* req) SrsStatisticStream* SrsStatistic::create_stream(SrsStatisticVhost* vhost, SrsRequest* req) { - std::string url = req->get_stream_url(); + // To identify a stream, use url without extension, for example, the bellow are the same stream: + // ossrs.io/live/livestream + // ossrs.io/live/livestream.flv + // ossrs.io/live/livestream.m3u8 + // Note that we also don't use schema, and vhost is optional. + string url = req->get_stream_url(); SrsStatisticStream* stream = NULL; @@ -694,6 +710,7 @@ SrsStatisticStream* SrsStatistic::create_stream(SrsStatisticVhost* vhost, SrsReq stream->stream = req->stream; stream->app = req->app; stream->url = url; + stream->tcUrl = req->tcUrl; rstreams[url] = stream; streams[stream->id] = stream; return stream; diff --git a/trunk/src/app/srs_app_statistic.hpp b/trunk/src/app/srs_app_statistic.hpp index 07d9a918a3..2b54d55b28 100644 --- a/trunk/src/app/srs_app_statistic.hpp +++ b/trunk/src/app/srs_app_statistic.hpp @@ -53,6 +53,7 @@ struct SrsStatisticStream std::string app; std::string stream; std::string url; + std::string tcUrl; bool active; // The publisher connection id. std::string publisher_id; @@ -147,6 +148,7 @@ class SrsStatistic virtual SrsStatisticVhost* find_vhost_by_id(std::string vid); virtual SrsStatisticVhost* find_vhost_by_name(std::string name); virtual SrsStatisticStream* find_stream(std::string sid); + virtual SrsStatisticStream* find_stream_by_url(std::string url); virtual SrsStatisticClient* find_client(std::string client_id); public: // When got video info for stream. @@ -175,7 +177,7 @@ class SrsStatistic // @remark the on_disconnect always call, while the on_client is call when // only got the request object, so the client specified by id maybe not // exists in stat. - virtual void on_disconnect(std::string id, bool* exists = NULL); + virtual void on_disconnect(std::string id); private: // Cleanup the stream if stream is not active and for the last client. void cleanup_stream(SrsStatisticStream* stream); diff --git a/trunk/src/core/srs_core_version5.hpp b/trunk/src/core/srs_core_version5.hpp index 8745650045..3e3eb5815e 100644 --- a/trunk/src/core/srs_core_version5.hpp +++ b/trunk/src/core/srs_core_version5.hpp @@ -9,6 +9,6 @@ #define VERSION_MAJOR 5 #define VERSION_MINOR 0 -#define VERSION_REVISION 54 +#define VERSION_REVISION 55 #endif