winlin

edge support play and ingest origin stream. change to 0.9.77

@@ -893,20 +893,23 @@ vhost refer.anti_suck.com { @@ -893,20 +893,23 @@ vhost refer.anti_suck.com {
893 pithy_print { 893 pithy_print {
894 # shared print interval for all publish clients, in milliseconds. 894 # shared print interval for all publish clients, in milliseconds.
895 # if not specified, set to 1100. 895 # if not specified, set to 1100.
896 - publish 2000; 896 + publish 10000;
897 # shared print interval for all play clients, in milliseconds. 897 # shared print interval for all play clients, in milliseconds.
898 # if not specified, set to 1300. 898 # if not specified, set to 1300.
899 - play 3000; 899 + play 10000;
900 # shared print interval for all forwarders, in milliseconds. 900 # shared print interval for all forwarders, in milliseconds.
901 # if not specified, set to 2000. 901 # if not specified, set to 2000.
902 - forwarder 3000; 902 + forwarder 10000;
903 # shared print interval for all encoders, in milliseconds. 903 # shared print interval for all encoders, in milliseconds.
904 # if not specified, set to 2000. 904 # if not specified, set to 2000.
905 - encoder 3000; 905 + encoder 10000;
906 # shared print interval for all ingesters, in milliseconds. 906 # shared print interval for all ingesters, in milliseconds.
907 # if not specified, set to 2000. 907 # if not specified, set to 2000.
908 - ingester 3000; 908 + ingester 10000;
909 # shared print interval for all hls, in milliseconds. 909 # shared print interval for all hls, in milliseconds.
910 # if not specified, set to 2000. 910 # if not specified, set to 2000.
911 - hls 3000; 911 + hls 10000;
  912 + # shared print interval for all edge, in milliseconds.
  913 + # if not specified, set to 2000.
  914 + edge 10000;
912 } 915 }
@@ -1396,6 +1396,21 @@ int SrsConfig::get_pithy_print_play() @@ -1396,6 +1396,21 @@ int SrsConfig::get_pithy_print_play()
1396 return ::atoi(pithy->arg0().c_str()); 1396 return ::atoi(pithy->arg0().c_str());
1397 } 1397 }
1398 1398
  1399 +int SrsConfig::get_pithy_print_edge()
  1400 +{
  1401 + SrsConfDirective* pithy = root->get("pithy_print");
  1402 + if (!pithy) {
  1403 + return SRS_STAGE_EDGE_INTERVAL_MS;
  1404 + }
  1405 +
  1406 + pithy = pithy->get("edge");
  1407 + if (!pithy) {
  1408 + return SRS_STAGE_EDGE_INTERVAL_MS;
  1409 + }
  1410 +
  1411 + return ::atoi(pithy->arg0().c_str());
  1412 +}
  1413 +
1399 SrsConfDirective* SrsConfig::get_vhost(string vhost) 1414 SrsConfDirective* SrsConfig::get_vhost(string vhost)
1400 { 1415 {
1401 srs_assert(root); 1416 srs_assert(root);
@@ -1821,6 +1836,17 @@ bool SrsConfig::get_vhost_is_edge(std::string vhost) @@ -1821,6 +1836,17 @@ bool SrsConfig::get_vhost_is_edge(std::string vhost)
1821 return true; 1836 return true;
1822 } 1837 }
1823 1838
  1839 +SrsConfDirective* SrsConfig::get_vhost_edge_origin(string vhost)
  1840 +{
  1841 + SrsConfDirective* conf = get_vhost(vhost);
  1842 +
  1843 + if (!conf) {
  1844 + return NULL;
  1845 + }
  1846 +
  1847 + return conf->get("origin");
  1848 +}
  1849 +
