winlin

fix #257, support 0.1s+ latency. 2.0.70

@@ -453,6 +453,7 @@ Supported operating systems and hardware: @@ -453,6 +453,7 @@ Supported operating systems and hardware:
453 [CN](https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_SrsLibrtmp#publish-audio-raw-stream), 453 [CN](https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_SrsLibrtmp#publish-audio-raw-stream),
454 [EN](https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_SrsLibrtmp#publish-audio-raw-stream) 454 [EN](https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_SrsLibrtmp#publish-audio-raw-stream)
455 ) by srs-librtmp. 455 ) by srs-librtmp.
  456 +1. Support 0.1s+ latency, read [#257](https://github.com/winlinvip/simple-rtmp-server/issues/257).
456 1. [no-plan] Support <500ms latency, FRSC(Fast RTMP-compatible Stream Channel tech). 457 1. [no-plan] Support <500ms latency, FRSC(Fast RTMP-compatible Stream Channel tech).
457 1. [no-plan] Support RTMP 302 redirect [#92](https://github.com/winlinvip/simple-rtmp-server/issues/92). 458 1. [no-plan] Support RTMP 302 redirect [#92](https://github.com/winlinvip/simple-rtmp-server/issues/92).
458 1. [no-plan] Support multiple processes, for both origin and edge 459 1. [no-plan] Support multiple processes, for both origin and edge
@@ -486,6 +487,7 @@ Supported operating systems and hardware: @@ -486,6 +487,7 @@ Supported operating systems and hardware:
486 * 2013-10-17, Created.<br/> 487 * 2013-10-17, Created.<br/>
487 488
488 ## History 489 ## History
  490 +* v2.0, 2014-12-12, fix [#257](https://github.com/winlinvip/simple-rtmp-server/issues/257), support 0.1s+ latency. 2.0.70
489 * v2.0, 2014-12-08, update wiki for mr([EN](https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_LowLatency#merged-read), [CN](https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_LowLatency#merged-read)) and mw([EN](https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_LowLatency#merged-write), [CN](https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_LowLatency#merged-write)). 491 * v2.0, 2014-12-08, update wiki for mr([EN](https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_LowLatency#merged-read), [CN](https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_LowLatency#merged-read)) and mw([EN](https://github.com/winlinvip/simple-rtmp-server/wiki/v2_EN_LowLatency#merged-write), [CN](https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_LowLatency#merged-write)).
490 * v2.0, 2014-12-07, fix [#251](https://github.com/winlinvip/simple-rtmp-server/issues/251), 10k+ clients, use queue cond wait and fast vector. 2.0.67 492 * v2.0, 2014-12-07, fix [#251](https://github.com/winlinvip/simple-rtmp-server/issues/251), 10k+ clients, use queue cond wait and fast vector. 2.0.67
491 * v2.0, 2014-12-05, fix [#251](https://github.com/winlinvip/simple-rtmp-server/issues/251), 9k+ clients, use fast cache for msgs queue. 2.0.57 493 * v2.0, 2014-12-05, fix [#251](https://github.com/winlinvip/simple-rtmp-server/issues/251), 9k+ clients, use fast cache for msgs queue. 2.0.57
@@ -145,6 +145,13 @@ vhost __defaultVhost__ { @@ -145,6 +145,13 @@ vhost __defaultVhost__ {
145 # the MR(merged-read) setting for publisher. 145 # the MR(merged-read) setting for publisher.
146 # the MW(merged-write) settings for player. 146 # the MW(merged-write) settings for player.
147 vhost mrw.srs.com { 147 vhost mrw.srs.com {
  148 + # whether enable min delay mode for vhost.
  149 + # for min latence mode:
  150 + # 1. disable the mr for vhost.
  151 + # 2. use timeout for cond wait for consumer queue.
  152 + # @see https://github.com/winlinvip/simple-rtmp-server/issues/257
  153 + # default: on
  154 + min_latency off;
148 # about MR, read https://github.com/winlinvip/simple-rtmp-server/issues/241 155 # about MR, read https://github.com/winlinvip/simple-rtmp-server/issues/241
149 mr { 156 mr {
150 # whether enable the MR(merged-read) 157 # whether enable the MR(merged-read)
@@ -440,6 +447,12 @@ vhost debug.srs.com { @@ -440,6 +447,12 @@ vhost debug.srs.com {
440 447
441 # the vhost for min delay, donot cache any stream. 448 # the vhost for min delay, donot cache any stream.
442 vhost min.delay.com { 449 vhost min.delay.com {
  450 + # @see vhost mrw.srs.com for detail.
  451 + min_latency on;
  452 + mr {
  453 + enabled off;
  454 + }
  455 + mw_latency 100;
443 # whether cache the last gop. 456 # whether cache the last gop.
444 # if on, cache the last gop and dispatch to client, 457 # if on, cache the last gop and dispatch to client,
445 # to enabled fast startup for client, client play immediately. 458 # to enabled fast startup for client, client play immediately.
1 # the config for srs to delivery realtime RTMP stream 1 # the config for srs to delivery realtime RTMP stream
2 -# @see https://github.com/winlinvip/simple-rtmp-server/wiki/v1_CN_SampleRealtime 2 +# @see https://github.com/winlinvip/simple-rtmp-server/wiki/v2_CN_SampleRealtime
3 # @see full.conf for detail config. 3 # @see full.conf for detail config.
4 4
5 listen 1935; 5 listen 1935;
@@ -7,6 +7,7 @@ max_connections 1000; @@ -7,6 +7,7 @@ max_connections 1000;
7 vhost __defaultVhost__ { 7 vhost __defaultVhost__ {
8 gop_cache off; 8 gop_cache off;
9 queue_length 10; 9 queue_length 10;
  10 + min_latency on;
10 mr { 11 mr {
11 enabled off; 12 enabled off;
12 } 13 }
@@ -22,7 +22,7 @@ function SrsPlayer(container, width, height, private_object) { @@ -22,7 +22,7 @@ function SrsPlayer(container, width, height, private_object) {
22 this.height = height; 22 this.height = height;
23 this.id = SrsPlayer.__id++; 23 this.id = SrsPlayer.__id++;
24 this.stream_url = null; 24 this.stream_url = null;
25 - this.buffer_time = 0.8; // default to 0.8 25 + this.buffer_time = 0.3; // default to 0.3
26 this.volume = 1.0; // default to 100% 26 this.volume = 1.0; // default to 100%
27 this.callbackObj = null; 27 this.callbackObj = null;
28 28
@@ -96,7 +96,7 @@ @@ -96,7 +96,7 @@
96 96
97 srs_player = new SrsPlayer("player_id", srs_get_player_width(), srs_get_player_height()); 97 srs_player = new SrsPlayer("player_id", srs_get_player_width(), srs_get_player_height());
98 srs_player.on_player_ready = function() { 98 srs_player.on_player_ready = function() {
99 - select_buffer_time("#btn_bt_0_8", 0.8); 99 + select_buffer_time("#btn_bt_0_1", 0.1);
100 this.play(url); 100 this.play(url);
101 }; 101 };
102 srs_player.on_player_metadata = function(metadata) { 102 srs_player.on_player_metadata = function(metadata) {
@@ -231,6 +231,15 @@ @@ -231,6 +231,15 @@
231 } 231 }
232 232
233 if (true) { 233 if (true) {
  234 + $("#btn_bt_0_1").click(function(){
  235 + select_buffer_time("#btn_bt_0_1", 0.1);
  236 + });
  237 + $("#btn_bt_0_2").click(function(){
  238 + select_buffer_time("#btn_bt_0_2", 0.2);
  239 + });
  240 + $("#btn_bt_0_3").click(function(){
  241 + select_buffer_time("#btn_bt_0_3", 0.3);
  242 + });
234 $("#btn_bt_0_5").click(function(){ 243 $("#btn_bt_0_5").click(function(){
235 select_buffer_time("#btn_bt_0_5", 0.5); 244 select_buffer_time("#btn_bt_0_5", 0.5);
236 }); 245 });
@@ -504,6 +513,9 @@ @@ -504,6 +513,9 @@
504 <div class="btn-group dropup"> 513 <div class="btn-group dropup">
505 <button class="btn dropdown-toggle" data-toggle="dropdown">缓冲区<span class="caret"></span></button> 514 <button class="btn dropdown-toggle" data-toggle="dropdown">缓冲区<span class="caret"></span></button>
506 <ul class="dropdown-menu"> 515 <ul class="dropdown-menu">
  516 + <li><a id="btn_bt_0_1" href="#">0.1秒(实时)</a></li>
  517 + <li><a id="btn_bt_0_2" href="#">0.2秒(实时)</a></li>
  518 + <li><a id="btn_bt_0_3" href="#">0.3秒(实时)</a></li>
507 <li><a id="btn_bt_0_5" href="#">0.5秒(实时)</a></li> 519 <li><a id="btn_bt_0_5" href="#">0.5秒(实时)</a></li>
508 <li><a id="btn_bt_0_8" href="#">0.8秒(会议)</a></li> 520 <li><a id="btn_bt_0_8" href="#">0.8秒(会议)</a></li>
509 <li><a id="btn_bt_1" href="#">1秒(低延迟)</a></li> 521 <li><a id="btn_bt_1" href="#">1秒(低延迟)</a></li>
@@ -852,6 +852,17 @@ int SrsConfig::reload_vhost(SrsConfDirective* old_root) @@ -852,6 +852,17 @@ int SrsConfig::reload_vhost(SrsConfDirective* old_root)
852 } 852 }
853 srs_trace("vhost %s reload mw success.", vhost.c_str()); 853 srs_trace("vhost %s reload mw success.", vhost.c_str());
854 } 854 }
  855 + // min_latency, only one per vhost
  856 + if (!srs_directive_equals(new_vhost->get("min_latency"), old_vhost->get("min_latency"))) {
  857 + for (it = subscribes.begin(); it != subscribes.end(); ++it) {
  858 + ISrsReloadHandler* subscribe = *it;
  859 + if ((ret = subscribe->on_reload_vhost_realtime(vhost)) != ERROR_SUCCESS) {
  860 + srs_error("vhost %s notify subscribes min_latency failed. ret=%d", vhost.c_str(), ret);
  861 + return ret;
  862 + }
  863 + }
  864 + srs_trace("vhost %s reload min_latency success.", vhost.c_str());
  865 + }
855 // http, only one per vhost. 866 // http, only one per vhost.
856 if (!srs_directive_equals(new_vhost->get("http"), old_vhost->get("http"))) { 867 if (!srs_directive_equals(new_vhost->get("http"), old_vhost->get("http"))) {
857 for (it = subscribes.begin(); it != subscribes.end(); ++it) { 868 for (it = subscribes.begin(); it != subscribes.end(); ++it) {
@@ -1350,7 +1361,7 @@ int SrsConfig::check_config() @@ -1350,7 +1361,7 @@ int SrsConfig::check_config()
1350 && n != "time_jitter" 1361 && n != "time_jitter"
1351 && n != "atc" && n != "atc_auto" 1362 && n != "atc" && n != "atc_auto"
1352 && n != "debug_srs_upnode" 1363 && n != "debug_srs_upnode"
1353 - && n != "mr" && n != "mw_latency" 1364 + && n != "mr" && n != "mw_latency" && n != "min_latency"
1354 ) { 1365 ) {
1355 ret = ERROR_SYSTEM_CONFIG_INVALID; 1366 ret = ERROR_SYSTEM_CONFIG_INVALID;
1356 srs_error("unsupported vhost directive %s, ret=%d", n.c_str(), ret); 1367 srs_error("unsupported vhost directive %s, ret=%d", n.c_str(), ret);
@@ -2125,7 +2136,6 @@ int SrsConfig::get_chunk_size(string vhost) @@ -2125,7 +2136,6 @@ int SrsConfig::get_chunk_size(string vhost)
2125 2136
2126 bool SrsConfig::get_mr_enabled(string vhost) 2137 bool SrsConfig::get_mr_enabled(string vhost)
2127 { 2138 {
2128 -  
2129 SrsConfDirective* conf = get_vhost(vhost); 2139 SrsConfDirective* conf = get_vhost(vhost);
2130 2140
2131 if (!conf) { 2141 if (!conf) {
@@ -2147,7 +2157,6 @@ bool SrsConfig::get_mr_enabled(string vhost) @@ -2147,7 +2157,6 @@ bool SrsConfig::get_mr_enabled(string vhost)
2147 2157
2148 int SrsConfig::get_mr_sleep_ms(string vhost) 2158 int SrsConfig::get_mr_sleep_ms(string vhost)
2149 { 2159 {
2150 -  
2151 SrsConfDirective* conf = get_vhost(vhost); 2160 SrsConfDirective* conf = get_vhost(vhost);
2152 2161
2153 if (!conf) { 2162 if (!conf) {
@@ -2169,7 +2178,6 @@ int SrsConfig::get_mr_sleep_ms(string vhost) @@ -2169,7 +2178,6 @@ int SrsConfig::get_mr_sleep_ms(string vhost)
2169 2178
2170 int SrsConfig::get_mw_sleep_ms(string vhost) 2179 int SrsConfig::get_mw_sleep_ms(string vhost)
2171 { 2180 {
2172 -  
2173 SrsConfDirective* conf = get_vhost(vhost); 2181 SrsConfDirective* conf = get_vhost(vhost);
2174 2182
2175 if (!conf) { 2183 if (!conf) {
@@ -2184,6 +2192,22 @@ int SrsConfig::get_mw_sleep_ms(string vhost) @@ -2184,6 +2192,22 @@ int SrsConfig::get_mw_sleep_ms(string vhost)
2184 return ::atoi(conf->arg0().c_str()); 2192 return ::atoi(conf->arg0().c_str());
2185 } 2193 }
2186 2194
  2195 +bool SrsConfig::get_realtime_enabled(string vhost)
  2196 +{
  2197 + SrsConfDirective* conf = get_vhost(vhost);
  2198 +
  2199 + if (!conf) {
  2200 + return SRS_PERF_MIN_LATENCY_ENABLED;
  2201 + }
  2202 +
  2203 + conf = conf->get("min_latency");
  2204 + if (!conf || conf->arg0() != "off") {
  2205 + return SRS_PERF_MIN_LATENCY_ENABLED;
  2206 + }
  2207 +
  2208 + return false;
  2209 +}
  2210 +
2187 int SrsConfig::get_global_chunk_size() 2211 int SrsConfig::get_global_chunk_size()
2188 { 2212 {
2189 SrsConfDirective* conf = root->get("chunk_size"); 2213 SrsConfDirective* conf = root->get("chunk_size");
@@ -545,6 +545,12 @@ public: @@ -545,6 +545,12 @@ public:
545 */ 545 */
546 // TODO: FIXME: add utest for mw config. 546 // TODO: FIXME: add utest for mw config.
547 virtual int get_mw_sleep_ms(std::string vhost); 547 virtual int get_mw_sleep_ms(std::string vhost);
  548 + /**
  549 + * whether min latency mode enabled.
  550 + * @param vhost, the vhost to get the min_latency.
  551 + */
  552 + // TODO: FIXME: add utest for min_latency.
  553 + virtual bool get_realtime_enabled(std::string vhost);
548 private: 554 private:
549 /** 555 /**
550 * get the global chunk size. 556 * get the global chunk size.
@@ -251,6 +251,8 @@ SrsPublishRecvThread::SrsPublishRecvThread( @@ -251,6 +251,8 @@ SrsPublishRecvThread::SrsPublishRecvThread(
251 mr = _srs_config->get_mr_enabled(req->vhost); 251 mr = _srs_config->get_mr_enabled(req->vhost);
252 mr_sleep = _srs_config->get_mr_sleep_ms(req->vhost); 252 mr_sleep = _srs_config->get_mr_sleep_ms(req->vhost);
253 253
  254 + realtime = _srs_config->get_realtime_enabled(req->vhost);
  255 +
254 _srs_config->subscribe(this); 256 _srs_config->subscribe(this);
255 } 257 }
256 258
@@ -340,6 +342,10 @@ int SrsPublishRecvThread::handle(SrsCommonMessage* msg) @@ -340,6 +342,10 @@ int SrsPublishRecvThread::handle(SrsCommonMessage* msg)
340 int ret = ERROR_SUCCESS; 342 int ret = ERROR_SUCCESS;
341 343
342 _nb_msgs++; 344 _nb_msgs++;
  345 +
  346 + // log to show the time of recv thread.
  347 + srs_verbose("recv thread now=%"PRId64"us, got msg time=%"PRId64"ms, size=%d",
  348 + srs_update_system_time_ms(), msg->header.timestamp, msg->size);
343 349
344 // the rtmp connection will handle this message 350 // the rtmp connection will handle this message
345 ret = _conn->handle_publish_message(_source, msg, _is_fmle, _is_edge); 351 ret = _conn->handle_publish_message(_source, msg, _is_fmle, _is_edge);
@@ -363,7 +369,7 @@ void SrsPublishRecvThread::on_recv_error(int ret) @@ -363,7 +369,7 @@ void SrsPublishRecvThread::on_recv_error(int ret)
363 #ifdef SRS_PERF_MERGED_READ 369 #ifdef SRS_PERF_MERGED_READ
364 void SrsPublishRecvThread::on_read(ssize_t nread) 370 void SrsPublishRecvThread::on_read(ssize_t nread)
365 { 371 {
366 - if (!mr) { 372 + if (!mr || realtime) {
367 return; 373 return;
368 } 374 }
369 375
@@ -386,6 +392,10 @@ void SrsPublishRecvThread::on_read(ssize_t nread) @@ -386,6 +392,10 @@ void SrsPublishRecvThread::on_read(ssize_t nread)
386 int SrsPublishRecvThread::on_reload_vhost_mr(string vhost) 392 int SrsPublishRecvThread::on_reload_vhost_mr(string vhost)
387 { 393 {
388 int ret = ERROR_SUCCESS; 394 int ret = ERROR_SUCCESS;
  395 +
  396 + if (req->vhost != vhost) {
  397 + return ret;
  398 + }
389 399
390 // the mr settings, 400 // the mr settings,
391 // @see https://github.com/winlinvip/simple-rtmp-server/issues/241 401 // @see https://github.com/winlinvip/simple-rtmp-server/issues/241
@@ -419,6 +429,21 @@ int SrsPublishRecvThread::on_reload_vhost_mr(string vhost) @@ -419,6 +429,21 @@ int SrsPublishRecvThread::on_reload_vhost_mr(string vhost)
419 return ret; 429 return ret;
420 } 430 }
421 431
  432 +int SrsPublishRecvThread::on_reload_vhost_realtime(string vhost)
  433 +{
  434 + int ret = ERROR_SUCCESS;
  435 +
  436 + if (req->vhost != vhost) {
  437 + return ret;
  438 + }
  439 +
  440 + bool realtime_enabled = _srs_config->get_realtime_enabled(req->vhost);
  441 + srs_trace("realtime changed %d=>%d", realtime, realtime_enabled);
  442 + realtime = realtime_enabled;
  443 +
  444 + return ret;
  445 +}
  446 +
422 void SrsPublishRecvThread::set_socket_buffer(int sleep_ms) 447 void SrsPublishRecvThread::set_socket_buffer(int sleep_ms)
423 { 448 {
424 // the bytes: 449 // the bytes:
@@ -446,8 +471,9 @@ void SrsPublishRecvThread::set_socket_buffer(int sleep_ms) @@ -446,8 +471,9 @@ void SrsPublishRecvThread::set_socket_buffer(int sleep_ms)
446 } 471 }
447 getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &nb_rbuf, &sock_buf_size); 472 getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &nb_rbuf, &sock_buf_size);
448 473
449 - srs_trace("mr change sleep %d=>%d, erbuf=%d, rbuf %d=>%d, sbytes=%d",  
450 - mr_sleep, sleep_ms, socket_buffer_size, onb_rbuf, nb_rbuf, SRS_MR_SMALL_BYTES); 474 + srs_trace("mr change sleep %d=>%d, erbuf=%d, rbuf %d=>%d, sbytes=%d, realtime=%d",
  475 + mr_sleep, sleep_ms, socket_buffer_size, onb_rbuf, nb_rbuf,
  476 + SRS_MR_SMALL_BYTES, realtime);
451 477
452 rtmp->set_recv_buffer(nb_rbuf); 478 rtmp->set_recv_buffer(nb_rbuf);
453 } 479 }
@@ -153,6 +153,9 @@ private: @@ -153,6 +153,9 @@ private:
153 bool mr; 153 bool mr;
154 int mr_fd; 154 int mr_fd;
155 int mr_sleep; 155 int mr_sleep;
  156 + // for realtime
  157 + // @see https://github.com/winlinvip/simple-rtmp-server/issues/257
  158 + bool realtime;
156 // the recv thread error code. 159 // the recv thread error code.
157 int recv_error_code; 160 int recv_error_code;
158 SrsRtmpConn* _conn; 161 SrsRtmpConn* _conn;
@@ -193,6 +196,7 @@ public: @@ -193,6 +196,7 @@ public:
193 // interface ISrsReloadHandler 196 // interface ISrsReloadHandler
194 public: 197 public:
195 virtual int on_reload_vhost_mr(std::string vhost); 198 virtual int on_reload_vhost_mr(std::string vhost);
  199 + virtual int on_reload_vhost_realtime(std::string vhost);
196 private: 200 private:
197 virtual void set_socket_buffer(int sleep_ms); 201 virtual void set_socket_buffer(int sleep_ms);
198 }; 202 };
@@ -150,6 +150,11 @@ int ISrsReloadHandler::on_reload_vhost_mw(string /*vhost*/) @@ -150,6 +150,11 @@ int ISrsReloadHandler::on_reload_vhost_mw(string /*vhost*/)
150 return ERROR_SUCCESS; 150 return ERROR_SUCCESS;
151 } 151 }
152 152
  153 +int ISrsReloadHandler::on_reload_vhost_realtime(string /*vhost*/)
  154 +{
  155 + return ERROR_SUCCESS;
  156 +}
  157 +
153 int ISrsReloadHandler::on_reload_vhost_chunk_size(string /*vhost*/) 158 int ISrsReloadHandler::on_reload_vhost_chunk_size(string /*vhost*/)
154 { 159 {
155 return ERROR_SUCCESS; 160 return ERROR_SUCCESS;
@@ -67,6 +67,7 @@ public: @@ -67,6 +67,7 @@ public:
67 virtual int on_reload_vhost_dvr(std::string vhost); 67 virtual int on_reload_vhost_dvr(std::string vhost);
68 virtual int on_reload_vhost_mr(std::string vhost); 68 virtual int on_reload_vhost_mr(std::string vhost);
69 virtual int on_reload_vhost_mw(std::string vhost); 69 virtual int on_reload_vhost_mw(std::string vhost);
  70 + virtual int on_reload_vhost_realtime(std::string vhost);
70 virtual int on_reload_vhost_chunk_size(std::string vhost); 71 virtual int on_reload_vhost_chunk_size(std::string vhost);
71 virtual int on_reload_vhost_transcode(std::string vhost); 72 virtual int on_reload_vhost_transcode(std::string vhost);
72 virtual int on_reload_ingest_removed(std::string vhost, std::string ingest_id); 73 virtual int on_reload_ingest_removed(std::string vhost, std::string ingest_id);
@@ -50,6 +50,7 @@ using namespace std; @@ -50,6 +50,7 @@ using namespace std;
50 #include <srs_protocol_amf0.hpp> 50 #include <srs_protocol_amf0.hpp>
51 #include <srs_app_recv_thread.hpp> 51 #include <srs_app_recv_thread.hpp>
52 #include <srs_core_performance.hpp> 52 #include <srs_core_performance.hpp>
  53 +#include <srs_kernel_utility.hpp>
53 54
54 // when stream is busy, for example, streaming is already 55 // when stream is busy, for example, streaming is already
55 // publishing, when a new client to request to publish, 56 // publishing, when a new client to request to publish,
@@ -86,6 +87,7 @@ SrsRtmpConn::SrsRtmpConn(SrsServer* srs_server, st_netfd_t client_stfd) @@ -86,6 +87,7 @@ SrsRtmpConn::SrsRtmpConn(SrsServer* srs_server, st_netfd_t client_stfd)
86 87
87 mw_sleep = SRS_PERF_MW_SLEEP; 88 mw_sleep = SRS_PERF_MW_SLEEP;
88 mw_enabled = false; 89 mw_enabled = false;
  90 + realtime = SRS_PERF_MIN_LATENCY_ENABLED;
89 91
90 _srs_config->subscribe(this); 92 _srs_config->subscribe(this);
91 } 93 }
@@ -212,14 +214,35 @@ int SrsRtmpConn::on_reload_vhost_removed(string vhost) @@ -212,14 +214,35 @@ int SrsRtmpConn::on_reload_vhost_removed(string vhost)
212 return ret; 214 return ret;
213 } 215 }
214 216
215 -int SrsRtmpConn::on_reload_vhost_mw(string /*vhost*/) 217 +int SrsRtmpConn::on_reload_vhost_mw(string vhost)
216 { 218 {
  219 + int ret = ERROR_SUCCESS;
  220 +
  221 + if (req->vhost != vhost) {
  222 + return ret;
  223 + }
  224 +
217 int sleep_ms = _srs_config->get_mw_sleep_ms(req->vhost); 225 int sleep_ms = _srs_config->get_mw_sleep_ms(req->vhost);
218 226
219 // when mw_sleep changed, resize the socket send buffer. 227 // when mw_sleep changed, resize the socket send buffer.
220 change_mw_sleep(sleep_ms); 228 change_mw_sleep(sleep_ms);
221 229
222 - return ERROR_SUCCESS; 230 + return ret;
  231 +}
  232 +
  233 +int SrsRtmpConn::on_reload_vhost_realtime(string vhost)
  234 +{
  235 + int ret = ERROR_SUCCESS;
  236 +
  237 + if (req->vhost != vhost) {
  238 + return ret;
  239 + }
  240 +
  241 + bool realtime_enabled = _srs_config->get_realtime_enabled(req->vhost);
  242 + srs_trace("realtime changed %d=>%d", realtime, realtime_enabled);
  243 + realtime = realtime_enabled;
  244 +
  245 + return ret;
223 } 246 }
224 247
225 int64_t SrsRtmpConn::get_send_bytes_delta() 248 int64_t SrsRtmpConn::get_send_bytes_delta()
@@ -570,6 +593,7 @@ int SrsRtmpConn::do_playing(SrsSource* source, SrsQueueRecvThread* trd) @@ -570,6 +593,7 @@ int SrsRtmpConn::do_playing(SrsSource* source, SrsQueueRecvThread* trd)
570 // when mw_sleep changed, resize the socket send buffer. 593 // when mw_sleep changed, resize the socket send buffer.
571 mw_enabled = true; 594 mw_enabled = true;
572 change_mw_sleep(_srs_config->get_mw_sleep_ms(req->vhost)); 595 change_mw_sleep(_srs_config->get_mw_sleep_ms(req->vhost));
  596 + realtime = _srs_config->get_realtime_enabled(req->vhost);
573 597
574 while (true) { 598 while (true) {
575 // to use isolate thread to recv, can improve about 33% performance. 599 // to use isolate thread to recv, can improve about 33% performance.
@@ -599,9 +623,15 @@ int SrsRtmpConn::do_playing(SrsSource* source, SrsQueueRecvThread* trd) @@ -599,9 +623,15 @@ int SrsRtmpConn::do_playing(SrsSource* source, SrsQueueRecvThread* trd)
599 pithy_print.elapse(); 623 pithy_print.elapse();
600 624
601 #ifdef SRS_PERF_QUEUE_COND_WAIT 625 #ifdef SRS_PERF_QUEUE_COND_WAIT
  626 + // for send wait time debug
  627 + srs_verbose("send thread now=%"PRId64"us, wait %dms", srs_update_system_time_ms(), mw_sleep);
  628 +
602 // wait for message to incoming. 629 // wait for message to incoming.
603 // @see https://github.com/winlinvip/simple-rtmp-server/issues/251 630 // @see https://github.com/winlinvip/simple-rtmp-server/issues/251
604 - consumer->wait(SRS_PERF_MW_MIN_MSGS, mw_sleep); 631 + consumer->wait(SRS_PERF_MW_MIN_MSGS, mw_sleep, realtime);
  632 +
  633 + // for send wait time debug
  634 + srs_verbose("send thread now=%"PRId64"us wakeup", srs_update_system_time_ms());
605 #endif 635 #endif
606 636
607 // get messages from consumer. 637 // get messages from consumer.
@@ -613,10 +643,12 @@ int SrsRtmpConn::do_playing(SrsSource* source, SrsQueueRecvThread* trd) @@ -613,10 +643,12 @@ int SrsRtmpConn::do_playing(SrsSource* source, SrsQueueRecvThread* trd)
613 } 643 }
614 644
615 #ifdef SRS_PERF_QUEUE_COND_WAIT 645 #ifdef SRS_PERF_QUEUE_COND_WAIT
616 - // we use wait to get messages, so the count must be positive.  
617 - srs_assert(count > 0);  
618 - srs_info("mw wait %dms and got %d msgs %"PRId64"-%"PRId64"ms",  
619 - mw_sleep, count, msgs.msgs[0]->timestamp, msgs.msgs[count - 1]->timestamp); 646 + // we use wait timeout to get messages,
  647 + // for min latency event no message incoming,
  648 + // so the count maybe zero.
  649 + srs_verbose("mw wait %dms and got %d msgs %"PRId64"-%"PRId64"ms", mw_sleep, count,
  650 + (count > 0? msgs.msgs[0]->timestamp : 0),
  651 + (count > 0? msgs.msgs[count - 1]->timestamp : 0));
620 #else 652 #else
621 if (count <= 0) { 653 if (count <= 0) {
622 srs_info("mw sleep %dms for no msg", mw_sleep); 654 srs_info("mw sleep %dms for no msg", mw_sleep);
@@ -1037,12 +1069,12 @@ void SrsRtmpConn::change_mw_sleep(int sleep_ms) @@ -1037,12 +1069,12 @@ void SrsRtmpConn::change_mw_sleep(int sleep_ms)
1037 } 1069 }
1038 getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &nb_sbuf, &sock_buf_size); 1070 getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &nb_sbuf, &sock_buf_size);
1039 1071
1040 - srs_trace("mw changed sleep %d=>%d, max_msgs=%d, esbuf=%d, sbuf %d=>%d", 1072 + srs_trace("mw changed sleep %d=>%d, max_msgs=%d, esbuf=%d, sbuf %d=>%d, realtime=%d",
1041 mw_sleep, sleep_ms, SRS_PERF_MW_MSGS, socket_buffer_size, 1073 mw_sleep, sleep_ms, SRS_PERF_MW_MSGS, socket_buffer_size,
1042 - onb_sbuf, nb_sbuf); 1074 + onb_sbuf, nb_sbuf, realtime);
1043 #else 1075 #else
1044 - srs_trace("mw changed sleep %d=>%d, max_msgs=%d, sbuf %d",  
1045 - mw_sleep, sleep_ms, SRS_PERF_MW_MSGS, onb_sbuf); 1076 + srs_trace("mw changed sleep %d=>%d, max_msgs=%d, sbuf %d, realtime=%d",
  1077 + mw_sleep, sleep_ms, SRS_PERF_MW_MSGS, onb_sbuf, realtime);
1046 #endif 1078 #endif
1047 1079
1048 mw_sleep = sleep_ms; 1080 mw_sleep = sleep_ms;
@@ -75,6 +75,9 @@ private: @@ -75,6 +75,9 @@ private:
75 int mw_sleep; 75 int mw_sleep;
76 // the MR(merged-write) only enabled for play. 76 // the MR(merged-write) only enabled for play.
77 int mw_enabled; 77 int mw_enabled;
  78 + // for realtime
  79 + // @see https://github.com/winlinvip/simple-rtmp-server/issues/257
  80 + bool realtime;
78 public: 81 public:
79 SrsRtmpConn(SrsServer* srs_server, st_netfd_t client_stfd); 82 SrsRtmpConn(SrsServer* srs_server, st_netfd_t client_stfd);
80 virtual ~SrsRtmpConn(); 83 virtual ~SrsRtmpConn();
@@ -86,6 +89,7 @@ protected: @@ -86,6 +89,7 @@ protected:
86 public: 89 public:
87 virtual int on_reload_vhost_removed(std::string vhost); 90 virtual int on_reload_vhost_removed(std::string vhost);
88 virtual int on_reload_vhost_mw(std::string vhost); 91 virtual int on_reload_vhost_mw(std::string vhost);
  92 + virtual int on_reload_vhost_realtime(std::string vhost);
89 // interface IKbpsDelta 93 // interface IKbpsDelta
90 public: 94 public:
91 virtual int64_t get_send_bytes_delta(); 95 virtual int64_t get_send_bytes_delta();
@@ -493,7 +493,7 @@ int SrsConsumer::dump_packets(SrsMessageArray* msgs, int& count) @@ -493,7 +493,7 @@ int SrsConsumer::dump_packets(SrsMessageArray* msgs, int& count)
493 } 493 }
494 494
495 #ifdef SRS_PERF_QUEUE_COND_WAIT 495 #ifdef SRS_PERF_QUEUE_COND_WAIT
496 -void SrsConsumer::wait(int nb_msgs, int duration) 496 +void SrsConsumer::wait(int nb_msgs, int duration, bool realtime)
497 { 497 {
498 mw_min_msgs = nb_msgs; 498 mw_min_msgs = nb_msgs;
499 mw_duration = duration; 499 mw_duration = duration;
@@ -508,8 +508,15 @@ void SrsConsumer::wait(int nb_msgs, int duration) @@ -508,8 +508,15 @@ void SrsConsumer::wait(int nb_msgs, int duration)
508 508
509 // the enqueue will notify this cond. 509 // the enqueue will notify this cond.
510 mw_waiting = true; 510 mw_waiting = true;
511 - // wait for msgs to incoming.  
512 - st_cond_wait(mw_wait); 511 +
  512 + // use timeout wait for realtime mode.
  513 + // @see https://github.com/winlinvip/simple-rtmp-server/issues/257
  514 + if (realtime) {
  515 + st_cond_timedwait(mw_wait, duration * 1000);
  516 + } else {
  517 + // use cond block wait for high performance mode.
  518 + st_cond_wait(mw_wait);
  519 + }
513 } 520 }
514 #endif 521 #endif
515 522
@@ -245,8 +245,9 @@ public: @@ -245,8 +245,9 @@ public:
245 * wait for messages incomming, atleast nb_msgs and in duration. 245 * wait for messages incomming, atleast nb_msgs and in duration.
246 * @param nb_msgs the messages count to wait. 246 * @param nb_msgs the messages count to wait.
247 * @param duration the messgae duration to wait. 247 * @param duration the messgae duration to wait.
  248 + * @param realtime whether use realtime mode.
248 */ 249 */
249 - virtual void wait(int nb_msgs, int duration); 250 + virtual void wait(int nb_msgs, int duration, bool realtime);
250 #endif 251 #endif
251 /** 252 /**
252 * when client send the pause message. 253 * when client send the pause message.
@@ -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 2 32 #define VERSION_MAJOR 2
33 #define VERSION_MINOR 0 33 #define VERSION_MINOR 0
34 -#define VERSION_REVISION 69 34 +#define VERSION_REVISION 70
35 // server info. 35 // server info.
36 #define RTMP_SIG_SRS_KEY "SRS" 36 #define RTMP_SIG_SRS_KEY "SRS"
37 #define RTMP_SIG_SRS_ROLE "origin/edge server" 37 #define RTMP_SIG_SRS_ROLE "origin/edge server"
@@ -128,6 +128,15 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -128,6 +128,15 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
128 #ifdef SRS_PERF_QUEUE_COND_WAIT 128 #ifdef SRS_PERF_QUEUE_COND_WAIT
129 #define SRS_PERF_MW_MIN_MSGS 8 129 #define SRS_PERF_MW_MIN_MSGS 8
130 #endif 130 #endif
  131 +/**
  132 +* the default value of vhost for
  133 +* SRS whether use the min latency mode.
  134 +* for min latence mode:
  135 +* 1. disable the mr for vhost.
  136 +* 2. use timeout for cond wait for consumer queue.
  137 +* @see https://github.com/winlinvip/simple-rtmp-server/issues/257
  138 +*/
  139 +#define SRS_PERF_MIN_LATENCY_ENABLED true
131 140
132 /** 141 /**
133 * how many chunk stream to cache, [0, N]. 142 * how many chunk stream to cache, [0, N].
@@ -61,13 +61,13 @@ int64_t srs_get_system_startup_time_ms() @@ -61,13 +61,13 @@ int64_t srs_get_system_startup_time_ms()
61 61
62 return _srs_system_time_startup_time / 1000; 62 return _srs_system_time_startup_time / 1000;
63 } 63 }
64 -void srs_update_system_time_ms() 64 +int64_t srs_update_system_time_ms()
65 { 65 {
66 timeval now; 66 timeval now;
67 67
68 if (gettimeofday(&now, NULL) < 0) { 68 if (gettimeofday(&now, NULL) < 0) {
69 srs_warn("gettimeofday failed, ignore"); 69 srs_warn("gettimeofday failed, ignore");
70 - return; 70 + return -1;
71 } 71 }
72 72
73 // @see: https://github.com/winlinvip/simple-rtmp-server/issues/35 73 // @see: https://github.com/winlinvip/simple-rtmp-server/issues/35
@@ -83,7 +83,7 @@ void srs_update_system_time_ms() @@ -83,7 +83,7 @@ void srs_update_system_time_ms()
83 if (_srs_system_time_us_cache <= 0) { 83 if (_srs_system_time_us_cache <= 0) {
84 _srs_system_time_us_cache = now_us; 84 _srs_system_time_us_cache = now_us;
85 _srs_system_time_startup_time = now_us; 85 _srs_system_time_startup_time = now_us;
86 - return; 86 + return _srs_system_time_us_cache;
87 } 87 }
88 88
89 // use relative time. 89 // use relative time.
@@ -99,6 +99,8 @@ void srs_update_system_time_ms() @@ -99,6 +99,8 @@ void srs_update_system_time_ms()
99 _srs_system_time_us_cache = now_us; 99 _srs_system_time_us_cache = now_us;
100 srs_info("system time updated, startup=%"PRId64"us, now=%"PRId64"us", 100 srs_info("system time updated, startup=%"PRId64"us, now=%"PRId64"us",
101 _srs_system_time_startup_time, _srs_system_time_us_cache); 101 _srs_system_time_startup_time, _srs_system_time_us_cache);
  102 +
  103 + return _srs_system_time_us_cache;
102 } 104 }
103 105
104 string srs_dns_resolve(string host) 106 string srs_dns_resolve(string host)
@@ -40,7 +40,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -40,7 +40,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40 extern int64_t srs_get_system_time_ms(); 40 extern int64_t srs_get_system_time_ms();
41 extern int64_t srs_get_system_startup_time_ms(); 41 extern int64_t srs_get_system_startup_time_ms();
42 // the deamon st-thread will update it. 42 // the deamon st-thread will update it.
43 -extern void srs_update_system_time_ms(); 43 +extern int64_t srs_update_system_time_ms();
44 44
45 // dns resolve utility, return the resolved ip address. 45 // dns resolve utility, return the resolved ip address.
46 extern std::string srs_dns_resolve(std::string host); 46 extern std::string srs_dns_resolve(std::string host);