diff --git a/README.md b/README.md index 6a3e6e4bb..4d1cb22c0 100755 --- a/README.md +++ b/README.md @@ -168,6 +168,9 @@ For previous versions, please read: ## V3 changes +* v3.0, 2020-03-12, For [#1630][bug #1630], disable cache for stream changing, and drop dup header. 3.0.128 +* v3.0, 2020-03-12, For [#1594][bug #1594], detect and disable daemon for docker. 3.0.127 +* v3.0, 2020-03-12, For [#1634][bug #1634], always check status in thread loop. 3.0.126 * v3.0, 2020-03-11, For [#1634][bug #1634], refactor output with datetime for ingest/encoder/exec. 3.0.125 * v3.0, 2020-03-11, For [#1634][bug #1634], fix quit by accident SIGTERM while killing FFMPEG. 3.0.124 * v3.0, 2020-03-05, [3.0 beta2(3.0.123)][r3.0b2] released. 122170 lines. @@ -1696,6 +1699,8 @@ Winlin [bug #1615]: https://github.com/ossrs/srs/issues/1615 [bug #1621]: https://github.com/ossrs/srs/issues/1621 [bug #1634]: https://github.com/ossrs/srs/issues/1634 +[bug #1594]: https://github.com/ossrs/srs/issues/1594 +[bug #1630]: https://github.com/ossrs/srs/issues/1630 [bug #yyyyyyyyyyyyy]: https://github.com/ossrs/srs/issues/yyyyyyyyyyyyy [bug #1631]: https://github.com/ossrs/srs/issues/1631 diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf index 334827439..c7ddf4bd9 100644 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -93,6 +93,10 @@ grace_final_wait 3200; # @see https://github.com/ossrs/srs/issues/1579#issuecomment-587475077 # default: off force_grace_quit off; +# Whether disable daemon for docker. +# If on, it will set daemon to off in docker, even daemon is on. +# default: on +disable_daemon_for_docker on; ############################################################################################# # heartbeat/stats sections diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index f66ca5cec..84d5e609e 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -3489,7 +3489,7 @@ srs_error_t SrsConfig::check_normal_config() && n != "http_server" && n != "stream_caster" && n != "srt_server" && n != "utc_time" && n != "work_dir" && n != "asprocess" && n != "ff_log_level" && n != "grace_final_wait" && n != "force_grace_quit" - && n != "grace_start_wait" && n != "empty_ip_ok" + && n != "grace_start_wait" && n != "empty_ip_ok" && n != "disable_daemon_for_docker" ) { return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal directive %s", n.c_str()); } @@ -4114,6 +4114,18 @@ bool SrsConfig::is_force_grace_quit() return SRS_CONF_PERFER_FALSE(conf->arg0()); } +bool SrsConfig::disable_daemon_for_docker() +{ + static bool DEFAULT = true; + + SrsConfDirective* conf = root->get("disable_daemon_for_docker"); + if (!conf || conf->arg0().empty()) { + return DEFAULT; + } + + return SRS_CONF_PERFER_TRUE(conf->arg0()); +} + vector SrsConfig::get_stream_casters() { srs_assert(root); diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index c276b34db..4ea19c2e4 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -476,6 +476,8 @@ public: virtual srs_utime_t get_grace_final_wait(); // Whether force to gracefully quit, never fast quit. virtual bool is_force_grace_quit(); + // Whether disable daemon for docker. + virtual bool disable_daemon_for_docker(); // stream_caster section public: // Get all stream_caster in config file. diff --git a/trunk/src/app/srs_app_edge.cpp b/trunk/src/app/srs_app_edge.cpp index 8a0592dcf..8c057af51 100644 --- a/trunk/src/app/srs_app_edge.cpp +++ b/trunk/src/app/srs_app_edge.cpp @@ -234,15 +234,17 @@ srs_error_t SrsEdgeIngester::cycle() srs_error_t err = srs_success; while (true) { + // We always check status first. + // @see https://github.com/ossrs/srs/issues/1634#issuecomment-597571561 + if ((err = trd->pull()) != srs_success) { + return srs_error_wrap(err, "edge ingester"); + } + if ((err = do_cycle()) != srs_success) { srs_warn("EdgeIngester: Ignore error, %s", srs_error_desc(err).c_str()); srs_freep(err); } - - if ((err = trd->pull()) != srs_success) { - return srs_error_wrap(err, "edge ingester"); - } - + srs_usleep(SRS_EDGE_INGESTER_CIMS); } @@ -314,7 +316,6 @@ srs_error_t SrsEdgeIngester::ingest(string& redirect) redirect = ""; while (true) { - srs_error_t err = srs_success; if ((err = trd->pull()) != srs_success) { return srs_error_wrap(err, "thread quit"); } @@ -534,14 +535,16 @@ srs_error_t SrsEdgeForwarder::cycle() srs_error_t err = srs_success; while (true) { - if ((err = do_cycle()) != srs_success) { - return srs_error_wrap(err, "do cycle"); - } - + // We always check status first. + // @see https://github.com/ossrs/srs/issues/1634#issuecomment-597571561 if ((err = trd->pull()) != srs_success) { return srs_error_wrap(err, "thread pull"); } - + + if ((err = do_cycle()) != srs_success) { + return srs_error_wrap(err, "do cycle"); + } + srs_usleep(SRS_EDGE_FORWARDER_CIMS); } diff --git a/trunk/src/app/srs_app_forward.cpp b/trunk/src/app/srs_app_forward.cpp index 339d12bde..882d33a8c 100755 --- a/trunk/src/app/srs_app_forward.cpp +++ b/trunk/src/app/srs_app_forward.cpp @@ -181,15 +181,17 @@ srs_error_t SrsForwarder::cycle() srs_error_t err = srs_success; while (true) { + // We always check status first. + // @see https://github.com/ossrs/srs/issues/1634#issuecomment-597571561 + if ((err = trd->pull()) != srs_success) { + return srs_error_wrap(err, "forwarder"); + } + if ((err = do_cycle()) != srs_success) { srs_warn("Forwarder: Ignore error, %s", srs_error_desc(err).c_str()); srs_freep(err); } - - if ((err = trd->pull()) != srs_success) { - return srs_error_wrap(err, "forwarder"); - } - + srs_usleep(SRS_FORWARDER_CIMS); } diff --git a/trunk/src/app/srs_app_http_stream.cpp b/trunk/src/app/srs_app_http_stream.cpp index 7a0688fff..fb7bd54b3 100755 --- a/trunk/src/app/srs_app_http_stream.cpp +++ b/trunk/src/app/srs_app_http_stream.cpp @@ -646,13 +646,13 @@ srs_error_t SrsLiveStream::do_serve_http(ISrsHttpResponseWriter* w, ISrsHttpMess // TODO: free and erase the disabled entry after all related connections is closed. // TODO: FXIME: Support timeout for player, quit infinite-loop. while (entry->enabled) { - pprint->elapse(); - // Whether client closed the FD. if ((err = trd->pull()) != srs_success) { return srs_error_wrap(err, "recv thread"); } + pprint->elapse(); + // get messages from consumer. // each msg in msgs.msgs must be free, for the SrsMessageArray never free them. int count = 0; diff --git a/trunk/src/app/srs_app_ingest.cpp b/trunk/src/app/srs_app_ingest.cpp index addbd9bc2..44987f16c 100644 --- a/trunk/src/app/srs_app_ingest.cpp +++ b/trunk/src/app/srs_app_ingest.cpp @@ -201,15 +201,17 @@ srs_error_t SrsIngester::cycle() srs_error_t err = srs_success; while (!disposed) { + // We always check status first. + // @see https://github.com/ossrs/srs/issues/1634#issuecomment-597571561 + if ((err = trd->pull()) != srs_success) { + return srs_error_wrap(err, "ingester"); + } + if ((err = do_cycle()) != srs_success) { srs_warn("Ingester: Ignore error, %s", srs_error_desc(err).c_str()); srs_freep(err); } - - if ((err = trd->pull()) != srs_success) { - return srs_error_wrap(err, "ingester"); - } - + srs_usleep(SRS_AUTO_INGESTER_CIMS); } diff --git a/trunk/src/app/srs_app_ng_exec.cpp b/trunk/src/app/srs_app_ng_exec.cpp index 18d719e78..30ebc5ecb 100644 --- a/trunk/src/app/srs_app_ng_exec.cpp +++ b/trunk/src/app/srs_app_ng_exec.cpp @@ -83,16 +83,18 @@ srs_error_t SrsNgExec::cycle() srs_error_t err = srs_success; while (true) { - if ((err = do_cycle()) != srs_success) { - srs_warn("EXEC: Ignore error, %s", srs_error_desc(err).c_str()); - srs_freep(err); - } - + // We always check status first. + // @see https://github.com/ossrs/srs/issues/1634#issuecomment-597571561 if ((err = trd->pull()) != srs_success) { err = srs_error_wrap(err, "ng exec cycle"); break; } - + + if ((err = do_cycle()) != srs_success) { + srs_warn("EXEC: Ignore error, %s", srs_error_desc(err).c_str()); + srs_freep(err); + } + srs_usleep(SRS_RTMP_EXEC_CIMS); } diff --git a/trunk/src/app/srs_app_rtmp_conn.cpp b/trunk/src/app/srs_app_rtmp_conn.cpp index 98bfcd5fc..c7e943337 100644 --- a/trunk/src/app/srs_app_rtmp_conn.cpp +++ b/trunk/src/app/srs_app_rtmp_conn.cpp @@ -381,7 +381,6 @@ srs_error_t SrsRtmpConn::service_cycle() } while (true) { - srs_error_t err = srs_success; if ((err = trd->pull()) != srs_success) { return srs_error_wrap(err, "rtmp: thread quit"); } @@ -704,14 +703,14 @@ srs_error_t SrsRtmpConn::do_playing(SrsSource* source, SrsConsumer* consumer, Sr srsu2msi(send_min_interval), srsu2msi(mw_sleep), mw_enabled, realtime, tcp_nodelay); while (true) { - // collect elapse for pithy print. - pprint->elapse(); - // when source is set to expired, disconnect it. if ((err = trd->pull()) != srs_success) { return srs_error_wrap(err, "rtmp: thread quit"); } - + + // collect elapse for pithy print. + pprint->elapse(); + // to use isolate thread to recv, can improve about 33% performance. // @see: https://github.com/ossrs/srs/issues/196 // @see: https://github.com/ossrs/srs/issues/217 @@ -872,12 +871,12 @@ srs_error_t SrsRtmpConn::do_publishing(SrsSource* source, SrsPublishRecvThread* int64_t nb_msgs = 0; uint64_t nb_frames = 0; while (true) { - pprint->elapse(); - if ((err = trd->pull()) != srs_success) { return srs_error_wrap(err, "rtmp: thread quit"); } - + + pprint->elapse(); + // cond wait for timeout. if (nb_msgs == 0) { // when not got msgs, wait for a larger timeout. diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp index f5acb05da..3473909eb 100755 --- a/trunk/src/app/srs_app_source.cpp +++ b/trunk/src/app/srs_app_source.cpp @@ -1506,6 +1506,7 @@ void SrsOriginHub::destroy_forwarders() SrsMetaCache::SrsMetaCache() { meta = video = audio = NULL; + previous_video = previous_audio = NULL; vformat = new SrsRtmpFormat(); aformat = new SrsRtmpFormat(); } @@ -1516,6 +1517,13 @@ SrsMetaCache::~SrsMetaCache() } void SrsMetaCache::dispose() +{ + clear(); + srs_freep(previous_video); + srs_freep(previous_audio); +} + +void SrsMetaCache::clear() { srs_freep(meta); srs_freep(video); @@ -1570,6 +1578,28 @@ srs_error_t SrsMetaCache::dumps(SrsConsumer* consumer, bool atc, SrsRtmpJitterAl return err; } +SrsSharedPtrMessage* SrsMetaCache::previous_vsh() +{ + return previous_video; +} + +SrsSharedPtrMessage* SrsMetaCache::previous_ash() +{ + return previous_audio; +} + +void SrsMetaCache::update_previous_vsh() +{ + srs_freep(previous_video); + previous_video = video? video->copy() : NULL; +} + +void SrsMetaCache::update_previous_ash() +{ + srs_freep(previous_audio); + previous_audio = audio? audio->copy() : NULL; +} + srs_error_t SrsMetaCache::update_data(SrsMessageHeader* header, SrsOnMetaDataPacket* metadata, bool& updated) { updated = false; @@ -1636,6 +1666,7 @@ srs_error_t SrsMetaCache::update_ash(SrsSharedPtrMessage* msg) { srs_freep(audio); audio = msg->copy(); + update_previous_ash(); return aformat->on_audio(msg); } @@ -1643,6 +1674,7 @@ srs_error_t SrsMetaCache::update_vsh(SrsSharedPtrMessage* msg) { srs_freep(video); video = msg->copy(); + update_previous_vsh(); return vformat->on_video(msg); } @@ -2138,9 +2170,9 @@ srs_error_t SrsSource::on_audio_imp(SrsSharedPtrMessage* msg) // whether consumer should drop for the duplicated sequence header. bool drop_for_reduce = false; - if (is_sequence_header && meta->ash() && _srs_config->get_reduce_sequence_header(req->vhost)) { - if (meta->ash()->size == msg->size) { - drop_for_reduce = srs_bytes_equals(meta->ash()->payload, msg->payload, msg->size); + if (is_sequence_header && meta->previous_ash() && _srs_config->get_reduce_sequence_header(req->vhost)) { + if (meta->previous_ash()->size == msg->size) { + drop_for_reduce = srs_bytes_equals(meta->previous_ash()->payload, msg->payload, msg->size); srs_warn("drop for reduce sh audio, size=%d", msg->size); } } @@ -2257,9 +2289,9 @@ srs_error_t SrsSource::on_video_imp(SrsSharedPtrMessage* msg) // whether consumer should drop for the duplicated sequence header. bool drop_for_reduce = false; - if (is_sequence_header && meta->vsh() && _srs_config->get_reduce_sequence_header(req->vhost)) { - if (meta->vsh()->size == msg->size) { - drop_for_reduce = srs_bytes_equals(meta->vsh()->payload, msg->payload, msg->size); + if (is_sequence_header && meta->previous_vsh() && _srs_config->get_reduce_sequence_header(req->vhost)) { + if (meta->previous_vsh()->size == msg->size) { + drop_for_reduce = srs_bytes_equals(meta->previous_vsh()->payload, msg->payload, msg->size); srs_warn("drop for reduce sh video, size=%d", msg->size); } } @@ -2415,6 +2447,10 @@ srs_error_t SrsSource::on_publish() // reset the mix queue. mix_queue->clear(); + + // Reset the metadata cache, to make VLC happy when disable/enable stream. + // @see https://github.com/ossrs/srs/issues/1630#issuecomment-597979448 + meta->clear(); // detect the monotonically again. is_monotonically_increase = true; @@ -2450,7 +2486,12 @@ void SrsSource::on_unpublish() // donot clear the sequence header, for it maybe not changed, // when drop dup sequence header, drop the metadata also. gop_cache->clear(); - + + // Reset the metadata cache, to make VLC happy when disable/enable stream. + // @see https://github.com/ossrs/srs/issues/1630#issuecomment-597979448 + meta->update_previous_vsh(); + meta->update_previous_ash(); + srs_trace("cleanup when unpublish"); _can_publish = true; diff --git a/trunk/src/app/srs_app_source.hpp b/trunk/src/app/srs_app_source.hpp index 8cb79f478..f93bc314d 100644 --- a/trunk/src/app/srs_app_source.hpp +++ b/trunk/src/app/srs_app_source.hpp @@ -407,8 +407,10 @@ private: SrsSharedPtrMessage* meta; // The cached video sequence header, for example, sps/pps for h.264. SrsSharedPtrMessage* video; + SrsSharedPtrMessage* previous_video; // The cached audio sequence header, for example, asc for aac. SrsSharedPtrMessage* audio; + SrsSharedPtrMessage* previous_audio; // The format for sequence header. SrsRtmpFormat* vformat; SrsRtmpFormat* aformat; @@ -418,6 +420,8 @@ public: public: // Dispose the metadata cache. virtual void dispose(); + // For each publishing, clear the metadata cache. + virtual void clear(); public: // Get the cached metadata. virtual SrsSharedPtrMessage* data(); @@ -431,6 +435,13 @@ public: // @param dm Whether dumps the metadata. // @param ds Whether dumps the sequence header. virtual srs_error_t dumps(SrsConsumer* consumer, bool atc, SrsRtmpJitterAlgorithm ag, bool dm, bool ds); +public: + // Previous exists sequence header. + virtual SrsSharedPtrMessage* previous_vsh(); + virtual SrsSharedPtrMessage* previous_ash(); + // Update previous sequence header, drop old one, set to new sequence header. + virtual void update_previous_vsh(); + virtual void update_previous_ash(); public: // Update the cached metadata by packet. virtual srs_error_t update_data(SrsMessageHeader* header, SrsOnMetaDataPacket* metadata, bool& updated); diff --git a/trunk/src/core/srs_core_version3.hpp b/trunk/src/core/srs_core_version3.hpp index 8a69c55d2..c3a667511 100644 --- a/trunk/src/core/srs_core_version3.hpp +++ b/trunk/src/core/srs_core_version3.hpp @@ -24,6 +24,6 @@ #ifndef SRS_CORE_VERSION3_HPP #define SRS_CORE_VERSION3_HPP -#define SRS_VERSION3_REVISION 125 +#define SRS_VERSION3_REVISION 128 #endif diff --git a/trunk/src/main/srs_main_server.cpp b/trunk/src/main/srs_main_server.cpp index 190346e89..a3fb7fa0b 100644 --- a/trunk/src/main/srs_main_server.cpp +++ b/trunk/src/main/srs_main_server.cpp @@ -48,6 +48,7 @@ using namespace std; #include #include #include +#include #include #ifdef SRS_AUTO_SRT @@ -354,12 +355,56 @@ string srs_getenv(const char* name) return ""; } +// Detect docker by https://stackoverflow.com/a/41559867 +srs_error_t srs_detect_docker(bool* is_docker) +{ + srs_error_t err = srs_success; + + *is_docker = false; + + SrsFileReader fr; + if ((err = fr.open("/proc/1/cgroup")) != srs_success) { + return err; + } + + ssize_t nn; + char buf[1024]; + if ((err = fr.read(buf, sizeof(buf), &nn)) != srs_success) { + return err; + } + + if (nn <= 0) { + return err; + } + + string s(buf, nn); + if (srs_string_contains(s, "/docker")) { + *is_docker = true; + } + + return err; +} + srs_error_t run_directly_or_daemon() { srs_error_t err = srs_success; + + // Load daemon from config, disable it for docker. + // @see https://github.com/ossrs/srs/issues/1594 + bool in_daemon = _srs_config->get_daemon(); + if (in_daemon && _srs_config->disable_daemon_for_docker()) { + bool is_docker = false; + err = srs_detect_docker(&is_docker); + srs_error_reset(err); // Ignore any error while detecting docker. + + if (is_docker) { + srs_warn("disable daemon for docker"); + in_daemon = false; + } + } // If not daemon, directly run master. - if (!_srs_config->get_daemon()) { + if (!in_daemon) { if ((err = run_hybrid_server()) != srs_success) { return srs_error_wrap(err, "run master"); }