1824 SrsConfDirective* SrsConfig::get_transcode(string vhost, string scope) 1850 SrsConfDirective* SrsConfig::get_transcode(string vhost, string scope)
1825 { 1851 {
1826 SrsConfDirective* conf = get_vhost(vhost); 1852 SrsConfDirective* conf = get_vhost(vhost);
@@ -76,6 +76,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -76,6 +76,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
76 #define SRS_STAGE_ENCODER_INTERVAL_MS 2000 76 #define SRS_STAGE_ENCODER_INTERVAL_MS 2000
77 #define SRS_STAGE_INGESTER_INTERVAL_MS 2000 77 #define SRS_STAGE_INGESTER_INTERVAL_MS 2000
78 #define SRS_STAGE_HLS_INTERVAL_MS 2000 78 #define SRS_STAGE_HLS_INTERVAL_MS 2000
  79 +#define SRS_STAGE_EDGE_INTERVAL_MS 2000
79 80
80 #define SRS_AUTO_INGEST_TYPE_FILE "file" 81 #define SRS_AUTO_INGEST_TYPE_FILE "file"
81 #define SRS_AUTO_INGEST_TYPE_STREAM "stream" 82 #define SRS_AUTO_INGEST_TYPE_STREAM "stream"
@@ -163,6 +164,7 @@ public: @@ -163,6 +164,7 @@ public:
163 virtual int get_pithy_print_ingester(); 164 virtual int get_pithy_print_ingester();
164 virtual int get_pithy_print_hls(); 165 virtual int get_pithy_print_hls();
165 virtual int get_pithy_print_play(); 166 virtual int get_pithy_print_play();
  167 + virtual int get_pithy_print_edge();
166 // vhost specified section 168 // vhost specified section
167 public: 169 public:
168 virtual SrsConfDirective* get_vhost(std::string vhost); 170 virtual SrsConfDirective* get_vhost(std::string vhost);
@@ -193,6 +195,7 @@ public: @@ -193,6 +195,7 @@ public:
193 // vhost edge section 195 // vhost edge section
194 public: 196 public:
195 virtual bool get_vhost_is_edge(std::string vhost); 197 virtual bool get_vhost_is_edge(std::string vhost);
  198 + virtual SrsConfDirective* get_vhost_edge_origin(std::string vhost);
196 // vhost transcode section 199 // vhost transcode section
197 public: 200 public:
198 virtual SrsConfDirective* get_transcode(std::string vhost, std::string scope); 201 virtual SrsConfDirective* get_transcode(std::string vhost, std::string scope);
@@ -23,28 +23,55 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -23,28 +23,55 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 23
24 #include <srs_app_edge.hpp> 24 #include <srs_app_edge.hpp>
25 25
  26 +#include <stdlib.h>
  27 +#include <sys/socket.h>
  28 +#include <netinet/in.h>
  29 +#include <arpa/inet.h>
  30 +
26 #include <srs_kernel_error.hpp> 31 #include <srs_kernel_error.hpp>
27 #include <srs_protocol_rtmp.hpp> 32 #include <srs_protocol_rtmp.hpp>
28 #include <srs_kernel_log.hpp> 33 #include <srs_kernel_log.hpp>
  34 +#include <srs_protocol_rtmp.hpp>
  35 +#include <srs_protocol_io.hpp>
  36 +#include <srs_app_config.hpp>
  37 +#include <srs_protocol_utility.hpp>
  38 +#include <srs_protocol_rtmp.hpp>
  39 +#include <srs_app_socket.hpp>
  40 +#include <srs_protocol_rtmp_stack.hpp>
  41 +#include <srs_app_source.hpp>
  42 +#include <srs_app_pithy_print.hpp>
  43 +#include <srs_core_autofree.hpp>
29 44
30 // when error, edge ingester sleep for a while and retry. 45 // when error, edge ingester sleep for a while and retry.
31 -#define SRS_EDGE_INGESTER_SLEEP_US (int64_t)(3*1000*1000LL) 46 +#define SRS_EDGE_INGESTER_SLEEP_US (int64_t)(1*1000*1000LL)
  47 +
  48 +// when edge timeout, retry next.
  49 +#define SRS_EDGE_TIMEOUT_US (int64_t)(3*1000*1000LL)
32 50
33 SrsEdgeIngester::SrsEdgeIngester() 51 SrsEdgeIngester::SrsEdgeIngester()
34 { 52 {
  53 + io = NULL;
  54 + client = NULL;
35 _edge = NULL; 55 _edge = NULL;
36 _req = NULL; 56 _req = NULL;
  57 + origin_index = 0;
  58 + stream_id = 0;
  59 + stfd = NULL;
37 pthread = new SrsThread(this, SRS_EDGE_INGESTER_SLEEP_US); 60 pthread = new SrsThread(this, SRS_EDGE_INGESTER_SLEEP_US);
38 } 61 }
39 62
40 SrsEdgeIngester::~SrsEdgeIngester() 63 SrsEdgeIngester::~SrsEdgeIngester()
41 { 64 {
  65 + stop();
  66 +
  67 + srs_freep(pthread);
42 } 68 }
43 69
44 -int SrsEdgeIngester::initialize(SrsEdge* edge, SrsRequest* req) 70 +int SrsEdgeIngester::initialize(SrsSource* source, SrsEdge* edge, SrsRequest* req)
45 { 71 {
46 int ret = ERROR_SUCCESS; 72 int ret = ERROR_SUCCESS;
47 73
  74 + _source = source;
48 _edge = edge; 75 _edge = edge;
49 _req = req; 76 _req = req;
50 77
@@ -53,14 +80,229 @@ int SrsEdgeIngester::initialize(SrsEdge* edge, SrsRequest* req) @@ -53,14 +80,229 @@ int SrsEdgeIngester::initialize(SrsEdge* edge, SrsRequest* req)
53 80
54 int SrsEdgeIngester::start() 81 int SrsEdgeIngester::start()
55 { 82 {
  83 + return pthread->start();
  84 +}
  85 +
  86 +void SrsEdgeIngester::stop()
  87 +{
  88 + pthread->stop();
  89 +
  90 + close_underlayer_socket();
  91 +
  92 + srs_freep(client);
  93 + srs_freep(io);
  94 +}
  95 +
  96 +int SrsEdgeIngester::cycle()
  97 +{
56 int ret = ERROR_SUCCESS; 98 int ret = ERROR_SUCCESS;
  99 +
  100 + if ((ret = connect_server()) != ERROR_SUCCESS) {
  101 + return ret;
  102 + }
  103 + srs_assert(client);
  104 +
  105 + client->set_recv_timeout(SRS_RECV_TIMEOUT_US);
  106 + client->set_send_timeout(SRS_SEND_TIMEOUT_US);
  107 +
  108 + SrsRequest* req = _req;
  109 +
  110 + if ((ret = client->handshake()) != ERROR_SUCCESS) {
  111 + srs_error("handshake with server failed. ret=%d", ret);
  112 + return ret;
  113 + }
  114 + if ((ret = client->connect_app(req->app, req->tcUrl)) != ERROR_SUCCESS) {
  115 + srs_error("connect with server failed, tcUrl=%s. ret=%d", req->tcUrl.c_str(), ret);
  116 + return ret;
  117 + }
  118 + if ((ret = client->create_stream(stream_id)) != ERROR_SUCCESS) {
  119 + srs_error("connect with server failed, stream_id=%d. ret=%d", stream_id, ret);
  120 + return ret;
  121 + }
  122 +
  123 + if ((ret = client->play(req->stream, stream_id)) != ERROR_SUCCESS) {
  124 + srs_error("connect with server failed, stream=%s, stream_id=%d. ret=%d",
  125 + req->stream.c_str(), stream_id, ret);
  126 + return ret;
  127 + }
  128 +
  129 + if ((ret = _source->on_publish()) != ERROR_SUCCESS) {
  130 + srs_error("edge ingester play stream then publish to edge failed. ret=%d", ret);
  131 + return ret;
  132 + }
  133 +
  134 + if ((ret = _edge->on_ingest_play()) != ERROR_SUCCESS) {
  135 + return ret;
  136 + }
  137 +
  138 + if ((ret = ingest()) != ERROR_SUCCESS) {
  139 + return ret;
  140 + }
  141 +
57 return ret; 142 return ret;
58 - //return pthread->start();  
59 } 143 }
60 144
61 -int SrsEdgeIngester::cycle() 145 +int SrsEdgeIngester::ingest()
62 { 146 {
63 int ret = ERROR_SUCCESS; 147 int ret = ERROR_SUCCESS;
  148 +
  149 + client->set_recv_timeout(SRS_EDGE_TIMEOUT_US);
  150 +
  151 + SrsPithyPrint pithy_print(SRS_STAGE_EDGE);
  152 +
  153 + while (pthread->can_loop()) {
  154 + // switch to other st-threads.
  155 + st_usleep(0);
  156 +
  157 + pithy_print.elapse();
  158 +
  159 + // pithy print
  160 + if (pithy_print.can_print()) {
  161 + srs_trace("<- time=%"PRId64", obytes=%"PRId64", ibytes=%"PRId64", okbps=%d, ikbps=%d",
  162 + pithy_print.age(), client->get_send_bytes(), client->get_recv_bytes(), client->get_send_kbps(), client->get_recv_kbps());
  163 + }
  164 +
  165 + // read from client.
  166 + SrsCommonMessage* msg = NULL;
  167 + if ((ret = client->recv_message(&msg)) != ERROR_SUCCESS) {
  168 + srs_error("recv origin server message failed. ret=%d", ret);
  169 + return ret;
  170 + }
  171 + srs_verbose("edge loop recv message. ret=%d", ret);
  172 +
  173 + srs_assert(msg);
  174 + SrsAutoFree(SrsCommonMessage, msg, false);
  175 +
  176 + if ((ret = process_publish_message(msg)) != ERROR_SUCCESS) {
  177 + return ret;
  178 + }
  179 + }
  180 +
  181 + return ret;
  182 +}
  183 +
  184 +int SrsEdgeIngester::process_publish_message(SrsCommonMessage* msg)
  185 +{
  186 + int ret = ERROR_SUCCESS;
  187 +
  188 + SrsSource* source = _source;
  189 +
  190 + // process audio packet
  191 + if (msg->header.is_audio()) {
  192 + if ((ret = source->on_audio(msg)) != ERROR_SUCCESS) {
  193 + srs_error("source process audio message failed. ret=%d", ret);
  194 + return ret;
  195 + }
  196 + }
  197 +
  198 + // process video packet
  199 + if (msg->header.is_video()) {
  200 + if ((ret = source->on_video(msg)) != ERROR_SUCCESS) {
  201 + srs_error("source process video message failed. ret=%d", ret);
  202 + return ret;
  203 + }
  204 + }
  205 +
  206 + // process onMetaData
  207 + if (msg->header.is_amf0_data() || msg->header.is_amf3_data()) {
  208 + if ((ret = msg->decode_packet(client->get_protocol())) != ERROR_SUCCESS) {
  209 + srs_error("decode onMetaData message failed. ret=%d", ret);
  210 + return ret;
  211 + }
  212 +
  213 + SrsPacket* pkt = msg->get_packet();
  214 + if (dynamic_cast<SrsOnMetaDataPacket*>(pkt)) {
  215 + SrsOnMetaDataPacket* metadata = dynamic_cast<SrsOnMetaDataPacket*>(pkt);
  216 + if ((ret = source->on_meta_data(msg, metadata)) != ERROR_SUCCESS) {
  217 + srs_error("source process onMetaData message failed. ret=%d", ret);
  218 + return ret;
  219 + }
  220 + srs_trace("process onMetaData message success.");
  221 + return ret;
  222 + }
  223 +
  224 + srs_trace("ignore AMF0/AMF3 data message.");
  225 + return ret;
  226 + }
  227 +
  228 + return ret;
  229 +}
  230 +
  231 +void SrsEdgeIngester::close_underlayer_socket()
  232 +{
  233 + srs_close_stfd(stfd);
  234 +}
  235 +
  236 +int SrsEdgeIngester::connect_server()
  237 +{
  238 + int ret = ERROR_SUCCESS;
  239 +
  240 + // reopen
  241 + close_underlayer_socket();
  242 +
  243 + // TODO: FIXME: support reload
  244 + SrsConfDirective* conf = _srs_config->get_vhost_edge_origin(_req->vhost);
  245 + srs_assert(conf);
  246 +
  247 + // select the origin.
  248 + std::string server = conf->args.at(origin_index % conf->args.size());
  249 + origin_index = (origin_index + 1) % conf->args.size();
  250 +
  251 + std::string s_port = RTMP_DEFAULT_PORT;
  252 + int port = ::atoi(RTMP_DEFAULT_PORT);
  253 + size_t pos = server.find(":");
  254 + if (pos != std::string::npos) {
  255 + s_port = server.substr(pos + 1);
  256 + server = server.substr(0, pos);
  257 + port = ::atoi(s_port.c_str());
  258 + }
  259 +
  260 + // open socket.
  261 + srs_trace("connect edge stream=%s, tcUrl=%s to server=%s, port=%d",
  262 + _req->stream.c_str(), _req->tcUrl.c_str(), server.c_str(), port);
  263 +
  264 + // TODO: FIXME: extract utility method
  265 + int sock = socket(AF_INET, SOCK_STREAM, 0);
  266 + if(sock == -1){
  267 + ret = ERROR_SOCKET_CREATE;
  268 + srs_error("create socket error. ret=%d", ret);
  269 + return ret;
  270 + }
  271 +
  272 + srs_assert(!stfd);
  273 + stfd = st_netfd_open_socket(sock);
  274 + if(stfd == NULL){
  275 + ret = ERROR_ST_OPEN_SOCKET;
  276 + srs_error("st_netfd_open_socket failed. ret=%d", ret);
  277 + return ret;
  278 + }
  279 +
  280 + srs_freep(client);
  281 + srs_freep(io);
  282 +
  283 + io = new SrsSocket(stfd);
  284 + client = new SrsRtmpClient(io);
  285 +
  286 + // connect to server.
  287 + std::string ip = srs_dns_resolve(server);
  288 + if (ip.empty()) {
  289 + ret = ERROR_SYSTEM_IP_INVALID;
  290 + srs_error("dns resolve server error, ip empty. ret=%d", ret);
  291 + return ret;
  292 + }
  293 +
  294 + sockaddr_in addr;
  295 + addr.sin_family = AF_INET;
  296 + addr.sin_port = htons(port);
  297 + addr.sin_addr.s_addr = inet_addr(ip.c_str());
  298 +
  299 + if (st_connect(stfd, (const struct sockaddr*)&addr, sizeof(sockaddr_in), ST_UTIME_NO_TIMEOUT) == -1){
  300 + ret = ERROR_ST_CONNECT;
  301 + srs_error("connect to server error. ip=%s, port=%d, ret=%d", ip.c_str(), port, ret);
  302 + return ret;
  303 + }
  304 + srs_trace("connect to server success. server=%s, ip=%s, port=%d", server.c_str(), ip.c_str(), port);
  305 +
64 return ret; 306 return ret;
65 } 307 }
66 308
@@ -75,11 +317,11 @@ SrsEdge::~SrsEdge() @@ -75,11 +317,11 @@ SrsEdge::~SrsEdge()
75 srs_freep(ingester); 317 srs_freep(ingester);
76 } 318 }
77 319
78 -int SrsEdge::initialize(SrsRequest* req) 320 +int SrsEdge::initialize(SrsSource* source, SrsRequest* req)
79 { 321 {
80 int ret = ERROR_SUCCESS; 322 int ret = ERROR_SUCCESS;
81 323
82 - if ((ret = ingester->initialize(this, req)) != ERROR_SUCCESS) { 324 + if ((ret = ingester->initialize(source, this, req)) != ERROR_SUCCESS) {
83 return ret; 325 return ret;
84 } 326 }
85 327
@@ -106,3 +348,25 @@ int SrsEdge::on_client_play() @@ -106,3 +348,25 @@ int SrsEdge::on_client_play()
106 return ret; 348 return ret;
107 } 349 }
108 350
  351 +void SrsEdge::on_all_client_stop()
  352 +{
  353 + if (state == SrsEdgeStateIngestConnected) {
  354 + ingester->stop();
  355 + }
  356 +
  357 + SrsEdgeState pstate = state;
  358 + state = SrsEdgeStateInit;
  359 + srs_trace("edge change from %d to state %d (init).", pstate, state);
  360 +}
  361 +
  362 +int SrsEdge::on_ingest_play()
  363 +{
  364 + int ret = ERROR_SUCCESS;
  365 +
  366 + SrsEdgeState pstate = state;
  367 + state = SrsEdgeStateIngestConnected;
  368 +
  369 + srs_trace("edge change from %d to state %d (ingest connected).", pstate, state);
  370 +
  371 + return ret;
  372 +}
@@ -30,10 +30,15 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -30,10 +30,15 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 30
31 #include <srs_core.hpp> 31 #include <srs_core.hpp>
32 32
  33 +#include <srs_app_st.hpp>
33 #include <srs_app_thread.hpp> 34 #include <srs_app_thread.hpp>
34 35
35 class SrsEdge; 36 class SrsEdge;
  37 +class SrsSource;
36 class SrsRequest; 38 class SrsRequest;
  39 +class SrsRtmpClient;
  40 +class SrsCommonMessage;
  41 +class ISrsProtocolReaderWriter;
37 42
38 /** 43 /**
39 * the state of edge 44 * the state of edge
@@ -43,7 +48,10 @@ enum SrsEdgeState @@ -43,7 +48,10 @@ enum SrsEdgeState
43 SrsEdgeStateInit = 0, 48 SrsEdgeStateInit = 0,
44 SrsEdgeStatePlay = 100, 49 SrsEdgeStatePlay = 100,
45 SrsEdgeStatePublish, 50 SrsEdgeStatePublish,
46 - SrsEdgeStateConnected, 51 + // play stream from origin, ingest stream
  52 + SrsEdgeStateIngestConnected,
  53 + // publish stream to edge, forward to origin
  54 + SrsEdgeStateForwardConnected,
47 SrsEdgeStateAborting, 55 SrsEdgeStateAborting,
48 SrsEdgeStateReloading, 56 SrsEdgeStateReloading,
49 }; 57 };
@@ -54,18 +62,31 @@ enum SrsEdgeState @@ -54,18 +62,31 @@ enum SrsEdgeState
54 class SrsEdgeIngester : public ISrsThreadHandler 62 class SrsEdgeIngester : public ISrsThreadHandler
55 { 63 {
56 private: 64 private:
  65 + int stream_id;
  66 +private:
  67 + SrsSource* _source;
57 SrsEdge* _edge; 68 SrsEdge* _edge;
58 SrsRequest* _req; 69 SrsRequest* _req;
59 SrsThread* pthread; 70 SrsThread* pthread;
  71 + st_netfd_t stfd;
  72 + ISrsProtocolReaderWriter* io;
  73 + SrsRtmpClient* client;
  74 + int origin_index;
60 public: 75 public:
61 SrsEdgeIngester(); 76 SrsEdgeIngester();
62 virtual ~SrsEdgeIngester(); 77 virtual ~SrsEdgeIngester();
63 public: 78 public:
64 - virtual int initialize(SrsEdge* edge, SrsRequest* req); 79 + virtual int initialize(SrsSource* source, SrsEdge* edge, SrsRequest* req);
65 virtual int start(); 80 virtual int start();
  81 + virtual void stop();
66 // interface ISrsThreadHandler 82 // interface ISrsThreadHandler
67 public: 83 public:
68 virtual int cycle(); 84 virtual int cycle();
  85 +private:
  86 + virtual int ingest();
  87 + virtual void close_underlayer_socket();
  88 + virtual int connect_server();
  89 + virtual int process_publish_message(SrsCommonMessage* msg);
69 }; 90 };
70 91
71 /** 92 /**
@@ -80,11 +101,20 @@ public: @@ -80,11 +101,20 @@ public:
80 SrsEdge(); 101 SrsEdge();
81 virtual ~SrsEdge(); 102 virtual ~SrsEdge();
82 public: 103 public:
83 - virtual int initialize(SrsRequest* req); 104 + virtual int initialize(SrsSource* source, SrsRequest* req);
84 /** 105 /**
85 * when client play stream on edge. 106 * when client play stream on edge.
86 */ 107 */
87 virtual int on_client_play(); 108 virtual int on_client_play();
  109 + /**
  110 + * when all client stopped play, disconnect to origin.
  111 + */
  112 + virtual void on_all_client_stop();
  113 +public:
  114 + /**
  115 + * when ingester start to play stream.
  116 + */
  117 + virtual int on_ingest_play();
88 }; 118 };
89 119
90 #endif 120 #endif
@@ -113,7 +113,7 @@ int SrsEncoder::cycle() @@ -113,7 +113,7 @@ int SrsEncoder::cycle()
113 113
114 // pithy print 114 // pithy print
115 encoder(); 115 encoder();
116 - pithy_print->elapse(SRS_RTMP_ENCODER_SLEEP_US / 1000); 116 + pithy_print->elapse();
117 117
118 return ret; 118 return ret;
119 } 119 }
@@ -326,7 +326,7 @@ void SrsEncoder::encoder() @@ -326,7 +326,7 @@ void SrsEncoder::encoder()
326 if (pithy_print->can_print()) { 326 if (pithy_print->can_print()) {
327 // TODO: FIXME: show more info. 327 // TODO: FIXME: show more info.
328 srs_trace("-> time=%"PRId64", encoders=%d, input=%s", 328 srs_trace("-> time=%"PRId64", encoders=%d, input=%s",
329 - pithy_print->get_age(), (int)ffmpegs.size(), input_stream_name.c_str()); 329 + pithy_print->age(), (int)ffmpegs.size(), input_stream_name.c_str());
330 } 330 }
331 } 331 }
332 332
@@ -83,6 +83,7 @@ int SrsForwarder::on_publish(SrsRequest* req, std::string forward_server) @@ -83,6 +83,7 @@ int SrsForwarder::on_publish(SrsRequest* req, std::string forward_server)
83 std::string s_port = RTMP_DEFAULT_PORT; 83 std::string s_port = RTMP_DEFAULT_PORT;
84 port = ::atoi(RTMP_DEFAULT_PORT); 84 port = ::atoi(RTMP_DEFAULT_PORT);
85 85
  86 + // TODO: FIXME: parse complex params
