From f15867d865f143aea595dbc0aa3c5ac0a4045673 Mon Sep 17 00:00:00 2001 From: winlin Date: Sun, 27 Oct 2013 11:29:12 +0800 Subject: [PATCH 1/2] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index aeae5b7d6..49823f36d 100755 --- a/README.md +++ b/README.md @@ -3,7 +3,8 @@ simple-rtmp-server simple rtmp origin live server over state-threads, which can be used as origin server, or rtmp-server for encoder.
srs is a simple, high-performance, running in single process, origin live server, with single vhost(like FMS \_\_defaultVhost\_\_).
-blog: [http://blog.csdn.net/win_lin](http://blog.csdn.net/win_lin) +blog: [http://blog.csdn.net/win_lin](http://blog.csdn.net/win_lin)
+see also: [https://github.com/winlinvip/simple-rtmp-server](https://github.com/winlinvip/simple-rtmp-server)
see also: [http://winlinvip.github.io/simple-rtmp-server](http://winlinvip.github.io/simple-rtmp-server) ### Usage From bc79ee4361c95d1f14acbf51af6b241c2405bc6a Mon Sep 17 00:00:00 2001 From: winlin Date: Tue, 29 Oct 2013 07:51:08 +0800 Subject: [PATCH 2/2] support librtmp/ffmpeg without extended timestamp in 0xCX chunk packet. update signautre of server --- README.md | 1 + trunk/src/core/srs_core.hpp | 9 +++- trunk/src/core/srs_core_buffer.cpp | 7 ++- trunk/src/core/srs_core_client.cpp | 6 +-- trunk/src/core/srs_core_error.hpp | 2 + trunk/src/core/srs_core_protocol.cpp | 69 +++++++++++++++++++++++----- trunk/src/core/srs_core_protocol.hpp | 7 +-- trunk/src/core/srs_core_rtmp.cpp | 23 +++++++--- trunk/src/core/srs_core_rtmp.hpp | 5 +- trunk/src/core/srs_core_socket.cpp | 13 ++++-- trunk/src/core/srs_core_socket.hpp | 5 +- trunk/src/core/srs_core_source.cpp | 4 +- 12 files changed, 114 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 49823f36d..468c16d30 100755 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ url: rtmp://127.0.0.1:1935/live/livestream * nginx v1.5.0: 139524 lines
### History +* v0.3, 2013-10-28, support librtmp without extended-timestamp in 0xCX chunk packet. * v0.3, 2013-10-27, support cache last gop for client fast startup. * v0.2, 2013-10-25, v0.2 released. 10125 lines. * v0.2, 2013-10-25, support flash publish. diff --git a/trunk/src/core/srs_core.hpp b/trunk/src/core/srs_core.hpp index 25effe6a7..af05a23ff 100755 --- a/trunk/src/core/srs_core.hpp +++ b/trunk/src/core/srs_core.hpp @@ -62,13 +62,18 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. } \ (void)0 +// current release version +#define RTMP_SIG_SRS_VERSION "0.2" // server info. #define RTMP_SIG_SRS_KEY "srs" +#define RTMP_SIG_SRS_ROLE "origin server" #define RTMP_SIG_SRS_NAME RTMP_SIG_SRS_KEY"(simple rtmp server)" -#define RTMP_SIG_SRS_URL "https://github.com/winlinvip/simple-rtmp-server" +#define RTMP_SIG_SRS_URL "https://"RTMP_SIG_SRS_URL_SHORT +#define RTMP_SIG_SRS_URL_SHORT "github.com/winlinvip/simple-rtmp-server" #define RTMP_SIG_SRS_WEB "http://blog.csdn.net/win_lin" #define RTMP_SIG_SRS_EMAIL "winterserver@126.com" -#define RTMP_SIG_SRS_VERSION "0.1" +#define RTMP_SIG_SRS_LICENSE "The MIT License (MIT)" +#define RTMP_SIG_SRS_COPYRIGHT "Copyright (c) 2013 winlin" // compare #define srs_min(a, b) ((a < b)? a : b) diff --git a/trunk/src/core/srs_core_buffer.cpp b/trunk/src/core/srs_core_buffer.cpp index ca1d283f9..f1dce357f 100755 --- a/trunk/src/core/srs_core_buffer.cpp +++ b/trunk/src/core/srs_core_buffer.cpp @@ -25,6 +25,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include +#include #define SOCKET_READ_SIZE 4096 @@ -62,7 +63,11 @@ int SrsBuffer::ensure_buffer_bytes(SrsSocket* skt, int required_size) { int ret = ERROR_SUCCESS; - srs_assert(required_size >= 0); + if (required_size < 0) { + ret = ERROR_SYSTEM_SIZE_NEGATIVE; + srs_error("size is negative. size=%d, ret=%d", required_size, ret); + return ret; + } while (size() < required_size) { char buffer[SOCKET_READ_SIZE]; diff --git a/trunk/src/core/srs_core_client.cpp b/trunk/src/core/srs_core_client.cpp index 7cceb2367..1c64d04e9 100755 --- a/trunk/src/core/srs_core_client.cpp +++ b/trunk/src/core/srs_core_client.cpp @@ -63,8 +63,8 @@ int SrsClient::do_cycle() } srs_verbose("get peer ip success. ip=%s", ip); - rtmp->set_recv_timeout(SRS_SEND_TIMEOUT_MS); - rtmp->set_send_timeout(SRS_SEND_TIMEOUT_MS); + rtmp->set_recv_timeout(SRS_SEND_TIMEOUT_MS * 1000); + rtmp->set_send_timeout(SRS_SEND_TIMEOUT_MS * 1000); if ((ret = rtmp->handshake()) != ERROR_SUCCESS) { srs_error("rtmp handshake failed. ret=%d", ret); @@ -185,7 +185,7 @@ int SrsClient::streaming_play(SrsSource* source) SrsAutoFree(SrsConsumer, consumer, false); srs_verbose("consumer created success."); - rtmp->set_recv_timeout(SRS_PULSE_TIMEOUT_MS); + rtmp->set_recv_timeout(SRS_PULSE_TIMEOUT_MS * 1000); int64_t report_time = 0; int64_t reported_time = 0; diff --git a/trunk/src/core/srs_core_error.hpp b/trunk/src/core/srs_core_error.hpp index bac825066..427022592 100755 --- a/trunk/src/core/srs_core_error.hpp +++ b/trunk/src/core/srs_core_error.hpp @@ -64,11 +64,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define ERROR_RTMP_CHUNK_SIZE 310 #define ERROR_RTMP_TRY_SIMPLE_HS 311 #define ERROR_RTMP_CH_SCHEMA 312 +#define ERROR_RTMP_PACKET_SIZE 313 #define ERROR_SYSTEM_STREAM_INIT 400 #define ERROR_SYSTEM_PACKET_INVALID 401 #define ERROR_SYSTEM_CLIENT_INVALID 402 #define ERROR_SYSTEM_ASSERT_FAILED 403 +#define ERROR_SYSTEM_SIZE_NEGATIVE 404 // see librtmp. // failed when open ssl create the dh diff --git a/trunk/src/core/srs_core_protocol.cpp b/trunk/src/core/srs_core_protocol.cpp index 05b2e690d..e0e44d3f0 100755 --- a/trunk/src/core/srs_core_protocol.cpp +++ b/trunk/src/core/srs_core_protocol.cpp @@ -249,6 +249,9 @@ messages. /**************************************************************************** ***************************************************************************** ****************************************************************************/ +// when got a messae header, increase recv timeout to got an entire message. +#define SRS_MIN_RECV_TIMEOUT_US 3000 + SrsProtocol::AckWindowSize::AckWindowSize() { ack_window_size = acked_size = 0; @@ -278,14 +281,19 @@ SrsProtocol::~SrsProtocol() srs_freep(skt); } -void SrsProtocol::set_recv_timeout(int timeout_ms) +void SrsProtocol::set_recv_timeout(int64_t timeout_us) { - return skt->set_recv_timeout(timeout_ms); + return skt->set_recv_timeout(timeout_us); } -void SrsProtocol::set_send_timeout(int timeout_ms) +int64_t SrsProtocol::get_recv_timeout() { - return skt->set_send_timeout(timeout_ms); + return skt->get_recv_timeout(); +} + +void SrsProtocol::set_send_timeout(int64_t timeout_us) +{ + return skt->set_send_timeout(timeout_us); } int SrsProtocol::recv_message(SrsCommonMessage** pmsg) @@ -602,17 +610,31 @@ int SrsProtocol::recv_interlaced_message(SrsCommonMessage** pmsg) } return ret; } - srs_info("read basic header success. fmt=%d, cid=%d, bh_size=%d", fmt, cid, bh_size); + srs_verbose("read basic header success. fmt=%d, cid=%d, bh_size=%d", fmt, cid, bh_size); + + // once we got the chunk message header, + // that is there is a real message in cache, + // increase the timeout to got it. + // For example, in the play loop, we set timeout to 100ms, + // when we got a chunk header, we should increase the timeout, + // or we maybe timeout and disconnect the client. + int64_t timeout_us = skt->get_recv_timeout(); + if (timeout_us != (int64_t)ST_UTIME_NO_TIMEOUT) { + int64_t pkt_timeout_us = srs_max(timeout_us, SRS_MIN_RECV_TIMEOUT_US); + skt->set_recv_timeout(pkt_timeout_us); + srs_verbose("change recv timeout_us " + "from %"PRId64" to %"PRId64"", timeout_us, pkt_timeout_us); + } // get the cached chunk stream. SrsChunkStream* chunk = NULL; if (chunk_streams.find(cid) == chunk_streams.end()) { chunk = chunk_streams[cid] = new SrsChunkStream(cid); - srs_info("cache new chunk stream: fmt=%d, cid=%d", fmt, cid); + srs_verbose("cache new chunk stream: fmt=%d, cid=%d", fmt, cid); } else { chunk = chunk_streams[cid]; - srs_info("cached chunk stream: fmt=%d, cid=%d, size=%d, message(type=%d, size=%d, time=%d, sid=%d)", + srs_verbose("cached chunk stream: fmt=%d, cid=%d, size=%d, message(type=%d, size=%d, time=%d, sid=%d)", chunk->fmt, chunk->cid, (chunk->msg? chunk->msg->size : 0), chunk->header.message_type, chunk->header.payload_length, chunk->header.timestamp, chunk->header.stream_id); } @@ -625,7 +647,7 @@ int SrsProtocol::recv_interlaced_message(SrsCommonMessage** pmsg) } return ret; } - srs_info("read message header success. " + srs_verbose("read message header success. " "fmt=%d, mh_size=%d, ext_time=%d, size=%d, message(type=%d, size=%d, time=%d, sid=%d)", fmt, mh_size, chunk->extended_timestamp, (chunk->msg? chunk->msg->size : 0), chunk->header.message_type, chunk->header.payload_length, chunk->header.timestamp, chunk->header.stream_id); @@ -640,9 +662,15 @@ int SrsProtocol::recv_interlaced_message(SrsCommonMessage** pmsg) return ret; } + // reset the recv timeout + if (timeout_us != (int64_t)ST_UTIME_NO_TIMEOUT) { + skt->set_recv_timeout(timeout_us); + srs_verbose("reset recv timeout_us to %"PRId64"", timeout_us); + } + // not got an entire RTMP message, try next chunk. if (!msg) { - srs_info("get partial message success. chunk_payload_size=%d, size=%d, message(type=%d, size=%d, time=%d, sid=%d)", + srs_verbose("get partial message success. chunk_payload_size=%d, size=%d, message(type=%d, size=%d, time=%d, sid=%d)", payload_size, (msg? msg->size : (chunk->msg? chunk->msg->size : 0)), chunk->header.message_type, chunk->header.payload_length, chunk->header.timestamp, chunk->header.stream_id); return ret; @@ -827,6 +855,15 @@ int SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt, int bh_siz pp[0] = *p++; pp[3] = 0; + // if msg exists in cache, the size must not changed. + if (chunk->msg->size > 0 && chunk->msg->size != chunk->header.payload_length) { + ret = ERROR_RTMP_PACKET_SIZE; + srs_error("msg exists in chunk cache, " + "size=%d cannot change to %d, ret=%d", + chunk->msg->size, chunk->header.payload_length, ret); + return ret; + } + chunk->header.message_type = *p++; if (fmt == 0) { @@ -867,11 +904,21 @@ int SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt, int bh_siz return ret; } - char* pp = (char*)&chunk->header.timestamp; + // ffmpeg/librtmp may donot send this filed, need to detect the value. + // @see also: http://blog.csdn.net/win_lin/article/details/13363699 + int32_t timestamp = 0x00; + char* pp = (char*)×tamp; pp[3] = *p++; pp[2] = *p++; pp[1] = *p++; pp[0] = *p++; + + if (chunk->header.timestamp > RTMP_EXTENDED_TIMESTAMP && chunk->header.timestamp != timestamp) { + mh_size -= 4; + srs_verbose("ignore the 4bytes extended timestamp. mh_size=%d", mh_size); + } else { + chunk->header.timestamp = timestamp; + } srs_verbose("header read ext_time completed. time=%d", chunk->header.timestamp); } @@ -897,7 +944,7 @@ int SrsProtocol::read_message_payload(SrsChunkStream* chunk, int bh_size, int mh int ret = ERROR_SUCCESS; // empty message - if (chunk->header.payload_length == 0) { + if (chunk->header.payload_length <= 0) { // need erase the header in buffer. buffer->erase(bh_size + mh_size); diff --git a/trunk/src/core/srs_core_protocol.hpp b/trunk/src/core/srs_core_protocol.hpp index 5628762a6..601bb9c9c 100755 --- a/trunk/src/core/srs_core_protocol.hpp +++ b/trunk/src/core/srs_core_protocol.hpp @@ -104,11 +104,12 @@ public: virtual ~SrsProtocol(); public: /** - * set the timeout in ms. + * set the timeout in us. * if timeout, recv/send message return ERROR_SOCKET_TIMEOUT. */ - virtual void set_recv_timeout(int timeout_ms); - virtual void set_send_timeout(int timeout_ms); + virtual void set_recv_timeout(int64_t timeout_us); + virtual int64_t get_recv_timeout(); + virtual void set_send_timeout(int64_t timeout_us); /** * recv a message with raw/undecoded payload from peer. * the payload is not decoded, use srs_rtmp_expect_message if requires diff --git a/trunk/src/core/srs_core_rtmp.cpp b/trunk/src/core/srs_core_rtmp.cpp index e8a4e8fa8..ec72bde60 100755 --- a/trunk/src/core/srs_core_rtmp.cpp +++ b/trunk/src/core/srs_core_rtmp.cpp @@ -149,14 +149,19 @@ SrsRtmp::~SrsRtmp() srs_freep(complex_handshake); } -void SrsRtmp::set_recv_timeout(int timeout_ms) +void SrsRtmp::set_recv_timeout(int64_t timeout_us) { - return protocol->set_recv_timeout(timeout_ms); + return protocol->set_recv_timeout(timeout_us); } -void SrsRtmp::set_send_timeout(int timeout_ms) +int64_t SrsRtmp::get_recv_timeout() { - return protocol->set_send_timeout(timeout_ms); + return protocol->get_recv_timeout(); +} + +void SrsRtmp::set_send_timeout(int64_t timeout_us) +{ + return protocol->set_send_timeout(timeout_us); } int SrsRtmp::recv_message(SrsCommonMessage** pmsg) @@ -176,7 +181,6 @@ int SrsRtmp::handshake() ssize_t nsize; SrsSocket skt(stfd); - // TODO: complex handshake for h264/aac codec. char* c0c1 = new char[1537]; SrsAutoFree(char, c0c1, true); if ((ret = skt.read_fully(c0c1, 1537, &nsize)) != ERROR_SUCCESS) { @@ -325,10 +329,15 @@ int SrsRtmp::response_connect_app(SrsRequest* req) SrsASrsAmf0EcmaArray* data = new SrsASrsAmf0EcmaArray(); pkt->info->set("data", data); - data->set("version", new SrsAmf0String(RTMP_SIG_FMS_VER)); - data->set("server", new SrsAmf0String(RTMP_SIG_SRS_NAME)); + data->set("srs_version", new SrsAmf0String(RTMP_SIG_FMS_VER)); + data->set("srs_server", new SrsAmf0String(RTMP_SIG_SRS_NAME)); + data->set("srs_license", new SrsAmf0String(RTMP_SIG_SRS_LICENSE)); + data->set("srs_role", new SrsAmf0String(RTMP_SIG_SRS_ROLE)); data->set("srs_url", new SrsAmf0String(RTMP_SIG_SRS_URL)); data->set("srs_version", new SrsAmf0String(RTMP_SIG_SRS_VERSION)); + data->set("srs_site", new SrsAmf0String(RTMP_SIG_SRS_WEB)); + data->set("srs_email", new SrsAmf0String(RTMP_SIG_SRS_EMAIL)); + data->set("srs_copyright", new SrsAmf0String(RTMP_SIG_SRS_COPYRIGHT)); msg->set_packet(pkt, 0); diff --git a/trunk/src/core/srs_core_rtmp.hpp b/trunk/src/core/srs_core_rtmp.hpp index e9608392f..670f88fad 100755 --- a/trunk/src/core/srs_core_rtmp.hpp +++ b/trunk/src/core/srs_core_rtmp.hpp @@ -105,8 +105,9 @@ public: SrsRtmp(st_netfd_t client_stfd); virtual ~SrsRtmp(); public: - virtual void set_recv_timeout(int timeout_ms); - virtual void set_send_timeout(int timeout_ms); + virtual void set_recv_timeout(int64_t timeout_us); + virtual int64_t get_recv_timeout(); + virtual void set_send_timeout(int64_t timeout_us); virtual int recv_message(SrsCommonMessage** pmsg); virtual int send_message(ISrsMessage* msg); public: diff --git a/trunk/src/core/srs_core_socket.cpp b/trunk/src/core/srs_core_socket.cpp index 5f540baf0..46c11361d 100755 --- a/trunk/src/core/srs_core_socket.cpp +++ b/trunk/src/core/srs_core_socket.cpp @@ -36,14 +36,19 @@ SrsSocket::~SrsSocket() { } -void SrsSocket::set_recv_timeout(int timeout_ms) +void SrsSocket::set_recv_timeout(int64_t timeout_us) { - recv_timeout = timeout_ms * 1000; + recv_timeout = timeout_us; } -void SrsSocket::set_send_timeout(int timeout_ms) +int64_t SrsSocket::get_recv_timeout() { - send_timeout = timeout_ms * 1000; + return recv_timeout; +} + +void SrsSocket::set_send_timeout(int64_t timeout_us) +{ + send_timeout = timeout_us; } int64_t SrsSocket::get_recv_bytes() diff --git a/trunk/src/core/srs_core_socket.hpp b/trunk/src/core/srs_core_socket.hpp index 320487a03..e7495f74c 100755 --- a/trunk/src/core/srs_core_socket.hpp +++ b/trunk/src/core/srs_core_socket.hpp @@ -48,8 +48,9 @@ public: SrsSocket(st_netfd_t client_stfd); virtual ~SrsSocket(); public: - virtual void set_recv_timeout(int timeout_ms); - virtual void set_send_timeout(int timeout_ms); + virtual void set_recv_timeout(int64_t timeout_us); + virtual int64_t get_recv_timeout(); + virtual void set_send_timeout(int64_t timeout_us); virtual int64_t get_recv_bytes(); virtual int64_t get_send_bytes(); public: diff --git a/trunk/src/core/srs_core_source.cpp b/trunk/src/core/srs_core_source.cpp index 22a4da2eb..e9940e082 100755 --- a/trunk/src/core/srs_core_source.cpp +++ b/trunk/src/core/srs_core_source.cpp @@ -179,8 +179,8 @@ int SrsSource::on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata { int ret = ERROR_SUCCESS; - metadata->metadata->set("server", - new SrsAmf0String(RTMP_SIG_SRS_NAME""RTMP_SIG_SRS_VERSION)); + metadata->metadata->set("server", new SrsAmf0String( + RTMP_SIG_SRS_KEY" "RTMP_SIG_SRS_VERSION" ("RTMP_SIG_SRS_URL_SHORT")")); // encode the metadata to payload int size = metadata->get_payload_length();