diff --git a/README.md b/README.md index 2a0ce6261..8b29a91f8 100755 --- a/README.md +++ b/README.md @@ -214,6 +214,7 @@ Please select your language: ### V2 changes +* v2.0, 2017-04-15, Fix [#844][bug #844], support Haivision encoder. 2.0.238 * v2.0, 2017-04-15, Merge [#846][bug #846], fix fd leak for FLV stream caster. 2.0.237 * v2.0, 2017-04-15, Merge [#841][bug #841], avoid the duplicated sps/pps in ts. 2.0.236 * v2.0, 2017-04-09, Fix [#834][bug #834], crash for TS context corrupt. 2.0.235 @@ -1391,6 +1392,7 @@ Winlin [bug #834]: https://github.com/ossrs/srs/issues/834 [bug #841]: https://github.com/ossrs/srs/issues/841 [bug #846]: https://github.com/ossrs/srs/issues/846 +[bug #844]: https://github.com/ossrs/srs/issues/844 [bug #xxxxxxxxxx]: https://github.com/ossrs/srs/issues/xxxxxxxxxx [bug #735]: https://github.com/ossrs/srs/issues/735 diff --git a/trunk/src/app/srs_app_rtmp_conn.cpp b/trunk/src/app/srs_app_rtmp_conn.cpp index b2f45dfc4..4a72a9847 100644 --- a/trunk/src/app/srs_app_rtmp_conn.cpp +++ b/trunk/src/app/srs_app_rtmp_conn.cpp @@ -583,6 +583,16 @@ int SrsRtmpConn::stream_service_cycle() return publishing(source); } + case SrsRtmpConnHaivisionPublish: { + srs_verbose("Haivision start to publish stream %s.", req->stream.c_str()); + + if ((ret = rtmp->start_haivision_publish(res->stream_id)) != ERROR_SUCCESS) { + srs_error("start to publish stream failed. ret=%d", ret); + return ret; + } + + return publishing(source); + } case SrsRtmpConnFlashPublish: { srs_verbose("flash start to publish stream %s.", req->stream.c_str()); diff --git a/trunk/src/app/srs_app_security.cpp b/trunk/src/app/srs_app_security.cpp index ec865456b..352c7b152 100644 --- a/trunk/src/app/srs_app_security.cpp +++ b/trunk/src/app/srs_app_security.cpp @@ -90,6 +90,7 @@ int SrsSecurity::allow_check(SrsConfDirective* rules, SrsRtmpConnType type, std: break; case SrsRtmpConnFMLEPublish: case SrsRtmpConnFlashPublish: + case SrsRtmpConnHaivisionPublish: if (rule->arg0() != "publish") { break; } @@ -135,6 +136,7 @@ int SrsSecurity::deny_check(SrsConfDirective* rules, SrsRtmpConnType type, std:: break; case SrsRtmpConnFMLEPublish: case SrsRtmpConnFlashPublish: + case SrsRtmpConnHaivisionPublish: if (rule->arg0() != "publish") { break; } diff --git a/trunk/src/protocol/srs_rtmp_stack.cpp b/trunk/src/protocol/srs_rtmp_stack.cpp index a4efce82f..7f24c1f72 100644 --- a/trunk/src/protocol/srs_rtmp_stack.cpp +++ b/trunk/src/protocol/srs_rtmp_stack.cpp @@ -1808,6 +1808,7 @@ string srs_client_type_string(SrsRtmpConnType type) case SrsRtmpConnPlay: return "Play"; case SrsRtmpConnFlashPublish: return "flash-publish"; case SrsRtmpConnFMLEPublish: return "fmle-publish"; + case SrsRtmpConnHaivisionPublish: return "haivision-publish"; default: return "Unknown"; } } @@ -2764,6 +2765,14 @@ int SrsRtmpServer::identify_client(int stream_id, SrsRtmpConnType& type, string& } return ret; } + + // For encoder of Haivision, it always send a _checkbw call message. + // @Remark the next message is createStream, so we continue to identify it. + // @see https://github.com/ossrs/srs/issues/844 + if (call->command_name == "_checkbw") { + srs_info("Haivision encoder identified."); + continue; + } continue; } @@ -3039,6 +3048,60 @@ int SrsRtmpServer::start_fmle_publish(int stream_id) return ret; } +int SrsRtmpServer::start_haivision_publish(int stream_id) +{ + int ret = ERROR_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("Haivision publish success."); + + return ret; +} + int SrsRtmpServer::fmle_unpublish(int stream_id, double unpublish_tid) { int ret = ERROR_SUCCESS; @@ -3173,6 +3236,10 @@ int SrsRtmpServer::identify_create_stream_client(SrsCreateStreamPacket* req, int 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 FCPublish, haivision publish."); + return identify_haivision_publish_client(dynamic_cast(pkt), type, stream_name); + } srs_trace("ignore AMF0/AMF3 command message."); } @@ -3200,6 +3267,26 @@ int SrsRtmpServer::identify_fmle_publish_client(SrsFMLEStartPacket* req, SrsRtmp return ret; } +int SrsRtmpServer::identify_haivision_publish_client(SrsFMLEStartPacket* req, SrsRtmpConnType& type, string& stream_name) +{ + int ret = ERROR_SUCCESS; + + type = SrsRtmpConnHaivisionPublish; + stream_name = req->stream_name; + + // FCPublish response + if (true) { + SrsFMLEStartResPacket* pkt = new SrsFMLEStartResPacket(req->transaction_id); + 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."); + } + + return ret; +} + int SrsRtmpServer::identify_flash_publish_client(SrsPublishPacket* req, SrsRtmpConnType& type, string& stream_name) { int ret = ERROR_SUCCESS; diff --git a/trunk/src/protocol/srs_rtmp_stack.hpp b/trunk/src/protocol/srs_rtmp_stack.hpp index 4923b22cd..b4aaf76f3 100644 --- a/trunk/src/protocol/srs_rtmp_stack.hpp +++ b/trunk/src/protocol/srs_rtmp_stack.hpp @@ -65,6 +65,7 @@ class SrsCommonMessage; class SrsPacket; class SrsAmf0Object; class IMergeReadHandler; +class SrsCallPacket; /**************************************************************************** ***************************************************************************** @@ -635,6 +636,7 @@ enum SrsRtmpConnType SrsRtmpConnPlay, SrsRtmpConnFMLEPublish, SrsRtmpConnFlashPublish, + SrsRtmpConnHaivisionPublish, }; std::string srs_client_type_string(SrsRtmpConnType type); bool srs_client_type_is_publish(SrsRtmpConnType type); @@ -953,6 +955,11 @@ public: * onStatus(NetStream.Publish.Start) */ virtual int start_fmle_publish(int stream_id); + /** + * For encoder of Haivision, response the startup request. + * @see https://github.com/ossrs/srs/issues/844 + */ + virtual int start_haivision_publish(int stream_id); /** * process the FMLE unpublish event. * @unpublish_tid the unpublish request transaction id. @@ -989,6 +996,7 @@ public: 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_haivision_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); @@ -1257,7 +1265,7 @@ public: }; /** - * FMLE start publish: ReleaseStream/PublishStream + * FMLE start publish: ReleaseStream/PublishStream/FCPublish/FCUnpublish */ class SrsFMLEStartPacket : public SrsPacket {