86 size_t pos = forward_server.find(":"); 87 size_t pos = forward_server.find(":");
87 if (pos != std::string::npos) { 88 if (pos != std::string::npos) {
88 s_port = forward_server.substr(pos + 1); 89 s_port = forward_server.substr(pos + 1);
@@ -310,6 +311,8 @@ int SrsForwarder::forward() @@ -310,6 +311,8 @@ int SrsForwarder::forward()
310 // switch to other st-threads. 311 // switch to other st-threads.
311 st_usleep(0); 312 st_usleep(0);
312 313
  314 + pithy_print.elapse();
  315 +
313 // read from client. 316 // read from client.
314 if (true) { 317 if (true) {
315 SrsCommonMessage* msg = NULL; 318 SrsCommonMessage* msg = NULL;
@@ -330,19 +333,18 @@ int SrsForwarder::forward() @@ -330,19 +333,18 @@ int SrsForwarder::forward()
330 return ret; 333 return ret;
331 } 334 }
332 335
  336 + // pithy print
  337 + if (pithy_print.can_print()) {
  338 + srs_trace("-> time=%"PRId64", msgs=%d, obytes=%"PRId64", ibytes=%"PRId64", okbps=%d, ikbps=%d",
  339 + pithy_print.age(), count, client->get_send_bytes(), client->get_recv_bytes(), client->get_send_kbps(), client->get_recv_kbps());
  340 + }
  341 +
333 // ignore when no messages. 342 // ignore when no messages.
334 if (count <= 0) { 343 if (count <= 0) {
335 srs_verbose("no packets to forward."); 344 srs_verbose("no packets to forward.");
336 continue; 345 continue;
337 } 346 }
338 SrsAutoFree(SrsSharedPtrMessage*, msgs, true); 347 SrsAutoFree(SrsSharedPtrMessage*, msgs, true);
339 -  
340 - // pithy print  
341 - pithy_print.elapse(SRS_PULSE_TIMEOUT_US / 1000);  
342 - if (pithy_print.can_print()) {  
343 - srs_trace("-> time=%"PRId64", msgs=%d, obytes=%"PRId64", ibytes=%"PRId64", okbps=%d, ikbps=%d",  
344 - pithy_print.get_age(), count, client->get_send_bytes(), client->get_recv_bytes(), client->get_send_kbps(), client->get_recv_kbps());  
345 - }  
346 348
347 // all msgs to forward. 349 // all msgs to forward.
348 for (int i = 0; i < count; i++) { 350 for (int i = 0; i < count; i++) {
@@ -1470,10 +1470,10 @@ void SrsHls::hls_mux() @@ -1470,10 +1470,10 @@ void SrsHls::hls_mux()
1470 { 1470 {
1471 // reportable 1471 // reportable
1472 if (pithy_print->can_print()) { 1472 if (pithy_print->can_print()) {
1473 - srs_trace("-> time=%"PRId64"", pithy_print->get_age()); 1473 + srs_trace("-> time=%"PRId64"", pithy_print->age());
1474 } 1474 }
1475 1475
1476 - pithy_print->elapse(sample->cts); 1476 + pithy_print->elapse();
1477 } 1477 }
1478 1478
1479 #endif 1479 #endif
@@ -188,7 +188,7 @@ int SrsIngester::cycle() @@ -188,7 +188,7 @@ int SrsIngester::cycle()
188 188
189 // pithy print 189 // pithy print
190 ingester(); 190 ingester();
191 - pithy_print->elapse(SRS_AUTO_INGESTER_SLEEP_US / 1000); 191 + pithy_print->elapse();
192 192
193 return ret; 193 return ret;
194 } 194 }
@@ -350,7 +350,7 @@ void SrsIngester::ingester() @@ -350,7 +350,7 @@ void SrsIngester::ingester()
350 } 350 }
351 351
352 // TODO: FIXME: show more info. 352 // TODO: FIXME: show more info.
353 - srs_trace("-> time=%"PRId64", ingesters=%d", pithy_print->get_age(), (int)ingesters.size()); 353 + srs_trace("-> time=%"PRId64", ingesters=%d", pithy_print->age(), (int)ingesters.size());
354 } 354 }
355 355
356 int SrsIngester::on_reload_vhost_added(string vhost) 356 int SrsIngester::on_reload_vhost_added(string vhost)
@@ -30,6 +30,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -30,6 +30,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 #include <srs_app_config.hpp> 30 #include <srs_app_config.hpp>
31 #include <srs_app_reload.hpp> 31 #include <srs_app_reload.hpp>
32 #include <srs_kernel_error.hpp> 32 #include <srs_kernel_error.hpp>
  33 +#include <srs_kernel_utility.hpp>
