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