diff --git a/README.md b/README.md index cc8776c0f..f0d7d70fd 100755 --- a/README.md +++ b/README.md @@ -242,6 +242,7 @@ Supported operating systems and hardware: * 2013-10-17, Created.
## History +* v1.0, 2014-06-28, response the call message with null. 0.9.137 * v1.0, 2014-06-28, fix [#110](https://github.com/winlinvip/simple-rtmp-server/issues/110), thread start segment fault, thread cycle stop destroy thread. 0.9.136 * v1.0, 2014-06-27, fix [#109](https://github.com/winlinvip/simple-rtmp-server/issues/109), fix the system jump time, adjust system startup time. 0.9.135 * v1.0, 2014-06-27, [1.0 mainline5(0.9.134)](https://github.com/winlinvip/simple-rtmp-server/releases/tag/1.0.mainline5) released. 41573 lines. diff --git a/trunk/src/app/srs_app_rtmp_conn.cpp b/trunk/src/app/srs_app_rtmp_conn.cpp index 324243d6c..bb37c5b15 100644 --- a/trunk/src/app/srs_app_rtmp_conn.cpp +++ b/trunk/src/app/srs_app_rtmp_conn.cpp @@ -51,6 +51,7 @@ using namespace std; #include #include #include +#include // when stream is busy, for example, streaming is already // publishing, when a new client to request to publish, @@ -852,6 +853,22 @@ int SrsRtmpConn::process_play_control_msg(SrsConsumer* consumer, SrsMessage* msg return ret; } + // call msg, + // support response null first, + // @see https://github.com/winlinvip/simple-rtmp-server/issues/106 + 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 = rtmp->send_and_free_packet(res, 0)) != ERROR_SUCCESS) { + srs_warn("response call failed. ret=%d", ret); + return ret; + } + return ret; + } + + // pause or other msg. SrsPausePacket* pause = dynamic_cast(pkt); if (!pause) { srs_info("ignore all amf0/amf3 command except pause."); diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp index d0cf40dee..866a5e990 100644 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_source.cpp @@ -926,6 +926,10 @@ int SrsSource::on_meta_data(SrsMessage* msg, SrsOnMetaDataPacket* metadata) metadata->metadata->set("server", SrsAmf0Any::str(RTMP_SIG_SRS_KEY" "RTMP_SIG_SRS_VERSION" ("RTMP_SIG_SRS_URL_SHORT")")); metadata->metadata->set("authors", SrsAmf0Any::str(RTMP_SIG_SRS_PRIMARY_AUTHROS)); + // version, for example, 1.0.0 + // add version to metadata, please donot remove it, for debug. + metadata->metadata->set("server_version", SrsAmf0Any::str(RTMP_SIG_SRS_VERSION)); + if ((prop = metadata->metadata->get_property("audiosamplerate")) != NULL) { if (prop->is_number()) { sample_rate = (int)prop->to_number(); diff --git a/trunk/src/core/srs_core.hpp b/trunk/src/core/srs_core.hpp index 961e18c16..548c591d2 100644 --- a/trunk/src/core/srs_core.hpp +++ b/trunk/src/core/srs_core.hpp @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // current release version #define VERSION_MAJOR "0" #define VERSION_MINOR "9" -#define VERSION_REVISION "136" +#define VERSION_REVISION "137" #define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION // server info. #define RTMP_SIG_SRS_KEY "SRS" diff --git a/trunk/src/rtmp/srs_protocol_rtmp_stack.cpp b/trunk/src/rtmp/srs_protocol_rtmp_stack.cpp index 4cb503771..0a1ed1efc 100644 --- a/trunk/src/rtmp/srs_protocol_rtmp_stack.cpp +++ b/trunk/src/rtmp/srs_protocol_rtmp_stack.cpp @@ -700,6 +700,10 @@ int SrsProtocol::do_decode_message(SrsMessageHeader& header, SrsStream* stream, srs_info("decode the AMF0/AMF3 closeStream message."); *ppacket = packet = new SrsCloseStreamPacket(); return packet->decode(stream); + } else if (header.is_amf0_command() || header.is_amf3_command()) { + srs_info("decode the AMF0/AMF3 call message."); + *ppacket = packet = new SrsCallPacket(); + return packet->decode(stream); } // default packet to drop message. @@ -1976,6 +1980,202 @@ int SrsConnectAppResPacket::encode_packet(SrsStream* stream) return ret; } +SrsCallPacket::SrsCallPacket() +{ + command_name = ""; + transaction_id = 0; + command_object = NULL; + arguments = NULL; +} + +SrsCallPacket::~SrsCallPacket() +{ + srs_freep(command_object); + srs_freep(arguments); +} + +int SrsCallPacket::decode(SrsStream* stream) +{ + int ret = ERROR_SUCCESS; + + if ((ret = srs_amf0_read_string(stream, command_name)) != ERROR_SUCCESS) { + srs_error("amf0 decode call command_name failed. ret=%d", ret); + return ret; + } + if (command_name.empty()) { + ret = ERROR_RTMP_AMF0_DECODE; + srs_error("amf0 decode call command_name failed. " + "command_name=%s, ret=%d", command_name.c_str(), ret); + return ret; + } + + if ((ret = srs_amf0_read_number(stream, transaction_id)) != ERROR_SUCCESS) { + srs_error("amf0 decode call transaction_id failed. ret=%d", ret); + return ret; + } + + srs_freep(command_object); + if ((ret = SrsAmf0Any::discovery(stream, &command_object)) != ERROR_SUCCESS) { + srs_error("amf0 discovery call command_object failed. ret=%d", ret); + return ret; + } + if ((ret = command_object->read(stream)) != ERROR_SUCCESS) { + srs_error("amf0 decode call command_object failed. ret=%d", ret); + return ret; + } + + if (!stream->empty()) { + srs_freep(arguments); + if ((ret = SrsAmf0Any::discovery(stream, &arguments)) != ERROR_SUCCESS) { + srs_error("amf0 discovery call arguments failed. ret=%d", ret); + return ret; + } + if ((ret = arguments->read(stream)) != ERROR_SUCCESS) { + srs_error("amf0 decode call arguments failed. ret=%d", ret); + return ret; + } + } + + srs_info("amf0 decode call packet success"); + + return ret; +} + +int SrsCallPacket::get_perfer_cid() +{ + return RTMP_CID_OverConnection; +} + +int SrsCallPacket::get_message_type() +{ + return RTMP_MSG_AMF0CommandMessage; +} + +int SrsCallPacket::get_size() +{ + int size = 0; + + size += SrsAmf0Size::str(command_name) + SrsAmf0Size::number(); + + if (command_object) { + size += command_object->total_size(); + } + + if (arguments) { + size += arguments->total_size(); + } + + return size; +} + +int SrsCallPacket::encode_packet(SrsStream* stream) +{ + int ret = ERROR_SUCCESS; + + if ((ret = srs_amf0_write_string(stream, command_name)) != ERROR_SUCCESS) { + srs_error("encode command_name failed. ret=%d", ret); + return ret; + } + srs_verbose("encode command_name success."); + + if ((ret = srs_amf0_write_number(stream, transaction_id)) != ERROR_SUCCESS) { + srs_error("encode transaction_id failed. ret=%d", ret); + return ret; + } + srs_verbose("encode transaction_id success."); + + if (command_object && (ret = command_object->write(stream)) != ERROR_SUCCESS) { + srs_error("encode command_object failed. ret=%d", ret); + return ret; + } + srs_verbose("encode command_object success."); + + if (arguments && (ret = arguments->write(stream)) != ERROR_SUCCESS) { + srs_error("encode arguments failed. ret=%d", ret); + return ret; + } + srs_verbose("encode arguments success."); + + srs_info("encode create stream request packet success."); + + return ret; +} + +SrsCallResPacket::SrsCallResPacket(double _transaction_id) +{ + command_name = RTMP_AMF0_COMMAND_RESULT; + transaction_id = _transaction_id; + command_object = NULL; + response = NULL; +} + +SrsCallResPacket::~SrsCallResPacket() +{ + srs_freep(command_object); + srs_freep(response); +} + +int SrsCallResPacket::get_perfer_cid() +{ + return RTMP_CID_OverConnection; +} + +int SrsCallResPacket::get_message_type() +{ + return RTMP_MSG_AMF0CommandMessage; +} + +int SrsCallResPacket::get_size() +{ + int size = 0; + + size += SrsAmf0Size::str(command_name) + SrsAmf0Size::number(); + + if (command_object) { + size += command_object->total_size(); + } + + if (response) { + size += response->total_size(); + } + + return size; +} + +int SrsCallResPacket::encode_packet(SrsStream* stream) +{ + int ret = ERROR_SUCCESS; + + if ((ret = srs_amf0_write_string(stream, command_name)) != ERROR_SUCCESS) { + srs_error("encode command_name failed. ret=%d", ret); + return ret; + } + srs_verbose("encode command_name success."); + + if ((ret = srs_amf0_write_number(stream, transaction_id)) != ERROR_SUCCESS) { + srs_error("encode transaction_id failed. ret=%d", ret); + return ret; + } + srs_verbose("encode transaction_id success."); + + if (command_object && (ret = command_object->write(stream)) != ERROR_SUCCESS) { + srs_error("encode command_object failed. ret=%d", ret); + return ret; + } + srs_verbose("encode command_object success."); + + if (response && (ret = response->write(stream)) != ERROR_SUCCESS) { + srs_error("encode response failed. ret=%d", ret); + return ret; + } + srs_verbose("encode response success."); + + + srs_info("encode call response packet success."); + + return ret; +} + SrsCreateStreamPacket::SrsCreateStreamPacket() { command_name = RTMP_AMF0_COMMAND_CREATE_STREAM; diff --git a/trunk/src/rtmp/srs_protocol_rtmp_stack.hpp b/trunk/src/rtmp/srs_protocol_rtmp_stack.hpp index 928660207..d42448ea9 100644 --- a/trunk/src/rtmp/srs_protocol_rtmp_stack.hpp +++ b/trunk/src/rtmp/srs_protocol_rtmp_stack.hpp @@ -533,6 +533,73 @@ protected: virtual int encode_packet(SrsStream* stream); }; +/** +* 4.1.2. Call +* The call method of the NetConnection object runs remote procedure +* calls (RPC) at the receiving end. The called RPC name is passed as a +* parameter to the call command. +*/ +class SrsCallPacket : public SrsPacket +{ +protected: + virtual const char* get_class_name() + { + return CLASS_NAME_STRING(SrsCallPacket); + } +public: + std::string command_name; + double transaction_id; + /** + * If there exists any command info this + * is set, else this is set to null type. + */ + SrsAmf0Any* command_object; + // Any optional arguments to be provided + SrsAmf0Any* arguments; +public: + SrsCallPacket(); + virtual ~SrsCallPacket(); +public: + virtual int decode(SrsStream* stream); +public: + virtual int get_perfer_cid(); +public: + virtual int get_message_type(); +protected: + virtual int get_size(); + virtual int encode_packet(SrsStream* stream); +}; +/** +* response for SrsCallPacket. +*/ +class SrsCallResPacket : public SrsPacket +{ +protected: + virtual const char* get_class_name() + { + return CLASS_NAME_STRING(SrsCallResPacket); + } +public: + std::string command_name; + double transaction_id; + // If there exists any command info this + // is set, else this is set to null type. + SrsAmf0Any* command_object; + // Response from the method that was + // called. + SrsAmf0Any* response; +public: + SrsCallResPacket(double _transaction_id); + virtual ~SrsCallResPacket(); +public: + virtual int get_perfer_cid(); +public: + virtual int get_message_type(); +protected: + virtual int get_size(); + virtual int encode_packet(SrsStream* stream); +}; + /** * 4.1.3. createStream * The client sends this command to the server to create a logical @@ -592,6 +659,7 @@ protected: virtual int get_size(); virtual int encode_packet(SrsStream* stream); }; + /** * client close stream packet. */