33 34
34 #define SRS_STAGE_DEFAULT_INTERVAL_MS 1200 35 #define SRS_STAGE_DEFAULT_INTERVAL_MS 1200
35 36
@@ -75,6 +76,10 @@ struct SrsStageInfo : public ISrsReloadHandler @@ -75,6 +76,10 @@ struct SrsStageInfo : public ISrsReloadHandler
75 pithy_print_time_ms = _srs_config->get_pithy_print_ingester(); 76 pithy_print_time_ms = _srs_config->get_pithy_print_ingester();
76 break; 77 break;
77 } 78 }
  79 + case SRS_STAGE_EDGE: {
  80 + pithy_print_time_ms = _srs_config->get_pithy_print_edge();
  81 + break;
  82 + }
78 case SRS_STAGE_HLS: { 83 case SRS_STAGE_HLS: {
79 pithy_print_time_ms = _srs_config->get_pithy_print_hls(); 84 pithy_print_time_ms = _srs_config->get_pithy_print_hls();
80 break; 85 break;
@@ -98,7 +103,8 @@ SrsPithyPrint::SrsPithyPrint(int _stage_id) @@ -98,7 +103,8 @@ SrsPithyPrint::SrsPithyPrint(int _stage_id)
98 { 103 {
99 stage_id = _stage_id; 104 stage_id = _stage_id;
100 client_id = enter_stage(); 105 client_id = enter_stage();
101 - printed_age = age = 0; 106 + previous_tick = srs_get_system_time_ms();
  107 + printed_age = _age = 0;
102 } 108 }
103 109
104 SrsPithyPrint::~SrsPithyPrint() 110 SrsPithyPrint::~SrsPithyPrint()
@@ -138,9 +144,12 @@ void SrsPithyPrint::leave_stage() @@ -138,9 +144,12 @@ void SrsPithyPrint::leave_stage()
138 stage->stage_id, client_id, stage->nb_clients, stage->pithy_print_time_ms); 144 stage->stage_id, client_id, stage->nb_clients, stage->pithy_print_time_ms);
139 } 145 }
140 146
141 -void SrsPithyPrint::elapse(int64_t time_ms) 147 +void SrsPithyPrint::elapse()
142 { 148 {
143 - age += time_ms; 149 + int64_t diff = srs_get_system_time_ms() - previous_tick;
  150 +
  151 + _age += srs_max(0, diff);
  152 + previous_tick = srs_get_system_time_ms();
144 } 153 }
145 154
146 bool SrsPithyPrint::can_print() 155 bool SrsPithyPrint::can_print()
@@ -148,24 +157,19 @@ bool SrsPithyPrint::can_print() @@ -148,24 +157,19 @@ bool SrsPithyPrint::can_print()
148 SrsStageInfo* stage = _srs_stages[stage_id]; 157 SrsStageInfo* stage = _srs_stages[stage_id];
149 srs_assert(stage != NULL); 158 srs_assert(stage != NULL);
150 159
151 - int64_t alive_age = age - printed_age; 160 + int64_t alive_age = _age - printed_age;
152 int64_t can_print_age = stage->nb_clients * stage->pithy_print_time_ms; 161 int64_t can_print_age = stage->nb_clients * stage->pithy_print_time_ms;
153 162
154 bool can_print = alive_age >= can_print_age; 163 bool can_print = alive_age >= can_print_age;
155 if (can_print) { 164 if (can_print) {
156 - printed_age = age; 165 + printed_age = _age;
157 } 166 }
158 167
159 return can_print; 168 return can_print;
160 } 169 }
161 170
162 -int64_t SrsPithyPrint::get_age()  
163 -{  
164 - return age;  
165 -}  
166 -  
167 -void SrsPithyPrint::set_age(int64_t _age) 171 +int64_t SrsPithyPrint::age()
168 { 172 {
169 - age = _age; 173 + return _age;
170 } 174 }
171 175
@@ -42,6 +42,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -42,6 +42,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
42 #define SRS_STAGE_HLS 5 42 #define SRS_STAGE_HLS 5
43 // the pithy stage for all ingesters. 43 // the pithy stage for all ingesters.
44 #define SRS_STAGE_INGESTER 6 44 #define SRS_STAGE_INGESTER 6
  45 +// the pithy stage for all edge.
  46 +#define SRS_STAGE_EDGE 7
