diff --git a/trunk/configure b/trunk/configure index 57444e793..bc525c891 100755 --- a/trunk/configure +++ b/trunk/configure @@ -157,7 +157,7 @@ KERNEL_OBJS="${MODULE_OBJS[@]}" MODULE_ID="PROTOCOL" MODULE_DEPENDS=("CORE" "KERNEL") ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSSLRoot}) -MODULE_FILES=("srs_rtmp_amf0" "srs_rtmp_io" "srs_rtmp_stack" "srs_rtmp_sdk" +MODULE_FILES=("srs_rtmp_amf0" "srs_rtmp_io" "srs_rtmp_stack" "srs_rtmp_handshake" "srs_rtmp_utility" "srs_rtmp_msg_array" "srs_protocol_buffer" "srs_raw_avc" "srs_rtsp_stack" "srs_http_stack" "srs_protocol_kbps") PROTOCOL_INCS="src/protocol"; MODULE_DIR=${PROTOCOL_INCS} . auto/modules.sh diff --git a/trunk/ide/srs_upp/srs_upp.upp b/trunk/ide/srs_upp/srs_upp.upp index e80292576..b8eeba9dd 100755 --- a/trunk/ide/srs_upp/srs_upp.upp +++ b/trunk/ide/srs_upp/srs_upp.upp @@ -64,8 +64,6 @@ file ../../src/protocol/srs_rtmp_io.cpp, ../../src/protocol/srs_rtmp_msg_array.hpp, ../../src/protocol/srs_rtmp_msg_array.cpp, - ../../src/protocol/srs_rtmp_sdk.hpp, - ../../src/protocol/srs_rtmp_sdk.cpp, ../../src/protocol/srs_rtmp_stack.hpp, ../../src/protocol/srs_rtmp_stack.cpp, ../../src/protocol/srs_rtmp_utility.hpp, diff --git a/trunk/ide/srs_vs2010/srs.vcxproj b/trunk/ide/srs_vs2010/srs.vcxproj index 5ddd7892f..b2d0fea37 100755 --- a/trunk/ide/srs_vs2010/srs.vcxproj +++ b/trunk/ide/srs_vs2010/srs.vcxproj @@ -125,7 +125,6 @@ - @@ -208,7 +207,6 @@ - diff --git a/trunk/ide/srs_vs2010/srs.vcxproj.filters b/trunk/ide/srs_vs2010/srs.vcxproj.filters index 5a60d8b86..568d30380 100755 --- a/trunk/ide/srs_vs2010/srs.vcxproj.filters +++ b/trunk/ide/srs_vs2010/srs.vcxproj.filters @@ -214,9 +214,6 @@ srs - - srs - srs @@ -414,9 +411,6 @@ srs - - srs - srs @@ -450,4 +444,4 @@ {d45a9ecb-fcbe-4400-abe3-792cddecb47e} - \ No newline at end of file + diff --git a/trunk/ide/srs_xcode/srs_xcode.xcodeproj/project.pbxproj b/trunk/ide/srs_xcode/srs_xcode.xcodeproj/project.pbxproj index a6fbb1079..490ee5273 100644 --- a/trunk/ide/srs_xcode/srs_xcode.xcodeproj/project.pbxproj +++ b/trunk/ide/srs_xcode/srs_xcode.xcodeproj/project.pbxproj @@ -31,7 +31,6 @@ 3C1232441AAE81A400CE8F6C /* srs_rtmp_handshake.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C1232331AAE81A400CE8F6C /* srs_rtmp_handshake.cpp */; }; 3C1232451AAE81A400CE8F6C /* srs_rtmp_io.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C1232351AAE81A400CE8F6C /* srs_rtmp_io.cpp */; }; 3C1232461AAE81A400CE8F6C /* srs_rtmp_msg_array.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C1232371AAE81A400CE8F6C /* srs_rtmp_msg_array.cpp */; }; - 3C1232471AAE81A400CE8F6C /* srs_rtmp_sdk.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C1232391AAE81A400CE8F6C /* srs_rtmp_sdk.cpp */; }; 3C1232481AAE81A400CE8F6C /* srs_rtmp_stack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C12323B1AAE81A400CE8F6C /* srs_rtmp_stack.cpp */; }; 3C1232491AAE81A400CE8F6C /* srs_rtmp_utility.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C12323D1AAE81A400CE8F6C /* srs_rtmp_utility.cpp */; }; 3C12324A1AAE81A400CE8F6C /* srs_rtsp_stack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C12323F1AAE81A400CE8F6C /* srs_rtsp_stack.cpp */; }; @@ -172,8 +171,6 @@ 3C1232361AAE81A400CE8F6C /* srs_rtmp_io.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = srs_rtmp_io.hpp; path = ../../../src/protocol/srs_rtmp_io.hpp; sourceTree = ""; }; 3C1232371AAE81A400CE8F6C /* srs_rtmp_msg_array.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = srs_rtmp_msg_array.cpp; path = ../../../src/protocol/srs_rtmp_msg_array.cpp; sourceTree = ""; }; 3C1232381AAE81A400CE8F6C /* srs_rtmp_msg_array.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = srs_rtmp_msg_array.hpp; path = ../../../src/protocol/srs_rtmp_msg_array.hpp; sourceTree = ""; }; - 3C1232391AAE81A400CE8F6C /* srs_rtmp_sdk.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = srs_rtmp_sdk.cpp; path = ../../../src/protocol/srs_rtmp_sdk.cpp; sourceTree = ""; }; - 3C12323A1AAE81A400CE8F6C /* srs_rtmp_sdk.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = srs_rtmp_sdk.hpp; path = ../../../src/protocol/srs_rtmp_sdk.hpp; sourceTree = ""; }; 3C12323B1AAE81A400CE8F6C /* srs_rtmp_stack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = srs_rtmp_stack.cpp; path = ../../../src/protocol/srs_rtmp_stack.cpp; sourceTree = ""; }; 3C12323C1AAE81A400CE8F6C /* srs_rtmp_stack.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = srs_rtmp_stack.hpp; path = ../../../src/protocol/srs_rtmp_stack.hpp; sourceTree = ""; }; 3C12323D1AAE81A400CE8F6C /* srs_rtmp_utility.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = srs_rtmp_utility.cpp; path = ../../../src/protocol/srs_rtmp_utility.cpp; sourceTree = ""; }; @@ -508,8 +505,6 @@ 3C1232361AAE81A400CE8F6C /* srs_rtmp_io.hpp */, 3C1232371AAE81A400CE8F6C /* srs_rtmp_msg_array.cpp */, 3C1232381AAE81A400CE8F6C /* srs_rtmp_msg_array.hpp */, - 3C1232391AAE81A400CE8F6C /* srs_rtmp_sdk.cpp */, - 3C12323A1AAE81A400CE8F6C /* srs_rtmp_sdk.hpp */, 3C12323B1AAE81A400CE8F6C /* srs_rtmp_stack.cpp */, 3C12323C1AAE81A400CE8F6C /* srs_rtmp_stack.hpp */, 3C12323D1AAE81A400CE8F6C /* srs_rtmp_utility.cpp */, @@ -935,7 +930,6 @@ 3C663F141AB0155100286D8B /* srs_flv_parser.c in Sources */, 3C1232451AAE81A400CE8F6C /* srs_rtmp_io.cpp in Sources */, 3C1232211AAE814D00CE8F6C /* srs_kernel_buffer.cpp in Sources */, - 3C1232471AAE81A400CE8F6C /* srs_rtmp_sdk.cpp in Sources */, 3C36DB5B1ABD1CB90066CCAF /* srs_lib_bandwidth.cpp in Sources */, 3C12329D1AAE81D900CE8F6C /* srs_app_heartbeat.cpp in Sources */, 3C1232231AAE814D00CE8F6C /* srs_kernel_consts.cpp in Sources */, diff --git a/trunk/src/app/srs_app_bandwidth.cpp b/trunk/src/app/srs_app_bandwidth.cpp index 51252e15d..79b13c87b 100644 --- a/trunk/src/app/srs_app_bandwidth.cpp +++ b/trunk/src/app/srs_app_bandwidth.cpp @@ -29,7 +29,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. using namespace std; -#include +#include #include #include #include diff --git a/trunk/src/app/srs_app_caster_flv.cpp b/trunk/src/app/srs_app_caster_flv.cpp index 6d886f687..2f7112d69 100644 --- a/trunk/src/app/srs_app_caster_flv.cpp +++ b/trunk/src/app/srs_app_caster_flv.cpp @@ -36,7 +36,7 @@ using namespace std; #include #include #include -#include +#include #include #include #include diff --git a/trunk/src/app/srs_app_dvr.cpp b/trunk/src/app/srs_app_dvr.cpp index 078421c83..d7963bfba 100644 --- a/trunk/src/app/srs_app_dvr.cpp +++ b/trunk/src/app/srs_app_dvr.cpp @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. using namespace std; #include -#include +#include #include #include #include diff --git a/trunk/src/app/srs_app_edge.cpp b/trunk/src/app/srs_app_edge.cpp index 80afab666..86f060539 100644 --- a/trunk/src/app/srs_app_edge.cpp +++ b/trunk/src/app/srs_app_edge.cpp @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. using namespace std; #include -#include +#include #include #include #include diff --git a/trunk/src/app/srs_app_encoder.cpp b/trunk/src/app/srs_app_encoder.cpp index a64c81c6d..334bfce17 100644 --- a/trunk/src/app/srs_app_encoder.cpp +++ b/trunk/src/app/srs_app_encoder.cpp @@ -29,7 +29,7 @@ using namespace std; #include #include #include -#include +#include #include #include #include diff --git a/trunk/src/app/srs_app_forward.cpp b/trunk/src/app/srs_app_forward.cpp index dc9d1bb0d..673c191d2 100644 --- a/trunk/src/app/srs_app_forward.cpp +++ b/trunk/src/app/srs_app_forward.cpp @@ -36,7 +36,7 @@ using namespace std; #include #include #include -#include +#include #include #include #include diff --git a/trunk/src/app/srs_app_hds.cpp b/trunk/src/app/srs_app_hds.cpp index 7e05c7aa3..2255cc655 100644 --- a/trunk/src/app/srs_app_hds.cpp +++ b/trunk/src/app/srs_app_hds.cpp @@ -33,7 +33,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. using namespace std; #include -#include +#include #include #include #include diff --git a/trunk/src/app/srs_app_hls.cpp b/trunk/src/app/srs_app_hls.cpp index 6ce59cddb..51ecae374 100644 --- a/trunk/src/app/srs_app_hls.cpp +++ b/trunk/src/app/srs_app_hls.cpp @@ -41,7 +41,7 @@ using namespace std; #include #include #include -#include +#include #include #include #include diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 6b25c9544..910c6fb59 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -36,7 +36,7 @@ using namespace std; #include #include #include -#include +#include #include #include #include diff --git a/trunk/src/app/srs_app_http_conn.cpp b/trunk/src/app/srs_app_http_conn.cpp index 0336d129b..9a04a0cc2 100644 --- a/trunk/src/app/srs_app_http_conn.cpp +++ b/trunk/src/app/srs_app_http_conn.cpp @@ -43,7 +43,7 @@ using namespace std; #include #include #include -#include +#include #include #include #include diff --git a/trunk/src/app/srs_app_http_hooks.cpp b/trunk/src/app/srs_app_http_hooks.cpp index f9065226f..ea3908814 100644 --- a/trunk/src/app/srs_app_http_hooks.cpp +++ b/trunk/src/app/srs_app_http_hooks.cpp @@ -29,7 +29,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. using namespace std; #include -#include +#include #include #include #include diff --git a/trunk/src/app/srs_app_mpegts_udp.cpp b/trunk/src/app/srs_app_mpegts_udp.cpp index c9404d948..21c824e5e 100644 --- a/trunk/src/app/srs_app_mpegts_udp.cpp +++ b/trunk/src/app/srs_app_mpegts_udp.cpp @@ -42,7 +42,7 @@ using namespace std; #include #include #include -#include +#include #include #include #include diff --git a/trunk/src/app/srs_app_recv_thread.cpp b/trunk/src/app/srs_app_recv_thread.cpp index d5e5b9edf..e402643d4 100644 --- a/trunk/src/app/srs_app_recv_thread.cpp +++ b/trunk/src/app/srs_app_recv_thread.cpp @@ -23,7 +23,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include -#include +#include #include #include #include diff --git a/trunk/src/app/srs_app_rtmp_conn.cpp b/trunk/src/app/srs_app_rtmp_conn.cpp index b2c73307e..362d69d35 100644 --- a/trunk/src/app/srs_app_rtmp_conn.cpp +++ b/trunk/src/app/srs_app_rtmp_conn.cpp @@ -33,7 +33,7 @@ using namespace std; #include #include -#include +#include #include #include #include diff --git a/trunk/src/app/srs_app_rtsp.cpp b/trunk/src/app/srs_app_rtsp.cpp index bc961bd51..cad3a8546 100644 --- a/trunk/src/app/srs_app_rtsp.cpp +++ b/trunk/src/app/srs_app_rtsp.cpp @@ -35,7 +35,7 @@ using namespace std; #include #include #include -#include +#include #include #include #include diff --git a/trunk/src/app/srs_app_security.hpp b/trunk/src/app/srs_app_security.hpp index 43e22e218..467da3c5e 100644 --- a/trunk/src/app/srs_app_security.hpp +++ b/trunk/src/app/srs_app_security.hpp @@ -32,7 +32,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include -#include +#include class SrsConfDirective; diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp index 5e72852cc..cfe7a3112 100755 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_source.cpp @@ -35,7 +35,7 @@ using namespace std; #include #include #include -#include +#include #include #include #include diff --git a/trunk/src/app/srs_app_statistic.cpp b/trunk/src/app/srs_app_statistic.cpp index de108dcee..c33d6b8ca 100644 --- a/trunk/src/app/srs_app_statistic.cpp +++ b/trunk/src/app/srs_app_statistic.cpp @@ -27,7 +27,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include using namespace std; -#include +#include #include #include #include diff --git a/trunk/src/libs/srs_lib_bandwidth.cpp b/trunk/src/libs/srs_lib_bandwidth.cpp index b743aaf64..346fbae7f 100644 --- a/trunk/src/libs/srs_lib_bandwidth.cpp +++ b/trunk/src/libs/srs_lib_bandwidth.cpp @@ -33,7 +33,7 @@ using namespace std; #include #include -#include +#include #include #include #include diff --git a/trunk/src/libs/srs_librtmp.cpp b/trunk/src/libs/srs_librtmp.cpp index 65751d502..f9830039e 100644 --- a/trunk/src/libs/srs_librtmp.cpp +++ b/trunk/src/libs/srs_librtmp.cpp @@ -35,7 +35,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. using namespace std; #include -#include +#include #include #include #include diff --git a/trunk/src/main/srs_main_ingest_hls.cpp b/trunk/src/main/srs_main_ingest_hls.cpp index f9a4397f2..0c283b0a6 100644 --- a/trunk/src/main/srs_main_ingest_hls.cpp +++ b/trunk/src/main/srs_main_ingest_hls.cpp @@ -34,7 +34,7 @@ using namespace std; #include #include #include -#include +#include #include #include #include diff --git a/trunk/src/protocol/srs_rtmp_handshake.cpp b/trunk/src/protocol/srs_rtmp_handshake.cpp index 177c0a485..f32bc1d5e 100644 --- a/trunk/src/protocol/srs_rtmp_handshake.cpp +++ b/trunk/src/protocol/srs_rtmp_handshake.cpp @@ -30,7 +30,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include #include -#include +#include #include #ifdef SRS_AUTO_SSL diff --git a/trunk/src/protocol/srs_rtmp_sdk.cpp b/trunk/src/protocol/srs_rtmp_sdk.cpp deleted file mode 100644 index ba5757340..000000000 --- a/trunk/src/protocol/srs_rtmp_sdk.cpp +++ /dev/null @@ -1,1478 +0,0 @@ -/* -The MIT License (MIT) - -Copyright (c) 2013-2015 SRS(simple-rtmp-server) - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#include - -#include -#include -#include -#include -#include -#include -#include - -// for srs-librtmp, @see https://github.com/simple-rtmp-server/srs/issues/213 -#ifndef _WIN32 -#include -#endif - -using namespace std; - -// FMLE -#define RTMP_AMF0_COMMAND_ON_FC_PUBLISH "onFCPublish" -#define RTMP_AMF0_COMMAND_ON_FC_UNPUBLISH "onFCUnpublish" - -// default stream id for response the createStream request. -#define SRS_DEFAULT_SID 1 - -SrsRequest::SrsRequest() -{ - objectEncoding = RTMP_SIG_AMF0_VER; - duration = -1; - args = NULL; -} - -SrsRequest::~SrsRequest() -{ - srs_freep(args); -} - -SrsRequest* SrsRequest::copy() -{ - SrsRequest* cp = new SrsRequest(); - - cp->ip = ip; - cp->app = app; - cp->objectEncoding = objectEncoding; - cp->pageUrl = pageUrl; - cp->host = host; - cp->port = port; - cp->param = param; - cp->schema = schema; - cp->stream = stream; - cp->swfUrl = swfUrl; - cp->tcUrl = tcUrl; - cp->vhost = vhost; - cp->duration = duration; - if (args) { - cp->args = args->copy()->to_object(); - } - - return cp; -} - -void SrsRequest::update_auth(SrsRequest* req) -{ - pageUrl = req->pageUrl; - swfUrl = req->swfUrl; - tcUrl = req->tcUrl; - - if (args) { - srs_freep(args); - } - if (req->args) { - args = req->args->copy()->to_object(); - } - - srs_info("update req of soruce for auth ok"); -} - -string SrsRequest::get_stream_url() -{ - return srs_generate_stream_url(vhost, app, stream); -} - -void SrsRequest::strip() -{ - // remove the unsupported chars in names. - host = srs_string_remove(host, "/ \n\r\t"); - vhost = srs_string_remove(vhost, "/ \n\r\t"); - app = srs_string_remove(app, " \n\r\t"); - stream = srs_string_remove(stream, " \n\r\t"); - - // remove end slash of app/stream - app = srs_string_trim_end(app, "/"); - stream = srs_string_trim_end(stream, "/"); - - // remove start slash of app/stream - app = srs_string_trim_start(app, "/"); - stream = srs_string_trim_start(stream, "/"); -} - -SrsResponse::SrsResponse() -{ - stream_id = SRS_DEFAULT_SID; -} - -SrsResponse::~SrsResponse() -{ -} - -string srs_client_type_string(SrsRtmpConnType type) -{ - switch (type) { - case SrsRtmpConnPlay: return "Play"; - case SrsRtmpConnFlashPublish: return "publish(FlashPublish)"; - case SrsRtmpConnFMLEPublish: return "publish(FMLEPublish)"; - default: return "Unknown"; - } -} - -SrsHandshakeBytes::SrsHandshakeBytes() -{ - c0c1 = s0s1s2 = c2 = NULL; -} - -SrsHandshakeBytes::~SrsHandshakeBytes() -{ - srs_freep(c0c1); - srs_freep(s0s1s2); - srs_freep(c2); -} - -int SrsHandshakeBytes::read_c0c1(ISrsProtocolReaderWriter* io) -{ - int ret = ERROR_SUCCESS; - - if (c0c1) { - return ret; - } - - ssize_t nsize; - - c0c1 = new char[1537]; - if ((ret = io->read_fully(c0c1, 1537, &nsize)) != ERROR_SUCCESS) { - srs_warn("read c0c1 failed. ret=%d", ret); - return ret; - } - srs_verbose("read c0c1 success."); - - return ret; -} - -int SrsHandshakeBytes::read_s0s1s2(ISrsProtocolReaderWriter* io) -{ - int ret = ERROR_SUCCESS; - - if (s0s1s2) { - return ret; - } - - ssize_t nsize; - - s0s1s2 = new char[3073]; - if ((ret = io->read_fully(s0s1s2, 3073, &nsize)) != ERROR_SUCCESS) { - srs_warn("read s0s1s2 failed. ret=%d", ret); - return ret; - } - srs_verbose("read s0s1s2 success."); - - return ret; -} - -int SrsHandshakeBytes::read_c2(ISrsProtocolReaderWriter* io) -{ - int ret = ERROR_SUCCESS; - - if (c2) { - return ret; - } - - ssize_t nsize; - - c2 = new char[1536]; - if ((ret = io->read_fully(c2, 1536, &nsize)) != ERROR_SUCCESS) { - srs_warn("read c2 failed. ret=%d", ret); - return ret; - } - srs_verbose("read c2 success."); - - return ret; -} - -int SrsHandshakeBytes::create_c0c1() -{ - int ret = ERROR_SUCCESS; - - if (c0c1) { - return ret; - } - - c0c1 = new char[1537]; - srs_random_generate(c0c1, 1537); - - // plain text required. - SrsStream stream; - if ((ret = stream.initialize(c0c1, 9)) != ERROR_SUCCESS) { - return ret; - } - stream.write_1bytes(0x03); - stream.write_4bytes((int32_t)::time(NULL)); - stream.write_4bytes(0x00); - - return ret; -} - -int SrsHandshakeBytes::create_s0s1s2(const char* c1) -{ - int ret = ERROR_SUCCESS; - - if (s0s1s2) { - return ret; - } - - s0s1s2 = new char[3073]; - srs_random_generate(s0s1s2, 3073); - - // plain text required. - SrsStream stream; - if ((ret = stream.initialize(s0s1s2, 9)) != ERROR_SUCCESS) { - return ret; - } - stream.write_1bytes(0x03); - stream.write_4bytes((int32_t)::time(NULL)); - // s1 time2 copy from c1 - if (c0c1) { - stream.write_bytes(c0c1 + 1, 4); - } - - // if c1 specified, copy c1 to s2. - // @see: https://github.com/simple-rtmp-server/srs/issues/46 - if (c1) { - memcpy(s0s1s2 + 1537, c1, 1536); - } - - return ret; -} - -int SrsHandshakeBytes::create_c2() -{ - int ret = ERROR_SUCCESS; - - if (c2) { - return ret; - } - - c2 = new char[1536]; - srs_random_generate(c2, 1536); - - // time - SrsStream stream; - if ((ret = stream.initialize(c2, 8)) != ERROR_SUCCESS) { - return ret; - } - stream.write_4bytes((int32_t)::time(NULL)); - // c2 time2 copy from s1 - if (s0s1s2) { - stream.write_bytes(s0s1s2 + 1, 4); - } - - return ret; -} - -SrsRtmpClient::SrsRtmpClient(ISrsProtocolReaderWriter* skt) -{ - io = skt; - protocol = new SrsProtocol(skt); - hs_bytes = new SrsHandshakeBytes(); -} - -SrsRtmpClient::~SrsRtmpClient() -{ - srs_freep(protocol); - srs_freep(hs_bytes); -} - -void SrsRtmpClient::set_recv_timeout(int64_t timeout_us) -{ - protocol->set_recv_timeout(timeout_us); -} - -void SrsRtmpClient::set_send_timeout(int64_t timeout_us) -{ - protocol->set_send_timeout(timeout_us); -} - -int64_t SrsRtmpClient::get_recv_bytes() -{ - return protocol->get_recv_bytes(); -} - -int64_t SrsRtmpClient::get_send_bytes() -{ - return protocol->get_send_bytes(); -} - -int SrsRtmpClient::recv_message(SrsCommonMessage** pmsg) -{ - return protocol->recv_message(pmsg); -} - -int SrsRtmpClient::decode_message(SrsCommonMessage* msg, SrsPacket** ppacket) -{ - return protocol->decode_message(msg, ppacket); -} - -int SrsRtmpClient::send_and_free_message(SrsSharedPtrMessage* msg, int stream_id) -{ - return protocol->send_and_free_message(msg, stream_id); -} - -int SrsRtmpClient::send_and_free_messages(SrsSharedPtrMessage** msgs, int nb_msgs, int stream_id) -{ - return protocol->send_and_free_messages(msgs, nb_msgs, stream_id); -} - -int SrsRtmpClient::send_and_free_packet(SrsPacket* packet, int stream_id) -{ - return protocol->send_and_free_packet(packet, stream_id); -} - -int SrsRtmpClient::handshake() -{ - int ret = ERROR_SUCCESS; - - srs_assert(hs_bytes); - - SrsComplexHandshake complex_hs; - if ((ret = complex_hs.handshake_with_server(hs_bytes, io)) != ERROR_SUCCESS) { - if (ret == ERROR_RTMP_TRY_SIMPLE_HS) { - SrsSimpleHandshake simple_hs; - if ((ret = simple_hs.handshake_with_server(hs_bytes, io)) != ERROR_SUCCESS) { - return ret; - } - } - return ret; - } - - srs_freep(hs_bytes); - - return ret; -} - -int SrsRtmpClient::simple_handshake() -{ - int ret = ERROR_SUCCESS; - - srs_assert(hs_bytes); - - SrsSimpleHandshake simple_hs; - if ((ret = simple_hs.handshake_with_server(hs_bytes, io)) != ERROR_SUCCESS) { - return ret; - } - - srs_freep(hs_bytes); - - return ret; -} - -int SrsRtmpClient::complex_handshake() -{ - int ret = ERROR_SUCCESS; - - srs_assert(hs_bytes); - - SrsComplexHandshake complex_hs; - if ((ret = complex_hs.handshake_with_server(hs_bytes, io)) != ERROR_SUCCESS) { - return ret; - } - - srs_freep(hs_bytes); - - return ret; -} - -int SrsRtmpClient::connect_app(string app, string tc_url, - SrsRequest* req, bool debug_srs_upnode) -{ - std::string srs_server_ip; - std::string srs_server; - std::string srs_primary; - std::string srs_authors; - std::string srs_version; - int srs_id = 0; - int srs_pid = 0; - - return connect_app2(app, tc_url, req, debug_srs_upnode, - srs_server_ip, srs_server, srs_primary, srs_authors, - srs_version, srs_id, srs_pid); -} - -int SrsRtmpClient::connect_app2( - string app, string tc_url, SrsRequest* req, bool debug_srs_upnode, - string& srs_server_ip, string& srs_server, string& srs_primary, - string& srs_authors, string& srs_version, int& srs_id, - int& srs_pid -){ - int ret = ERROR_SUCCESS; - - // Connect(vhost, app) - if (true) { - SrsConnectAppPacket* pkt = new SrsConnectAppPacket(); - - pkt->command_object->set("app", SrsAmf0Any::str(app.c_str())); - pkt->command_object->set("flashVer", SrsAmf0Any::str("WIN 15,0,0,239")); - if (req) { - pkt->command_object->set("swfUrl", SrsAmf0Any::str(req->swfUrl.c_str())); - } else { - pkt->command_object->set("swfUrl", SrsAmf0Any::str()); - } - if (req && req->tcUrl != "") { - pkt->command_object->set("tcUrl", SrsAmf0Any::str(req->tcUrl.c_str())); - } else { - pkt->command_object->set("tcUrl", SrsAmf0Any::str(tc_url.c_str())); - } - pkt->command_object->set("fpad", SrsAmf0Any::boolean(false)); - pkt->command_object->set("capabilities", SrsAmf0Any::number(239)); - pkt->command_object->set("audioCodecs", SrsAmf0Any::number(3575)); - pkt->command_object->set("videoCodecs", SrsAmf0Any::number(252)); - pkt->command_object->set("videoFunction", SrsAmf0Any::number(1)); - if (req) { - pkt->command_object->set("pageUrl", SrsAmf0Any::str(req->pageUrl.c_str())); - } else { - pkt->command_object->set("pageUrl", SrsAmf0Any::str()); - } - pkt->command_object->set("objectEncoding", SrsAmf0Any::number(0)); - - // @see https://github.com/simple-rtmp-server/srs/issues/160 - // the debug_srs_upnode is config in vhost and default to true. - if (debug_srs_upnode && req && req->args) { - srs_freep(pkt->args); - pkt->args = req->args->copy()->to_object(); - } - - if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { - return ret; - } - } - - // Set Window Acknowledgement size(2500000) - if (true) { - SrsSetWindowAckSizePacket* pkt = new SrsSetWindowAckSizePacket(); - pkt->ackowledgement_window_size = 2500000; - if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { - return ret; - } - } - - // expect connect _result - SrsCommonMessage* msg = NULL; - SrsConnectAppResPacket* pkt = NULL; - if ((ret = expect_message(&msg, &pkt)) != ERROR_SUCCESS) { - srs_error("expect connect app response message failed. ret=%d", ret); - return ret; - } - SrsAutoFree(SrsCommonMessage, msg); - SrsAutoFree(SrsConnectAppResPacket, pkt); - - // server info - SrsAmf0Any* data = pkt->info->get_property("data"); - if (data && data->is_ecma_array()) { - SrsAmf0EcmaArray* arr = data->to_ecma_array(); - - SrsAmf0Any* prop = NULL; - if ((prop = arr->ensure_property_string("srs_primary")) != NULL) { - srs_primary = prop->to_str(); - } - if ((prop = arr->ensure_property_string("srs_authors")) != NULL) { - srs_authors = prop->to_str(); - } - if ((prop = arr->ensure_property_string("srs_version")) != NULL) { - srs_version = prop->to_str(); - } - if ((prop = arr->ensure_property_string("srs_server_ip")) != NULL) { - srs_server_ip = prop->to_str(); - } - if ((prop = arr->ensure_property_string("srs_server")) != NULL) { - srs_server = prop->to_str(); - } - if ((prop = arr->ensure_property_number("srs_id")) != NULL) { - srs_id = (int)prop->to_number(); - } - if ((prop = arr->ensure_property_number("srs_pid")) != NULL) { - srs_pid = (int)prop->to_number(); - } - } - srs_trace("connected, version=%s, ip=%s, pid=%d, id=%d, dsu=%d", - srs_version.c_str(), srs_server_ip.c_str(), srs_pid, srs_id, debug_srs_upnode); - - return ret; -} - -int SrsRtmpClient::create_stream(int& stream_id) -{ - int ret = ERROR_SUCCESS; - - // CreateStream - if (true) { - SrsCreateStreamPacket* pkt = new SrsCreateStreamPacket(); - if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { - return ret; - } - } - - // CreateStream _result. - if (true) { - SrsCommonMessage* msg = NULL; - SrsCreateStreamResPacket* pkt = NULL; - if ((ret = expect_message(&msg, &pkt)) != ERROR_SUCCESS) { - srs_error("expect create stream response message failed. ret=%d", ret); - return ret; - } - SrsAutoFree(SrsCommonMessage, msg); - SrsAutoFree(SrsCreateStreamResPacket, pkt); - srs_info("get create stream response message"); - - stream_id = (int)pkt->stream_id; - } - - return ret; -} - -int SrsRtmpClient::play(string stream, int stream_id) -{ - int ret = ERROR_SUCCESS; - - // Play(stream) - if (true) { - SrsPlayPacket* pkt = new SrsPlayPacket(); - pkt->stream_name = stream; - if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { - srs_error("send play stream failed. " - "stream=%s, stream_id=%d, ret=%d", - stream.c_str(), stream_id, ret); - return ret; - } - } - - // SetBufferLength(1000ms) - int buffer_length_ms = 1000; - if (true) { - SrsUserControlPacket* pkt = new SrsUserControlPacket(); - - pkt->event_type = SrcPCUCSetBufferLength; - pkt->event_data = stream_id; - pkt->extra_data = buffer_length_ms; - - if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { - srs_error("send set buffer length failed. " - "stream=%s, stream_id=%d, bufferLength=%d, ret=%d", - stream.c_str(), stream_id, buffer_length_ms, ret); - return ret; - } - } - - // SetChunkSize - if (true) { - SrsSetChunkSizePacket* pkt = new SrsSetChunkSizePacket(); - pkt->chunk_size = SRS_CONSTS_RTMP_SRS_CHUNK_SIZE; - if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { - srs_error("send set chunk size failed. " - "stream=%s, chunk_size=%d, ret=%d", - stream.c_str(), SRS_CONSTS_RTMP_SRS_CHUNK_SIZE, ret); - return ret; - } - } - - return ret; -} - -int SrsRtmpClient::publish(string stream, int stream_id) -{ - int ret = ERROR_SUCCESS; - - // SetChunkSize - if (true) { - SrsSetChunkSizePacket* pkt = new SrsSetChunkSizePacket(); - pkt->chunk_size = SRS_CONSTS_RTMP_SRS_CHUNK_SIZE; - if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { - srs_error("send set chunk size failed. " - "stream=%s, chunk_size=%d, ret=%d", - stream.c_str(), SRS_CONSTS_RTMP_SRS_CHUNK_SIZE, ret); - return ret; - } - } - - // publish(stream) - if (true) { - SrsPublishPacket* pkt = new SrsPublishPacket(); - pkt->stream_name = stream; - if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { - srs_error("send publish message failed. " - "stream=%s, stream_id=%d, ret=%d", - stream.c_str(), stream_id, ret); - return ret; - } - } - - return ret; -} - -int SrsRtmpClient::fmle_publish(string stream, int& stream_id) -{ - stream_id = 0; - - int ret = ERROR_SUCCESS; - - // SrsFMLEStartPacket - if (true) { - SrsFMLEStartPacket* pkt = SrsFMLEStartPacket::create_release_stream(stream); - if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { - srs_error("send FMLE publish " - "release stream failed. stream=%s, ret=%d", stream.c_str(), ret); - return ret; - } - } - - // FCPublish - if (true) { - SrsFMLEStartPacket* pkt = SrsFMLEStartPacket::create_FC_publish(stream); - if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { - srs_error("send FMLE publish " - "FCPublish failed. stream=%s, ret=%d", stream.c_str(), ret); - return ret; - } - } - - // CreateStream - if (true) { - SrsCreateStreamPacket* pkt = new SrsCreateStreamPacket(); - pkt->transaction_id = 4; - if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { - srs_error("send FMLE publish " - "createStream failed. stream=%s, ret=%d", stream.c_str(), ret); - return ret; - } - } - - // expect result of CreateStream - if (true) { - SrsCommonMessage* msg = NULL; - SrsCreateStreamResPacket* pkt = NULL; - if ((ret = expect_message(&msg, &pkt)) != ERROR_SUCCESS) { - srs_error("expect create stream response message failed. ret=%d", ret); - return ret; - } - SrsAutoFree(SrsCommonMessage, msg); - SrsAutoFree(SrsCreateStreamResPacket, pkt); - srs_info("get create stream response message"); - - stream_id = (int)pkt->stream_id; - } - - // publish(stream) - if (true) { - SrsPublishPacket* pkt = new SrsPublishPacket(); - pkt->stream_name = stream; - if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { - srs_error("send FMLE publish publish failed. " - "stream=%s, stream_id=%d, ret=%d", stream.c_str(), stream_id, ret); - return ret; - } - } - - return ret; -} - -SrsRtmpServer::SrsRtmpServer(ISrsProtocolReaderWriter* skt) -{ - io = skt; - protocol = new SrsProtocol(skt); - hs_bytes = new SrsHandshakeBytes(); -} - -SrsRtmpServer::~SrsRtmpServer() -{ - srs_freep(protocol); - srs_freep(hs_bytes); -} - -void SrsRtmpServer::set_auto_response(bool v) -{ - protocol->set_auto_response(v); -} - -#ifdef SRS_PERF_MERGED_READ -void SrsRtmpServer::set_merge_read(bool v, IMergeReadHandler* handler) -{ - protocol->set_merge_read(v, handler); -} - -void SrsRtmpServer::set_recv_buffer(int buffer_size) -{ - protocol->set_recv_buffer(buffer_size); -} -#endif - -void SrsRtmpServer::set_recv_timeout(int64_t timeout_us) -{ - protocol->set_recv_timeout(timeout_us); -} - -int64_t SrsRtmpServer::get_recv_timeout() -{ - return protocol->get_recv_timeout(); -} - -void SrsRtmpServer::set_send_timeout(int64_t timeout_us) -{ - protocol->set_send_timeout(timeout_us); -} - -int64_t SrsRtmpServer::get_send_timeout() -{ - return protocol->get_send_timeout(); -} - -int64_t SrsRtmpServer::get_recv_bytes() -{ - return protocol->get_recv_bytes(); -} - -int64_t SrsRtmpServer::get_send_bytes() -{ - return protocol->get_send_bytes(); -} - -int SrsRtmpServer::recv_message(SrsCommonMessage** pmsg) -{ - return protocol->recv_message(pmsg); -} - -int SrsRtmpServer::decode_message(SrsCommonMessage* msg, SrsPacket** ppacket) -{ - return protocol->decode_message(msg, ppacket); -} - -int SrsRtmpServer::send_and_free_message(SrsSharedPtrMessage* msg, int stream_id) -{ - return protocol->send_and_free_message(msg, stream_id); -} - -int SrsRtmpServer::send_and_free_messages(SrsSharedPtrMessage** msgs, int nb_msgs, int stream_id) -{ - return protocol->send_and_free_messages(msgs, nb_msgs, stream_id); -} - -int SrsRtmpServer::send_and_free_packet(SrsPacket* packet, int stream_id) -{ - return protocol->send_and_free_packet(packet, stream_id); -} - -int SrsRtmpServer::handshake() -{ - int ret = ERROR_SUCCESS; - - srs_assert(hs_bytes); - - SrsComplexHandshake complex_hs; - if ((ret = complex_hs.handshake_with_client(hs_bytes, io)) != ERROR_SUCCESS) { - if (ret == ERROR_RTMP_TRY_SIMPLE_HS) { - SrsSimpleHandshake simple_hs; - if ((ret = simple_hs.handshake_with_client(hs_bytes, io)) != ERROR_SUCCESS) { - return ret; - } - } - return ret; - } - - srs_freep(hs_bytes); - - return ret; -} - -int SrsRtmpServer::connect_app(SrsRequest* req) -{ - int ret = ERROR_SUCCESS; - - SrsCommonMessage* msg = NULL; - SrsConnectAppPacket* pkt = NULL; - if ((ret = expect_message(&msg, &pkt)) != ERROR_SUCCESS) { - srs_error("expect connect app message failed. ret=%d", ret); - return ret; - } - SrsAutoFree(SrsCommonMessage, msg); - SrsAutoFree(SrsConnectAppPacket, pkt); - srs_info("get connect app message"); - - SrsAmf0Any* prop = NULL; - - if ((prop = pkt->command_object->ensure_property_string("tcUrl")) == NULL) { - ret = ERROR_RTMP_REQ_CONNECT; - srs_error("invalid request, must specifies the tcUrl. ret=%d", ret); - return ret; - } - req->tcUrl = prop->to_str(); - - if ((prop = pkt->command_object->ensure_property_string("pageUrl")) != NULL) { - req->pageUrl = prop->to_str(); - } - - if ((prop = pkt->command_object->ensure_property_string("swfUrl")) != NULL) { - req->swfUrl = prop->to_str(); - } - - if ((prop = pkt->command_object->ensure_property_number("objectEncoding")) != NULL) { - req->objectEncoding = prop->to_number(); - } - - if (pkt->args) { - srs_freep(req->args); - req->args = pkt->args->copy()->to_object(); - srs_info("copy edge traverse to origin auth args."); - } - - srs_info("get connect app message params success."); - - srs_discovery_tc_url(req->tcUrl, - req->schema, req->host, req->vhost, req->app, req->port, - req->param); - req->strip(); - - return ret; -} - -int SrsRtmpServer::set_window_ack_size(int ack_size) -{ - int ret = ERROR_SUCCESS; - - SrsSetWindowAckSizePacket* pkt = new SrsSetWindowAckSizePacket(); - pkt->ackowledgement_window_size = ack_size; - if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { - srs_error("send ack size message failed. ret=%d", ret); - return ret; - } - srs_info("send ack size message success. ack_size=%d", ack_size); - - return ret; -} - -int SrsRtmpServer::set_peer_bandwidth(int bandwidth, int type) -{ - int ret = ERROR_SUCCESS; - - SrsSetPeerBandwidthPacket* pkt = new SrsSetPeerBandwidthPacket(); - pkt->bandwidth = bandwidth; - pkt->type = type; - if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { - srs_error("send set bandwidth message failed. ret=%d", ret); - return ret; - } - srs_info("send set bandwidth message " - "success. bandwidth=%d, type=%d", bandwidth, type); - - return ret; -} - -int SrsRtmpServer::response_connect_app(SrsRequest *req, const char* server_ip) -{ - int ret = ERROR_SUCCESS; - - SrsConnectAppResPacket* pkt = new SrsConnectAppResPacket(); - - pkt->props->set("fmsVer", SrsAmf0Any::str("FMS/"RTMP_SIG_FMS_VER)); - pkt->props->set("capabilities", SrsAmf0Any::number(127)); - pkt->props->set("mode", SrsAmf0Any::number(1)); - - pkt->info->set(StatusLevel, SrsAmf0Any::str(StatusLevelStatus)); - pkt->info->set(StatusCode, SrsAmf0Any::str(StatusCodeConnectSuccess)); - pkt->info->set(StatusDescription, SrsAmf0Any::str("Connection succeeded")); - pkt->info->set("objectEncoding", SrsAmf0Any::number(req->objectEncoding)); - SrsAmf0EcmaArray* data = SrsAmf0Any::ecma_array(); - pkt->info->set("data", data); - - data->set("version", SrsAmf0Any::str(RTMP_SIG_FMS_VER)); - data->set("srs_sig", SrsAmf0Any::str(RTMP_SIG_SRS_KEY)); - data->set("srs_server", SrsAmf0Any::str(RTMP_SIG_SRS_SERVER)); - data->set("srs_license", SrsAmf0Any::str(RTMP_SIG_SRS_LICENSE)); - data->set("srs_role", SrsAmf0Any::str(RTMP_SIG_SRS_ROLE)); - data->set("srs_url", SrsAmf0Any::str(RTMP_SIG_SRS_URL)); - data->set("srs_version", SrsAmf0Any::str(RTMP_SIG_SRS_VERSION)); - data->set("srs_site", SrsAmf0Any::str(RTMP_SIG_SRS_WEB)); - data->set("srs_email", SrsAmf0Any::str(RTMP_SIG_SRS_EMAIL)); - data->set("srs_copyright", SrsAmf0Any::str(RTMP_SIG_SRS_COPYRIGHT)); - data->set("srs_primary", SrsAmf0Any::str(RTMP_SIG_SRS_PRIMARY)); - data->set("srs_authors", SrsAmf0Any::str(RTMP_SIG_SRS_AUTHROS)); - - if (server_ip) { - data->set("srs_server_ip", SrsAmf0Any::str(server_ip)); - } - // for edge to directly get the id of client. - data->set("srs_pid", SrsAmf0Any::number(getpid())); - data->set("srs_id", SrsAmf0Any::number(_srs_context->get_id())); - - if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { - srs_error("send connect app response message failed. ret=%d", ret); - return ret; - } - srs_info("send connect app response message success."); - - return ret; -} - -void SrsRtmpServer::response_connect_reject(SrsRequest* /*req*/, const char* desc) -{ - int ret = ERROR_SUCCESS; - - SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket(); - pkt->data->set(StatusLevel, SrsAmf0Any::str(StatusLevelError)); - pkt->data->set(StatusCode, SrsAmf0Any::str(StatusCodeConnectRejected)); - pkt->data->set(StatusDescription, SrsAmf0Any::str(desc)); - - if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { - srs_error("send connect app response rejected message failed. ret=%d", ret); - return; - } - srs_info("send connect app response rejected message success."); - - return; -} - -int SrsRtmpServer::on_bw_done() -{ - int ret = ERROR_SUCCESS; - - SrsOnBWDonePacket* pkt = new SrsOnBWDonePacket(); - if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { - srs_error("send onBWDone message failed. ret=%d", ret); - return ret; - } - srs_info("send onBWDone message success."); - - return ret; -} - -int SrsRtmpServer::identify_client(int stream_id, SrsRtmpConnType& type, string& stream_name, double& duration) -{ - type = SrsRtmpConnUnknown; - int ret = ERROR_SUCCESS; - - while (true) { - SrsCommonMessage* msg = NULL; - if ((ret = protocol->recv_message(&msg)) != ERROR_SUCCESS) { - if (!srs_is_client_gracefully_close(ret)) { - srs_error("recv identify client message failed. ret=%d", ret); - } - return ret; - } - - SrsAutoFree(SrsCommonMessage, msg); - SrsMessageHeader& h = msg->header; - - if (h.is_ackledgement() || h.is_set_chunk_size() || h.is_window_ackledgement_size() || h.is_user_control_message()) { - continue; - } - - if (!h.is_amf0_command() && !h.is_amf3_command()) { - srs_trace("identify ignore messages except " - "AMF0/AMF3 command message. type=%#x", h.message_type); - continue; - } - - SrsPacket* pkt = NULL; - if ((ret = protocol->decode_message(msg, &pkt)) != ERROR_SUCCESS) { - srs_error("identify decode message failed. ret=%d", ret); - return ret; - } - - SrsAutoFree(SrsPacket, pkt); - - 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, duration); - } - if (dynamic_cast(pkt)) { - srs_info("identify client by releaseStream, fmle publish."); - return identify_fmle_publish_client(dynamic_cast(pkt), type, stream_name); - } - if (dynamic_cast(pkt)) { - srs_info("level0 identify client by play."); - return identify_play_client(dynamic_cast(pkt), type, stream_name, duration); - } - // call msg, - // support response null first, - // @see https://github.com/simple-rtmp-server/srs/issues/106 - // TODO: FIXME: response in right way, or forward in edge mode. - SrsCallPacket* call = dynamic_cast(pkt); - if (call) { - SrsCallResPacket* res = new SrsCallResPacket(call->transaction_id); - res->command_object = SrsAmf0Any::null(); - res->response = SrsAmf0Any::null(); - if ((ret = protocol->send_and_free_packet(res, 0)) != ERROR_SUCCESS) { - srs_warn("response call failed. ret=%d", ret); - return ret; - } - continue; - } - - srs_trace("ignore AMF0/AMF3 command message."); - } - - return ret; -} - -int SrsRtmpServer::set_chunk_size(int chunk_size) -{ - int ret = ERROR_SUCCESS; - - SrsSetChunkSizePacket* pkt = new SrsSetChunkSizePacket(); - pkt->chunk_size = chunk_size; - if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { - srs_error("send set chunk size message failed. ret=%d", ret); - return ret; - } - srs_info("send set chunk size message success. chunk_size=%d", chunk_size); - - return ret; -} - -int SrsRtmpServer::start_play(int stream_id) -{ - int ret = ERROR_SUCCESS; - - // StreamBegin - if (true) { - SrsUserControlPacket* pkt = new SrsUserControlPacket(); - pkt->event_type = SrcPCUCStreamBegin; - pkt->event_data = stream_id; - if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { - srs_error("send PCUC(StreamBegin) message failed. ret=%d", ret); - return ret; - } - srs_info("send PCUC(StreamBegin) message success."); - } - - // onStatus(NetStream.Play.Reset) - if (true) { - SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket(); - - pkt->data->set(StatusLevel, SrsAmf0Any::str(StatusLevelStatus)); - pkt->data->set(StatusCode, SrsAmf0Any::str(StatusCodeStreamReset)); - pkt->data->set(StatusDescription, SrsAmf0Any::str("Playing and resetting stream.")); - pkt->data->set(StatusDetails, SrsAmf0Any::str("stream")); - pkt->data->set(StatusClientId, SrsAmf0Any::str(RTMP_SIG_CLIENT_ID)); - - if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { - srs_error("send onStatus(NetStream.Play.Reset) message failed. ret=%d", ret); - return ret; - } - srs_info("send onStatus(NetStream.Play.Reset) message success."); - } - - // onStatus(NetStream.Play.Start) - if (true) { - SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket(); - - pkt->data->set(StatusLevel, SrsAmf0Any::str(StatusLevelStatus)); - pkt->data->set(StatusCode, SrsAmf0Any::str(StatusCodeStreamStart)); - pkt->data->set(StatusDescription, SrsAmf0Any::str("Started playing stream.")); - pkt->data->set(StatusDetails, SrsAmf0Any::str("stream")); - pkt->data->set(StatusClientId, SrsAmf0Any::str(RTMP_SIG_CLIENT_ID)); - - if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { - srs_error("send onStatus(NetStream.Play.Start) message failed. ret=%d", ret); - return ret; - } - srs_info("send onStatus(NetStream.Play.Start) message success."); - } - - // |RtmpSampleAccess(false, false) - if (true) { - SrsSampleAccessPacket* pkt = new SrsSampleAccessPacket(); - - // allow audio/video sample. - // @see: https://github.com/simple-rtmp-server/srs/issues/49 - pkt->audio_sample_access = true; - pkt->video_sample_access = true; - - if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { - srs_error("send |RtmpSampleAccess(false, false) message failed. ret=%d", ret); - return ret; - } - srs_info("send |RtmpSampleAccess(false, false) message success."); - } - - // onStatus(NetStream.Data.Start) - if (true) { - SrsOnStatusDataPacket* pkt = new SrsOnStatusDataPacket(); - pkt->data->set(StatusCode, SrsAmf0Any::str(StatusCodeDataStart)); - if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { - srs_error("send onStatus(NetStream.Data.Start) message failed. ret=%d", ret); - return ret; - } - srs_info("send onStatus(NetStream.Data.Start) message success."); - } - - srs_info("start play success."); - - return ret; -} - -int SrsRtmpServer::on_play_client_pause(int stream_id, bool is_pause) -{ - int ret = ERROR_SUCCESS; - - if (is_pause) { - // onStatus(NetStream.Pause.Notify) - if (true) { - SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket(); - - pkt->data->set(StatusLevel, SrsAmf0Any::str(StatusLevelStatus)); - pkt->data->set(StatusCode, SrsAmf0Any::str(StatusCodeStreamPause)); - pkt->data->set(StatusDescription, SrsAmf0Any::str("Paused stream.")); - - if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { - srs_error("send onStatus(NetStream.Pause.Notify) message failed. ret=%d", ret); - return ret; - } - srs_info("send onStatus(NetStream.Pause.Notify) message success."); - } - // StreamEOF - if (true) { - SrsUserControlPacket* pkt = new SrsUserControlPacket(); - - pkt->event_type = SrcPCUCStreamEOF; - pkt->event_data = stream_id; - - if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { - srs_error("send PCUC(StreamEOF) message failed. ret=%d", ret); - return ret; - } - srs_info("send PCUC(StreamEOF) message success."); - } - } else { - // onStatus(NetStream.Unpause.Notify) - if (true) { - SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket(); - - pkt->data->set(StatusLevel, SrsAmf0Any::str(StatusLevelStatus)); - pkt->data->set(StatusCode, SrsAmf0Any::str(StatusCodeStreamUnpause)); - pkt->data->set(StatusDescription, SrsAmf0Any::str("Unpaused stream.")); - - if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { - srs_error("send onStatus(NetStream.Unpause.Notify) message failed. ret=%d", ret); - return ret; - } - srs_info("send onStatus(NetStream.Unpause.Notify) message success."); - } - // StreanBegin - if (true) { - SrsUserControlPacket* pkt = new SrsUserControlPacket(); - - pkt->event_type = SrcPCUCStreamBegin; - pkt->event_data = stream_id; - - if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { - srs_error("send PCUC(StreanBegin) message failed. ret=%d", ret); - return ret; - } - srs_info("send PCUC(StreanBegin) message success."); - } - } - - return ret; -} - -int SrsRtmpServer::start_fmle_publish(int stream_id) -{ - int ret = ERROR_SUCCESS; - - // FCPublish - double fc_publish_tid = 0; - if (true) { - SrsCommonMessage* msg = NULL; - SrsFMLEStartPacket* pkt = NULL; - if ((ret = expect_message(&msg, &pkt)) != ERROR_SUCCESS) { - srs_error("recv FCPublish message failed. ret=%d", ret); - return ret; - } - srs_info("recv FCPublish request message success."); - - SrsAutoFree(SrsCommonMessage, msg); - SrsAutoFree(SrsFMLEStartPacket, pkt); - - fc_publish_tid = pkt->transaction_id; - } - // FCPublish response - if (true) { - SrsFMLEStartResPacket* pkt = new SrsFMLEStartResPacket(fc_publish_tid); - if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { - srs_error("send FCPublish response message failed. ret=%d", ret); - return ret; - } - srs_info("send FCPublish response message success."); - } - - // createStream - double create_stream_tid = 0; - if (true) { - SrsCommonMessage* msg = NULL; - SrsCreateStreamPacket* pkt = NULL; - if ((ret = expect_message(&msg, &pkt)) != ERROR_SUCCESS) { - srs_error("recv createStream message failed. ret=%d", ret); - return ret; - } - srs_info("recv createStream request message success."); - - SrsAutoFree(SrsCommonMessage, msg); - SrsAutoFree(SrsCreateStreamPacket, pkt); - - create_stream_tid = pkt->transaction_id; - } - // createStream response - if (true) { - SrsCreateStreamResPacket* pkt = new SrsCreateStreamResPacket(create_stream_tid, stream_id); - if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { - srs_error("send createStream response message failed. ret=%d", ret); - return ret; - } - srs_info("send createStream response message success."); - } - - // publish - if (true) { - SrsCommonMessage* msg = NULL; - SrsPublishPacket* pkt = NULL; - if ((ret = expect_message(&msg, &pkt)) != ERROR_SUCCESS) { - srs_error("recv publish message failed. ret=%d", ret); - return ret; - } - srs_info("recv publish request message success."); - - SrsAutoFree(SrsCommonMessage, msg); - SrsAutoFree(SrsPublishPacket, pkt); - } - // publish response onFCPublish(NetStream.Publish.Start) - if (true) { - SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket(); - - pkt->command_name = RTMP_AMF0_COMMAND_ON_FC_PUBLISH; - pkt->data->set(StatusCode, SrsAmf0Any::str(StatusCodePublishStart)); - pkt->data->set(StatusDescription, SrsAmf0Any::str("Started publishing stream.")); - - if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { - srs_error("send onFCPublish(NetStream.Publish.Start) message failed. ret=%d", ret); - return ret; - } - srs_info("send onFCPublish(NetStream.Publish.Start) message success."); - } - // publish response onStatus(NetStream.Publish.Start) - if (true) { - SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket(); - - pkt->data->set(StatusLevel, SrsAmf0Any::str(StatusLevelStatus)); - pkt->data->set(StatusCode, SrsAmf0Any::str(StatusCodePublishStart)); - pkt->data->set(StatusDescription, SrsAmf0Any::str("Started publishing stream.")); - pkt->data->set(StatusClientId, SrsAmf0Any::str(RTMP_SIG_CLIENT_ID)); - - if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { - srs_error("send onStatus(NetStream.Publish.Start) message failed. ret=%d", ret); - return ret; - } - srs_info("send onStatus(NetStream.Publish.Start) message success."); - } - - srs_info("FMLE publish success."); - - return ret; -} - -int SrsRtmpServer::fmle_unpublish(int stream_id, double unpublish_tid) -{ - int ret = ERROR_SUCCESS; - - // publish response onFCUnpublish(NetStream.unpublish.Success) - if (true) { - SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket(); - - pkt->command_name = RTMP_AMF0_COMMAND_ON_FC_UNPUBLISH; - pkt->data->set(StatusCode, SrsAmf0Any::str(StatusCodeUnpublishSuccess)); - pkt->data->set(StatusDescription, SrsAmf0Any::str("Stop publishing stream.")); - - if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { - srs_error("send onFCUnpublish(NetStream.unpublish.Success) message failed. ret=%d", ret); - return ret; - } - srs_info("send onFCUnpublish(NetStream.unpublish.Success) message success."); - } - // FCUnpublish response - if (true) { - SrsFMLEStartResPacket* pkt = new SrsFMLEStartResPacket(unpublish_tid); - if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { - srs_error("send FCUnpublish response message failed. ret=%d", ret); - return ret; - } - srs_info("send FCUnpublish response message success."); - } - // publish response onStatus(NetStream.Unpublish.Success) - if (true) { - SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket(); - - pkt->data->set(StatusLevel, SrsAmf0Any::str(StatusLevelStatus)); - pkt->data->set(StatusCode, SrsAmf0Any::str(StatusCodeUnpublishSuccess)); - pkt->data->set(StatusDescription, SrsAmf0Any::str("Stream is now unpublished")); - pkt->data->set(StatusClientId, SrsAmf0Any::str(RTMP_SIG_CLIENT_ID)); - - if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { - srs_error("send onStatus(NetStream.Unpublish.Success) message failed. ret=%d", ret); - return ret; - } - srs_info("send onStatus(NetStream.Unpublish.Success) message success."); - } - - srs_info("FMLE unpublish success."); - - return ret; -} - -int SrsRtmpServer::start_flash_publish(int stream_id) -{ - int ret = ERROR_SUCCESS; - - // publish response onStatus(NetStream.Publish.Start) - if (true) { - SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket(); - - pkt->data->set(StatusLevel, SrsAmf0Any::str(StatusLevelStatus)); - pkt->data->set(StatusCode, SrsAmf0Any::str(StatusCodePublishStart)); - pkt->data->set(StatusDescription, SrsAmf0Any::str("Started publishing stream.")); - pkt->data->set(StatusClientId, SrsAmf0Any::str(RTMP_SIG_CLIENT_ID)); - - if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { - srs_error("send onStatus(NetStream.Publish.Start) message failed. ret=%d", ret); - return ret; - } - srs_info("send onStatus(NetStream.Publish.Start) message success."); - } - - srs_info("flash publish success."); - - return ret; -} - -int SrsRtmpServer::identify_create_stream_client(SrsCreateStreamPacket* req, int stream_id, SrsRtmpConnType& type, string& stream_name, double& duration) -{ - int ret = ERROR_SUCCESS; - - if (true) { - SrsCreateStreamResPacket* pkt = new SrsCreateStreamResPacket(req->transaction_id, stream_id); - if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { - srs_error("send createStream response message failed. ret=%d", ret); - return ret; - } - srs_info("send createStream response message success."); - } - - while (true) { - SrsCommonMessage* msg = NULL; - if ((ret = protocol->recv_message(&msg)) != ERROR_SUCCESS) { - if (!srs_is_client_gracefully_close(ret)) { - srs_error("recv identify client message failed. ret=%d", ret); - } - return ret; - } - - SrsAutoFree(SrsCommonMessage, msg); - SrsMessageHeader& h = msg->header; - - if (h.is_ackledgement() || h.is_set_chunk_size() || h.is_window_ackledgement_size() || h.is_user_control_message()) { - continue; - } - - if (!h.is_amf0_command() && !h.is_amf3_command()) { - srs_trace("identify ignore messages except " - "AMF0/AMF3 command message. type=%#x", h.message_type); - continue; - } - - SrsPacket* pkt = NULL; - if ((ret = protocol->decode_message(msg, &pkt)) != ERROR_SUCCESS) { - srs_error("identify decode message failed. ret=%d", ret); - return ret; - } - - SrsAutoFree(SrsPacket, pkt); - - if (dynamic_cast(pkt)) { - srs_info("level1 identify client by play."); - return identify_play_client(dynamic_cast(pkt), type, stream_name, duration); - } - if (dynamic_cast(pkt)) { - srs_info("identify client by publish, falsh publish."); - return identify_flash_publish_client(dynamic_cast(pkt), type, stream_name); - } - 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, duration); - } - - srs_trace("ignore AMF0/AMF3 command message."); - } - - return ret; -} - -int SrsRtmpServer::identify_fmle_publish_client(SrsFMLEStartPacket* req, SrsRtmpConnType& type, string& stream_name) -{ - int ret = ERROR_SUCCESS; - - type = SrsRtmpConnFMLEPublish; - stream_name = req->stream_name; - - // releaseStream response - if (true) { - SrsFMLEStartResPacket* pkt = new SrsFMLEStartResPacket(req->transaction_id); - if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { - srs_error("send releaseStream response message failed. ret=%d", ret); - return ret; - } - srs_info("send releaseStream response message success."); - } - - return ret; -} - -int SrsRtmpServer::identify_flash_publish_client(SrsPublishPacket* req, SrsRtmpConnType& type, string& stream_name) -{ - int ret = ERROR_SUCCESS; - - type = SrsRtmpConnFlashPublish; - stream_name = req->stream_name; - - return ret; -} - -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_info("identity client type=play, stream_name=%s, duration=%.2f", stream_name.c_str(), duration); - - return ret; -} - - diff --git a/trunk/src/protocol/srs_rtmp_sdk.hpp b/trunk/src/protocol/srs_rtmp_sdk.hpp deleted file mode 100644 index 1baf457b9..000000000 --- a/trunk/src/protocol/srs_rtmp_sdk.hpp +++ /dev/null @@ -1,571 +0,0 @@ -/* -The MIT License (MIT) - -Copyright (c) 2013-2015 SRS(simple-rtmp-server) - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#ifndef SRS_RTMP_PROTOCOL_RTMP_HPP -#define SRS_RTMP_PROTOCOL_RTMP_HPP - -/* -#include -*/ - -#include - -#include - -#include -#include - -class SrsProtocol; -class ISrsProtocolReaderWriter; -class SrsCommonMessage; -class SrsCreateStreamPacket; -class SrsFMLEStartPacket; -class SrsPublishPacket; -class SrsOnMetaDataPacket; -class SrsPlayPacket; -class SrsCommonMessage; -class SrsPacket; -class SrsAmf0Object; -class IMergeReadHandler; - -/** - * the signature for packets to client. - */ -#define RTMP_SIG_FMS_VER "3,5,3,888" -#define RTMP_SIG_AMF0_VER 0 -#define RTMP_SIG_CLIENT_ID "ASAICiss" - -/** - * onStatus consts. - */ -#define StatusLevel "level" -#define StatusCode "code" -#define StatusDescription "description" -#define StatusDetails "details" -#define StatusClientId "clientid" -// status value -#define StatusLevelStatus "status" -// status error -#define StatusLevelError "error" -// code value -#define StatusCodeConnectSuccess "NetConnection.Connect.Success" -#define StatusCodeConnectRejected "NetConnection.Connect.Rejected" -#define StatusCodeStreamReset "NetStream.Play.Reset" -#define StatusCodeStreamStart "NetStream.Play.Start" -#define StatusCodeStreamPause "NetStream.Pause.Notify" -#define StatusCodeStreamUnpause "NetStream.Unpause.Notify" -#define StatusCodePublishStart "NetStream.Publish.Start" -#define StatusCodeDataStart "NetStream.Data.Start" -#define StatusCodeUnpublishSuccess "NetStream.Unpublish.Success" - -/** -* the original request from client. -*/ -class SrsRequest -{ -public: - // client ip. - std::string ip; -public: - /** - * tcUrl: rtmp://request_vhost:port/app/stream - * support pass vhost in query string, such as: - * rtmp://ip:port/app?vhost=request_vhost/stream - * rtmp://ip:port/app...vhost...request_vhost/stream - */ - std::string tcUrl; - std::string pageUrl; - std::string swfUrl; - double objectEncoding; -// data discovery from request. -public: - // discovery from tcUrl and play/publish. - std::string schema; - // the vhost in tcUrl. - std::string vhost; - // the host in tcUrl. - std::string host; - // the port in tcUrl. - std::string port; - // the app in tcUrl, without param. - std::string app; - // the param in tcUrl(app). - std::string param; - // the stream in play/publish - std::string stream; - // for play live stream, - // used to specified the stop when exceed the duration. - // @see https://github.com/simple-rtmp-server/srs/issues/45 - // in ms. - double duration; - // the token in the connect request, - // used for edge traverse to origin authentication, - // @see https://github.com/simple-rtmp-server/srs/issues/104 - SrsAmf0Object* args; -public: - SrsRequest(); - virtual ~SrsRequest(); -public: - /** - * deep copy the request, for source to use it to support reload, - * for when initialize the source, the request is valid, - * when reload it, the request maybe invalid, so need to copy it. - */ - virtual SrsRequest* copy(); - /** - * update the auth info of request, - * to keep the current request ptr is ok, - * for many components use the ptr of request. - */ - virtual void update_auth(SrsRequest* req); - /** - * get the stream identify, vhost/app/stream. - */ - virtual std::string get_stream_url(); - /** - * strip url, user must strip when update the url. - */ - virtual void strip(); -}; - -/** -* the response to client. -*/ -class SrsResponse -{ -public: - /** - * the stream id to response client createStream. - */ - int stream_id; -public: - SrsResponse(); - virtual ~SrsResponse(); -}; - -/** -* the rtmp client type. -*/ -enum SrsRtmpConnType -{ - SrsRtmpConnUnknown, - SrsRtmpConnPlay, - SrsRtmpConnFMLEPublish, - SrsRtmpConnFlashPublish, -}; -std::string srs_client_type_string(SrsRtmpConnType type); - -/** -* store the handshake bytes, -* for smart switch between complex and simple handshake. -*/ -class SrsHandshakeBytes -{ -public: - // [1+1536] - char* c0c1; - // [1+1536+1536] - char* s0s1s2; - // [1536] - char* c2; -public: - SrsHandshakeBytes(); - virtual ~SrsHandshakeBytes(); -public: - virtual int read_c0c1(ISrsProtocolReaderWriter* io); - virtual int read_s0s1s2(ISrsProtocolReaderWriter* io); - virtual int read_c2(ISrsProtocolReaderWriter* io); - virtual int create_c0c1(); - virtual int create_s0s1s2(const char* c1 = NULL); - virtual int create_c2(); -}; - -/** -* implements the client role protocol. -*/ -class SrsRtmpClient -{ -private: - SrsHandshakeBytes* hs_bytes; -protected: - SrsProtocol* protocol; - ISrsProtocolReaderWriter* io; -public: - SrsRtmpClient(ISrsProtocolReaderWriter* skt); - virtual ~SrsRtmpClient(); -// protocol methods proxy -public: - /** - * set the recv timeout in us. - * if timeout, recv/send message return ERROR_SOCKET_TIMEOUT. - */ - virtual void set_recv_timeout(int64_t timeout_us); - /** - * set the send timeout in us. - * if timeout, recv/send message return ERROR_SOCKET_TIMEOUT. - */ - virtual void set_send_timeout(int64_t timeout_us); - /** - * get recv/send bytes. - */ - virtual int64_t get_recv_bytes(); - virtual int64_t get_send_bytes(); - /** - * recv a RTMP message, which is bytes oriented. - * user can use decode_message to get the decoded RTMP packet. - * @param pmsg, set the received message, - * always NULL if error, - * NULL for unknown packet but return success. - * never NULL if decode success. - * @remark, drop message when msg is empty or payload length is empty. - */ - virtual int recv_message(SrsCommonMessage** pmsg); - /** - * decode bytes oriented RTMP message to RTMP packet, - * @param ppacket, output decoded packet, - * always NULL if error, never NULL if success. - * @return error when unknown packet, error when decode failed. - */ - virtual int decode_message(SrsCommonMessage* msg, SrsPacket** ppacket); - /** - * send the RTMP message and always free it. - * user must never free or use the msg after this method, - * for it will always free the msg. - * @param msg, the msg to send out, never be NULL. - * @param stream_id, the stream id of packet to send over, 0 for control message. - */ - virtual int send_and_free_message(SrsSharedPtrMessage* msg, int stream_id); - /** - * send the RTMP message and always free it. - * user must never free or use the msg after this method, - * for it will always free the msg. - * @param msgs, the msgs to send out, never be NULL. - * @param nb_msgs, the size of msgs to send out. - * @param stream_id, the stream id of packet to send over, 0 for control message. - */ - virtual int send_and_free_messages(SrsSharedPtrMessage** msgs, int nb_msgs, int stream_id); - /** - * send the RTMP packet and always free it. - * user must never free or use the packet after this method, - * for it will always free the packet. - * @param packet, the packet to send out, never be NULL. - * @param stream_id, the stream id of packet to send over, 0 for control message. - */ - virtual int send_and_free_packet(SrsPacket* packet, int stream_id); -public: - /** - * handshake with server, try complex, then simple handshake. - */ - virtual int handshake(); - /** - * only use simple handshake - */ - virtual int simple_handshake(); - /** - * only use complex handshake - */ - virtual int complex_handshake(); - /** - * set req to use the original request of client: - * pageUrl and swfUrl for refer antisuck. - * args for edge to origin traverse auth, @see SrsRequest.args - */ - virtual int connect_app(std::string app, std::string tc_url, - SrsRequest* req, bool debug_srs_upnode); - /** - * connect to server, get the debug srs info. - * - * @param app, the app to connect at. - * @param tc_url, the tcUrl to connect at. - * @param req, the optional req object, use the swfUrl/pageUrl if specified. NULL to ignore. - * - * SRS debug info: - * @param srs_server_ip, debug info, server ip client connected at. - * @param srs_server, server info. - * @param srs_primary, primary authors. - * @param srs_authors, authors. - * @param srs_id, int, debug info, client id in server log. - * @param srs_pid, int, debug info, server pid in log. - */ - virtual int connect_app2( - std::string app, std::string tc_url, SrsRequest* req, bool debug_srs_upnode, - std::string& srs_server_ip, std::string& srs_server, std::string& srs_primary, - std::string& srs_authors, std::string& srs_version, int& srs_id, - int& srs_pid - ); - /** - * create a stream, then play/publish data over this stream. - */ - virtual int create_stream(int& stream_id); - /** - * start play stream. - */ - virtual int play(std::string stream, int stream_id); - /** - * start publish stream. use flash publish workflow: - * connect-app => create-stream => flash-publish - */ - virtual int publish(std::string stream, int stream_id); - /** - * start publish stream. use FMLE publish workflow: - * connect-app => FMLE publish - */ - virtual int fmle_publish(std::string stream, int& stream_id); -public: - /** - * expect a specified message, drop others util got specified one. - * @pmsg, user must free it. NULL if not success. - * @ppacket, store in the pmsg, user must never free it. NULL if not success. - * @remark, only when success, user can use and must free the pmsg/ppacket. - * for example: - SrsCommonMessage* msg = NULL; - SrsConnectAppResPacket* pkt = NULL; - if ((ret = srs_rtmp_expect_message(protocol, &msg, &pkt)) != ERROR_SUCCESS) { - return ret; - } - // use pkt - * user should never recv message and convert it, use this method instead. - * if need to set timeout, use set timeout of SrsProtocol. - */ - template - int expect_message(SrsCommonMessage** pmsg, T** ppacket) - { - return protocol->expect_message(pmsg, ppacket); - } -}; - -/** -* the rtmp provices rtmp-command-protocol services, -* a high level protocol, media stream oriented services, -* such as connect to vhost/app, play stream, get audio/video data. -*/ -class SrsRtmpServer -{ -private: - SrsHandshakeBytes* hs_bytes; - SrsProtocol* protocol; - ISrsProtocolReaderWriter* io; -public: - SrsRtmpServer(ISrsProtocolReaderWriter* skt); - virtual ~SrsRtmpServer(); -// protocol methods proxy -public: - /** - * set the auto response message when recv for protocol stack. - * @param v, whether auto response message when recv message. - * @see: https://github.com/simple-rtmp-server/srs/issues/217 - */ - virtual void set_auto_response(bool v); -#ifdef SRS_PERF_MERGED_READ - /** - * to improve read performance, merge some packets then read, - * when it on and read small bytes, we sleep to wait more data., - * that is, we merge some data to read together. - * @param v true to ename merged read. - * @param handler the handler when merge read is enabled. - * @see https://github.com/simple-rtmp-server/srs/issues/241 - */ - virtual void set_merge_read(bool v, IMergeReadHandler* handler); - /** - * create buffer with specifeid size. - * @param buffer the size of buffer. - * @remark when MR(SRS_PERF_MERGED_READ) disabled, always set to 8K. - * @remark when buffer changed, the previous ptr maybe invalid. - * @see https://github.com/simple-rtmp-server/srs/issues/241 - */ - virtual void set_recv_buffer(int buffer_size); -#endif - /** - * set/get the recv timeout in us. - * if timeout, recv/send message return ERROR_SOCKET_TIMEOUT. - */ - virtual void set_recv_timeout(int64_t timeout_us); - virtual int64_t get_recv_timeout(); - /** - * set/get the send timeout in us. - * if timeout, recv/send message return ERROR_SOCKET_TIMEOUT. - */ - virtual void set_send_timeout(int64_t timeout_us); - virtual int64_t get_send_timeout(); - /** - * get recv/send bytes. - */ - virtual int64_t get_recv_bytes(); - virtual int64_t get_send_bytes(); - /** - * recv a RTMP message, which is bytes oriented. - * user can use decode_message to get the decoded RTMP packet. - * @param pmsg, set the received message, - * always NULL if error, - * NULL for unknown packet but return success. - * never NULL if decode success. - * @remark, drop message when msg is empty or payload length is empty. - */ - virtual int recv_message(SrsCommonMessage** pmsg); - /** - * decode bytes oriented RTMP message to RTMP packet, - * @param ppacket, output decoded packet, - * always NULL if error, never NULL if success. - * @return error when unknown packet, error when decode failed. - */ - virtual int decode_message(SrsCommonMessage* msg, SrsPacket** ppacket); - /** - * send the RTMP message and always free it. - * user must never free or use the msg after this method, - * for it will always free the msg. - * @param msg, the msg to send out, never be NULL. - * @param stream_id, the stream id of packet to send over, 0 for control message. - */ - virtual int send_and_free_message(SrsSharedPtrMessage* msg, int stream_id); - /** - * send the RTMP message and always free it. - * user must never free or use the msg after this method, - * for it will always free the msg. - * @param msgs, the msgs to send out, never be NULL. - * @param nb_msgs, the size of msgs to send out. - * @param stream_id, the stream id of packet to send over, 0 for control message. - * - * @remark performance issue, to support 6k+ 250kbps client, - * @see https://github.com/simple-rtmp-server/srs/issues/194 - */ - virtual int send_and_free_messages(SrsSharedPtrMessage** msgs, int nb_msgs, int stream_id); - /** - * send the RTMP packet and always free it. - * user must never free or use the packet after this method, - * for it will always free the packet. - * @param packet, the packet to send out, never be NULL. - * @param stream_id, the stream id of packet to send over, 0 for control message. - */ - virtual int send_and_free_packet(SrsPacket* packet, int stream_id); -public: - /** - * handshake with client, try complex then simple. - */ - virtual int handshake(); - /** - * do connect app with client, to discovery tcUrl. - */ - virtual int connect_app(SrsRequest* req); - /** - * set ack size to client, client will send ack-size for each ack window - */ - virtual int set_window_ack_size(int ack_size); - /** - * @type: The sender can mark this message hard (0), soft (1), or dynamic (2) - * using the Limit type field. - */ - virtual int set_peer_bandwidth(int bandwidth, int type); - /** - * @param server_ip the ip of server. - */ - virtual int response_connect_app(SrsRequest* req, const char* server_ip = NULL); - /** - * reject the connect app request. - */ - virtual void response_connect_reject(SrsRequest* req, const char* desc); - /** - * response client the onBWDone message. - */ - virtual int on_bw_done(); - /** - * recv some message to identify the client. - * @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, double& duration); - /** - * set the chunk size when client type identified. - */ - virtual int set_chunk_size(int chunk_size); - /** - * when client type is play, response with packets: - * StreamBegin, - * onStatus(NetStream.Play.Reset), onStatus(NetStream.Play.Start)., - * |RtmpSampleAccess(false, false), - * onStatus(NetStream.Data.Start). - */ - virtual int start_play(int stream_id); - /** - * when client(type is play) send pause message, - * if is_pause, response the following packets: - * onStatus(NetStream.Pause.Notify) - * StreamEOF - * if not is_pause, response the following packets: - * onStatus(NetStream.Unpause.Notify) - * StreamBegin - */ - virtual int on_play_client_pause(int stream_id, bool is_pause); - /** - * when client type is publish, response with packets: - * releaseStream response - * FCPublish - * FCPublish response - * createStream response - * onFCPublish(NetStream.Publish.Start) - * onStatus(NetStream.Publish.Start) - */ - virtual int start_fmle_publish(int stream_id); - /** - * process the FMLE unpublish event. - * @unpublish_tid the unpublish request transaction id. - */ - virtual int fmle_unpublish(int stream_id, double unpublish_tid); - /** - * when client type is publish, response with packets: - * onStatus(NetStream.Publish.Start) - */ - virtual int start_flash_publish(int stream_id); -public: - /** - * expect a specified message, drop others util got specified one. - * @pmsg, user must free it. NULL if not success. - * @ppacket, store in the pmsg, user must never free it. NULL if not success. - * @remark, only when success, user can use and must free the pmsg/ppacket. - * for example: - SrsCommonMessage* msg = NULL; - SrsConnectAppResPacket* pkt = NULL; - if ((ret = srs_rtmp_expect_message(protocol, &msg, &pkt)) != ERROR_SUCCESS) { - return ret; - } - // use pkt - * user should never recv message and convert it, use this method instead. - * if need to set timeout, use set timeout of SrsProtocol. - */ - template - int expect_message(SrsCommonMessage** pmsg, T** ppacket) - { - return protocol->expect_message(pmsg, ppacket); - } -private: - 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, double& duration); -}; - -#endif - diff --git a/trunk/src/protocol/srs_rtmp_stack.cpp b/trunk/src/protocol/srs_rtmp_stack.cpp index 77a66249a..38c9ed46c 100644 --- a/trunk/src/protocol/srs_rtmp_stack.cpp +++ b/trunk/src/protocol/srs_rtmp_stack.cpp @@ -30,6 +30,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include #include +#include // for srs-librtmp, @see https://github.com/simple-rtmp-server/srs/issues/213 #ifndef _WIN32 @@ -39,6 +40,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include using namespace std; +// FMLE +#define RTMP_AMF0_COMMAND_ON_FC_PUBLISH "onFCPublish" +#define RTMP_AMF0_COMMAND_ON_FC_UNPUBLISH "onFCUnpublish" + +// default stream id for response the createStream request. +#define SRS_DEFAULT_SID 1 + // when got a messae header, there must be some data, // increase recv timeout to got an entire message. #define SRS_MIN_RECV_TIMEOUT_US (int64_t)(60*1000*1000LL) @@ -1652,6 +1660,1435 @@ SrsChunkStream::~SrsChunkStream() srs_freep(msg); } +SrsRequest::SrsRequest() +{ + objectEncoding = RTMP_SIG_AMF0_VER; + duration = -1; + args = NULL; +} + +SrsRequest::~SrsRequest() +{ + srs_freep(args); +} + +SrsRequest* SrsRequest::copy() +{ + SrsRequest* cp = new SrsRequest(); + + cp->ip = ip; + cp->app = app; + cp->objectEncoding = objectEncoding; + cp->pageUrl = pageUrl; + cp->host = host; + cp->port = port; + cp->param = param; + cp->schema = schema; + cp->stream = stream; + cp->swfUrl = swfUrl; + cp->tcUrl = tcUrl; + cp->vhost = vhost; + cp->duration = duration; + if (args) { + cp->args = args->copy()->to_object(); + } + + return cp; +} + +void SrsRequest::update_auth(SrsRequest* req) +{ + pageUrl = req->pageUrl; + swfUrl = req->swfUrl; + tcUrl = req->tcUrl; + + if (args) { + srs_freep(args); + } + if (req->args) { + args = req->args->copy()->to_object(); + } + + srs_info("update req of soruce for auth ok"); +} + +string SrsRequest::get_stream_url() +{ + return srs_generate_stream_url(vhost, app, stream); +} + +void SrsRequest::strip() +{ + // remove the unsupported chars in names. + host = srs_string_remove(host, "/ \n\r\t"); + vhost = srs_string_remove(vhost, "/ \n\r\t"); + app = srs_string_remove(app, " \n\r\t"); + stream = srs_string_remove(stream, " \n\r\t"); + + // remove end slash of app/stream + app = srs_string_trim_end(app, "/"); + stream = srs_string_trim_end(stream, "/"); + + // remove start slash of app/stream + app = srs_string_trim_start(app, "/"); + stream = srs_string_trim_start(stream, "/"); +} + +SrsResponse::SrsResponse() +{ + stream_id = SRS_DEFAULT_SID; +} + +SrsResponse::~SrsResponse() +{ +} + +string srs_client_type_string(SrsRtmpConnType type) +{ + switch (type) { + case SrsRtmpConnPlay: return "Play"; + case SrsRtmpConnFlashPublish: return "publish(FlashPublish)"; + case SrsRtmpConnFMLEPublish: return "publish(FMLEPublish)"; + default: return "Unknown"; + } +} + +SrsHandshakeBytes::SrsHandshakeBytes() +{ + c0c1 = s0s1s2 = c2 = NULL; +} + +SrsHandshakeBytes::~SrsHandshakeBytes() +{ + srs_freep(c0c1); + srs_freep(s0s1s2); + srs_freep(c2); +} + +int SrsHandshakeBytes::read_c0c1(ISrsProtocolReaderWriter* io) +{ + int ret = ERROR_SUCCESS; + + if (c0c1) { + return ret; + } + + ssize_t nsize; + + c0c1 = new char[1537]; + if ((ret = io->read_fully(c0c1, 1537, &nsize)) != ERROR_SUCCESS) { + srs_warn("read c0c1 failed. ret=%d", ret); + return ret; + } + srs_verbose("read c0c1 success."); + + return ret; +} + +int SrsHandshakeBytes::read_s0s1s2(ISrsProtocolReaderWriter* io) +{ + int ret = ERROR_SUCCESS; + + if (s0s1s2) { + return ret; + } + + ssize_t nsize; + + s0s1s2 = new char[3073]; + if ((ret = io->read_fully(s0s1s2, 3073, &nsize)) != ERROR_SUCCESS) { + srs_warn("read s0s1s2 failed. ret=%d", ret); + return ret; + } + srs_verbose("read s0s1s2 success."); + + return ret; +} + +int SrsHandshakeBytes::read_c2(ISrsProtocolReaderWriter* io) +{ + int ret = ERROR_SUCCESS; + + if (c2) { + return ret; + } + + ssize_t nsize; + + c2 = new char[1536]; + if ((ret = io->read_fully(c2, 1536, &nsize)) != ERROR_SUCCESS) { + srs_warn("read c2 failed. ret=%d", ret); + return ret; + } + srs_verbose("read c2 success."); + + return ret; +} + +int SrsHandshakeBytes::create_c0c1() +{ + int ret = ERROR_SUCCESS; + + if (c0c1) { + return ret; + } + + c0c1 = new char[1537]; + srs_random_generate(c0c1, 1537); + + // plain text required. + SrsStream stream; + if ((ret = stream.initialize(c0c1, 9)) != ERROR_SUCCESS) { + return ret; + } + stream.write_1bytes(0x03); + stream.write_4bytes((int32_t)::time(NULL)); + stream.write_4bytes(0x00); + + return ret; +} + +int SrsHandshakeBytes::create_s0s1s2(const char* c1) +{ + int ret = ERROR_SUCCESS; + + if (s0s1s2) { + return ret; + } + + s0s1s2 = new char[3073]; + srs_random_generate(s0s1s2, 3073); + + // plain text required. + SrsStream stream; + if ((ret = stream.initialize(s0s1s2, 9)) != ERROR_SUCCESS) { + return ret; + } + stream.write_1bytes(0x03); + stream.write_4bytes((int32_t)::time(NULL)); + // s1 time2 copy from c1 + if (c0c1) { + stream.write_bytes(c0c1 + 1, 4); + } + + // if c1 specified, copy c1 to s2. + // @see: https://github.com/simple-rtmp-server/srs/issues/46 + if (c1) { + memcpy(s0s1s2 + 1537, c1, 1536); + } + + return ret; +} + +int SrsHandshakeBytes::create_c2() +{ + int ret = ERROR_SUCCESS; + + if (c2) { + return ret; + } + + c2 = new char[1536]; + srs_random_generate(c2, 1536); + + // time + SrsStream stream; + if ((ret = stream.initialize(c2, 8)) != ERROR_SUCCESS) { + return ret; + } + stream.write_4bytes((int32_t)::time(NULL)); + // c2 time2 copy from s1 + if (s0s1s2) { + stream.write_bytes(s0s1s2 + 1, 4); + } + + return ret; +} + +SrsRtmpClient::SrsRtmpClient(ISrsProtocolReaderWriter* skt) +{ + io = skt; + protocol = new SrsProtocol(skt); + hs_bytes = new SrsHandshakeBytes(); +} + +SrsRtmpClient::~SrsRtmpClient() +{ + srs_freep(protocol); + srs_freep(hs_bytes); +} + +void SrsRtmpClient::set_recv_timeout(int64_t timeout_us) +{ + protocol->set_recv_timeout(timeout_us); +} + +void SrsRtmpClient::set_send_timeout(int64_t timeout_us) +{ + protocol->set_send_timeout(timeout_us); +} + +int64_t SrsRtmpClient::get_recv_bytes() +{ + return protocol->get_recv_bytes(); +} + +int64_t SrsRtmpClient::get_send_bytes() +{ + return protocol->get_send_bytes(); +} + +int SrsRtmpClient::recv_message(SrsCommonMessage** pmsg) +{ + return protocol->recv_message(pmsg); +} + +int SrsRtmpClient::decode_message(SrsCommonMessage* msg, SrsPacket** ppacket) +{ + return protocol->decode_message(msg, ppacket); +} + +int SrsRtmpClient::send_and_free_message(SrsSharedPtrMessage* msg, int stream_id) +{ + return protocol->send_and_free_message(msg, stream_id); +} + +int SrsRtmpClient::send_and_free_messages(SrsSharedPtrMessage** msgs, int nb_msgs, int stream_id) +{ + return protocol->send_and_free_messages(msgs, nb_msgs, stream_id); +} + +int SrsRtmpClient::send_and_free_packet(SrsPacket* packet, int stream_id) +{ + return protocol->send_and_free_packet(packet, stream_id); +} + +int SrsRtmpClient::handshake() +{ + int ret = ERROR_SUCCESS; + + srs_assert(hs_bytes); + + SrsComplexHandshake complex_hs; + if ((ret = complex_hs.handshake_with_server(hs_bytes, io)) != ERROR_SUCCESS) { + if (ret == ERROR_RTMP_TRY_SIMPLE_HS) { + SrsSimpleHandshake simple_hs; + if ((ret = simple_hs.handshake_with_server(hs_bytes, io)) != ERROR_SUCCESS) { + return ret; + } + } + return ret; + } + + srs_freep(hs_bytes); + + return ret; +} + +int SrsRtmpClient::simple_handshake() +{ + int ret = ERROR_SUCCESS; + + srs_assert(hs_bytes); + + SrsSimpleHandshake simple_hs; + if ((ret = simple_hs.handshake_with_server(hs_bytes, io)) != ERROR_SUCCESS) { + return ret; + } + + srs_freep(hs_bytes); + + return ret; +} + +int SrsRtmpClient::complex_handshake() +{ + int ret = ERROR_SUCCESS; + + srs_assert(hs_bytes); + + SrsComplexHandshake complex_hs; + if ((ret = complex_hs.handshake_with_server(hs_bytes, io)) != ERROR_SUCCESS) { + return ret; + } + + srs_freep(hs_bytes); + + return ret; +} + +int SrsRtmpClient::connect_app(string app, string tc_url, SrsRequest* req, bool debug_srs_upnode) +{ + std::string srs_server_ip; + std::string srs_server; + std::string srs_primary; + std::string srs_authors; + std::string srs_version; + int srs_id = 0; + int srs_pid = 0; + + return connect_app2(app, tc_url, req, debug_srs_upnode, + srs_server_ip, srs_server, srs_primary, srs_authors, + srs_version, srs_id, srs_pid); +} + +int SrsRtmpClient::connect_app2( + string app, string tc_url, SrsRequest* req, bool debug_srs_upnode, + string& srs_server_ip, string& srs_server, string& srs_primary, + string& srs_authors, string& srs_version, int& srs_id, + int& srs_pid +){ + int ret = ERROR_SUCCESS; + + // Connect(vhost, app) + if (true) { + SrsConnectAppPacket* pkt = new SrsConnectAppPacket(); + + pkt->command_object->set("app", SrsAmf0Any::str(app.c_str())); + pkt->command_object->set("flashVer", SrsAmf0Any::str("WIN 15,0,0,239")); + if (req) { + pkt->command_object->set("swfUrl", SrsAmf0Any::str(req->swfUrl.c_str())); + } else { + pkt->command_object->set("swfUrl", SrsAmf0Any::str()); + } + if (req && req->tcUrl != "") { + pkt->command_object->set("tcUrl", SrsAmf0Any::str(req->tcUrl.c_str())); + } else { + pkt->command_object->set("tcUrl", SrsAmf0Any::str(tc_url.c_str())); + } + pkt->command_object->set("fpad", SrsAmf0Any::boolean(false)); + pkt->command_object->set("capabilities", SrsAmf0Any::number(239)); + pkt->command_object->set("audioCodecs", SrsAmf0Any::number(3575)); + pkt->command_object->set("videoCodecs", SrsAmf0Any::number(252)); + pkt->command_object->set("videoFunction", SrsAmf0Any::number(1)); + if (req) { + pkt->command_object->set("pageUrl", SrsAmf0Any::str(req->pageUrl.c_str())); + } else { + pkt->command_object->set("pageUrl", SrsAmf0Any::str()); + } + pkt->command_object->set("objectEncoding", SrsAmf0Any::number(0)); + + // @see https://github.com/simple-rtmp-server/srs/issues/160 + // the debug_srs_upnode is config in vhost and default to true. + if (debug_srs_upnode && req && req->args) { + srs_freep(pkt->args); + pkt->args = req->args->copy()->to_object(); + } + + if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { + return ret; + } + } + + // Set Window Acknowledgement size(2500000) + if (true) { + SrsSetWindowAckSizePacket* pkt = new SrsSetWindowAckSizePacket(); + pkt->ackowledgement_window_size = 2500000; + if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { + return ret; + } + } + + // expect connect _result + SrsCommonMessage* msg = NULL; + SrsConnectAppResPacket* pkt = NULL; + if ((ret = expect_message(&msg, &pkt)) != ERROR_SUCCESS) { + srs_error("expect connect app response message failed. ret=%d", ret); + return ret; + } + SrsAutoFree(SrsCommonMessage, msg); + SrsAutoFree(SrsConnectAppResPacket, pkt); + + // server info + SrsAmf0Any* data = pkt->info->get_property("data"); + if (data && data->is_ecma_array()) { + SrsAmf0EcmaArray* arr = data->to_ecma_array(); + + SrsAmf0Any* prop = NULL; + if ((prop = arr->ensure_property_string("srs_primary")) != NULL) { + srs_primary = prop->to_str(); + } + if ((prop = arr->ensure_property_string("srs_authors")) != NULL) { + srs_authors = prop->to_str(); + } + if ((prop = arr->ensure_property_string("srs_version")) != NULL) { + srs_version = prop->to_str(); + } + if ((prop = arr->ensure_property_string("srs_server_ip")) != NULL) { + srs_server_ip = prop->to_str(); + } + if ((prop = arr->ensure_property_string("srs_server")) != NULL) { + srs_server = prop->to_str(); + } + if ((prop = arr->ensure_property_number("srs_id")) != NULL) { + srs_id = (int)prop->to_number(); + } + if ((prop = arr->ensure_property_number("srs_pid")) != NULL) { + srs_pid = (int)prop->to_number(); + } + } + srs_trace("connected, version=%s, ip=%s, pid=%d, id=%d, dsu=%d", + srs_version.c_str(), srs_server_ip.c_str(), srs_pid, srs_id, debug_srs_upnode); + + return ret; +} + +int SrsRtmpClient::create_stream(int& stream_id) +{ + int ret = ERROR_SUCCESS; + + // CreateStream + if (true) { + SrsCreateStreamPacket* pkt = new SrsCreateStreamPacket(); + if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { + return ret; + } + } + + // CreateStream _result. + if (true) { + SrsCommonMessage* msg = NULL; + SrsCreateStreamResPacket* pkt = NULL; + if ((ret = expect_message(&msg, &pkt)) != ERROR_SUCCESS) { + srs_error("expect create stream response message failed. ret=%d", ret); + return ret; + } + SrsAutoFree(SrsCommonMessage, msg); + SrsAutoFree(SrsCreateStreamResPacket, pkt); + srs_info("get create stream response message"); + + stream_id = (int)pkt->stream_id; + } + + return ret; +} + +int SrsRtmpClient::play(string stream, int stream_id) +{ + int ret = ERROR_SUCCESS; + + // Play(stream) + if (true) { + SrsPlayPacket* pkt = new SrsPlayPacket(); + pkt->stream_name = stream; + if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { + srs_error("send play stream failed. " + "stream=%s, stream_id=%d, ret=%d", + stream.c_str(), stream_id, ret); + return ret; + } + } + + // SetBufferLength(1000ms) + int buffer_length_ms = 1000; + if (true) { + SrsUserControlPacket* pkt = new SrsUserControlPacket(); + + pkt->event_type = SrcPCUCSetBufferLength; + pkt->event_data = stream_id; + pkt->extra_data = buffer_length_ms; + + if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { + srs_error("send set buffer length failed. " + "stream=%s, stream_id=%d, bufferLength=%d, ret=%d", + stream.c_str(), stream_id, buffer_length_ms, ret); + return ret; + } + } + + // SetChunkSize + if (true) { + SrsSetChunkSizePacket* pkt = new SrsSetChunkSizePacket(); + pkt->chunk_size = SRS_CONSTS_RTMP_SRS_CHUNK_SIZE; + if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { + srs_error("send set chunk size failed. " + "stream=%s, chunk_size=%d, ret=%d", + stream.c_str(), SRS_CONSTS_RTMP_SRS_CHUNK_SIZE, ret); + return ret; + } + } + + return ret; +} + +int SrsRtmpClient::publish(string stream, int stream_id) +{ + int ret = ERROR_SUCCESS; + + // SetChunkSize + if (true) { + SrsSetChunkSizePacket* pkt = new SrsSetChunkSizePacket(); + pkt->chunk_size = SRS_CONSTS_RTMP_SRS_CHUNK_SIZE; + if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { + srs_error("send set chunk size failed. " + "stream=%s, chunk_size=%d, ret=%d", + stream.c_str(), SRS_CONSTS_RTMP_SRS_CHUNK_SIZE, ret); + return ret; + } + } + + // publish(stream) + if (true) { + SrsPublishPacket* pkt = new SrsPublishPacket(); + pkt->stream_name = stream; + if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { + srs_error("send publish message failed. " + "stream=%s, stream_id=%d, ret=%d", + stream.c_str(), stream_id, ret); + return ret; + } + } + + return ret; +} + +int SrsRtmpClient::fmle_publish(string stream, int& stream_id) +{ + stream_id = 0; + + int ret = ERROR_SUCCESS; + + // SrsFMLEStartPacket + if (true) { + SrsFMLEStartPacket* pkt = SrsFMLEStartPacket::create_release_stream(stream); + if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { + srs_error("send FMLE publish " + "release stream failed. stream=%s, ret=%d", stream.c_str(), ret); + return ret; + } + } + + // FCPublish + if (true) { + SrsFMLEStartPacket* pkt = SrsFMLEStartPacket::create_FC_publish(stream); + if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { + srs_error("send FMLE publish " + "FCPublish failed. stream=%s, ret=%d", stream.c_str(), ret); + return ret; + } + } + + // CreateStream + if (true) { + SrsCreateStreamPacket* pkt = new SrsCreateStreamPacket(); + pkt->transaction_id = 4; + if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { + srs_error("send FMLE publish " + "createStream failed. stream=%s, ret=%d", stream.c_str(), ret); + return ret; + } + } + + // expect result of CreateStream + if (true) { + SrsCommonMessage* msg = NULL; + SrsCreateStreamResPacket* pkt = NULL; + if ((ret = expect_message(&msg, &pkt)) != ERROR_SUCCESS) { + srs_error("expect create stream response message failed. ret=%d", ret); + return ret; + } + SrsAutoFree(SrsCommonMessage, msg); + SrsAutoFree(SrsCreateStreamResPacket, pkt); + srs_info("get create stream response message"); + + stream_id = (int)pkt->stream_id; + } + + // publish(stream) + if (true) { + SrsPublishPacket* pkt = new SrsPublishPacket(); + pkt->stream_name = stream; + if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { + srs_error("send FMLE publish publish failed. " + "stream=%s, stream_id=%d, ret=%d", stream.c_str(), stream_id, ret); + return ret; + } + } + + return ret; +} + +SrsRtmpServer::SrsRtmpServer(ISrsProtocolReaderWriter* skt) +{ + io = skt; + protocol = new SrsProtocol(skt); + hs_bytes = new SrsHandshakeBytes(); +} + +SrsRtmpServer::~SrsRtmpServer() +{ + srs_freep(protocol); + srs_freep(hs_bytes); +} + +void SrsRtmpServer::set_auto_response(bool v) +{ + protocol->set_auto_response(v); +} + +#ifdef SRS_PERF_MERGED_READ +void SrsRtmpServer::set_merge_read(bool v, IMergeReadHandler* handler) +{ + protocol->set_merge_read(v, handler); +} + +void SrsRtmpServer::set_recv_buffer(int buffer_size) +{ + protocol->set_recv_buffer(buffer_size); +} +#endif + +void SrsRtmpServer::set_recv_timeout(int64_t timeout_us) +{ + protocol->set_recv_timeout(timeout_us); +} + +int64_t SrsRtmpServer::get_recv_timeout() +{ + return protocol->get_recv_timeout(); +} + +void SrsRtmpServer::set_send_timeout(int64_t timeout_us) +{ + protocol->set_send_timeout(timeout_us); +} + +int64_t SrsRtmpServer::get_send_timeout() +{ + return protocol->get_send_timeout(); +} + +int64_t SrsRtmpServer::get_recv_bytes() +{ + return protocol->get_recv_bytes(); +} + +int64_t SrsRtmpServer::get_send_bytes() +{ + return protocol->get_send_bytes(); +} + +int SrsRtmpServer::recv_message(SrsCommonMessage** pmsg) +{ + return protocol->recv_message(pmsg); +} + +int SrsRtmpServer::decode_message(SrsCommonMessage* msg, SrsPacket** ppacket) +{ + return protocol->decode_message(msg, ppacket); +} + +int SrsRtmpServer::send_and_free_message(SrsSharedPtrMessage* msg, int stream_id) +{ + return protocol->send_and_free_message(msg, stream_id); +} + +int SrsRtmpServer::send_and_free_messages(SrsSharedPtrMessage** msgs, int nb_msgs, int stream_id) +{ + return protocol->send_and_free_messages(msgs, nb_msgs, stream_id); +} + +int SrsRtmpServer::send_and_free_packet(SrsPacket* packet, int stream_id) +{ + return protocol->send_and_free_packet(packet, stream_id); +} + +int SrsRtmpServer::handshake() +{ + int ret = ERROR_SUCCESS; + + srs_assert(hs_bytes); + + SrsComplexHandshake complex_hs; + if ((ret = complex_hs.handshake_with_client(hs_bytes, io)) != ERROR_SUCCESS) { + if (ret == ERROR_RTMP_TRY_SIMPLE_HS) { + SrsSimpleHandshake simple_hs; + if ((ret = simple_hs.handshake_with_client(hs_bytes, io)) != ERROR_SUCCESS) { + return ret; + } + } + return ret; + } + + srs_freep(hs_bytes); + + return ret; +} + +int SrsRtmpServer::connect_app(SrsRequest* req) +{ + int ret = ERROR_SUCCESS; + + SrsCommonMessage* msg = NULL; + SrsConnectAppPacket* pkt = NULL; + if ((ret = expect_message(&msg, &pkt)) != ERROR_SUCCESS) { + srs_error("expect connect app message failed. ret=%d", ret); + return ret; + } + SrsAutoFree(SrsCommonMessage, msg); + SrsAutoFree(SrsConnectAppPacket, pkt); + srs_info("get connect app message"); + + SrsAmf0Any* prop = NULL; + + if ((prop = pkt->command_object->ensure_property_string("tcUrl")) == NULL) { + ret = ERROR_RTMP_REQ_CONNECT; + srs_error("invalid request, must specifies the tcUrl. ret=%d", ret); + return ret; + } + req->tcUrl = prop->to_str(); + + if ((prop = pkt->command_object->ensure_property_string("pageUrl")) != NULL) { + req->pageUrl = prop->to_str(); + } + + if ((prop = pkt->command_object->ensure_property_string("swfUrl")) != NULL) { + req->swfUrl = prop->to_str(); + } + + if ((prop = pkt->command_object->ensure_property_number("objectEncoding")) != NULL) { + req->objectEncoding = prop->to_number(); + } + + if (pkt->args) { + srs_freep(req->args); + req->args = pkt->args->copy()->to_object(); + srs_info("copy edge traverse to origin auth args."); + } + + srs_info("get connect app message params success."); + + srs_discovery_tc_url(req->tcUrl, + req->schema, req->host, req->vhost, req->app, req->port, + req->param); + req->strip(); + + return ret; +} + +int SrsRtmpServer::set_window_ack_size(int ack_size) +{ + int ret = ERROR_SUCCESS; + + SrsSetWindowAckSizePacket* pkt = new SrsSetWindowAckSizePacket(); + pkt->ackowledgement_window_size = ack_size; + if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { + srs_error("send ack size message failed. ret=%d", ret); + return ret; + } + srs_info("send ack size message success. ack_size=%d", ack_size); + + return ret; +} + +int SrsRtmpServer::set_peer_bandwidth(int bandwidth, int type) +{ + int ret = ERROR_SUCCESS; + + SrsSetPeerBandwidthPacket* pkt = new SrsSetPeerBandwidthPacket(); + pkt->bandwidth = bandwidth; + pkt->type = type; + if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { + srs_error("send set bandwidth message failed. ret=%d", ret); + return ret; + } + srs_info("send set bandwidth message " + "success. bandwidth=%d, type=%d", bandwidth, type); + + return ret; +} + +int SrsRtmpServer::response_connect_app(SrsRequest *req, const char* server_ip) +{ + int ret = ERROR_SUCCESS; + + SrsConnectAppResPacket* pkt = new SrsConnectAppResPacket(); + + pkt->props->set("fmsVer", SrsAmf0Any::str("FMS/"RTMP_SIG_FMS_VER)); + pkt->props->set("capabilities", SrsAmf0Any::number(127)); + pkt->props->set("mode", SrsAmf0Any::number(1)); + + pkt->info->set(StatusLevel, SrsAmf0Any::str(StatusLevelStatus)); + pkt->info->set(StatusCode, SrsAmf0Any::str(StatusCodeConnectSuccess)); + pkt->info->set(StatusDescription, SrsAmf0Any::str("Connection succeeded")); + pkt->info->set("objectEncoding", SrsAmf0Any::number(req->objectEncoding)); + SrsAmf0EcmaArray* data = SrsAmf0Any::ecma_array(); + pkt->info->set("data", data); + + data->set("version", SrsAmf0Any::str(RTMP_SIG_FMS_VER)); + data->set("srs_sig", SrsAmf0Any::str(RTMP_SIG_SRS_KEY)); + data->set("srs_server", SrsAmf0Any::str(RTMP_SIG_SRS_SERVER)); + data->set("srs_license", SrsAmf0Any::str(RTMP_SIG_SRS_LICENSE)); + data->set("srs_role", SrsAmf0Any::str(RTMP_SIG_SRS_ROLE)); + data->set("srs_url", SrsAmf0Any::str(RTMP_SIG_SRS_URL)); + data->set("srs_version", SrsAmf0Any::str(RTMP_SIG_SRS_VERSION)); + data->set("srs_site", SrsAmf0Any::str(RTMP_SIG_SRS_WEB)); + data->set("srs_email", SrsAmf0Any::str(RTMP_SIG_SRS_EMAIL)); + data->set("srs_copyright", SrsAmf0Any::str(RTMP_SIG_SRS_COPYRIGHT)); + data->set("srs_primary", SrsAmf0Any::str(RTMP_SIG_SRS_PRIMARY)); + data->set("srs_authors", SrsAmf0Any::str(RTMP_SIG_SRS_AUTHROS)); + + if (server_ip) { + data->set("srs_server_ip", SrsAmf0Any::str(server_ip)); + } + // for edge to directly get the id of client. + data->set("srs_pid", SrsAmf0Any::number(getpid())); + data->set("srs_id", SrsAmf0Any::number(_srs_context->get_id())); + + if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { + srs_error("send connect app response message failed. ret=%d", ret); + return ret; + } + srs_info("send connect app response message success."); + + return ret; +} + +void SrsRtmpServer::response_connect_reject(SrsRequest* /*req*/, const char* desc) +{ + int ret = ERROR_SUCCESS; + + SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket(); + pkt->data->set(StatusLevel, SrsAmf0Any::str(StatusLevelError)); + pkt->data->set(StatusCode, SrsAmf0Any::str(StatusCodeConnectRejected)); + pkt->data->set(StatusDescription, SrsAmf0Any::str(desc)); + + if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { + srs_error("send connect app response rejected message failed. ret=%d", ret); + return; + } + srs_info("send connect app response rejected message success."); + + return; +} + +int SrsRtmpServer::on_bw_done() +{ + int ret = ERROR_SUCCESS; + + SrsOnBWDonePacket* pkt = new SrsOnBWDonePacket(); + if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { + srs_error("send onBWDone message failed. ret=%d", ret); + return ret; + } + srs_info("send onBWDone message success."); + + return ret; +} + +int SrsRtmpServer::identify_client(int stream_id, SrsRtmpConnType& type, string& stream_name, double& duration) +{ + type = SrsRtmpConnUnknown; + int ret = ERROR_SUCCESS; + + while (true) { + SrsCommonMessage* msg = NULL; + if ((ret = protocol->recv_message(&msg)) != ERROR_SUCCESS) { + if (!srs_is_client_gracefully_close(ret)) { + srs_error("recv identify client message failed. ret=%d", ret); + } + return ret; + } + + SrsAutoFree(SrsCommonMessage, msg); + SrsMessageHeader& h = msg->header; + + if (h.is_ackledgement() || h.is_set_chunk_size() || h.is_window_ackledgement_size() || h.is_user_control_message()) { + continue; + } + + if (!h.is_amf0_command() && !h.is_amf3_command()) { + srs_trace("identify ignore messages except " + "AMF0/AMF3 command message. type=%#x", h.message_type); + continue; + } + + SrsPacket* pkt = NULL; + if ((ret = protocol->decode_message(msg, &pkt)) != ERROR_SUCCESS) { + srs_error("identify decode message failed. ret=%d", ret); + return ret; + } + + SrsAutoFree(SrsPacket, pkt); + + 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, duration); + } + if (dynamic_cast(pkt)) { + srs_info("identify client by releaseStream, fmle publish."); + return identify_fmle_publish_client(dynamic_cast(pkt), type, stream_name); + } + if (dynamic_cast(pkt)) { + srs_info("level0 identify client by play."); + return identify_play_client(dynamic_cast(pkt), type, stream_name, duration); + } + // call msg, + // support response null first, + // @see https://github.com/simple-rtmp-server/srs/issues/106 + // TODO: FIXME: response in right way, or forward in edge mode. + SrsCallPacket* call = dynamic_cast(pkt); + if (call) { + SrsCallResPacket* res = new SrsCallResPacket(call->transaction_id); + res->command_object = SrsAmf0Any::null(); + res->response = SrsAmf0Any::null(); + if ((ret = protocol->send_and_free_packet(res, 0)) != ERROR_SUCCESS) { + srs_warn("response call failed. ret=%d", ret); + return ret; + } + continue; + } + + srs_trace("ignore AMF0/AMF3 command message."); + } + + return ret; +} + +int SrsRtmpServer::set_chunk_size(int chunk_size) +{ + int ret = ERROR_SUCCESS; + + SrsSetChunkSizePacket* pkt = new SrsSetChunkSizePacket(); + pkt->chunk_size = chunk_size; + if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { + srs_error("send set chunk size message failed. ret=%d", ret); + return ret; + } + srs_info("send set chunk size message success. chunk_size=%d", chunk_size); + + return ret; +} + +int SrsRtmpServer::start_play(int stream_id) +{ + int ret = ERROR_SUCCESS; + + // StreamBegin + if (true) { + SrsUserControlPacket* pkt = new SrsUserControlPacket(); + pkt->event_type = SrcPCUCStreamBegin; + pkt->event_data = stream_id; + if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { + srs_error("send PCUC(StreamBegin) message failed. ret=%d", ret); + return ret; + } + srs_info("send PCUC(StreamBegin) message success."); + } + + // onStatus(NetStream.Play.Reset) + if (true) { + SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket(); + + pkt->data->set(StatusLevel, SrsAmf0Any::str(StatusLevelStatus)); + pkt->data->set(StatusCode, SrsAmf0Any::str(StatusCodeStreamReset)); + pkt->data->set(StatusDescription, SrsAmf0Any::str("Playing and resetting stream.")); + pkt->data->set(StatusDetails, SrsAmf0Any::str("stream")); + pkt->data->set(StatusClientId, SrsAmf0Any::str(RTMP_SIG_CLIENT_ID)); + + if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { + srs_error("send onStatus(NetStream.Play.Reset) message failed. ret=%d", ret); + return ret; + } + srs_info("send onStatus(NetStream.Play.Reset) message success."); + } + + // onStatus(NetStream.Play.Start) + if (true) { + SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket(); + + pkt->data->set(StatusLevel, SrsAmf0Any::str(StatusLevelStatus)); + pkt->data->set(StatusCode, SrsAmf0Any::str(StatusCodeStreamStart)); + pkt->data->set(StatusDescription, SrsAmf0Any::str("Started playing stream.")); + pkt->data->set(StatusDetails, SrsAmf0Any::str("stream")); + pkt->data->set(StatusClientId, SrsAmf0Any::str(RTMP_SIG_CLIENT_ID)); + + if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { + srs_error("send onStatus(NetStream.Play.Start) message failed. ret=%d", ret); + return ret; + } + srs_info("send onStatus(NetStream.Play.Start) message success."); + } + + // |RtmpSampleAccess(false, false) + if (true) { + SrsSampleAccessPacket* pkt = new SrsSampleAccessPacket(); + + // allow audio/video sample. + // @see: https://github.com/simple-rtmp-server/srs/issues/49 + pkt->audio_sample_access = true; + pkt->video_sample_access = true; + + if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { + srs_error("send |RtmpSampleAccess(false, false) message failed. ret=%d", ret); + return ret; + } + srs_info("send |RtmpSampleAccess(false, false) message success."); + } + + // onStatus(NetStream.Data.Start) + if (true) { + SrsOnStatusDataPacket* pkt = new SrsOnStatusDataPacket(); + pkt->data->set(StatusCode, SrsAmf0Any::str(StatusCodeDataStart)); + if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { + srs_error("send onStatus(NetStream.Data.Start) message failed. ret=%d", ret); + return ret; + } + srs_info("send onStatus(NetStream.Data.Start) message success."); + } + + srs_info("start play success."); + + return ret; +} + +int SrsRtmpServer::on_play_client_pause(int stream_id, bool is_pause) +{ + int ret = ERROR_SUCCESS; + + if (is_pause) { + // onStatus(NetStream.Pause.Notify) + if (true) { + SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket(); + + pkt->data->set(StatusLevel, SrsAmf0Any::str(StatusLevelStatus)); + pkt->data->set(StatusCode, SrsAmf0Any::str(StatusCodeStreamPause)); + pkt->data->set(StatusDescription, SrsAmf0Any::str("Paused stream.")); + + if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { + srs_error("send onStatus(NetStream.Pause.Notify) message failed. ret=%d", ret); + return ret; + } + srs_info("send onStatus(NetStream.Pause.Notify) message success."); + } + // StreamEOF + if (true) { + SrsUserControlPacket* pkt = new SrsUserControlPacket(); + + pkt->event_type = SrcPCUCStreamEOF; + pkt->event_data = stream_id; + + if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { + srs_error("send PCUC(StreamEOF) message failed. ret=%d", ret); + return ret; + } + srs_info("send PCUC(StreamEOF) message success."); + } + } else { + // onStatus(NetStream.Unpause.Notify) + if (true) { + SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket(); + + pkt->data->set(StatusLevel, SrsAmf0Any::str(StatusLevelStatus)); + pkt->data->set(StatusCode, SrsAmf0Any::str(StatusCodeStreamUnpause)); + pkt->data->set(StatusDescription, SrsAmf0Any::str("Unpaused stream.")); + + if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { + srs_error("send onStatus(NetStream.Unpause.Notify) message failed. ret=%d", ret); + return ret; + } + srs_info("send onStatus(NetStream.Unpause.Notify) message success."); + } + // StreanBegin + if (true) { + SrsUserControlPacket* pkt = new SrsUserControlPacket(); + + pkt->event_type = SrcPCUCStreamBegin; + pkt->event_data = stream_id; + + if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { + srs_error("send PCUC(StreanBegin) message failed. ret=%d", ret); + return ret; + } + srs_info("send PCUC(StreanBegin) message success."); + } + } + + return ret; +} + +int SrsRtmpServer::start_fmle_publish(int stream_id) +{ + int ret = ERROR_SUCCESS; + + // FCPublish + double fc_publish_tid = 0; + if (true) { + SrsCommonMessage* msg = NULL; + SrsFMLEStartPacket* pkt = NULL; + if ((ret = expect_message(&msg, &pkt)) != ERROR_SUCCESS) { + srs_error("recv FCPublish message failed. ret=%d", ret); + return ret; + } + srs_info("recv FCPublish request message success."); + + SrsAutoFree(SrsCommonMessage, msg); + SrsAutoFree(SrsFMLEStartPacket, pkt); + + fc_publish_tid = pkt->transaction_id; + } + // FCPublish response + if (true) { + SrsFMLEStartResPacket* pkt = new SrsFMLEStartResPacket(fc_publish_tid); + if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { + srs_error("send FCPublish response message failed. ret=%d", ret); + return ret; + } + srs_info("send FCPublish response message success."); + } + + // createStream + double create_stream_tid = 0; + if (true) { + SrsCommonMessage* msg = NULL; + SrsCreateStreamPacket* pkt = NULL; + if ((ret = expect_message(&msg, &pkt)) != ERROR_SUCCESS) { + srs_error("recv createStream message failed. ret=%d", ret); + return ret; + } + srs_info("recv createStream request message success."); + + SrsAutoFree(SrsCommonMessage, msg); + SrsAutoFree(SrsCreateStreamPacket, pkt); + + create_stream_tid = pkt->transaction_id; + } + // createStream response + if (true) { + SrsCreateStreamResPacket* pkt = new SrsCreateStreamResPacket(create_stream_tid, stream_id); + if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { + srs_error("send createStream response message failed. ret=%d", ret); + return ret; + } + srs_info("send createStream response message success."); + } + + // publish + if (true) { + SrsCommonMessage* msg = NULL; + SrsPublishPacket* pkt = NULL; + if ((ret = expect_message(&msg, &pkt)) != ERROR_SUCCESS) { + srs_error("recv publish message failed. ret=%d", ret); + return ret; + } + srs_info("recv publish request message success."); + + SrsAutoFree(SrsCommonMessage, msg); + SrsAutoFree(SrsPublishPacket, pkt); + } + // publish response onFCPublish(NetStream.Publish.Start) + if (true) { + SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket(); + + pkt->command_name = RTMP_AMF0_COMMAND_ON_FC_PUBLISH; + pkt->data->set(StatusCode, SrsAmf0Any::str(StatusCodePublishStart)); + pkt->data->set(StatusDescription, SrsAmf0Any::str("Started publishing stream.")); + + if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { + srs_error("send onFCPublish(NetStream.Publish.Start) message failed. ret=%d", ret); + return ret; + } + srs_info("send onFCPublish(NetStream.Publish.Start) message success."); + } + // publish response onStatus(NetStream.Publish.Start) + if (true) { + SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket(); + + pkt->data->set(StatusLevel, SrsAmf0Any::str(StatusLevelStatus)); + pkt->data->set(StatusCode, SrsAmf0Any::str(StatusCodePublishStart)); + pkt->data->set(StatusDescription, SrsAmf0Any::str("Started publishing stream.")); + pkt->data->set(StatusClientId, SrsAmf0Any::str(RTMP_SIG_CLIENT_ID)); + + if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { + srs_error("send onStatus(NetStream.Publish.Start) message failed. ret=%d", ret); + return ret; + } + srs_info("send onStatus(NetStream.Publish.Start) message success."); + } + + srs_info("FMLE publish success."); + + return ret; +} + +int SrsRtmpServer::fmle_unpublish(int stream_id, double unpublish_tid) +{ + int ret = ERROR_SUCCESS; + + // publish response onFCUnpublish(NetStream.unpublish.Success) + if (true) { + SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket(); + + pkt->command_name = RTMP_AMF0_COMMAND_ON_FC_UNPUBLISH; + pkt->data->set(StatusCode, SrsAmf0Any::str(StatusCodeUnpublishSuccess)); + pkt->data->set(StatusDescription, SrsAmf0Any::str("Stop publishing stream.")); + + if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { + srs_error("send onFCUnpublish(NetStream.unpublish.Success) message failed. ret=%d", ret); + return ret; + } + srs_info("send onFCUnpublish(NetStream.unpublish.Success) message success."); + } + // FCUnpublish response + if (true) { + SrsFMLEStartResPacket* pkt = new SrsFMLEStartResPacket(unpublish_tid); + if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { + srs_error("send FCUnpublish response message failed. ret=%d", ret); + return ret; + } + srs_info("send FCUnpublish response message success."); + } + // publish response onStatus(NetStream.Unpublish.Success) + if (true) { + SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket(); + + pkt->data->set(StatusLevel, SrsAmf0Any::str(StatusLevelStatus)); + pkt->data->set(StatusCode, SrsAmf0Any::str(StatusCodeUnpublishSuccess)); + pkt->data->set(StatusDescription, SrsAmf0Any::str("Stream is now unpublished")); + pkt->data->set(StatusClientId, SrsAmf0Any::str(RTMP_SIG_CLIENT_ID)); + + if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { + srs_error("send onStatus(NetStream.Unpublish.Success) message failed. ret=%d", ret); + return ret; + } + srs_info("send onStatus(NetStream.Unpublish.Success) message success."); + } + + srs_info("FMLE unpublish success."); + + return ret; +} + +int SrsRtmpServer::start_flash_publish(int stream_id) +{ + int ret = ERROR_SUCCESS; + + // publish response onStatus(NetStream.Publish.Start) + if (true) { + SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket(); + + pkt->data->set(StatusLevel, SrsAmf0Any::str(StatusLevelStatus)); + pkt->data->set(StatusCode, SrsAmf0Any::str(StatusCodePublishStart)); + pkt->data->set(StatusDescription, SrsAmf0Any::str("Started publishing stream.")); + pkt->data->set(StatusClientId, SrsAmf0Any::str(RTMP_SIG_CLIENT_ID)); + + if ((ret = protocol->send_and_free_packet(pkt, stream_id)) != ERROR_SUCCESS) { + srs_error("send onStatus(NetStream.Publish.Start) message failed. ret=%d", ret); + return ret; + } + srs_info("send onStatus(NetStream.Publish.Start) message success."); + } + + srs_info("flash publish success."); + + return ret; +} + +int SrsRtmpServer::identify_create_stream_client(SrsCreateStreamPacket* req, int stream_id, SrsRtmpConnType& type, string& stream_name, double& duration) +{ + int ret = ERROR_SUCCESS; + + if (true) { + SrsCreateStreamResPacket* pkt = new SrsCreateStreamResPacket(req->transaction_id, stream_id); + if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { + srs_error("send createStream response message failed. ret=%d", ret); + return ret; + } + srs_info("send createStream response message success."); + } + + while (true) { + SrsCommonMessage* msg = NULL; + if ((ret = protocol->recv_message(&msg)) != ERROR_SUCCESS) { + if (!srs_is_client_gracefully_close(ret)) { + srs_error("recv identify client message failed. ret=%d", ret); + } + return ret; + } + + SrsAutoFree(SrsCommonMessage, msg); + SrsMessageHeader& h = msg->header; + + if (h.is_ackledgement() || h.is_set_chunk_size() || h.is_window_ackledgement_size() || h.is_user_control_message()) { + continue; + } + + if (!h.is_amf0_command() && !h.is_amf3_command()) { + srs_trace("identify ignore messages except " + "AMF0/AMF3 command message. type=%#x", h.message_type); + continue; + } + + SrsPacket* pkt = NULL; + if ((ret = protocol->decode_message(msg, &pkt)) != ERROR_SUCCESS) { + srs_error("identify decode message failed. ret=%d", ret); + return ret; + } + + SrsAutoFree(SrsPacket, pkt); + + if (dynamic_cast(pkt)) { + srs_info("level1 identify client by play."); + return identify_play_client(dynamic_cast(pkt), type, stream_name, duration); + } + if (dynamic_cast(pkt)) { + srs_info("identify client by publish, falsh publish."); + return identify_flash_publish_client(dynamic_cast(pkt), type, stream_name); + } + 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, duration); + } + + srs_trace("ignore AMF0/AMF3 command message."); + } + + return ret; +} + +int SrsRtmpServer::identify_fmle_publish_client(SrsFMLEStartPacket* req, SrsRtmpConnType& type, string& stream_name) +{ + int ret = ERROR_SUCCESS; + + type = SrsRtmpConnFMLEPublish; + stream_name = req->stream_name; + + // releaseStream response + if (true) { + SrsFMLEStartResPacket* pkt = new SrsFMLEStartResPacket(req->transaction_id); + if ((ret = protocol->send_and_free_packet(pkt, 0)) != ERROR_SUCCESS) { + srs_error("send releaseStream response message failed. ret=%d", ret); + return ret; + } + srs_info("send releaseStream response message success."); + } + + return ret; +} + +int SrsRtmpServer::identify_flash_publish_client(SrsPublishPacket* req, SrsRtmpConnType& type, string& stream_name) +{ + int ret = ERROR_SUCCESS; + + type = SrsRtmpConnFlashPublish; + stream_name = req->stream_name; + + return ret; +} + +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_info("identity client type=play, stream_name=%s, duration=%.2f", stream_name.c_str(), duration); + + return ret; +} + SrsConnectAppPacket::SrsConnectAppPacket() { command_name = RTMP_AMF0_COMMAND_CONNECT; diff --git a/trunk/src/protocol/srs_rtmp_stack.hpp b/trunk/src/protocol/srs_rtmp_stack.hpp index 31b45ce95..db6d76f46 100644 --- a/trunk/src/protocol/srs_rtmp_stack.hpp +++ b/trunk/src/protocol/srs_rtmp_stack.hpp @@ -57,6 +57,19 @@ class SrsChunkStream; class SrsSharedPtrMessage; class IMergeReadHandler; +class SrsProtocol; +class ISrsProtocolReaderWriter; +class SrsCommonMessage; +class SrsCreateStreamPacket; +class SrsFMLEStartPacket; +class SrsPublishPacket; +class SrsOnMetaDataPacket; +class SrsPlayPacket; +class SrsCommonMessage; +class SrsPacket; +class SrsAmf0Object; +class IMergeReadHandler; + /**************************************************************************** ***************************************************************************** ****************************************************************************/ @@ -78,6 +91,36 @@ class IMergeReadHandler; #define RTMP_AMF0_COMMAND_PUBLISH "publish" #define RTMP_AMF0_DATA_SAMPLE_ACCESS "|RtmpSampleAccess" +/** + * the signature for packets to client. + */ +#define RTMP_SIG_FMS_VER "3,5,3,888" +#define RTMP_SIG_AMF0_VER 0 +#define RTMP_SIG_CLIENT_ID "ASAICiss" + +/** + * onStatus consts. + */ +#define StatusLevel "level" +#define StatusCode "code" +#define StatusDescription "description" +#define StatusDetails "details" +#define StatusClientId "clientid" +// status value +#define StatusLevelStatus "status" +// status error +#define StatusLevelError "error" +// code value +#define StatusCodeConnectSuccess "NetConnection.Connect.Success" +#define StatusCodeConnectRejected "NetConnection.Connect.Rejected" +#define StatusCodeStreamReset "NetStream.Play.Reset" +#define StatusCodeStreamStart "NetStream.Play.Start" +#define StatusCodeStreamPause "NetStream.Pause.Notify" +#define StatusCodeStreamUnpause "NetStream.Unpause.Notify" +#define StatusCodePublishStart "NetStream.Publish.Start" +#define StatusCodeDataStart "NetStream.Data.Start" +#define StatusCodeUnpublishSuccess "NetStream.Unpublish.Success" + /**************************************************************************** ***************************************************************************** ****************************************************************************/ @@ -322,20 +365,22 @@ public: virtual int send_and_free_packet(SrsPacket* packet, int stream_id); public: /** - * expect a specified message, drop others util got specified one. - * @pmsg, user must free it. NULL if not success. - * @ppacket, store in the pmsg, user must never free it. NULL if not success. - * @remark, only when success, user can use and must free the pmsg/ppacket. - * for example: - SrsCommonMessage* msg = NULL; - SrsConnectAppResPacket* pkt = NULL; - if ((ret = srs_rtmp_expect_message(protocol, &msg, &pkt)) != ERROR_SUCCESS) { - return ret; - } - // use pkt - * user should never recv message and convert it, use this method instead. - * if need to set timeout, use set timeout of SrsProtocol. - */ + * expect a specified message, drop others util got specified one. + * @pmsg, user must free it. NULL if not success. + * @ppacket, user must free it, which decode from payload of message. NULL if not success. + * @remark, only when success, user can use and must free the pmsg and ppacket. + * for example: + * SrsCommonMessage* msg = NULL; + * SrsConnectAppResPacket* pkt = NULL; + * if ((ret = protocol->expect_message(protocol, &msg, &pkt)) != ERROR_SUCCESS) { + * return ret; + * } + * // use then free msg and pkt + * srs_freep(msg); + * srs_freep(pkt); + * user should never recv message and convert it, use this method instead. + * if need to set timeout, use set timeout of SrsProtocol. + */ template int expect_message(SrsCommonMessage** pmsg, T** ppacket) { @@ -444,43 +489,535 @@ private: }; /** -* incoming chunk stream maybe interlaced, -* use the chunk stream to cache the input RTMP chunk streams. -*/ + * incoming chunk stream maybe interlaced, + * use the chunk stream to cache the input RTMP chunk streams. + */ class SrsChunkStream { public: /** - * represents the basic header fmt, - * which used to identify the variant message header type. - */ + * represents the basic header fmt, + * which used to identify the variant message header type. + */ char fmt; /** - * represents the basic header cid, - * which is the chunk stream id. - */ + * represents the basic header cid, + * which is the chunk stream id. + */ int cid; /** - * cached message header - */ + * cached message header + */ SrsMessageHeader header; /** - * whether the chunk message header has extended timestamp. - */ + * whether the chunk message header has extended timestamp. + */ bool extended_timestamp; /** - * partially read message. - */ + * partially read message. + */ SrsCommonMessage* msg; /** - * decoded msg count, to identify whether the chunk stream is fresh. - */ + * decoded msg count, to identify whether the chunk stream is fresh. + */ int64_t msg_count; public: SrsChunkStream(int _cid); virtual ~SrsChunkStream(); }; +/** + * the original request from client. + */ +class SrsRequest +{ +public: + // client ip. + std::string ip; +public: + /** + * tcUrl: rtmp://request_vhost:port/app/stream + * support pass vhost in query string, such as: + * rtmp://ip:port/app?vhost=request_vhost/stream + * rtmp://ip:port/app...vhost...request_vhost/stream + */ + std::string tcUrl; + std::string pageUrl; + std::string swfUrl; + double objectEncoding; + // data discovery from request. +public: + // discovery from tcUrl and play/publish. + std::string schema; + // the vhost in tcUrl. + std::string vhost; + // the host in tcUrl. + std::string host; + // the port in tcUrl. + std::string port; + // the app in tcUrl, without param. + std::string app; + // the param in tcUrl(app). + std::string param; + // the stream in play/publish + std::string stream; + // for play live stream, + // used to specified the stop when exceed the duration. + // @see https://github.com/simple-rtmp-server/srs/issues/45 + // in ms. + double duration; + // the token in the connect request, + // used for edge traverse to origin authentication, + // @see https://github.com/simple-rtmp-server/srs/issues/104 + SrsAmf0Object* args; +public: + SrsRequest(); + virtual ~SrsRequest(); +public: + /** + * deep copy the request, for source to use it to support reload, + * for when initialize the source, the request is valid, + * when reload it, the request maybe invalid, so need to copy it. + */ + virtual SrsRequest* copy(); + /** + * update the auth info of request, + * to keep the current request ptr is ok, + * for many components use the ptr of request. + */ + virtual void update_auth(SrsRequest* req); + /** + * get the stream identify, vhost/app/stream. + */ + virtual std::string get_stream_url(); + /** + * strip url, user must strip when update the url. + */ + virtual void strip(); +}; + +/** + * the response to client. + */ +class SrsResponse +{ +public: + /** + * the stream id to response client createStream. + */ + int stream_id; +public: + SrsResponse(); + virtual ~SrsResponse(); +}; + +/** + * the rtmp client type. + */ +enum SrsRtmpConnType +{ + SrsRtmpConnUnknown, + SrsRtmpConnPlay, + SrsRtmpConnFMLEPublish, + SrsRtmpConnFlashPublish, +}; +std::string srs_client_type_string(SrsRtmpConnType type); + +/** + * store the handshake bytes, + * for smart switch between complex and simple handshake. + */ +class SrsHandshakeBytes +{ +public: + // [1+1536] + char* c0c1; + // [1+1536+1536] + char* s0s1s2; + // [1536] + char* c2; +public: + SrsHandshakeBytes(); + virtual ~SrsHandshakeBytes(); +public: + virtual int read_c0c1(ISrsProtocolReaderWriter* io); + virtual int read_s0s1s2(ISrsProtocolReaderWriter* io); + virtual int read_c2(ISrsProtocolReaderWriter* io); + virtual int create_c0c1(); + virtual int create_s0s1s2(const char* c1 = NULL); + virtual int create_c2(); +}; + +/** + * implements the client role protocol. + */ +class SrsRtmpClient +{ +private: + SrsHandshakeBytes* hs_bytes; +protected: + SrsProtocol* protocol; + ISrsProtocolReaderWriter* io; +public: + SrsRtmpClient(ISrsProtocolReaderWriter* skt); + virtual ~SrsRtmpClient(); + // protocol methods proxy +public: + /** + * set the recv timeout in us. + * if timeout, recv/send message return ERROR_SOCKET_TIMEOUT. + */ + virtual void set_recv_timeout(int64_t timeout_us); + /** + * set the send timeout in us. + * if timeout, recv/send message return ERROR_SOCKET_TIMEOUT. + */ + virtual void set_send_timeout(int64_t timeout_us); + /** + * get recv/send bytes. + */ + virtual int64_t get_recv_bytes(); + virtual int64_t get_send_bytes(); + /** + * recv a RTMP message, which is bytes oriented. + * user can use decode_message to get the decoded RTMP packet. + * @param pmsg, set the received message, + * always NULL if error, + * NULL for unknown packet but return success. + * never NULL if decode success. + * @remark, drop message when msg is empty or payload length is empty. + */ + virtual int recv_message(SrsCommonMessage** pmsg); + /** + * decode bytes oriented RTMP message to RTMP packet, + * @param ppacket, output decoded packet, + * always NULL if error, never NULL if success. + * @return error when unknown packet, error when decode failed. + */ + virtual int decode_message(SrsCommonMessage* msg, SrsPacket** ppacket); + /** + * send the RTMP message and always free it. + * user must never free or use the msg after this method, + * for it will always free the msg. + * @param msg, the msg to send out, never be NULL. + * @param stream_id, the stream id of packet to send over, 0 for control message. + */ + virtual int send_and_free_message(SrsSharedPtrMessage* msg, int stream_id); + /** + * send the RTMP message and always free it. + * user must never free or use the msg after this method, + * for it will always free the msg. + * @param msgs, the msgs to send out, never be NULL. + * @param nb_msgs, the size of msgs to send out. + * @param stream_id, the stream id of packet to send over, 0 for control message. + */ + virtual int send_and_free_messages(SrsSharedPtrMessage** msgs, int nb_msgs, int stream_id); + /** + * send the RTMP packet and always free it. + * user must never free or use the packet after this method, + * for it will always free the packet. + * @param packet, the packet to send out, never be NULL. + * @param stream_id, the stream id of packet to send over, 0 for control message. + */ + virtual int send_and_free_packet(SrsPacket* packet, int stream_id); +public: + /** + * handshake with server, try complex, then simple handshake. + */ + virtual int handshake(); + /** + * only use simple handshake + */ + virtual int simple_handshake(); + /** + * only use complex handshake + */ + virtual int complex_handshake(); + /** + * set req to use the original request of client: + * pageUrl and swfUrl for refer antisuck. + * args for edge to origin traverse auth, @see SrsRequest.args + */ + virtual int connect_app(std::string app, std::string tc_url, SrsRequest* req, bool debug_srs_upnode); + /** + * connect to server, get the debug srs info. + * + * @param app, the app to connect at. + * @param tc_url, the tcUrl to connect at. + * @param req, the optional req object, use the swfUrl/pageUrl if specified. NULL to ignore. + * + * SRS debug info: + * @param srs_server_ip, debug info, server ip client connected at. + * @param srs_server, server info. + * @param srs_primary, primary authors. + * @param srs_authors, authors. + * @param srs_id, int, debug info, client id in server log. + * @param srs_pid, int, debug info, server pid in log. + */ + virtual int connect_app2( + std::string app, std::string tc_url, SrsRequest* req, bool debug_srs_upnode, + std::string& srs_server_ip, std::string& srs_server, std::string& srs_primary, + std::string& srs_authors, std::string& srs_version, int& srs_id, + int& srs_pid + ); + /** + * create a stream, then play/publish data over this stream. + */ + virtual int create_stream(int& stream_id); + /** + * start play stream. + */ + virtual int play(std::string stream, int stream_id); + /** + * start publish stream. use flash publish workflow: + * connect-app => create-stream => flash-publish + */ + virtual int publish(std::string stream, int stream_id); + /** + * start publish stream. use FMLE publish workflow: + * connect-app => FMLE publish + */ + virtual int fmle_publish(std::string stream, int& stream_id); +public: + /** + * expect a specified message, drop others util got specified one. + * @pmsg, user must free it. NULL if not success. + * @ppacket, user must free it, which decode from payload of message. NULL if not success. + * @remark, only when success, user can use and must free the pmsg and ppacket. + * for example: + * SrsCommonMessage* msg = NULL; + * SrsConnectAppResPacket* pkt = NULL; + * if ((ret = client->expect_message(protocol, &msg, &pkt)) != ERROR_SUCCESS) { + * return ret; + * } + * // use then free msg and pkt + * srs_freep(msg); + * srs_freep(pkt); + * user should never recv message and convert it, use this method instead. + * if need to set timeout, use set timeout of SrsProtocol. + */ + template + int expect_message(SrsCommonMessage** pmsg, T** ppacket) + { + return protocol->expect_message(pmsg, ppacket); + } +}; + +/** + * the rtmp provices rtmp-command-protocol services, + * a high level protocol, media stream oriented services, + * such as connect to vhost/app, play stream, get audio/video data. + */ +class SrsRtmpServer +{ +private: + SrsHandshakeBytes* hs_bytes; + SrsProtocol* protocol; + ISrsProtocolReaderWriter* io; +public: + SrsRtmpServer(ISrsProtocolReaderWriter* skt); + virtual ~SrsRtmpServer(); + // protocol methods proxy +public: + /** + * set the auto response message when recv for protocol stack. + * @param v, whether auto response message when recv message. + * @see: https://github.com/simple-rtmp-server/srs/issues/217 + */ + virtual void set_auto_response(bool v); +#ifdef SRS_PERF_MERGED_READ + /** + * to improve read performance, merge some packets then read, + * when it on and read small bytes, we sleep to wait more data., + * that is, we merge some data to read together. + * @param v true to ename merged read. + * @param handler the handler when merge read is enabled. + * @see https://github.com/simple-rtmp-server/srs/issues/241 + */ + virtual void set_merge_read(bool v, IMergeReadHandler* handler); + /** + * create buffer with specifeid size. + * @param buffer the size of buffer. + * @remark when MR(SRS_PERF_MERGED_READ) disabled, always set to 8K. + * @remark when buffer changed, the previous ptr maybe invalid. + * @see https://github.com/simple-rtmp-server/srs/issues/241 + */ + virtual void set_recv_buffer(int buffer_size); +#endif + /** + * set/get the recv timeout in us. + * if timeout, recv/send message return ERROR_SOCKET_TIMEOUT. + */ + virtual void set_recv_timeout(int64_t timeout_us); + virtual int64_t get_recv_timeout(); + /** + * set/get the send timeout in us. + * if timeout, recv/send message return ERROR_SOCKET_TIMEOUT. + */ + virtual void set_send_timeout(int64_t timeout_us); + virtual int64_t get_send_timeout(); + /** + * get recv/send bytes. + */ + virtual int64_t get_recv_bytes(); + virtual int64_t get_send_bytes(); + /** + * recv a RTMP message, which is bytes oriented. + * user can use decode_message to get the decoded RTMP packet. + * @param pmsg, set the received message, + * always NULL if error, + * NULL for unknown packet but return success. + * never NULL if decode success. + * @remark, drop message when msg is empty or payload length is empty. + */ + virtual int recv_message(SrsCommonMessage** pmsg); + /** + * decode bytes oriented RTMP message to RTMP packet, + * @param ppacket, output decoded packet, + * always NULL if error, never NULL if success. + * @return error when unknown packet, error when decode failed. + */ + virtual int decode_message(SrsCommonMessage* msg, SrsPacket** ppacket); + /** + * send the RTMP message and always free it. + * user must never free or use the msg after this method, + * for it will always free the msg. + * @param msg, the msg to send out, never be NULL. + * @param stream_id, the stream id of packet to send over, 0 for control message. + */ + virtual int send_and_free_message(SrsSharedPtrMessage* msg, int stream_id); + /** + * send the RTMP message and always free it. + * user must never free or use the msg after this method, + * for it will always free the msg. + * @param msgs, the msgs to send out, never be NULL. + * @param nb_msgs, the size of msgs to send out. + * @param stream_id, the stream id of packet to send over, 0 for control message. + * + * @remark performance issue, to support 6k+ 250kbps client, + * @see https://github.com/simple-rtmp-server/srs/issues/194 + */ + virtual int send_and_free_messages(SrsSharedPtrMessage** msgs, int nb_msgs, int stream_id); + /** + * send the RTMP packet and always free it. + * user must never free or use the packet after this method, + * for it will always free the packet. + * @param packet, the packet to send out, never be NULL. + * @param stream_id, the stream id of packet to send over, 0 for control message. + */ + virtual int send_and_free_packet(SrsPacket* packet, int stream_id); +public: + /** + * handshake with client, try complex then simple. + */ + virtual int handshake(); + /** + * do connect app with client, to discovery tcUrl. + */ + virtual int connect_app(SrsRequest* req); + /** + * set ack size to client, client will send ack-size for each ack window + */ + virtual int set_window_ack_size(int ack_size); + /** + * @type: The sender can mark this message hard (0), soft (1), or dynamic (2) + * using the Limit type field. + */ + virtual int set_peer_bandwidth(int bandwidth, int type); + /** + * @param server_ip the ip of server. + */ + virtual int response_connect_app(SrsRequest* req, const char* server_ip = NULL); + /** + * reject the connect app request. + */ + virtual void response_connect_reject(SrsRequest* req, const char* desc); + /** + * response client the onBWDone message. + */ + virtual int on_bw_done(); + /** + * recv some message to identify the client. + * @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, double& duration); + /** + * set the chunk size when client type identified. + */ + virtual int set_chunk_size(int chunk_size); + /** + * when client type is play, response with packets: + * StreamBegin, + * onStatus(NetStream.Play.Reset), onStatus(NetStream.Play.Start)., + * |RtmpSampleAccess(false, false), + * onStatus(NetStream.Data.Start). + */ + virtual int start_play(int stream_id); + /** + * when client(type is play) send pause message, + * if is_pause, response the following packets: + * onStatus(NetStream.Pause.Notify) + * StreamEOF + * if not is_pause, response the following packets: + * onStatus(NetStream.Unpause.Notify) + * StreamBegin + */ + virtual int on_play_client_pause(int stream_id, bool is_pause); + /** + * when client type is publish, response with packets: + * releaseStream response + * FCPublish + * FCPublish response + * createStream response + * onFCPublish(NetStream.Publish.Start) + * onStatus(NetStream.Publish.Start) + */ + virtual int start_fmle_publish(int stream_id); + /** + * process the FMLE unpublish event. + * @unpublish_tid the unpublish request transaction id. + */ + virtual int fmle_unpublish(int stream_id, double unpublish_tid); + /** + * when client type is publish, response with packets: + * onStatus(NetStream.Publish.Start) + */ + virtual int start_flash_publish(int stream_id); +public: + /** + * expect a specified message, drop others util got specified one. + * @pmsg, user must free it. NULL if not success. + * @ppacket, user must free it, which decode from payload of message. NULL if not success. + * @remark, only when success, user can use and must free the pmsg and ppacket. + * for example: + * SrsCommonMessage* msg = NULL; + * SrsConnectAppResPacket* pkt = NULL; + * if ((ret = server->expect_message(protocol, &msg, &pkt)) != ERROR_SUCCESS) { + * return ret; + * } + * // use then free msg and pkt + * srs_freep(msg); + * srs_freep(pkt); + * user should never recv message and convert it, use this method instead. + * if need to set timeout, use set timeout of SrsProtocol. + */ + template + int expect_message(SrsCommonMessage** pmsg, T** ppacket) + { + return protocol->expect_message(pmsg, ppacket); + } +private: + 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, double& duration); +}; + /** * 4.1.1. connect * The client sends the connect command to the server to request diff --git a/trunk/src/utest/srs_utest_protocol.cpp b/trunk/src/utest/srs_utest_protocol.cpp index c51d96271..c30e4405c 100644 --- a/trunk/src/utest/srs_utest_protocol.cpp +++ b/trunk/src/utest/srs_utest_protocol.cpp @@ -32,7 +32,7 @@ using namespace std; #include #include #include -#include +#include MockEmptyIO::MockEmptyIO() { diff --git a/trunk/src/utest/srs_utest_protocol.hpp b/trunk/src/utest/srs_utest_protocol.hpp index 889e467a1..9a5aaad55 100644 --- a/trunk/src/utest/srs_utest_protocol.hpp +++ b/trunk/src/utest/srs_utest_protocol.hpp @@ -32,7 +32,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include -#include +#include #include #include