fix #78 st joinable thread must be stop by other threads, 0.9.113
正在显示
14 个修改的文件
包含
96 行增加
和
16 行删除
| @@ -231,6 +231,7 @@ Supported operating systems and hardware: | @@ -231,6 +231,7 @@ Supported operating systems and hardware: | ||
| 231 | * 2013-10-17, Created.<br/> | 231 | * 2013-10-17, Created.<br/> |
| 232 | 232 | ||
| 233 | ## History | 233 | ## History |
| 234 | +* 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 | ||
| 234 | * v1.0, 2014-05-22, support amf0 StrictArray(0x0a). 0.9.111. | 235 | * v1.0, 2014-05-22, support amf0 StrictArray(0x0a). 0.9.111. |
| 235 | * v1.0, 2014-05-22, support flv parser, add amf0 to librtmp. 0.9.110 | 236 | * v1.0, 2014-05-22, support flv parser, add amf0 to librtmp. 0.9.110 |
| 236 | * 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 | 237 | * 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 |
| @@ -35,7 +35,11 @@ SrsConnection::SrsConnection(SrsServer* srs_server, st_netfd_t client_stfd) | @@ -35,7 +35,11 @@ SrsConnection::SrsConnection(SrsServer* srs_server, st_netfd_t client_stfd) | ||
| 35 | server = srs_server; | 35 | server = srs_server; |
| 36 | stfd = client_stfd; | 36 | stfd = client_stfd; |
| 37 | connection_id = 0; | 37 | connection_id = 0; |
| 38 | - pthread = new SrsThread(this, 0); | 38 | + // the client thread should reap itself, |
| 39 | + // so we never use joinable. | ||
| 40 | + // TODO: FIXME: maybe other thread need to stop it. | ||
| 41 | + // @see: https://github.com/winlinvip/simple-rtmp-server/issues/78 | ||
| 42 | + pthread = new SrsThread(this, 0, false); | ||
| 39 | } | 43 | } |
| 40 | 44 | ||
| 41 | SrsConnection::~SrsConnection() | 45 | SrsConnection::~SrsConnection() |
| @@ -69,7 +69,7 @@ SrsEdgeIngester::SrsEdgeIngester() | @@ -69,7 +69,7 @@ SrsEdgeIngester::SrsEdgeIngester() | ||
| 69 | origin_index = 0; | 69 | origin_index = 0; |
| 70 | stream_id = 0; | 70 | stream_id = 0; |
| 71 | stfd = NULL; | 71 | stfd = NULL; |
| 72 | - pthread = new SrsThread(this, SRS_EDGE_INGESTER_SLEEP_US); | 72 | + pthread = new SrsThread(this, SRS_EDGE_INGESTER_SLEEP_US, true); |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | SrsEdgeIngester::~SrsEdgeIngester() | 75 | SrsEdgeIngester::~SrsEdgeIngester() |
| @@ -344,7 +344,7 @@ SrsEdgeForwarder::SrsEdgeForwarder() | @@ -344,7 +344,7 @@ SrsEdgeForwarder::SrsEdgeForwarder() | ||
| 344 | origin_index = 0; | 344 | origin_index = 0; |
| 345 | stream_id = 0; | 345 | stream_id = 0; |
| 346 | stfd = NULL; | 346 | stfd = NULL; |
| 347 | - pthread = new SrsThread(this, SRS_EDGE_FORWARDER_SLEEP_US); | 347 | + pthread = new SrsThread(this, SRS_EDGE_FORWARDER_SLEEP_US, true); |
| 348 | queue = new SrsMessageQueue(); | 348 | queue = new SrsMessageQueue(); |
| 349 | send_error_code = ERROR_SUCCESS; | 349 | send_error_code = ERROR_SUCCESS; |
| 350 | } | 350 | } |
| @@ -44,7 +44,7 @@ static std::vector<std::string> _transcoded_url; | @@ -44,7 +44,7 @@ static std::vector<std::string> _transcoded_url; | ||
| 44 | 44 | ||
| 45 | SrsEncoder::SrsEncoder() | 45 | SrsEncoder::SrsEncoder() |
| 46 | { | 46 | { |
| 47 | - pthread = new SrsThread(this, SRS_RTMP_ENCODER_SLEEP_US); | 47 | + pthread = new SrsThread(this, SRS_RTMP_ENCODER_SLEEP_US, true); |
| 48 | pithy_print = new SrsPithyPrint(SRS_STAGE_ENCODER); | 48 | pithy_print = new SrsPithyPrint(SRS_STAGE_ENCODER); |
| 49 | } | 49 | } |
| 50 | 50 |
| @@ -54,7 +54,7 @@ SrsForwarder::SrsForwarder(SrsSource* _source) | @@ -54,7 +54,7 @@ SrsForwarder::SrsForwarder(SrsSource* _source) | ||
| 54 | kbps = new SrsKbps(); | 54 | kbps = new SrsKbps(); |
| 55 | stream_id = 0; | 55 | stream_id = 0; |
| 56 | 56 | ||
| 57 | - pthread = new SrsThread(this, SRS_FORWARDER_SLEEP_US); | 57 | + pthread = new SrsThread(this, SRS_FORWARDER_SLEEP_US, true); |
| 58 | queue = new SrsMessageQueue(); | 58 | queue = new SrsMessageQueue(); |
| 59 | jitter = new SrsRtmpJitter(); | 59 | jitter = new SrsRtmpJitter(); |
| 60 | } | 60 | } |
| @@ -291,6 +291,13 @@ SrsHttpHandler* SrsHttpHandler::res_content_type_mpegts(stringstream& ss) | @@ -291,6 +291,13 @@ SrsHttpHandler* SrsHttpHandler::res_content_type_mpegts(stringstream& ss) | ||
| 291 | return this; | 291 | return this; |
| 292 | } | 292 | } |
| 293 | 293 | ||
| 294 | +SrsHttpHandler* SrsHttpHandler::res_content_type_flv(stringstream& ss) | ||
| 295 | +{ | ||
| 296 | + ss << "Content-Type: video/x-flv" << __CRLF | ||
| 297 | + << "Allow: DELETE, GET, HEAD, OPTIONS, POST, PUT" << __CRLF; | ||
| 298 | + return this; | ||
| 299 | +} | ||
| 300 | + | ||
| 294 | SrsHttpHandler* SrsHttpHandler::res_content_length(stringstream& ss, int64_t length) | 301 | SrsHttpHandler* SrsHttpHandler::res_content_length(stringstream& ss, int64_t length) |
| 295 | { | 302 | { |
| 296 | ss << "Content-Length: "<< length << __CRLF; | 303 | ss << "Content-Length: "<< length << __CRLF; |
| @@ -1008,7 +1015,7 @@ const char* SrsHttpUri::get_path() | @@ -1008,7 +1015,7 @@ const char* SrsHttpUri::get_path() | ||
| 1008 | 1015 | ||
| 1009 | const char* SrsHttpUri::get_query() | 1016 | const char* SrsHttpUri::get_query() |
| 1010 | { | 1017 | { |
| 1011 | - return path.data(); | 1018 | + return query.data(); |
| 1012 | } | 1019 | } |
| 1013 | 1020 | ||
| 1014 | string SrsHttpUri::get_uri_field(string uri, http_parser_url* hp_u, http_parser_url_fields field) | 1021 | string SrsHttpUri::get_uri_field(string uri, http_parser_url* hp_u, http_parser_url_fields field) |
| @@ -250,6 +250,7 @@ public: | @@ -250,6 +250,7 @@ public: | ||
| 250 | virtual SrsHttpHandler* res_content_type_json(std::stringstream& ss); | 250 | virtual SrsHttpHandler* res_content_type_json(std::stringstream& ss); |
| 251 | virtual SrsHttpHandler* res_content_type_m3u8(std::stringstream& ss); | 251 | virtual SrsHttpHandler* res_content_type_m3u8(std::stringstream& ss); |
| 252 | virtual SrsHttpHandler* res_content_type_mpegts(std::stringstream& ss); | 252 | virtual SrsHttpHandler* res_content_type_mpegts(std::stringstream& ss); |
| 253 | + virtual SrsHttpHandler* res_content_type_flv(std::stringstream& ss); | ||
| 253 | virtual SrsHttpHandler* res_content_length(std::stringstream& ss, int64_t length); | 254 | virtual SrsHttpHandler* res_content_length(std::stringstream& ss, int64_t length); |
| 254 | virtual SrsHttpHandler* res_enable_crossdomain(std::stringstream& ss); | 255 | virtual SrsHttpHandler* res_enable_crossdomain(std::stringstream& ss); |
| 255 | virtual SrsHttpHandler* res_header_eof(std::stringstream& ss); | 256 | virtual SrsHttpHandler* res_header_eof(std::stringstream& ss); |
| @@ -165,6 +165,8 @@ int SrsHttpVhost::do_process_request(SrsSocket* skt, SrsHttpMessage* req) | @@ -165,6 +165,8 @@ int SrsHttpVhost::do_process_request(SrsSocket* skt, SrsHttpMessage* req) | ||
| 165 | 165 | ||
| 166 | if (srs_string_ends_with(fullpath, ".ts")) { | 166 | if (srs_string_ends_with(fullpath, ".ts")) { |
| 167 | return response_ts_file(skt, req, fullpath); | 167 | return response_ts_file(skt, req, fullpath); |
| 168 | + } else if (srs_string_ends_with(fullpath, ".flv") || srs_string_ends_with(fullpath, ".fhv")) { | ||
| 169 | + return response_flv_file(skt, req, fullpath); | ||
| 168 | } else { | 170 | } else { |
| 169 | return response_regular_file(skt, req, fullpath); | 171 | return response_regular_file(skt, req, fullpath); |
| 170 | } | 172 | } |
| @@ -225,6 +227,62 @@ int SrsHttpVhost::response_regular_file(SrsSocket* skt, SrsHttpMessage* req, str | @@ -225,6 +227,62 @@ int SrsHttpVhost::response_regular_file(SrsSocket* skt, SrsHttpMessage* req, str | ||
| 225 | return ret; | 227 | return ret; |
| 226 | } | 228 | } |
| 227 | 229 | ||
| 230 | +int SrsHttpVhost::response_flv_file(SrsSocket* skt, SrsHttpMessage* req, string fullpath) | ||
| 231 | +{ | ||
| 232 | + int ret = ERROR_SUCCESS; | ||
| 233 | + | ||
| 234 | + // TODO: FIXME: use more advance cache. | ||
| 235 | + // for ts video large file, use bytes to write it. | ||
| 236 | + int fd = ::open(fullpath.c_str(), O_RDONLY); | ||
| 237 | + if (fd < 0) { | ||
| 238 | + ret = ERROR_HTTP_OPEN_FILE; | ||
| 239 | + srs_warn("open file %s failed, ret=%d", fullpath.c_str(), ret); | ||
| 240 | + return ret; | ||
| 241 | + } | ||
| 242 | + | ||
| 243 | + int64_t length = (int64_t)::lseek(fd, 0, SEEK_END); | ||
| 244 | + ::lseek(fd, 0, SEEK_SET); | ||
| 245 | + | ||
| 246 | + // write http header for ts. | ||
| 247 | + std::stringstream ss; | ||
| 248 | + | ||
| 249 | + res_status_line(ss)->res_content_type_flv(ss) | ||
| 250 | + ->res_content_length(ss, (int)length); | ||
| 251 | + | ||
| 252 | + if (req->requires_crossdomain()) { | ||
| 253 | + res_enable_crossdomain(ss); | ||
| 254 | + } | ||
| 255 | + | ||
| 256 | + res_header_eof(ss); | ||
| 257 | + | ||
| 258 | + // flush http header to peer | ||
| 259 | + if ((ret = res_flush(skt, ss)) != ERROR_SUCCESS) { | ||
| 260 | + return ret; | ||
| 261 | + } | ||
| 262 | + | ||
| 263 | + // write body. | ||
| 264 | + int64_t left = length; | ||
| 265 | + char* buf = req->http_ts_send_buffer(); | ||
| 266 | + | ||
| 267 | + while (left > 0) { | ||
| 268 | + ssize_t nread = -1; | ||
| 269 | + // TODO: FIXME: use st_read. | ||
| 270 | + if ((nread = ::read(fd, buf, HTTP_TS_SEND_BUFFER_SIZE)) < 0) { | ||
| 271 | + ret = ERROR_HTTP_READ_FILE; | ||
| 272 | + srs_warn("read file %s failed, ret=%d", fullpath.c_str(), ret); | ||
| 273 | + break; | ||
| 274 | + } | ||
| 275 | + | ||
| 276 | + left -= nread; | ||
| 277 | + if ((ret = skt->write(buf, nread, NULL)) != ERROR_SUCCESS) { | ||
| 278 | + break; | ||
| 279 | + } | ||
| 280 | + } | ||
| 281 | + ::close(fd); | ||
| 282 | + | ||
| 283 | + return ret; | ||
| 284 | +} | ||
| 285 | + | ||
| 228 | int SrsHttpVhost::response_ts_file(SrsSocket* skt, SrsHttpMessage* req, string fullpath) | 286 | int SrsHttpVhost::response_ts_file(SrsSocket* skt, SrsHttpMessage* req, string fullpath) |
| 229 | { | 287 | { |
| 230 | int ret = ERROR_SUCCESS; | 288 | int ret = ERROR_SUCCESS; |
| @@ -266,10 +324,9 @@ int SrsHttpVhost::response_ts_file(SrsSocket* skt, SrsHttpMessage* req, string f | @@ -266,10 +324,9 @@ int SrsHttpVhost::response_ts_file(SrsSocket* skt, SrsHttpMessage* req, string f | ||
| 266 | ssize_t nread = -1; | 324 | ssize_t nread = -1; |
| 267 | // TODO: FIXME: use st_read. | 325 | // TODO: FIXME: use st_read. |
| 268 | if ((nread = ::read(fd, buf, HTTP_TS_SEND_BUFFER_SIZE)) < 0) { | 326 | if ((nread = ::read(fd, buf, HTTP_TS_SEND_BUFFER_SIZE)) < 0) { |
| 269 | - ::close(fd); | ||
| 270 | ret = ERROR_HTTP_READ_FILE; | 327 | ret = ERROR_HTTP_READ_FILE; |
| 271 | srs_warn("read file %s failed, ret=%d", fullpath.c_str(), ret); | 328 | srs_warn("read file %s failed, ret=%d", fullpath.c_str(), ret); |
| 272 | - return ret; | 329 | + break; |
| 273 | } | 330 | } |
| 274 | 331 | ||
| 275 | left -= nread; | 332 | left -= nread; |
| @@ -71,6 +71,7 @@ protected: | @@ -71,6 +71,7 @@ protected: | ||
| 71 | virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req); | 71 | virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req); |
| 72 | private: | 72 | private: |
| 73 | virtual int response_regular_file(SrsSocket* skt, SrsHttpMessage* req, std::string fullpath); | 73 | virtual int response_regular_file(SrsSocket* skt, SrsHttpMessage* req, std::string fullpath); |
| 74 | + virtual int response_flv_file(SrsSocket* skt, SrsHttpMessage* req, std::string fullpath); | ||
| 74 | virtual int response_ts_file(SrsSocket* skt, SrsHttpMessage* req, std::string fullpath); | 75 | virtual int response_ts_file(SrsSocket* skt, SrsHttpMessage* req, std::string fullpath); |
| 75 | virtual std::string get_request_file(SrsHttpMessage* req); | 76 | virtual std::string get_request_file(SrsHttpMessage* req); |
| 76 | public: | 77 | public: |
| @@ -53,7 +53,7 @@ SrsIngester::SrsIngester() | @@ -53,7 +53,7 @@ SrsIngester::SrsIngester() | ||
| 53 | { | 53 | { |
| 54 | _srs_config->subscribe(this); | 54 | _srs_config->subscribe(this); |
| 55 | 55 | ||
| 56 | - pthread = new SrsThread(this, SRS_AUTO_INGESTER_SLEEP_US); | 56 | + pthread = new SrsThread(this, SRS_AUTO_INGESTER_SLEEP_US, true); |
| 57 | pithy_print = new SrsPithyPrint(SRS_STAGE_INGESTER); | 57 | pithy_print = new SrsPithyPrint(SRS_STAGE_INGESTER); |
| 58 | } | 58 | } |
| 59 | 59 |
| @@ -84,7 +84,7 @@ SrsListener::SrsListener(SrsServer* server, SrsListenerType type) | @@ -84,7 +84,7 @@ SrsListener::SrsListener(SrsServer* server, SrsListenerType type) | ||
| 84 | _server = server; | 84 | _server = server; |
| 85 | _type = type; | 85 | _type = type; |
| 86 | 86 | ||
| 87 | - pthread = new SrsThread(this, 0); | 87 | + pthread = new SrsThread(this, 0, true); |
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | SrsListener::~SrsListener() | 90 | SrsListener::~SrsListener() |
| @@ -197,7 +197,7 @@ SrsSignalManager::SrsSignalManager(SrsServer* server) | @@ -197,7 +197,7 @@ SrsSignalManager::SrsSignalManager(SrsServer* server) | ||
| 197 | 197 | ||
| 198 | _server = server; | 198 | _server = server; |
| 199 | sig_pipe[0] = sig_pipe[1] = -1; | 199 | sig_pipe[0] = sig_pipe[1] = -1; |
| 200 | - pthread = new SrsThread(this, 0); | 200 | + pthread = new SrsThread(this, 0, true); |
| 201 | signal_read_stfd = NULL; | 201 | signal_read_stfd = NULL; |
| 202 | } | 202 | } |
| 203 | 203 |
| @@ -54,7 +54,7 @@ void ISrsThreadHandler::on_thread_stop() | @@ -54,7 +54,7 @@ void ISrsThreadHandler::on_thread_stop() | ||
| 54 | { | 54 | { |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | -SrsThread::SrsThread(ISrsThreadHandler* thread_handler, int64_t interval_us) | 57 | +SrsThread::SrsThread(ISrsThreadHandler* thread_handler, int64_t interval_us, bool joinable) |
| 58 | { | 58 | { |
| 59 | handler = thread_handler; | 59 | handler = thread_handler; |
| 60 | cycle_interval_us = interval_us; | 60 | cycle_interval_us = interval_us; |
| @@ -62,6 +62,7 @@ SrsThread::SrsThread(ISrsThreadHandler* thread_handler, int64_t interval_us) | @@ -62,6 +62,7 @@ SrsThread::SrsThread(ISrsThreadHandler* thread_handler, int64_t interval_us) | ||
| 62 | tid = NULL; | 62 | tid = NULL; |
| 63 | loop = false; | 63 | loop = false; |
| 64 | _cid = -1; | 64 | _cid = -1; |
| 65 | + _joinable = joinable; | ||
| 65 | } | 66 | } |
| 66 | 67 | ||
| 67 | SrsThread::~SrsThread() | 68 | SrsThread::~SrsThread() |
| @@ -83,7 +84,7 @@ int SrsThread::start() | @@ -83,7 +84,7 @@ int SrsThread::start() | ||
| 83 | return ret; | 84 | return ret; |
| 84 | } | 85 | } |
| 85 | 86 | ||
| 86 | - if((tid = st_thread_create(thread_fun, this, 1, 0)) == NULL){ | 87 | + if((tid = st_thread_create(thread_fun, this, (_joinable? 1:0), 0)) == NULL){ |
| 87 | ret = ERROR_ST_CREATE_CYCLE_THREAD; | 88 | ret = ERROR_ST_CREATE_CYCLE_THREAD; |
| 88 | srs_error("st_thread_create failed. ret=%d", ret); | 89 | srs_error("st_thread_create failed. ret=%d", ret); |
| 89 | return ret; | 90 | return ret; |
| @@ -93,7 +94,7 @@ int SrsThread::start() | @@ -93,7 +94,7 @@ int SrsThread::start() | ||
| 93 | loop = true; | 94 | loop = true; |
| 94 | 95 | ||
| 95 | // wait for cid to ready, for parent thread to get the cid. | 96 | // wait for cid to ready, for parent thread to get the cid. |
| 96 | - while (_cid < 0) { | 97 | + while (_cid < 0 && loop) { |
| 97 | st_usleep(10 * SRS_TIME_MILLISECONDS); | 98 | st_usleep(10 * SRS_TIME_MILLISECONDS); |
| 98 | } | 99 | } |
| 99 | 100 |
| @@ -88,6 +88,7 @@ private: | @@ -88,6 +88,7 @@ private: | ||
| 88 | st_thread_t tid; | 88 | st_thread_t tid; |
| 89 | int _cid; | 89 | int _cid; |
| 90 | bool loop; | 90 | bool loop; |
| 91 | + bool _joinable; | ||
| 91 | private: | 92 | private: |
| 92 | ISrsThreadHandler* handler; | 93 | ISrsThreadHandler* handler; |
| 93 | int64_t cycle_interval_us; | 94 | int64_t cycle_interval_us; |
| @@ -96,8 +97,15 @@ public: | @@ -96,8 +97,15 @@ public: | ||
| 96 | * initialize the thread. | 97 | * initialize the thread. |
| 97 | * @param thread_handler, the cycle handler for the thread. | 98 | * @param thread_handler, the cycle handler for the thread. |
| 98 | * @param interval_us, the sleep interval when cycle finished. | 99 | * @param interval_us, the sleep interval when cycle finished. |
| 100 | + * @param joinable, if joinable, other thread must stop the thread. | ||
| 101 | + * @remark if joinable, thread never quit itself, or memory leak. | ||
| 102 | + * @see: https://github.com/winlinvip/simple-rtmp-server/issues/78 | ||
| 99 | */ | 103 | */ |
| 100 | - SrsThread(ISrsThreadHandler* thread_handler, int64_t interval_us); | 104 | + /** |
| 105 | + * TODO: FIXME: maybe all thread must be reap by others threads, | ||
| 106 | + * @see: https://github.com/winlinvip/simple-rtmp-server/issues/77 | ||
| 107 | + */ | ||
| 108 | + SrsThread(ISrsThreadHandler* thread_handler, int64_t interval_us, bool joinable); | ||
| 101 | virtual ~SrsThread(); | 109 | virtual ~SrsThread(); |
| 102 | public: | 110 | public: |
| 103 | /** | 111 | /** |
| @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 31 | // current release version | 31 | // current release version |
| 32 | #define VERSION_MAJOR "0" | 32 | #define VERSION_MAJOR "0" |
| 33 | #define VERSION_MINOR "9" | 33 | #define VERSION_MINOR "9" |
| 34 | -#define VERSION_REVISION "112" | 34 | +#define VERSION_REVISION "113" |
| 35 | #define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION | 35 | #define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION |
| 36 | // server info. | 36 | // server info. |
| 37 | #define RTMP_SIG_SRS_KEY "SRS" | 37 | #define RTMP_SIG_SRS_KEY "SRS" |
-
请 注册 或 登录 后发表评论