45 47
46 /** 48 /**
47 * the stage is used for a collection of object to do print, 49 * the stage is used for a collection of object to do print,
@@ -55,8 +57,9 @@ private: @@ -55,8 +57,9 @@ private:
55 int client_id; 57 int client_id;
56 int stage_id; 58 int stage_id;
57 // in ms. 59 // in ms.
58 - int64_t age; 60 + int64_t _age;
59 int64_t printed_age; 61 int64_t printed_age;
  62 + int64_t previous_tick;
60 public: 63 public:
61 /** 64 /**
62 * @param _stage_id defined in SRS_STAGE_xxx, eg. SRS_STAGE_PLAY_USER. 65 * @param _stage_id defined in SRS_STAGE_xxx, eg. SRS_STAGE_PLAY_USER.
@@ -74,9 +77,9 @@ private: @@ -74,9 +77,9 @@ private:
74 virtual void leave_stage(); 77 virtual void leave_stage();
75 public: 78 public:
76 /** 79 /**
77 - * specified client elapse some time. 80 + * auto calc the elapse time
78 */ 81 */
79 - virtual void elapse(int64_t time_ms); 82 + virtual void elapse();
80 /** 83 /**
81 * whether current client can print. 84 * whether current client can print.
82 */ 85 */
@@ -84,8 +87,7 @@ public: @@ -84,8 +87,7 @@ public:
84 /** 87 /**
85 * get the elapsed time in ms. 88 * get the elapsed time in ms.
86 */ 89 */
87 - virtual int64_t get_age();  
88 - virtual void set_age(int64_t _age); 90 + virtual int64_t age();
89 }; 91 };
90 92
91 #endif 93 #endif
@@ -297,8 +297,8 @@ int SrsRtmpConn::stream_service_cycle() @@ -297,8 +297,8 @@ int SrsRtmpConn::stream_service_cycle()
297 srs_verbose("start to play stream %s.", req->stream.c_str()); 297 srs_verbose("start to play stream %s.", req->stream.c_str());
298 298
299 if (vhost_is_edge) { 299 if (vhost_is_edge) {
300 - if ((ret = source->on_edge_play_stream()) != ERROR_SUCCESS) {  
301 - srs_error("notice edge play stream failed. ret=%d", ret); 300 + if ((ret = source->on_edge_start_play()) != ERROR_SUCCESS) {
  301 + srs_error("notice edge start play stream failed. ret=%d", ret);
302 return ret; 302 return ret;
303 } 303 }
304 } 304 }
@@ -311,9 +311,11 @@ int SrsRtmpConn::stream_service_cycle() @@ -311,9 +311,11 @@ int SrsRtmpConn::stream_service_cycle()
311 srs_error("http hook on_play failed. ret=%d", ret); 311 srs_error("http hook on_play failed. ret=%d", ret);
312 return ret; 312 return ret;
313 } 313 }
  314 +
