diff --git a/README.md b/README.md index 9afd47193..ec5c60198 100755 --- a/README.md +++ b/README.md @@ -231,6 +231,7 @@ Supported operating systems and hardware: * 2013-10-17, Created.
## History +* v1.0, 2014-05-22, fix [#78](https://github.com/winlinvip/simple-rtmp-server/issues/78), st joinable thread must be stop by other threads, 0.9.113 * v1.0, 2014-05-22, support amf0 StrictArray(0x0a). 0.9.111. * v1.0, 2014-05-22, support flv parser, add amf0 to librtmp. 0.9.110 * v1.0, 2014-05-22, fix [#74](https://github.com/winlinvip/simple-rtmp-server/issues/74), add tcUrl for http callback on_connect, 0.9.109 diff --git a/trunk/src/app/srs_app_conn.cpp b/trunk/src/app/srs_app_conn.cpp index 35e637395..13e14e3cf 100644 --- a/trunk/src/app/srs_app_conn.cpp +++ b/trunk/src/app/srs_app_conn.cpp @@ -35,7 +35,11 @@ SrsConnection::SrsConnection(SrsServer* srs_server, st_netfd_t client_stfd) server = srs_server; stfd = client_stfd; connection_id = 0; - pthread = new SrsThread(this, 0); + // the client thread should reap itself, + // so we never use joinable. + // TODO: FIXME: maybe other thread need to stop it. + // @see: https://github.com/winlinvip/simple-rtmp-server/issues/78 + pthread = new SrsThread(this, 0, false); } SrsConnection::~SrsConnection() diff --git a/trunk/src/app/srs_app_edge.cpp b/trunk/src/app/srs_app_edge.cpp index a746dd9bc..d6c39ff4c 100644 --- a/trunk/src/app/srs_app_edge.cpp +++ b/trunk/src/app/srs_app_edge.cpp @@ -69,7 +69,7 @@ SrsEdgeIngester::SrsEdgeIngester() origin_index = 0; stream_id = 0; stfd = NULL; - pthread = new SrsThread(this, SRS_EDGE_INGESTER_SLEEP_US); + pthread = new SrsThread(this, SRS_EDGE_INGESTER_SLEEP_US, true); } SrsEdgeIngester::~SrsEdgeIngester() @@ -344,7 +344,7 @@ SrsEdgeForwarder::SrsEdgeForwarder() origin_index = 0; stream_id = 0; stfd = NULL; - pthread = new SrsThread(this, SRS_EDGE_FORWARDER_SLEEP_US); + pthread = new SrsThread(this, SRS_EDGE_FORWARDER_SLEEP_US, true); queue = new SrsMessageQueue(); send_error_code = ERROR_SUCCESS; } diff --git a/trunk/src/app/srs_app_encoder.cpp b/trunk/src/app/srs_app_encoder.cpp index 59772f792..3c01f8ca8 100644 --- a/trunk/src/app/srs_app_encoder.cpp +++ b/trunk/src/app/srs_app_encoder.cpp @@ -44,7 +44,7 @@ static std::vector _transcoded_url; SrsEncoder::SrsEncoder() { - pthread = new SrsThread(this, SRS_RTMP_ENCODER_SLEEP_US); + pthread = new SrsThread(this, SRS_RTMP_ENCODER_SLEEP_US, true); pithy_print = new SrsPithyPrint(SRS_STAGE_ENCODER); } diff --git a/trunk/src/app/srs_app_forward.cpp b/trunk/src/app/srs_app_forward.cpp index 18dc27b9b..f469a1038 100644 --- a/trunk/src/app/srs_app_forward.cpp +++ b/trunk/src/app/srs_app_forward.cpp @@ -54,7 +54,7 @@ SrsForwarder::SrsForwarder(SrsSource* _source) kbps = new SrsKbps(); stream_id = 0; - pthread = new SrsThread(this, SRS_FORWARDER_SLEEP_US); + pthread = new SrsThread(this, SRS_FORWARDER_SLEEP_US, true); queue = new SrsMessageQueue(); jitter = new SrsRtmpJitter(); } diff --git a/trunk/src/app/srs_app_http.cpp b/trunk/src/app/srs_app_http.cpp index 15e6c648a..8a1f2d130 100644 --- a/trunk/src/app/srs_app_http.cpp +++ b/trunk/src/app/srs_app_http.cpp @@ -291,6 +291,13 @@ SrsHttpHandler* SrsHttpHandler::res_content_type_mpegts(stringstream& ss) return this; } +SrsHttpHandler* SrsHttpHandler::res_content_type_flv(stringstream& ss) +{ + ss << "Content-Type: video/x-flv" << __CRLF + << "Allow: DELETE, GET, HEAD, OPTIONS, POST, PUT" << __CRLF; + return this; +} + SrsHttpHandler* SrsHttpHandler::res_content_length(stringstream& ss, int64_t length) { ss << "Content-Length: "<< length << __CRLF; @@ -1008,7 +1015,7 @@ const char* SrsHttpUri::get_path() const char* SrsHttpUri::get_query() { - return path.data(); + return query.data(); } string SrsHttpUri::get_uri_field(string uri, http_parser_url* hp_u, http_parser_url_fields field) diff --git a/trunk/src/app/srs_app_http.hpp b/trunk/src/app/srs_app_http.hpp index 525a69985..869b14e40 100644 --- a/trunk/src/app/srs_app_http.hpp +++ b/trunk/src/app/srs_app_http.hpp @@ -250,6 +250,7 @@ public: virtual SrsHttpHandler* res_content_type_json(std::stringstream& ss); virtual SrsHttpHandler* res_content_type_m3u8(std::stringstream& ss); virtual SrsHttpHandler* res_content_type_mpegts(std::stringstream& ss); + virtual SrsHttpHandler* res_content_type_flv(std::stringstream& ss); virtual SrsHttpHandler* res_content_length(std::stringstream& ss, int64_t length); virtual SrsHttpHandler* res_enable_crossdomain(std::stringstream& ss); virtual SrsHttpHandler* res_header_eof(std::stringstream& ss); diff --git a/trunk/src/app/srs_app_http_conn.cpp b/trunk/src/app/srs_app_http_conn.cpp index acc33ac59..e8b404c4e 100644 --- a/trunk/src/app/srs_app_http_conn.cpp +++ b/trunk/src/app/srs_app_http_conn.cpp @@ -165,6 +165,8 @@ int SrsHttpVhost::do_process_request(SrsSocket* skt, SrsHttpMessage* req) if (srs_string_ends_with(fullpath, ".ts")) { return response_ts_file(skt, req, fullpath); + } else if (srs_string_ends_with(fullpath, ".flv") || srs_string_ends_with(fullpath, ".fhv")) { + return response_flv_file(skt, req, fullpath); } else { return response_regular_file(skt, req, fullpath); } @@ -225,6 +227,62 @@ int SrsHttpVhost::response_regular_file(SrsSocket* skt, SrsHttpMessage* req, str return ret; } +int SrsHttpVhost::response_flv_file(SrsSocket* skt, SrsHttpMessage* req, string fullpath) +{ + int ret = ERROR_SUCCESS; + + // TODO: FIXME: use more advance cache. + // for ts video large file, use bytes to write it. + int fd = ::open(fullpath.c_str(), O_RDONLY); + if (fd < 0) { + ret = ERROR_HTTP_OPEN_FILE; + srs_warn("open file %s failed, ret=%d", fullpath.c_str(), ret); + return ret; + } + + int64_t length = (int64_t)::lseek(fd, 0, SEEK_END); + ::lseek(fd, 0, SEEK_SET); + + // write http header for ts. + std::stringstream ss; + + res_status_line(ss)->res_content_type_flv(ss) + ->res_content_length(ss, (int)length); + + if (req->requires_crossdomain()) { + res_enable_crossdomain(ss); + } + + res_header_eof(ss); + + // flush http header to peer + if ((ret = res_flush(skt, ss)) != ERROR_SUCCESS) { + return ret; + } + + // write body. + int64_t left = length; + char* buf = req->http_ts_send_buffer(); + + while (left > 0) { + ssize_t nread = -1; + // TODO: FIXME: use st_read. + if ((nread = ::read(fd, buf, HTTP_TS_SEND_BUFFER_SIZE)) < 0) { + ret = ERROR_HTTP_READ_FILE; + srs_warn("read file %s failed, ret=%d", fullpath.c_str(), ret); + break; + } + + left -= nread; + if ((ret = skt->write(buf, nread, NULL)) != ERROR_SUCCESS) { + break; + } + } + ::close(fd); + + return ret; +} + int SrsHttpVhost::response_ts_file(SrsSocket* skt, SrsHttpMessage* req, string fullpath) { int ret = ERROR_SUCCESS; @@ -266,10 +324,9 @@ int SrsHttpVhost::response_ts_file(SrsSocket* skt, SrsHttpMessage* req, string f ssize_t nread = -1; // TODO: FIXME: use st_read. if ((nread = ::read(fd, buf, HTTP_TS_SEND_BUFFER_SIZE)) < 0) { - ::close(fd); ret = ERROR_HTTP_READ_FILE; srs_warn("read file %s failed, ret=%d", fullpath.c_str(), ret); - return ret; + break; } left -= nread; diff --git a/trunk/src/app/srs_app_http_conn.hpp b/trunk/src/app/srs_app_http_conn.hpp index a9d3a116d..12a4e1795 100644 --- a/trunk/src/app/srs_app_http_conn.hpp +++ b/trunk/src/app/srs_app_http_conn.hpp @@ -71,6 +71,7 @@ protected: virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req); private: virtual int response_regular_file(SrsSocket* skt, SrsHttpMessage* req, std::string fullpath); + virtual int response_flv_file(SrsSocket* skt, SrsHttpMessage* req, std::string fullpath); virtual int response_ts_file(SrsSocket* skt, SrsHttpMessage* req, std::string fullpath); virtual std::string get_request_file(SrsHttpMessage* req); public: diff --git a/trunk/src/app/srs_app_ingest.cpp b/trunk/src/app/srs_app_ingest.cpp index b3c61622a..d33bb3359 100644 --- a/trunk/src/app/srs_app_ingest.cpp +++ b/trunk/src/app/srs_app_ingest.cpp @@ -53,7 +53,7 @@ SrsIngester::SrsIngester() { _srs_config->subscribe(this); - pthread = new SrsThread(this, SRS_AUTO_INGESTER_SLEEP_US); + pthread = new SrsThread(this, SRS_AUTO_INGESTER_SLEEP_US, true); pithy_print = new SrsPithyPrint(SRS_STAGE_INGESTER); } diff --git a/trunk/src/app/srs_app_server.cpp b/trunk/src/app/srs_app_server.cpp index 4d63f9fcd..6a8481f5c 100644 --- a/trunk/src/app/srs_app_server.cpp +++ b/trunk/src/app/srs_app_server.cpp @@ -84,7 +84,7 @@ SrsListener::SrsListener(SrsServer* server, SrsListenerType type) _server = server; _type = type; - pthread = new SrsThread(this, 0); + pthread = new SrsThread(this, 0, true); } SrsListener::~SrsListener() @@ -197,7 +197,7 @@ SrsSignalManager::SrsSignalManager(SrsServer* server) _server = server; sig_pipe[0] = sig_pipe[1] = -1; - pthread = new SrsThread(this, 0); + pthread = new SrsThread(this, 0, true); signal_read_stfd = NULL; } diff --git a/trunk/src/app/srs_app_thread.cpp b/trunk/src/app/srs_app_thread.cpp index b638263fc..efd971547 100644 --- a/trunk/src/app/srs_app_thread.cpp +++ b/trunk/src/app/srs_app_thread.cpp @@ -54,7 +54,7 @@ void ISrsThreadHandler::on_thread_stop() { } -SrsThread::SrsThread(ISrsThreadHandler* thread_handler, int64_t interval_us) +SrsThread::SrsThread(ISrsThreadHandler* thread_handler, int64_t interval_us, bool joinable) { handler = thread_handler; cycle_interval_us = interval_us; @@ -62,6 +62,7 @@ SrsThread::SrsThread(ISrsThreadHandler* thread_handler, int64_t interval_us) tid = NULL; loop = false; _cid = -1; + _joinable = joinable; } SrsThread::~SrsThread() @@ -83,7 +84,7 @@ int SrsThread::start() return ret; } - if((tid = st_thread_create(thread_fun, this, 1, 0)) == NULL){ + if((tid = st_thread_create(thread_fun, this, (_joinable? 1:0), 0)) == NULL){ ret = ERROR_ST_CREATE_CYCLE_THREAD; srs_error("st_thread_create failed. ret=%d", ret); return ret; @@ -93,7 +94,7 @@ int SrsThread::start() loop = true; // wait for cid to ready, for parent thread to get the cid. - while (_cid < 0) { + while (_cid < 0 && loop) { st_usleep(10 * SRS_TIME_MILLISECONDS); } diff --git a/trunk/src/app/srs_app_thread.hpp b/trunk/src/app/srs_app_thread.hpp index 46ceefc9e..ec9522bb9 100644 --- a/trunk/src/app/srs_app_thread.hpp +++ b/trunk/src/app/srs_app_thread.hpp @@ -88,6 +88,7 @@ private: st_thread_t tid; int _cid; bool loop; + bool _joinable; private: ISrsThreadHandler* handler; int64_t cycle_interval_us; @@ -96,8 +97,15 @@ public: * initialize the thread. * @param thread_handler, the cycle handler for the thread. * @param interval_us, the sleep interval when cycle finished. + * @param joinable, if joinable, other thread must stop the thread. + * @remark if joinable, thread never quit itself, or memory leak. + * @see: https://github.com/winlinvip/simple-rtmp-server/issues/78 */ - SrsThread(ISrsThreadHandler* thread_handler, int64_t interval_us); + /** + * TODO: FIXME: maybe all thread must be reap by others threads, + * @see: https://github.com/winlinvip/simple-rtmp-server/issues/77 + */ + SrsThread(ISrsThreadHandler* thread_handler, int64_t interval_us, bool joinable); virtual ~SrsThread(); public: /** diff --git a/trunk/src/core/srs_core.hpp b/trunk/src/core/srs_core.hpp index acc449014..a56f84802 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 "112" +#define VERSION_REVISION "113" #define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION // server info. #define RTMP_SIG_SRS_KEY "SRS"