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"