314 srs_info("start to play stream %s success", req->stream.c_str()); 315 srs_info("start to play stream %s success", req->stream.c_str());
315 ret = playing(source); 316 ret = playing(source);
316 on_stop(); 317 on_stop();
  318 +
317 return ret; 319 return ret;
318 } 320 }
319 case SrsRtmpConnFMLEPublish: { 321 case SrsRtmpConnFMLEPublish: {
@@ -423,10 +425,10 @@ int SrsRtmpConn::playing(SrsSource* source) @@ -423,10 +425,10 @@ int SrsRtmpConn::playing(SrsSource* source)
423 425
424 int64_t starttime = -1; 426 int64_t starttime = -1;
425 while (true) { 427 while (true) {
426 - pithy_print.elapse(SRS_PULSE_TIMEOUT_US / 1000);  
427 -  
428 // switch to other st-threads. 428 // switch to other st-threads.
429 st_usleep(0); 429 st_usleep(0);
  430 +
  431 + pithy_print.elapse();
430 432
431 // read from client. 433 // read from client.
432 int ctl_msg_ret = ERROR_SUCCESS; 434 int ctl_msg_ret = ERROR_SUCCESS;
@@ -460,7 +462,7 @@ int SrsRtmpConn::playing(SrsSource* source) @@ -460,7 +462,7 @@ int SrsRtmpConn::playing(SrsSource* source)
460 // reportable 462 // reportable
461 if (pithy_print.can_print()) { 463 if (pithy_print.can_print()) {
462 srs_trace("-> time=%"PRId64", duration=%"PRId64", cmr=%d, msgs=%d, obytes=%"PRId64", ibytes=%"PRId64", okbps=%d, ikbps=%d", 464 srs_trace("-> time=%"PRId64", duration=%"PRId64", cmr=%d, msgs=%d, obytes=%"PRId64", ibytes=%"PRId64", okbps=%d, ikbps=%d",
463 - pithy_print.get_age(), duration, ctl_msg_ret, count, rtmp->get_send_bytes(), rtmp->get_recv_bytes(), rtmp->get_send_kbps(), rtmp->get_recv_kbps()); 465 + pithy_print.age(), duration, ctl_msg_ret, count, rtmp->get_send_bytes(), rtmp->get_recv_bytes(), rtmp->get_send_kbps(), rtmp->get_recv_kbps());
464 } 466 }
465 467
466 if (count <= 0) { 468 if (count <= 0) {
@@ -531,14 +533,15 @@ int SrsRtmpConn::fmle_publish(SrsSource* source) @@ -531,14 +533,15 @@ int SrsRtmpConn::fmle_publish(SrsSource* source)
531 return ret; 533 return ret;
532 } 534 }
533 535
  536 + srs_assert(msg);
534 SrsAutoFree(SrsCommonMessage, msg, false); 537 SrsAutoFree(SrsCommonMessage, msg, false);
535 538
536 - pithy_print.set_age(msg->header.timestamp); 539 + pithy_print.elapse();
537 540
538 // reportable 541 // reportable
539 if (pithy_print.can_print()) { 542 if (pithy_print.can_print()) {
540 srs_trace("<- time=%"PRId64", obytes=%"PRId64", ibytes=%"PRId64", okbps=%d, ikbps=%d", 543 srs_trace("<- time=%"PRId64", obytes=%"PRId64", ibytes=%"PRId64", okbps=%d, ikbps=%d",
541 - pithy_print.get_age(), rtmp->get_send_bytes(), rtmp->get_recv_bytes(), rtmp->get_send_kbps(), rtmp->get_recv_kbps()); 544 + pithy_print.age(), rtmp->get_send_bytes(), rtmp->get_recv_bytes(), rtmp->get_send_kbps(), rtmp->get_recv_kbps());
542 } 545 }
543 546
544 // process UnPublish event. 547 // process UnPublish event.
@@ -604,12 +607,12 @@ int SrsRtmpConn::flash_publish(SrsSource* source) @@ -604,12 +607,12 @@ int SrsRtmpConn::flash_publish(SrsSource* source)
604 607
605 SrsAutoFree(SrsCommonMessage, msg, false); 608 SrsAutoFree(SrsCommonMessage, msg, false);
606 609
607 - pithy_print.set_age(msg->header.timestamp); 610 + pithy_print.elapse();
608 611
609 // reportable 612 // reportable
610 if (pithy_print.can_print()) { 613 if (pithy_print.can_print()) {
611 srs_trace("<- time=%"PRId64", obytes=%"PRId64", ibytes=%"PRId64", okbps=%d, ikbps=%d", 614 srs_trace("<- time=%"PRId64", obytes=%"PRId64", ibytes=%"PRId64", okbps=%d, ikbps=%d",
612 - pithy_print.get_age(), rtmp->get_send_bytes(), rtmp->get_recv_bytes(), rtmp->get_send_kbps(), rtmp->get_recv_kbps()); 615 + pithy_print.age(), rtmp->get_send_bytes(), rtmp->get_recv_bytes(), rtmp->get_send_kbps(), rtmp->get_recv_kbps());
613 } 616 }
614 617
615 // process UnPublish event. 618 // process UnPublish event.
@@ -515,7 +515,7 @@ int SrsSource::initialize() @@ -515,7 +515,7 @@ int SrsSource::initialize()
515 } 515 }
516 #endif 516 #endif
517 517
518 - if ((ret = edge->initialize(_req)) != ERROR_SUCCESS) { 518 + if ((ret = edge->initialize(this, _req)) != ERROR_SUCCESS) {
519 return ret; 519 return ret;
520 } 520 }
521 521
@@ -1168,6 +1168,10 @@ void SrsSource::on_consumer_destroy(SrsConsumer* consumer) @@ -1168,6 +1168,10 @@ void SrsSource::on_consumer_destroy(SrsConsumer* consumer)
1168 consumers.erase(it); 1168 consumers.erase(it);
1169 } 1169 }
1170 srs_info("handle consumer destroy success."); 1170 srs_info("handle consumer destroy success.");
  1171 +
  1172 + if (consumers.empty()) {
  1173 + edge->on_all_client_stop();
  1174 + }
