mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
parent
2ed2513f08
commit
ea9a5f26d9
18 changed files with 174 additions and 274 deletions
|
@ -28,9 +28,6 @@ using namespace std;
|
|||
#include <srs_kernel_error.hpp>
|
||||
#include <srs_kernel_log.hpp>
|
||||
|
||||
// the sleep interval in ms for http async callback.
|
||||
#define SRS_AUTO_ASYNC_CALLBACL_CIMS 30
|
||||
|
||||
ISrsAsyncCallTask::ISrsAsyncCallTask()
|
||||
{
|
||||
}
|
||||
|
@ -41,13 +38,13 @@ ISrsAsyncCallTask::~ISrsAsyncCallTask()
|
|||
|
||||
SrsAsyncCallWorker::SrsAsyncCallWorker()
|
||||
{
|
||||
pthread = new SrsReusableThread("async", this, SRS_AUTO_ASYNC_CALLBACL_CIMS);
|
||||
trd = NULL;
|
||||
wait = st_cond_new();
|
||||
}
|
||||
|
||||
SrsAsyncCallWorker::~SrsAsyncCallWorker()
|
||||
{
|
||||
srs_freep(pthread);
|
||||
srs_freep(trd);
|
||||
|
||||
std::vector<ISrsAsyncCallTask*>::iterator it;
|
||||
for (it = tasks.begin(); it != tasks.end(); ++it) {
|
||||
|
@ -76,29 +73,31 @@ int SrsAsyncCallWorker::count()
|
|||
|
||||
int SrsAsyncCallWorker::start()
|
||||
{
|
||||
return pthread->start();
|
||||
srs_freep(trd);
|
||||
trd = new SrsCoroutine("async", this, _srs_context->get_id());
|
||||
return trd->start();
|
||||
}
|
||||
|
||||
void SrsAsyncCallWorker::stop()
|
||||
{
|
||||
st_cond_signal(wait);
|
||||
pthread->stop();
|
||||
trd->stop();
|
||||
}
|
||||
|
||||
int SrsAsyncCallWorker::cycle()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
while (pthread->can_loop()) {
|
||||
while (!trd->pull()) {
|
||||
if (tasks.empty()) {
|
||||
st_cond_wait(wait);
|
||||
}
|
||||
|
||||
std::vector<ISrsAsyncCallTask*> copies = tasks;
|
||||
std::vector<ISrsAsyncCallTask*> copy = tasks;
|
||||
tasks.clear();
|
||||
|
||||
std::vector<ISrsAsyncCallTask*>::iterator it;
|
||||
for (it = copies.begin(); it != copies.end(); ++it) {
|
||||
for (it = copy.begin(); it != copy.end(); ++it) {
|
||||
ISrsAsyncCallTask* task = *it;
|
||||
if ((ret = task->call()) != ERROR_SUCCESS) {
|
||||
srs_warn("ignore async callback %s, ret=%d", task->to_string().c_str(), ret);
|
||||
|
|
|
@ -63,10 +63,10 @@ public:
|
|||
* when worker call with the task, the worker will do it in isolate thread.
|
||||
* that is, the task is execute/call in async mode.
|
||||
*/
|
||||
class SrsAsyncCallWorker : public ISrsReusableThreadHandler
|
||||
class SrsAsyncCallWorker : public ISrsCoroutineHandler
|
||||
{
|
||||
private:
|
||||
SrsReusableThread* pthread;
|
||||
SrsCoroutine* trd;
|
||||
protected:
|
||||
std::vector<ISrsAsyncCallTask*> tasks;
|
||||
st_cond_t wait;
|
||||
|
|
|
@ -36,15 +36,12 @@ using namespace std;
|
|||
|
||||
#ifdef SRS_AUTO_TRANSCODE
|
||||
|
||||
// when error, encoder sleep for a while and retry.
|
||||
#define SRS_RTMP_ENCODER_CIMS (3000)
|
||||
|
||||
// for encoder to detect the dead loop
|
||||
static std::vector<std::string> _transcoded_url;
|
||||
|
||||
SrsEncoder::SrsEncoder()
|
||||
{
|
||||
pthread = new SrsReusableThread("encoder", this, SRS_RTMP_ENCODER_CIMS);
|
||||
trd = NULL;
|
||||
pprint = SrsPithyPrint::create_encoder();
|
||||
}
|
||||
|
||||
|
@ -52,7 +49,7 @@ SrsEncoder::~SrsEncoder()
|
|||
{
|
||||
on_unpublish();
|
||||
|
||||
srs_freep(pthread);
|
||||
srs_freep(trd);
|
||||
srs_freep(pprint);
|
||||
}
|
||||
|
||||
|
@ -76,24 +73,35 @@ int SrsEncoder::on_publish(SrsRequest* req)
|
|||
}
|
||||
|
||||
// start thread to run all encoding engines.
|
||||
if ((ret = pthread->start()) != ERROR_SUCCESS) {
|
||||
srs_freep(trd);
|
||||
trd = new SrsCoroutine("encoder", this, _srs_context->get_id());
|
||||
if ((ret = trd->start()) != ERROR_SUCCESS) {
|
||||
srs_error("st_thread_create failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
srs_trace("encoder thread cid=%d, current_cid=%d", pthread->cid(), _srs_context->get_id());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SrsEncoder::on_unpublish()
|
||||
{
|
||||
pthread->stop();
|
||||
trd->stop();
|
||||
clear_engines();
|
||||
}
|
||||
|
||||
// when error, encoder sleep for a while and retry.
|
||||
#define SRS_RTMP_ENCODER_CIMS (3000)
|
||||
|
||||
int SrsEncoder::cycle()
|
||||
{
|
||||
int ret = do_cycle();
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
while (!trd->pull()) {
|
||||
if ((ret = do_cycle()) != ERROR_SUCCESS) {
|
||||
srs_warn("Encoder: Ignore error, ret=%d", ret);
|
||||
}
|
||||
st_usleep(SRS_RTMP_ENCODER_CIMS * 1000);
|
||||
}
|
||||
|
||||
// kill ffmpeg when finished and it alive
|
||||
std::vector<SrsFFMPEG*>::iterator it;
|
||||
|
|
|
@ -42,13 +42,13 @@ class SrsFFMPEG;
|
|||
* the encoder for a stream,
|
||||
* may use multiple ffmpegs to transcode the specified stream.
|
||||
*/
|
||||
class SrsEncoder : public ISrsReusableThreadHandler
|
||||
class SrsEncoder : public ISrsCoroutineHandler
|
||||
{
|
||||
private:
|
||||
std::string input_stream_name;
|
||||
std::vector<SrsFFMPEG*> ffmpegs;
|
||||
private:
|
||||
SrsReusableThread* pthread;
|
||||
SrsCoroutine* trd;
|
||||
SrsPithyPrint* pprint;
|
||||
public:
|
||||
SrsEncoder();
|
||||
|
|
|
@ -37,10 +37,6 @@ using namespace std;
|
|||
#include <srs_app_utility.hpp>
|
||||
#include <srs_protocol_utility.hpp>
|
||||
|
||||
// when error, ingester sleep for a while and retry.
|
||||
// ingest never sleep a long time, for we must start the stream ASAP.
|
||||
#define SRS_AUTO_INGESTER_CIMS (3000)
|
||||
|
||||
SrsIngesterFFMPEG::SrsIngesterFFMPEG()
|
||||
{
|
||||
ffmpeg = NULL;
|
||||
|
@ -109,7 +105,7 @@ SrsIngester::SrsIngester()
|
|||
|
||||
expired = false;
|
||||
|
||||
pthread = new SrsReusableThread("ingest", this, SRS_AUTO_INGESTER_CIMS);
|
||||
trd = NULL;
|
||||
pprint = SrsPithyPrint::create_ingester();
|
||||
}
|
||||
|
||||
|
@ -117,7 +113,7 @@ SrsIngester::~SrsIngester()
|
|||
{
|
||||
_srs_config->unsubscribe(this);
|
||||
|
||||
srs_freep(pthread);
|
||||
srs_freep(trd);
|
||||
clear_engines();
|
||||
}
|
||||
|
||||
|
@ -144,18 +140,19 @@ int SrsIngester::start()
|
|||
// for the reload may add more ingesters.
|
||||
|
||||
// start thread to run all encoding engines.
|
||||
if ((ret = pthread->start()) != ERROR_SUCCESS) {
|
||||
srs_freep(trd);
|
||||
trd = new SrsCoroutine("ingest", this, _srs_context->get_id());
|
||||
if ((ret = trd->start()) != ERROR_SUCCESS) {
|
||||
srs_error("st_thread_create failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
srs_trace("ingest thread cid=%d, current_cid=%d", pthread->cid(), _srs_context->get_id());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SrsIngester::stop()
|
||||
{
|
||||
pthread->stop();
|
||||
trd->stop();
|
||||
clear_engines();
|
||||
}
|
||||
|
||||
|
@ -172,10 +169,28 @@ void SrsIngester::fast_stop()
|
|||
}
|
||||
}
|
||||
|
||||
// when error, ingester sleep for a while and retry.
|
||||
// ingest never sleep a long time, for we must start the stream ASAP.
|
||||
#define SRS_AUTO_INGESTER_CIMS (3000)
|
||||
|
||||
int SrsIngester::cycle()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
while (!trd->pull()) {
|
||||
if ((ret = do_cycle()) != ERROR_SUCCESS) {
|
||||
srs_warn("Ingester: Ignore error, ret=%d", ret);
|
||||
}
|
||||
st_usleep(SRS_AUTO_INGESTER_CIMS * 1000);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SrsIngester::do_cycle()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
// when expired, restart all ingesters.
|
||||
if (expired) {
|
||||
expired = false;
|
||||
|
|
|
@ -71,12 +71,12 @@ public:
|
|||
* encode with FFMPEG(optional),
|
||||
* push to SRS(or any RTMP server) over RTMP.
|
||||
*/
|
||||
class SrsIngester : public ISrsReusableThreadHandler, public ISrsReloadHandler
|
||||
class SrsIngester : public ISrsCoroutineHandler, public ISrsReloadHandler
|
||||
{
|
||||
private:
|
||||
std::vector<SrsIngesterFFMPEG*> ingesters;
|
||||
private:
|
||||
SrsReusableThread* pthread;
|
||||
SrsCoroutine* trd;
|
||||
SrsPithyPrint* pprint;
|
||||
// whether the ingesters are expired,
|
||||
// for example, the listen port changed,
|
||||
|
@ -95,6 +95,8 @@ private:
|
|||
// interface ISrsReusableThreadHandler.
|
||||
public:
|
||||
virtual int cycle();
|
||||
private:
|
||||
virtual int do_cycle();
|
||||
private:
|
||||
virtual void clear_engines();
|
||||
virtual int parse();
|
||||
|
|
|
@ -40,7 +40,6 @@ using namespace std;
|
|||
|
||||
#ifdef SRS_AUTO_KAFKA
|
||||
|
||||
#define SRS_KAKFA_CIMS 3000
|
||||
#define SRS_KAFKA_PRODUCER_TIMEOUT 30000
|
||||
#define SRS_KAFKA_PRODUCER_AGGREGATE_SIZE 1
|
||||
|
||||
|
@ -366,7 +365,7 @@ SrsKafkaProducer::SrsKafkaProducer()
|
|||
metadata_expired = st_cond_new();
|
||||
|
||||
lock = st_mutex_new();
|
||||
pthread = new SrsReusableThread("kafka", this, SRS_KAKFA_CIMS);
|
||||
trd = NULL;
|
||||
worker = new SrsAsyncCallWorker();
|
||||
cache = new SrsKafkaCache();
|
||||
|
||||
|
@ -380,7 +379,7 @@ SrsKafkaProducer::~SrsKafkaProducer()
|
|||
srs_freep(lb);
|
||||
|
||||
srs_freep(worker);
|
||||
srs_freep(pthread);
|
||||
srs_freep(trd);
|
||||
srs_freep(cache);
|
||||
|
||||
st_mutex_destroy(lock);
|
||||
|
@ -410,7 +409,9 @@ int SrsKafkaProducer::start()
|
|||
return ret;
|
||||
}
|
||||
|
||||
if ((ret = pthread->start()) != ERROR_SUCCESS) {
|
||||
srs_freep(trd);
|
||||
trd = new SrsCoroutine("kafka", this, _srs_context->get_id());
|
||||
if ((ret = trd->start()) != ERROR_SUCCESS) {
|
||||
srs_error("start kafka thread failed. ret=%d", ret);
|
||||
}
|
||||
|
||||
|
@ -425,7 +426,7 @@ void SrsKafkaProducer::stop()
|
|||
return;
|
||||
}
|
||||
|
||||
pthread->stop();
|
||||
trd->stop();
|
||||
worker->stop();
|
||||
}
|
||||
|
||||
|
@ -491,13 +492,17 @@ int SrsKafkaProducer::on_close(int key)
|
|||
return worker->execute(new SrsKafkaMessage(this, key, obj));
|
||||
}
|
||||
|
||||
#define SRS_KAKFA_CIMS 3000
|
||||
int SrsKafkaProducer::cycle()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
while (!trd->pull()) {
|
||||
if ((ret = do_cycle()) != ERROR_SUCCESS) {
|
||||
srs_warn("ignore kafka error. ret=%d", ret);
|
||||
}
|
||||
st_usleep(SRS_KAKFA_CIMS * 1000);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -158,13 +158,13 @@ extern void srs_dispose_kafka();
|
|||
/**
|
||||
* the kafka producer used to save log to kafka cluster.
|
||||
*/
|
||||
class SrsKafkaProducer : virtual public ISrsReusableThreadHandler, virtual public ISrsKafkaCluster
|
||||
class SrsKafkaProducer : virtual public ISrsCoroutineHandler, virtual public ISrsKafkaCluster
|
||||
{
|
||||
private:
|
||||
// TODO: FIXME: support reload.
|
||||
bool enabled;
|
||||
st_mutex_t lock;
|
||||
SrsReusableThread* pthread;
|
||||
SrsCoroutine* trd;
|
||||
private:
|
||||
bool metadata_ok;
|
||||
st_cond_t metadata_expired;
|
||||
|
|
|
@ -79,7 +79,7 @@ SrsUdpListener::SrsUdpListener(ISrsUdpHandler* h, string i, int p)
|
|||
nb_buf = SRS_UDP_MAX_PACKET_SIZE;
|
||||
buf = new char[nb_buf];
|
||||
|
||||
pthread = new SrsReusableThread("udp", this);
|
||||
trd = NULL;
|
||||
}
|
||||
|
||||
SrsUdpListener::~SrsUdpListener()
|
||||
|
@ -87,8 +87,7 @@ SrsUdpListener::~SrsUdpListener()
|
|||
// close the stfd to trigger thread to interrupted.
|
||||
srs_close_stfd(_stfd);
|
||||
|
||||
pthread->stop();
|
||||
srs_freep(pthread);
|
||||
srs_freep(trd);
|
||||
|
||||
// st does not close it sometimes,
|
||||
// close it manually.
|
||||
|
@ -118,13 +117,8 @@ int SrsUdpListener::listen()
|
|||
}
|
||||
srs_verbose("create linux socket success. ip=%s, port=%d, fd=%d", ip.c_str(), port, _fd);
|
||||
|
||||
int reuse_socket = 1;
|
||||
if (setsockopt(_fd, SOL_SOCKET, SO_REUSEADDR, &reuse_socket, sizeof(int)) == -1) {
|
||||
ret = ERROR_SOCKET_SETREUSE;
|
||||
srs_error("setsockopt reuse-addr error. ip=%s, port=%d, ret=%d", ip.c_str(), port, ret);
|
||||
return ret;
|
||||
}
|
||||
srs_verbose("setsockopt reuse-addr success. ip=%s, port=%d, fd=%d", ip.c_str(), port, _fd);
|
||||
srs_fd_close_exec(_fd);
|
||||
srs_socket_reuse_addr(_fd);
|
||||
|
||||
sockaddr_in addr;
|
||||
addr.sin_family = AF_INET;
|
||||
|
@ -144,7 +138,9 @@ int SrsUdpListener::listen()
|
|||
}
|
||||
srs_verbose("st open socket success. ep=%s:%d, fd=%d", ip.c_str(), port, _fd);
|
||||
|
||||
if ((ret = pthread->start()) != ERROR_SUCCESS) {
|
||||
srs_freep(trd);
|
||||
trd = new SrsCoroutine("udp", this);
|
||||
if ((ret = trd->start()) != ERROR_SUCCESS) {
|
||||
srs_error("st_thread_create listen thread error. ep=%s:%d, ret=%d", ip.c_str(), port, ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -157,6 +153,7 @@ int SrsUdpListener::cycle()
|
|||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
while (!trd->pull()) {
|
||||
// TODO: FIXME: support ipv6, @see man 7 ipv6
|
||||
sockaddr_in from;
|
||||
int nb_from = sizeof(sockaddr_in);
|
||||
|
@ -175,6 +172,7 @@ int SrsUdpListener::cycle()
|
|||
if (SRS_UDP_PACKET_RECV_CYCLE_INTERVAL_MS > 0) {
|
||||
st_usleep(SRS_UDP_PACKET_RECV_CYCLE_INTERVAL_MS * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -188,13 +186,12 @@ SrsTcpListener::SrsTcpListener(ISrsTcpHandler* h, string i, int p)
|
|||
_fd = -1;
|
||||
_stfd = NULL;
|
||||
|
||||
pthread = new SrsReusableThread("tcp", this);
|
||||
trd = NULL;
|
||||
}
|
||||
|
||||
SrsTcpListener::~SrsTcpListener()
|
||||
{
|
||||
pthread->stop();
|
||||
srs_freep(pthread);
|
||||
srs_freep(trd);
|
||||
|
||||
srs_close_stfd(_stfd);
|
||||
}
|
||||
|
@ -215,13 +212,8 @@ int SrsTcpListener::listen()
|
|||
}
|
||||
srs_verbose("create linux socket success. port=%d, fd=%d", port, _fd);
|
||||
|
||||
int reuse_socket = 1;
|
||||
if (setsockopt(_fd, SOL_SOCKET, SO_REUSEADDR, &reuse_socket, sizeof(int)) == -1) {
|
||||
ret = ERROR_SOCKET_SETREUSE;
|
||||
srs_error("setsockopt reuse-addr error. port=%d, ret=%d", port, ret);
|
||||
return ret;
|
||||
}
|
||||
srs_verbose("setsockopt reuse-addr success. port=%d, fd=%d", port, _fd);
|
||||
srs_fd_close_exec(_fd);
|
||||
srs_socket_reuse_addr(_fd);
|
||||
|
||||
sockaddr_in addr;
|
||||
addr.sin_family = AF_INET;
|
||||
|
@ -248,7 +240,9 @@ int SrsTcpListener::listen()
|
|||
}
|
||||
srs_verbose("st open socket success. ep=%s:%d, fd=%d", ip.c_str(), port, _fd);
|
||||
|
||||
if ((ret = pthread->start()) != ERROR_SUCCESS) {
|
||||
srs_freep(trd);
|
||||
trd = new SrsCoroutine("tcp", this);
|
||||
if ((ret = trd->start()) != ERROR_SUCCESS) {
|
||||
srs_error("st_thread_create listen thread error. ep=%s:%d, ret=%d", ip.c_str(), port, ret);
|
||||
return ret;
|
||||
}
|
||||
|
@ -261,21 +255,26 @@ int SrsTcpListener::cycle()
|
|||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
st_netfd_t client_stfd = st_accept(_stfd, NULL, NULL, ST_UTIME_NO_TIMEOUT);
|
||||
while (!trd->pull()) {
|
||||
st_netfd_t stfd = st_accept(_stfd, NULL, NULL, ST_UTIME_NO_TIMEOUT);
|
||||
int fd = st_netfd_fileno(stfd);
|
||||
|
||||
if(client_stfd == NULL){
|
||||
srs_fd_close_exec(fd);
|
||||
|
||||
if(stfd == NULL){
|
||||
// ignore error.
|
||||
if (errno != EINTR) {
|
||||
srs_error("ignore accept thread stoppped for accept client error");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
srs_verbose("get a client. fd=%d", st_netfd_fileno(client_stfd));
|
||||
srs_verbose("get a client. fd=%d", fd);
|
||||
|
||||
if ((ret = handler->on_tcp_client(client_stfd)) != ERROR_SUCCESS) {
|
||||
if ((ret = handler->on_tcp_client(stfd)) != ERROR_SUCCESS) {
|
||||
srs_warn("accept client error. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -78,12 +78,12 @@ public:
|
|||
/**
|
||||
* bind udp port, start thread to recv packet and handler it.
|
||||
*/
|
||||
class SrsUdpListener : public ISrsReusableThreadHandler
|
||||
class SrsUdpListener : public ISrsCoroutineHandler
|
||||
{
|
||||
private:
|
||||
int _fd;
|
||||
st_netfd_t _stfd;
|
||||
SrsReusableThread* pthread;
|
||||
SrsCoroutine* trd;
|
||||
private:
|
||||
char* buf;
|
||||
int nb_buf;
|
||||
|
@ -107,12 +107,12 @@ public:
|
|||
/**
|
||||
* bind and listen tcp port, use handler to process the client.
|
||||
*/
|
||||
class SrsTcpListener : public ISrsReusableThreadHandler
|
||||
class SrsTcpListener : public ISrsCoroutineHandler
|
||||
{
|
||||
private:
|
||||
int _fd;
|
||||
st_netfd_t _stfd;
|
||||
SrsReusableThread* pthread;
|
||||
SrsCoroutine* trd;
|
||||
private:
|
||||
ISrsTcpHandler* handler;
|
||||
std::string ip;
|
||||
|
|
|
@ -36,12 +36,9 @@ using namespace std;
|
|||
#include <srs_kernel_consts.hpp>
|
||||
#include <srs_protocol_utility.hpp>
|
||||
|
||||
// when error, ng-exec sleep for a while and retry.
|
||||
#define SRS_RTMP_EXEC_CIMS (3000)
|
||||
|
||||
SrsNgExec::SrsNgExec()
|
||||
{
|
||||
pthread = new SrsReusableThread("encoder", this, SRS_RTMP_EXEC_CIMS);
|
||||
trd = NULL;
|
||||
pprint = SrsPithyPrint::create_exec();
|
||||
}
|
||||
|
||||
|
@ -49,7 +46,7 @@ SrsNgExec::~SrsNgExec()
|
|||
{
|
||||
on_unpublish();
|
||||
|
||||
srs_freep(pthread);
|
||||
srs_freep(trd);
|
||||
srs_freep(pprint);
|
||||
}
|
||||
|
||||
|
@ -63,24 +60,34 @@ int SrsNgExec::on_publish(SrsRequest* req)
|
|||
}
|
||||
|
||||
// start thread to run all processes.
|
||||
if ((ret = pthread->start()) != ERROR_SUCCESS) {
|
||||
srs_freep(trd);
|
||||
trd = new SrsCoroutine("encoder", this, _srs_context->get_id());
|
||||
if ((ret = trd->start()) != ERROR_SUCCESS) {
|
||||
srs_error("st_thread_create failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
srs_trace("exec thread cid=%d, current_cid=%d", pthread->cid(), _srs_context->get_id());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SrsNgExec::on_unpublish()
|
||||
{
|
||||
pthread->stop();
|
||||
trd->stop();
|
||||
clear_exec_publish();
|
||||
}
|
||||
|
||||
// when error, ng-exec sleep for a while and retry.
|
||||
#define SRS_RTMP_EXEC_CIMS (3000)
|
||||
int SrsNgExec::cycle()
|
||||
{
|
||||
int ret = do_cycle();
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
while (!trd->pull()) {
|
||||
if ((ret = do_cycle()) != ERROR_SUCCESS) {
|
||||
srs_warn("EXEC: Ignore error, ret=%d", ret);
|
||||
}
|
||||
st_usleep(SRS_RTMP_EXEC_CIMS * 1000);
|
||||
}
|
||||
|
||||
std::vector<SrsProcess*>::iterator it;
|
||||
for (it = exec_publishs.begin(); it != exec_publishs.end(); ++it) {
|
||||
|
|
|
@ -40,10 +40,10 @@ class SrsProcess;
|
|||
* @see https://github.com/arut/nginx-rtmp-module/wiki/Directives#exec_push
|
||||
* @see https://github.com/ossrs/srs/issues/367
|
||||
*/
|
||||
class SrsNgExec : public ISrsReusableThreadHandler
|
||||
class SrsNgExec : public ISrsCoroutineHandler
|
||||
{
|
||||
private:
|
||||
SrsReusableThread* pthread;
|
||||
SrsCoroutine* trd;
|
||||
SrsPithyPrint* pprint;
|
||||
std::string input_stream_name;
|
||||
std::vector<SrsProcess*> exec_publishs;
|
||||
|
|
|
@ -124,9 +124,13 @@ int SrsCoroutine::cid()
|
|||
|
||||
int SrsCoroutine::cycle()
|
||||
{
|
||||
if (!context && _srs_context) {
|
||||
if (_srs_context) {
|
||||
if (context) {
|
||||
_srs_context->set_id(context);
|
||||
} else {
|
||||
context = _srs_context->generate_id();
|
||||
}
|
||||
}
|
||||
srs_info("Thread.cycle: Start with cid=%d, err=%d", context, err);
|
||||
|
||||
int ret = handler->cycle();
|
||||
|
|
|
@ -78,89 +78,6 @@ void SrsCoroutineManager::clear()
|
|||
}
|
||||
}
|
||||
|
||||
ISrsReusableThreadHandler::ISrsReusableThreadHandler()
|
||||
{
|
||||
}
|
||||
|
||||
ISrsReusableThreadHandler::~ISrsReusableThreadHandler()
|
||||
{
|
||||
}
|
||||
|
||||
void ISrsReusableThreadHandler::on_thread_start()
|
||||
{
|
||||
}
|
||||
|
||||
int ISrsReusableThreadHandler::on_before_cycle()
|
||||
{
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int ISrsReusableThreadHandler::on_end_cycle()
|
||||
{
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
void ISrsReusableThreadHandler::on_thread_stop()
|
||||
{
|
||||
}
|
||||
|
||||
SrsReusableThread::SrsReusableThread(const char* n, ISrsReusableThreadHandler* h, int64_t cims)
|
||||
{
|
||||
handler = h;
|
||||
pthread = new internal::SrsThread(n, this, cims, true);
|
||||
}
|
||||
|
||||
SrsReusableThread::~SrsReusableThread()
|
||||
{
|
||||
pthread->stop();
|
||||
srs_freep(pthread);
|
||||
}
|
||||
|
||||
int SrsReusableThread::start()
|
||||
{
|
||||
return pthread->start();
|
||||
}
|
||||
|
||||
void SrsReusableThread::stop()
|
||||
{
|
||||
pthread->stop();
|
||||
}
|
||||
|
||||
bool SrsReusableThread::can_loop()
|
||||
{
|
||||
return pthread->can_loop();
|
||||
}
|
||||
|
||||
int SrsReusableThread::cid()
|
||||
{
|
||||
return pthread->cid();
|
||||
}
|
||||
|
||||
int SrsReusableThread::cycle()
|
||||
{
|
||||
return handler->cycle();
|
||||
}
|
||||
|
||||
void SrsReusableThread::on_thread_start()
|
||||
{
|
||||
handler->on_thread_start();
|
||||
}
|
||||
|
||||
int SrsReusableThread::on_before_cycle()
|
||||
{
|
||||
return handler->on_before_cycle();
|
||||
}
|
||||
|
||||
int SrsReusableThread::on_end_cycle()
|
||||
{
|
||||
return handler->on_end_cycle();
|
||||
}
|
||||
|
||||
void SrsReusableThread::on_thread_stop()
|
||||
{
|
||||
handler->on_thread_stop();
|
||||
}
|
||||
|
||||
ISrsReusableThread2Handler::ISrsReusableThread2Handler()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -58,85 +58,6 @@ private:
|
|||
void clear();
|
||||
};
|
||||
|
||||
/**
|
||||
* the reuse thread is a thread stop and start by other thread.
|
||||
* user can create thread and stop then start again and again,
|
||||
* generally must provides a start and stop method, @see SrsIngester.
|
||||
* the step to create a thread stop by other thread:
|
||||
* 1. create SrsReusableThread field.
|
||||
* 2. must manually stop the thread when started it.
|
||||
* for example:
|
||||
* class SrsIngester : public ISrsReusableThreadHandler {
|
||||
* public: SrsIngester() { pthread = new SrsReusableThread("ingest", this, SRS_AUTO_INGESTER_CIMS); }
|
||||
* public: virtual int start() { return pthread->start(); }
|
||||
* public: virtual void stop() { pthread->stop(); }
|
||||
* public: virtual int cycle() {
|
||||
* // check status, start ffmpeg when stopped.
|
||||
* }
|
||||
* };
|
||||
*/
|
||||
class ISrsReusableThreadHandler
|
||||
{
|
||||
public:
|
||||
ISrsReusableThreadHandler();
|
||||
virtual ~ISrsReusableThreadHandler();
|
||||
public:
|
||||
/**
|
||||
* the cycle method for the one cycle thread.
|
||||
* @remark when the cycle has its inner loop, it must check whether
|
||||
* the thread is interrupted.
|
||||
*/
|
||||
virtual int cycle() = 0;
|
||||
public:
|
||||
/**
|
||||
* other callback for handler.
|
||||
* @remark all callback is optional, handler can ignore it.
|
||||
*/
|
||||
virtual void on_thread_start();
|
||||
virtual int on_before_cycle();
|
||||
virtual int on_end_cycle();
|
||||
virtual void on_thread_stop();
|
||||
};
|
||||
class SrsReusableThread : public internal::ISrsThreadHandler
|
||||
{
|
||||
private:
|
||||
internal::SrsThread* pthread;
|
||||
ISrsReusableThreadHandler* handler;
|
||||
public:
|
||||
SrsReusableThread(const char* n, ISrsReusableThreadHandler* h, int64_t cims = 0);
|
||||
virtual ~SrsReusableThread();
|
||||
public:
|
||||
/**
|
||||
* for the reusable thread, start and stop by user.
|
||||
*/
|
||||
virtual int start();
|
||||
/**
|
||||
* stop the thread, wait for the thread to terminate.
|
||||
* @remark user can stop multiple times, ignore if already stopped.
|
||||
*/
|
||||
virtual void stop();
|
||||
/**
|
||||
* whether the thread should loop,
|
||||
* used for handler->cycle() which has a loop method,
|
||||
* to check this method, break if false.
|
||||
*/
|
||||
virtual bool can_loop();
|
||||
public:
|
||||
/**
|
||||
* get the context id. @see: ISrsThreadContext.get_id().
|
||||
* used for parent thread to get the id.
|
||||
* @remark when start thread, parent thread will block and wait for this id ready.
|
||||
*/
|
||||
virtual int cid();
|
||||
// interface internal::ISrsThreadHandler
|
||||
public:
|
||||
virtual int cycle();
|
||||
virtual void on_thread_start();
|
||||
virtual int on_before_cycle();
|
||||
virtual int on_end_cycle();
|
||||
virtual void on_thread_stop();
|
||||
};
|
||||
|
||||
/**
|
||||
* the reuse thread is a thread stop and start by other thread.
|
||||
* the version 2, is the thread cycle has its inner loop, which should
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
|
||||
#include <srs_service_st.hpp>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
using namespace std;
|
||||
|
||||
#include <srs_kernel_error.hpp>
|
||||
|
@ -88,6 +90,19 @@ void srs_close_stfd(st_netfd_t& stfd)
|
|||
}
|
||||
}
|
||||
|
||||
void srs_fd_close_exec(int fd)
|
||||
{
|
||||
int flags = fcntl(fd, F_GETFD);
|
||||
flags |= FD_CLOEXEC;
|
||||
fcntl(fd, F_SETFD, flags);
|
||||
}
|
||||
|
||||
void srs_socket_reuse_addr(int fd)
|
||||
{
|
||||
int v = 1;
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(int));
|
||||
}
|
||||
|
||||
SrsStSocket::SrsStSocket()
|
||||
{
|
||||
stfd = NULL;
|
||||
|
|
|
@ -38,6 +38,12 @@ extern int srs_st_init();
|
|||
// @remark when close, user must ensure io completed.
|
||||
extern void srs_close_stfd(st_netfd_t& stfd);
|
||||
|
||||
// Set the FD_CLOEXEC of FD.
|
||||
extern void srs_fd_close_exec(int fd);
|
||||
|
||||
// Set the SO_REUSEADDR of socket.
|
||||
extern void srs_socket_reuse_addr(int fd);
|
||||
|
||||
/**
|
||||
* the socket provides TCP socket over st,
|
||||
* that is, the sync socket mechanism.
|
||||
|
|
|
@ -56,6 +56,8 @@ int srs_socket_connect(string server, int port, int64_t tm, st_netfd_t* pstfd)
|
|||
return ret;
|
||||
}
|
||||
|
||||
srs_fd_close_exec(sock);
|
||||
|
||||
srs_assert(!stfd);
|
||||
stfd = st_netfd_open_socket(sock);
|
||||
if(stfd == NULL){
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue