diff --git a/trunk/src/app/srs_app_pithy_print.hpp b/trunk/src/app/srs_app_pithy_print.hpp index 518584809..df1052c43 100644 --- a/trunk/src/app/srs_app_pithy_print.hpp +++ b/trunk/src/app/srs_app_pithy_print.hpp @@ -54,6 +54,7 @@ class SrsPithyPrint private: int client_id; int stage_id; + // in ms. int64_t age; int64_t printed_age; public: diff --git a/trunk/src/app/srs_app_rtmp_conn.cpp b/trunk/src/app/srs_app_rtmp_conn.cpp index 532d86003..40daa0b43 100644 --- a/trunk/src/app/srs_app_rtmp_conn.cpp +++ b/trunk/src/app/srs_app_rtmp_conn.cpp @@ -254,13 +254,13 @@ int SrsRtmpConn::stream_service_cycle() int ret = ERROR_SUCCESS; SrsRtmpConnType type; - if ((ret = rtmp->identify_client(res->stream_id, type, req->stream)) != ERROR_SUCCESS) { + if ((ret = rtmp->identify_client(res->stream_id, type, req->stream, req->duration)) != ERROR_SUCCESS) { srs_error("identify client failed. ret=%d", ret); return ret; } req->strip(); - srs_trace("identify client success. type=%s, stream_name=%s", - srs_client_type_string(type).c_str(), req->stream.c_str()); + srs_trace("identify client success. type=%s, stream_name=%s, duration=%.2f", + srs_client_type_string(type).c_str(), req->stream.c_str(), req->duration); // client is identified, set the timeout to service timeout. rtmp->set_recv_timeout(SRS_RECV_TIMEOUT_US); @@ -417,6 +417,15 @@ int SrsRtmpConn::playing(SrsSource* source) while (true) { pithy_print.elapse(SRS_PULSE_TIMEOUT_US / 1000); + // if duration specified, and exceed it, stop play live. + // @see: https://github.com/winlinvip/simple-rtmp-server/issues/45 + // TODO: maybe the duration should use the stream duration. + if (req->duration > 0 && pithy_print.get_age() >= (int64_t)req->duration) { + ret = ERROR_RTMP_DURATION_EXCEED; + srs_trace("stop live for duration exceed. ret=%d", ret); + return ret; + } + // switch to other st-threads. st_usleep(0); diff --git a/trunk/src/core/srs_core.hpp b/trunk/src/core/srs_core.hpp index 23dac206b..704804b13 100644 --- a/trunk/src/core/srs_core.hpp +++ b/trunk/src/core/srs_core.hpp @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // current release version #define VERSION_MAJOR "0" #define VERSION_MINOR "9" -#define VERSION_REVISION "61" +#define VERSION_REVISION "62" #define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION // server info. #define RTMP_SIG_SRS_KEY "srs" diff --git a/trunk/src/kernel/srs_kernel_error.hpp b/trunk/src/kernel/srs_kernel_error.hpp index c299fb177..2c4e09d44 100644 --- a/trunk/src/kernel/srs_kernel_error.hpp +++ b/trunk/src/kernel/srs_kernel_error.hpp @@ -75,6 +75,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // 1. srs is ok, ignore and turn to simple handshake. // 2. srs-librtmp return error, to terminate the program. #define ERROR_RTMP_HS_SSL_REQUIRE 318 +#define ERROR_RTMP_DURATION_EXCEED 319 #define ERROR_SYSTEM_STREAM_INIT 400 #define ERROR_SYSTEM_PACKET_INVALID 401 diff --git a/trunk/src/rtmp/srs_protocol_rtmp.cpp b/trunk/src/rtmp/srs_protocol_rtmp.cpp index d38cdfcfd..f27ff6fc3 100644 --- a/trunk/src/rtmp/srs_protocol_rtmp.cpp +++ b/trunk/src/rtmp/srs_protocol_rtmp.cpp @@ -74,6 +74,7 @@ using namespace std; SrsRequest::SrsRequest() { objectEncoding = RTMP_SIG_AMF0_VER; + duration = -1; } SrsRequest::~SrsRequest() @@ -94,6 +95,7 @@ SrsRequest* SrsRequest::copy() cp->swfUrl = swfUrl; cp->tcUrl = tcUrl; cp->vhost = vhost; + cp->duration = duration; return cp; } @@ -940,7 +942,7 @@ int SrsRtmpServer::on_bw_done() return ret; } -int SrsRtmpServer::identify_client(int stream_id, SrsRtmpConnType& type, string& stream_name) +int SrsRtmpServer::identify_client(int stream_id, SrsRtmpConnType& type, string& stream_name, double& duration) { type = SrsRtmpConnUnknown; int ret = ERROR_SUCCESS; @@ -968,7 +970,7 @@ int SrsRtmpServer::identify_client(int stream_id, SrsRtmpConnType& type, string& SrsPacket* pkt = msg->get_packet(); if (dynamic_cast(pkt)) { srs_info("identify client by create stream, play or flash publish."); - return identify_create_stream_client(dynamic_cast(pkt), stream_id, type, stream_name); + return identify_create_stream_client(dynamic_cast(pkt), stream_id, type, stream_name, duration); } if (dynamic_cast(pkt)) { srs_info("identify client by releaseStream, fmle publish."); @@ -976,7 +978,7 @@ int SrsRtmpServer::identify_client(int stream_id, SrsRtmpConnType& type, string& } if (dynamic_cast(pkt)) { srs_info("level0 identify client by play."); - return identify_play_client(dynamic_cast(pkt), type, stream_name); + return identify_play_client(dynamic_cast(pkt), type, stream_name, duration); } srs_trace("ignore AMF0/AMF3 command message."); @@ -1373,7 +1375,7 @@ int SrsRtmpServer::start_flash_publish(int stream_id) return ret; } -int SrsRtmpServer::identify_create_stream_client(SrsCreateStreamPacket* req, int stream_id, SrsRtmpConnType& type, string& stream_name) +int SrsRtmpServer::identify_create_stream_client(SrsCreateStreamPacket* req, int stream_id, SrsRtmpConnType& type, string& stream_name, double& duration) { int ret = ERROR_SUCCESS; @@ -1413,7 +1415,7 @@ int SrsRtmpServer::identify_create_stream_client(SrsCreateStreamPacket* req, int SrsPacket* pkt = msg->get_packet(); if (dynamic_cast(pkt)) { srs_info("level1 identify client by play."); - return identify_play_client(dynamic_cast(pkt), type, stream_name); + return identify_play_client(dynamic_cast(pkt), type, stream_name, duration); } if (dynamic_cast(pkt)) { srs_info("identify client by publish, falsh publish."); @@ -1460,14 +1462,15 @@ int SrsRtmpServer::identify_flash_publish_client(SrsPublishPacket* req, SrsRtmpC return ret; } -int SrsRtmpServer::identify_play_client(SrsPlayPacket* req, SrsRtmpConnType& type, string& stream_name) +int SrsRtmpServer::identify_play_client(SrsPlayPacket* req, SrsRtmpConnType& type, string& stream_name, double& duration) { int ret = ERROR_SUCCESS; type = SrsRtmpConnPlay; stream_name = req->stream_name; + duration = req->duration; - srs_trace("identity client type=play, stream_name=%s", stream_name.c_str()); + srs_trace("identity client type=play, stream_name=%s, duration=%.2f", stream_name.c_str(), duration); return ret; } diff --git a/trunk/src/rtmp/srs_protocol_rtmp.hpp b/trunk/src/rtmp/srs_protocol_rtmp.hpp index 5c7099072..09b3f6af8 100644 --- a/trunk/src/rtmp/srs_protocol_rtmp.hpp +++ b/trunk/src/rtmp/srs_protocol_rtmp.hpp @@ -67,6 +67,12 @@ public: std::string app; std::string stream; + // for play live stream, + // used to specified the stop when exceed the duration. + // @see https://github.com/winlinvip/simple-rtmp-server/issues/45 + // in ms. + double duration; + SrsRequest(); virtual ~SrsRequest(); @@ -222,8 +228,10 @@ public: * @stream_id, client will createStream to play or publish by flash, * the stream_id used to response the createStream request. * @type, output the client type. + * @stream_name, output the client publish/play stream name. @see: SrsRequest.stream + * @duration, output the play client duration. @see: SrsRequest.duration */ - virtual int identify_client(int stream_id, SrsRtmpConnType& type, std::string& stream_name); + virtual int identify_client(int stream_id, SrsRtmpConnType& type, std::string& stream_name, double& duration); /** * set the chunk size when client type identified. */ @@ -267,11 +275,11 @@ public: */ virtual int start_flash_publish(int stream_id); private: - virtual int identify_create_stream_client(SrsCreateStreamPacket* req, int stream_id, SrsRtmpConnType& type, std::string& stream_name); + virtual int identify_create_stream_client(SrsCreateStreamPacket* req, int stream_id, SrsRtmpConnType& type, std::string& stream_name, double& duration); virtual int identify_fmle_publish_client(SrsFMLEStartPacket* req, SrsRtmpConnType& type, std::string& stream_name); virtual int identify_flash_publish_client(SrsPublishPacket* req, SrsRtmpConnType& type, std::string& stream_name); private: - virtual int identify_play_client(SrsPlayPacket* req, SrsRtmpConnType& type, std::string& stream_name); + virtual int identify_play_client(SrsPlayPacket* req, SrsRtmpConnType& type, std::string& stream_name, double& duration); }; #endif