1171 } 1175 }
1172 1176
1173 void SrsSource::set_cache(bool enabled) 1177 void SrsSource::set_cache(bool enabled)
@@ -1180,7 +1184,7 @@ bool SrsSource::is_atc() @@ -1180,7 +1184,7 @@ bool SrsSource::is_atc()
1180 return atc; 1184 return atc;
1181 } 1185 }
1182 1186
1183 -int SrsSource::on_edge_play_stream() 1187 +int SrsSource::on_edge_start_play()
1184 { 1188 {
1185 return edge->on_client_play(); 1189 return edge->on_client_play();
1186 } 1190 }
@@ -313,7 +313,7 @@ public: @@ -313,7 +313,7 @@ public:
313 // for consumer, atc feature. 313 // for consumer, atc feature.
314 virtual bool is_atc(); 314 virtual bool is_atc();
315 // for edge, when play edge stream, check the state 315 // for edge, when play edge stream, check the state
316 - virtual int on_edge_play_stream(); 316 + virtual int on_edge_start_play();
317 private: 317 private:
318 virtual int create_forwarders(); 318 virtual int create_forwarders();
319 virtual void destroy_forwarders(); 319 virtual void destroy_forwarders();
@@ -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 "76" 34 +#define VERSION_REVISION "77"
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"
@@ -337,6 +337,11 @@ SrsRtmpClient::~SrsRtmpClient() @@ -337,6 +337,11 @@ SrsRtmpClient::~SrsRtmpClient()
337 srs_freep(hs_bytes); 337 srs_freep(hs_bytes);
338 } 338 }
339 339
  340 +SrsProtocol* SrsRtmpClient::get_protocol()
  341 +{
  342 + return protocol;
  343 +}
  344 +
340 void SrsRtmpClient::set_recv_timeout(int64_t timeout_us) 345 void SrsRtmpClient::set_recv_timeout(int64_t timeout_us)
341 { 346 {
342 protocol->set_recv_timeout(timeout_us); 347 protocol->set_recv_timeout(timeout_us);
@@ -155,6 +155,7 @@ public: @@ -155,6 +155,7 @@ public:
155 SrsRtmpClient(ISrsProtocolReaderWriter* skt); 155 SrsRtmpClient(ISrsProtocolReaderWriter* skt);
156 virtual ~SrsRtmpClient(); 156 virtual ~SrsRtmpClient();
157 public: 157 public:
  158 + virtual SrsProtocol* get_protocol();
158 virtual void set_recv_timeout(int64_t timeout_us); 159 virtual void set_recv_timeout(int64_t timeout_us);
159 virtual void set_send_timeout(int64_t timeout_us); 160 virtual void set_send_timeout(int64_t timeout_us);
160 virtual int64_t get_recv_bytes(); 161 virtual int64_t get_recv_bytes();