winlin

support forward stream to origin/edge

要显示太多修改。

为保证性能只显示 9 of 9+ 个文件。

@@ -47,14 +47,16 @@ m3u8 url: http://127.0.0.1:80/live/livestream.m3u8 @@ -47,14 +47,16 @@ m3u8 url: http://127.0.0.1:80/live/livestream.m3u8
47 8. support cache last gop for flash player to fast startup.<br/> 47 8. support cache last gop for flash player to fast startup.<br/>
48 9. support listen at multiple ports.<br/> 48 9. support listen at multiple ports.<br/>
49 10. support long time(>4.6hours) publish/play.<br/> 49 10. support long time(>4.6hours) publish/play.<br/>
50 -11. [dev] support forward publish stream to build active-standby cluster.<br/>  
51 -12. [plan] support live stream transcoding by ffmpeg.<br/>  
52 -13. [plan] support full http callback api.<br/>  
53 -14. [plan] support network based cli and json result.<br/>  
54 -15. [plan] support bandwidth test api and flash client.<br/>  
55 -16. no edge server, origin server only.<br/>  
56 -17. no vod streaming, live streaming only.<br/>  
57 -18. no multiple processes, single process only.<br/> 50 +11. high performace, 1800 connections(500kbps), 900Mbps, CPU 90.2%, 41MB<br/>
  51 +12. support forward publish stream to build active-standby cluster.<br/>
  52 +13. support broadcast by forward the stream to other servers(origin/edge).<br/>
  53 +14. [plan] support live stream transcoding by ffmpeg.<br/>
  54 +15. [plan] support full http callback api.<br/>
  55 +16. [plan] support network based cli and json result.<br/>
  56 +17. [plan] support bandwidth test api and flash client.<br/>
  57 +18. no edge server, origin server only.<br/>
  58 +19. no vod streaming, live streaming only.<br/>
  59 +20. no multiple processes, single process only.<br/>
58 60
59 ### Performance 61 ### Performance
60 1. 300 connections, 150Mbps, 500kbps, CPU 18.8%, 5956KB. 62 1. 300 connections, 150Mbps, 500kbps, CPU 18.8%, 5956KB.
@@ -15,7 +15,7 @@ vhost __defaultVhost__ { @@ -15,7 +15,7 @@ vhost __defaultVhost__ {
15 hls_path ./objs/nginx/html; 15 hls_path ./objs/nginx/html;
16 hls_fragment 5; 16 hls_fragment 5;
17 hls_window 30; 17 hls_window 30;
18 - forward 192.168.1.50; 18 + forward 127.0.0.1:1936;
19 } 19 }
20 # the vhost which forward publish streams. 20 # the vhost which forward publish streams.
21 vhost forward.vhost.com { 21 vhost forward.vhost.com {
@@ -103,6 +103,9 @@ pithy_print { @@ -103,6 +103,9 @@ pithy_print {
103 publish 2000; 103 publish 2000;
104 # shared print interval for all play clients, in milliseconds. 104 # shared print interval for all play clients, in milliseconds.
105 # if not specified, set to 1300. 105 # if not specified, set to 1300.
106 - play 3000; 106 + play 3000;
  107 + # shared print interval for all forwarders, in milliseconds.
  108 + # if not specified, set to 2000.
  109 + forwarder 3000;
107 } 110 }
108 111
1 -/*  
2 -The MIT License (MIT)  
3 -  
4 -Copyright (c) 2013 winlin  
5 -  
6 -Permission is hereby granted, free of charge, to any person obtaining a copy of  
7 -this software and associated documentation files (the "Software"), to deal in  
8 -the Software without restriction, including without limitation the rights to  
9 -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of  
10 -the Software, and to permit persons to whom the Software is furnished to do so,  
11 -subject to the following conditions:  
12 -  
13 -The above copyright notice and this permission notice shall be included in all  
14 -copies or substantial portions of the Software.  
15 -  
16 -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  
17 -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS  
18 -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR  
19 -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER  
20 -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN  
21 -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  
22 -*/  
23 -  
24 -#include <srs_core_client.hpp>  
25 -  
26 -#include <arpa/inet.h>  
27 -#include <stdlib.h>  
28 -  
29 -#include <srs_core_error.hpp>  
30 -#include <srs_core_log.hpp>  
31 -#include <srs_core_rtmp.hpp>  
32 -#include <srs_core_protocol.hpp>  
33 -#include <srs_core_autofree.hpp>  
34 -#include <srs_core_source.hpp>  
35 -#include <srs_core_server.hpp>  
36 -#include <srs_core_pithy_print.hpp>  
37 -#include <srs_core_config.hpp>  
38 -#include <srs_core_refer.hpp>  
39 -#include <srs_core_hls.hpp>  
40 -  
41 -#define SRS_PULSE_TIMEOUT_MS 100  
42 -#define SRS_SEND_TIMEOUT_US 5000000L  
43 -#define SRS_RECV_TIMEOUT_US SRS_SEND_TIMEOUT_US  
44 -#define SRS_STREAM_BUSY_SLEEP_MS 2000  
45 -  
46 -SrsClient::SrsClient(SrsServer* srs_server, st_netfd_t client_stfd)  
47 - : SrsConnection(srs_server, client_stfd)  
48 -{  
49 - ip = NULL;  
50 - req = new SrsRequest();  
51 - res = new SrsResponse();  
52 - rtmp = new SrsRtmp(client_stfd);  
53 - refer = new SrsRefer();  
54 -}  
55 -  
56 -SrsClient::~SrsClient()  
57 -{  
58 - srs_freepa(ip);  
59 - srs_freep(req);  
60 - srs_freep(res);  
61 - srs_freep(rtmp);  
62 - srs_freep(refer);  
63 -}  
64 -  
65 -// TODO: return detail message when error for client.  
66 -int SrsClient::do_cycle()  
67 -{  
68 - int ret = ERROR_SUCCESS;  
69 -  
70 - if ((ret = get_peer_ip()) != ERROR_SUCCESS) {  
71 - srs_error("get peer ip failed. ret=%d", ret);  
72 - return ret;  
73 - }  
74 - srs_trace("get peer ip success. ip=%s, send_to=%"PRId64", recv_to=%"PRId64"",  
75 - ip, SRS_SEND_TIMEOUT_US, SRS_RECV_TIMEOUT_US);  
76 -  
77 - rtmp->set_recv_timeout(SRS_RECV_TIMEOUT_US);  
78 - rtmp->set_send_timeout(SRS_SEND_TIMEOUT_US);  
79 -  
80 - if ((ret = rtmp->handshake()) != ERROR_SUCCESS) {  
81 - srs_error("rtmp handshake failed. ret=%d", ret);  
82 - return ret;  
83 - }  
84 - srs_verbose("rtmp handshake success");  
85 -  
86 - if ((ret = rtmp->connect_app(req)) != ERROR_SUCCESS) {  
87 - srs_error("rtmp connect vhost/app failed. ret=%d", ret);  
88 - return ret;  
89 - }  
90 - srs_verbose("rtmp connect app success");  
91 -  
92 - if ((ret = check_vhost()) != ERROR_SUCCESS) {  
93 - srs_error("check vhost failed. ret=%d", ret);  
94 - return ret;  
95 - }  
96 - srs_verbose("check vhost success.");  
97 -  
98 - srs_trace("rtmp connect app success. "  
99 - "tcUrl=%s, pageUrl=%s, swfUrl=%s, schema=%s, vhost=%s, port=%s, app=%s",  
100 - req->tcUrl.c_str(), req->pageUrl.c_str(), req->swfUrl.c_str(),  
101 - req->schema.c_str(), req->vhost.c_str(), req->port.c_str(),  
102 - req->app.c_str());  
103 -  
104 - if ((ret = refer->check(req->pageUrl, config->get_refer(req->vhost))) != ERROR_SUCCESS) {  
105 - srs_error("check refer failed. ret=%d", ret);  
106 - return ret;  
107 - }  
108 - srs_verbose("check refer success.");  
109 -  
110 - if ((ret = rtmp->set_window_ack_size(2.5 * 1000 * 1000)) != ERROR_SUCCESS) {  
111 - srs_error("set window acknowledgement size failed. ret=%d", ret);  
112 - return ret;  
113 - }  
114 - srs_verbose("set window acknowledgement size success");  
115 -  
116 - if ((ret = rtmp->set_peer_bandwidth(2.5 * 1000 * 1000, 2)) != ERROR_SUCCESS) {  
117 - srs_error("set peer bandwidth failed. ret=%d", ret);  
118 - return ret;  
119 - }  
120 - srs_verbose("set peer bandwidth success");  
121 -  
122 - if ((ret = rtmp->response_connect_app(req)) != ERROR_SUCCESS) {  
123 - srs_error("response connect app failed. ret=%d", ret);  
124 - return ret;  
125 - }  
126 - srs_verbose("response connect app success");  
127 -  
128 - if ((ret = rtmp->on_bw_done()) != ERROR_SUCCESS) {  
129 - srs_error("on_bw_done failed. ret=%d", ret);  
130 - return ret;  
131 - }  
132 - srs_verbose("on_bw_done success");  
133 -  
134 - SrsClientType type;  
135 - if ((ret = rtmp->identify_client(res->stream_id, type, req->stream)) != ERROR_SUCCESS) {  
136 - srs_error("identify client failed. ret=%d", ret);  
137 - return ret;  
138 - }  
139 - req->strip();  
140 - srs_trace("identify client success. type=%d, stream_name=%s", type, req->stream.c_str());  
141 -  
142 - int chunk_size = 4096;  
143 - SrsConfDirective* conf = config->get_chunk_size();  
144 - if (conf && !conf->arg0().empty()) {  
145 - chunk_size = ::atoi(conf->arg0().c_str());  
146 - }  
147 - if ((ret = rtmp->set_chunk_size(chunk_size)) != ERROR_SUCCESS) {  
148 - srs_error("set chunk_size=%d failed. ret=%d", chunk_size, ret);  
149 - return ret;  
150 - }  
151 - srs_trace("set chunk_size=%d success", chunk_size);  
152 -  
153 - // find a source to publish.  
154 - SrsSource* source = SrsSource::find(req->get_stream_url());  
155 - srs_assert(source != NULL);  
156 -  
157 - // check publish available.  
158 - if (type != SrsClientPlay && !source->can_publish()) {  
159 - ret = ERROR_SYSTEM_STREAM_BUSY;  
160 - srs_warn("stream %s is already publishing. ret=%d",  
161 - req->get_stream_url().c_str(), ret);  
162 - // to delay request  
163 - st_usleep(SRS_STREAM_BUSY_SLEEP_MS * 1000);  
164 - return ret;  
165 - }  
166 -  
167 - bool enabled_cache = true;  
168 - conf = config->get_gop_cache(req->vhost);  
169 - if (conf && conf->arg0() == "off") {  
170 - enabled_cache = false;  
171 - }  
172 - source->set_cache(enabled_cache);  
173 -  
174 - srs_info("source found, url=%s, enabled_cache=%d", req->get_stream_url().c_str(), enabled_cache);  
175 -  
176 - switch (type) {  
177 - case SrsClientPlay: {  
178 - srs_verbose("start to play stream %s.", req->stream.c_str());  
179 -  
180 - if ((ret = rtmp->start_play(res->stream_id)) != ERROR_SUCCESS) {  
181 - srs_error("start to play stream failed. ret=%d", ret);  
182 - return ret;  
183 - }  
184 - srs_info("start to play stream %s success", req->stream.c_str());  
185 - return playing(source);  
186 - }  
187 - case SrsClientFMLEPublish: {  
188 - srs_verbose("FMLE start to publish stream %s.", req->stream.c_str());  
189 -  
190 - if ((ret = rtmp->start_fmle_publish(res->stream_id)) != ERROR_SUCCESS) {  
191 - srs_error("start to publish stream failed. ret=%d", ret);  
192 - return ret;  
193 - }  
194 - srs_info("start to publish stream %s success", req->stream.c_str());  
195 - ret = publish(source, true);  
196 - source->on_unpublish();  
197 - return ret;  
198 - }  
199 - case SrsClientFlashPublish: {  
200 - srs_verbose("flash start to publish stream %s.", req->stream.c_str());  
201 -  
202 - if ((ret = rtmp->start_flash_publish(res->stream_id)) != ERROR_SUCCESS) {  
203 - srs_error("flash start to publish stream failed. ret=%d", ret);  
204 - return ret;  
205 - }  
206 - srs_info("flash start to publish stream %s success", req->stream.c_str());  
207 - ret = publish(source, false);  
208 - source->on_unpublish();  
209 - return ret;  
210 - }  
211 - default: {  
212 - ret = ERROR_SYSTEM_CLIENT_INVALID;  
213 - srs_info("invalid client type=%d. ret=%d", type, ret);  
214 - return ret;  
215 - }  
216 - }  
217 -  
218 - return ret;  
219 -}  
220 -  
221 -int SrsClient::check_vhost()  
222 -{  
223 - int ret = ERROR_SUCCESS;  
224 -  
225 - srs_assert(req != NULL);  
226 -  
227 - SrsConfDirective* vhost = config->get_vhost(req->vhost);  
228 - if (vhost == NULL) {  
229 - ret = ERROR_RTMP_VHOST_NOT_FOUND;  
230 - srs_error("vhost %s not found. ret=%d", req->vhost.c_str(), ret);  
231 - return ret;  
232 - }  
233 -  
234 - SrsConfDirective* conf = NULL;  
235 - if ((conf = config->get_vhost_enabled(req->vhost)) != NULL && conf->arg0() != "on") {  
236 - ret = ERROR_RTMP_VHOST_NOT_FOUND;  
237 - srs_error("vhost %s disabled. ret=%d", req->vhost.c_str(), ret);  
238 - return ret;  
239 - }  
240 -  
241 - if (req->vhost != vhost->arg0()) {  
242 - srs_trace("vhost change from %s to %s", req->vhost.c_str(), vhost->arg0().c_str());  
243 - req->vhost = vhost->arg0();  
244 - }  
245 -  
246 - return ret;  
247 -}  
248 -  
249 -int SrsClient::playing(SrsSource* source)  
250 -{  
251 - int ret = ERROR_SUCCESS;  
252 -  
253 - if ((ret = refer->check(req->pageUrl, config->get_refer_play(req->vhost))) != ERROR_SUCCESS) {  
254 - srs_error("check play_refer failed. ret=%d", ret);  
255 - return ret;  
256 - }  
257 - srs_verbose("check play_refer success.");  
258 -  
259 - SrsConsumer* consumer = NULL;  
260 - if ((ret = source->create_consumer(consumer)) != ERROR_SUCCESS) {  
261 - srs_error("create consumer failed. ret=%d", ret);  
262 - return ret;  
263 - }  
264 -  
265 - srs_assert(consumer != NULL);  
266 - SrsAutoFree(SrsConsumer, consumer, false);  
267 - srs_verbose("consumer created success.");  
268 -  
269 - rtmp->set_recv_timeout(SRS_PULSE_TIMEOUT_MS * 1000);  
270 -  
271 - SrsPithyPrint pithy_print(SRS_STAGE_PLAY_USER);  
272 -  
273 - while (true) {  
274 - pithy_print.elapse(SRS_PULSE_TIMEOUT_MS);  
275 -  
276 - // switch to other st-threads.  
277 - st_usleep(0);  
278 -  
279 - // read from client.  
280 - int ctl_msg_ret = ERROR_SUCCESS;  
281 - if (true) {  
282 - SrsCommonMessage* msg = NULL;  
283 - ctl_msg_ret = ret = rtmp->recv_message(&msg);  
284 -  
285 - srs_verbose("play loop recv message. ret=%d", ret);  
286 - if (ret != ERROR_SUCCESS && ret != ERROR_SOCKET_TIMEOUT) {  
287 - srs_error("recv client control message failed. ret=%d", ret);  
288 - return ret;  
289 - }  
290 - if ((ret = process_play_control_msg(consumer, msg)) != ERROR_SUCCESS) {  
291 - srs_error("process play control message failed. ret=%d", ret);  
292 - return ret;  
293 - }  
294 - }  
295 -  
296 - // get messages from consumer.  
297 - SrsSharedPtrMessage** msgs = NULL;  
298 - int count = 0;  
299 - if ((ret = consumer->get_packets(0, msgs, count)) != ERROR_SUCCESS) {  
300 - srs_error("get messages from consumer failed. ret=%d", ret);  
301 - return ret;  
302 - }  
303 -  
304 - // reportable  
305 - if (pithy_print.can_print()) {  
306 - srs_trace("-> clock=%u, time=%"PRId64", cmr=%d, msgs=%d, obytes=%"PRId64", ibytes=%"PRId64", okbps=%d, ikbps=%d",  
307 - (int)(srs_get_system_time_ms()/1000), pithy_print.get_age(), ctl_msg_ret, count, rtmp->get_send_bytes(), rtmp->get_recv_bytes(), rtmp->get_send_kbps(), rtmp->get_recv_kbps());  
308 - }  
309 -  
310 - if (count <= 0) {  
311 - srs_verbose("no packets in queue.");  
312 - continue;  
313 - }  
314 - SrsAutoFree(SrsSharedPtrMessage*, msgs, true);  
315 -  
316 - // sendout messages  
317 - for (int i = 0; i < count; i++) {  
318 - SrsSharedPtrMessage* msg = msgs[i];  
319 -  
320 - // the send_message will free the msg,  
321 - // so set the msgs[i] to NULL.  
322 - msgs[i] = NULL;  
323 -  
324 - if ((ret = rtmp->send_message(msg)) != ERROR_SUCCESS) {  
325 - srs_error("send message to client failed. ret=%d", ret);  
326 - return ret;  
327 - }  
328 - }  
329 - }  
330 -  
331 - return ret;  
332 -}  
333 -  
334 -int SrsClient::publish(SrsSource* source, bool is_fmle)  
335 -{  
336 - int ret = ERROR_SUCCESS;  
337 -  
338 - if ((ret = refer->check(req->pageUrl, config->get_refer_publish(req->vhost))) != ERROR_SUCCESS) {  
339 - srs_error("check publish_refer failed. ret=%d", ret);  
340 - return ret;  
341 - }  
342 - srs_verbose("check publish_refer success.");  
343 -  
344 - SrsPithyPrint pithy_print(SRS_STAGE_PUBLISH_USER);  
345 -  
346 - // notify the hls to prepare when publish start.  
347 - if ((ret = source->on_publish(req->vhost, req->app, req->stream)) != ERROR_SUCCESS) {  
348 - srs_error("hls on_publish failed. ret=%d", ret);  
349 - return ret;  
350 - }  
351 - srs_verbose("hls on_publish success.");  
352 -  
353 - while (true) {  
354 - // switch to other st-threads.  
355 - st_usleep(0);  
356 -  
357 - SrsCommonMessage* msg = NULL;  
358 - if ((ret = rtmp->recv_message(&msg)) != ERROR_SUCCESS) {  
359 - srs_error("recv identify client message failed. ret=%d", ret);  
360 - return ret;  
361 - }  
362 -  
363 - SrsAutoFree(SrsCommonMessage, msg, false);  
364 -  
365 - pithy_print.set_age(msg->header.timestamp);  
366 -  
367 - // reportable  
368 - if (pithy_print.can_print()) {  
369 - srs_trace("<- clock=%u, time=%"PRId64", obytes=%"PRId64", ibytes=%"PRId64", okbps=%d, ikbps=%d",  
370 - (int)(srs_get_system_time_ms()/1000), pithy_print.get_age(), rtmp->get_send_bytes(), rtmp->get_recv_bytes(), rtmp->get_send_kbps(), rtmp->get_recv_kbps());  
371 - }  
372 -  
373 - if ((ret = process_publish_message(source, msg, is_fmle)) != ERROR_SUCCESS) {  
374 - srs_error("process publish message failed. ret=%d", ret);  
375 - return ret;  
376 - }  
377 - }  
378 -  
379 - return ret;  
380 -}  
381 -  
382 -int SrsClient::process_publish_message(SrsSource* source, SrsCommonMessage* msg, bool is_fmle)  
383 -{  
384 - int ret = ERROR_SUCCESS;  
385 -  
386 - // process audio packet  
387 - if (msg->header.is_audio()) {  
388 - if ((ret = source->on_audio(msg)) != ERROR_SUCCESS) {  
389 - srs_error("source process audio message failed. ret=%d", ret);  
390 - return ret;  
391 - }  
392 - }  
393 - // process video packet  
394 - if (msg->header.is_video()) {  
395 - if ((ret = source->on_video(msg)) != ERROR_SUCCESS) {  
396 - srs_error("source process video message failed. ret=%d", ret);  
397 - return ret;  
398 - }  
399 - }  
400 -  
401 - // process onMetaData  
402 - if (msg->header.is_amf0_data() || msg->header.is_amf3_data()) {  
403 - if ((ret = msg->decode_packet(rtmp->get_protocol())) != ERROR_SUCCESS) {  
404 - srs_error("decode onMetaData message failed. ret=%d", ret);  
405 - return ret;  
406 - }  
407 -  
408 - SrsPacket* pkt = msg->get_packet();  
409 - if (dynamic_cast<SrsOnMetaDataPacket*>(pkt)) {  
410 - SrsOnMetaDataPacket* metadata = dynamic_cast<SrsOnMetaDataPacket*>(pkt);  
411 - if ((ret = source->on_meta_data(msg, metadata)) != ERROR_SUCCESS) {  
412 - srs_error("source process onMetaData message failed. ret=%d", ret);  
413 - return ret;  
414 - }  
415 - srs_trace("process onMetaData message success.");  
416 - return ret;  
417 - }  
418 -  
419 - srs_trace("ignore AMF0/AMF3 data message.");  
420 - return ret;  
421 - }  
422 -  
423 - // process UnPublish event.  
424 - if (msg->header.is_amf0_command() || msg->header.is_amf3_command()) {  
425 - if ((ret = msg->decode_packet(rtmp->get_protocol())) != ERROR_SUCCESS) {  
426 - srs_error("decode unpublish message failed. ret=%d", ret);  
427 - return ret;  
428 - }  
429 -  
430 - // flash unpublish.  
431 - if (!is_fmle) {  
432 - srs_trace("flash publish finished.");  
433 - return ret;  
434 - }  
435 -  
436 - SrsPacket* pkt = msg->get_packet();  
437 - if (dynamic_cast<SrsFMLEStartPacket*>(pkt)) {  
438 - SrsFMLEStartPacket* unpublish = dynamic_cast<SrsFMLEStartPacket*>(pkt);  
439 - return rtmp->fmle_unpublish(res->stream_id, unpublish->transaction_id);  
440 - }  
441 -  
442 - srs_trace("ignore AMF0/AMF3 command message.");  
443 - return ret;  
444 - }  
445 -  
446 - return ret;  
447 -}  
448 -  
449 -int SrsClient::get_peer_ip()  
450 -{  
451 - int ret = ERROR_SUCCESS;  
452 -  
453 - int fd = st_netfd_fileno(stfd);  
454 -  
455 - // discovery client information  
456 - sockaddr_in addr;  
457 - socklen_t addrlen = sizeof(addr);  
458 - if (getpeername(fd, (sockaddr*)&addr, &addrlen) == -1) {  
459 - ret = ERROR_SOCKET_GET_PEER_NAME;  
460 - srs_error("discovery client information failed. ret=%d", ret);  
461 - return ret;  
462 - }  
463 - srs_verbose("get peer name success.");  
464 -  
465 - // ip v4 or v6  
466 - char buf[INET6_ADDRSTRLEN];  
467 - memset(buf, 0, sizeof(buf));  
468 -  
469 - if ((inet_ntop(addr.sin_family, &addr.sin_addr, buf, sizeof(buf))) == NULL) {  
470 - ret = ERROR_SOCKET_GET_PEER_IP;  
471 - srs_error("convert client information failed. ret=%d", ret);  
472 - return ret;  
473 - }  
474 - srs_verbose("get peer ip of client ip=%s, fd=%d", buf, fd);  
475 -  
476 - ip = new char[strlen(buf) + 1];  
477 - strcpy(ip, buf);  
478 -  
479 - srs_verbose("get peer ip success. ip=%s, fd=%d", ip, fd);  
480 -  
481 - return ret;  
482 -}  
483 -  
484 -int SrsClient::process_play_control_msg(SrsConsumer* consumer, SrsCommonMessage* msg)  
485 -{  
486 - int ret = ERROR_SUCCESS;  
487 -  
488 - if (!msg) {  
489 - srs_verbose("ignore all empty message.");  
490 - return ret;  
491 - }  
492 - SrsAutoFree(SrsCommonMessage, msg, false);  
493 -  
494 - if (!msg->header.is_amf0_command() && !msg->header.is_amf3_command()) {  
495 - srs_info("ignore all message except amf0/amf3 command.");  
496 - return ret;  
497 - }  
498 -  
499 - if ((ret = msg->decode_packet(rtmp->get_protocol())) != ERROR_SUCCESS) {  
500 - srs_error("decode the amf0/amf3 command packet failed. ret=%d", ret);  
501 - return ret;  
502 - }  
503 - srs_info("decode the amf0/amf3 command packet success.");  
504 -  
505 - SrsPausePacket* pause = dynamic_cast<SrsPausePacket*>(msg->get_packet());  
506 - if (!pause) {  
507 - srs_info("ignore all amf0/amf3 command except pause.");  
508 - return ret;  
509 - }  
510 -  
511 - if ((ret = rtmp->on_play_client_pause(res->stream_id, pause->is_pause)) != ERROR_SUCCESS) {  
512 - srs_error("rtmp process play client pause failed. ret=%d", ret);  
513 - return ret;  
514 - }  
515 -  
516 - if ((ret = consumer->on_play_client_pause(pause->is_pause)) != ERROR_SUCCESS) {  
517 - srs_error("consumer process play client pause failed. ret=%d", ret);  
518 - return ret;  
519 - }  
520 - srs_info("process pause success, is_pause=%d, time=%d.", pause->is_pause, pause->time_ms);  
521 -  
522 - return ret;  
523 -}  
524 - 1 +/*
  2 +The MIT License (MIT)
  3 +
  4 +Copyright (c) 2013 winlin
  5 +
  6 +Permission is hereby granted, free of charge, to any person obtaining a copy of
  7 +this software and associated documentation files (the "Software"), to deal in
  8 +the Software without restriction, including without limitation the rights to
  9 +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  10 +the Software, and to permit persons to whom the Software is furnished to do so,
  11 +subject to the following conditions:
  12 +
  13 +The above copyright notice and this permission notice shall be included in all
  14 +copies or substantial portions of the Software.
  15 +
  16 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  18 +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  19 +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  20 +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21 +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22 +*/
  23 +
  24 +#include <srs_core_client.hpp>
  25 +
  26 +#include <arpa/inet.h>
  27 +#include <stdlib.h>
  28 +
  29 +#include <srs_core_error.hpp>
  30 +#include <srs_core_log.hpp>
  31 +#include <srs_core_rtmp.hpp>
  32 +#include <srs_core_protocol.hpp>
  33 +#include <srs_core_autofree.hpp>
  34 +#include <srs_core_source.hpp>
  35 +#include <srs_core_server.hpp>
  36 +#include <srs_core_pithy_print.hpp>
  37 +#include <srs_core_config.hpp>
  38 +#include <srs_core_refer.hpp>
  39 +#include <srs_core_hls.hpp>
  40 +
  41 +#define SRS_PULSE_TIMEOUT_MS 100
  42 +#define SRS_SEND_TIMEOUT_US 5000000L
  43 +#define SRS_RECV_TIMEOUT_US SRS_SEND_TIMEOUT_US
  44 +#define SRS_STREAM_BUSY_SLEEP_MS 2000
  45 +
  46 +SrsClient::SrsClient(SrsServer* srs_server, st_netfd_t client_stfd)
  47 + : SrsConnection(srs_server, client_stfd)
  48 +{
  49 + ip = NULL;
  50 + req = new SrsRequest();
  51 + res = new SrsResponse();
  52 + rtmp = new SrsRtmp(client_stfd);
  53 + refer = new SrsRefer();
  54 +}
  55 +
  56 +SrsClient::~SrsClient()
  57 +{
  58 + srs_freepa(ip);
  59 + srs_freep(req);
  60 + srs_freep(res);
  61 + srs_freep(rtmp);
  62 + srs_freep(refer);
  63 +}
  64 +
  65 +// TODO: return detail message when error for client.
  66 +int SrsClient::do_cycle()
  67 +{
  68 + int ret = ERROR_SUCCESS;
  69 +
  70 + if ((ret = get_peer_ip()) != ERROR_SUCCESS) {
  71 + srs_error("get peer ip failed. ret=%d", ret);
  72 + return ret;
  73 + }
  74 + srs_trace("get peer ip success. ip=%s, send_to=%"PRId64", recv_to=%"PRId64"",
  75 + ip, SRS_SEND_TIMEOUT_US, SRS_RECV_TIMEOUT_US);
  76 +
  77 + rtmp->set_recv_timeout(SRS_RECV_TIMEOUT_US);
  78 + rtmp->set_send_timeout(SRS_SEND_TIMEOUT_US);
  79 +
  80 + if ((ret = rtmp->handshake()) != ERROR_SUCCESS) {
  81 + srs_error("rtmp handshake failed. ret=%d", ret);
  82 + return ret;
  83 + }
  84 + srs_verbose("rtmp handshake success");
  85 +
  86 + if ((ret = rtmp->connect_app(req)) != ERROR_SUCCESS) {
  87 + srs_error("rtmp connect vhost/app failed. ret=%d", ret);
  88 + return ret;
  89 + }
  90 + srs_verbose("rtmp connect app success");
  91 +
  92 + if ((ret = check_vhost()) != ERROR_SUCCESS) {
  93 + srs_error("check vhost failed. ret=%d", ret);
  94 + return ret;
  95 + }
  96 + srs_verbose("check vhost success.");
  97 +
  98 + srs_trace("rtmp connect app success. "
  99 + "tcUrl=%s, pageUrl=%s, swfUrl=%s, schema=%s, vhost=%s, port=%s, app=%s",
  100 + req->tcUrl.c_str(), req->pageUrl.c_str(), req->swfUrl.c_str(),
  101 + req->schema.c_str(), req->vhost.c_str(), req->port.c_str(),
  102 + req->app.c_str());
  103 +
  104 + if ((ret = refer->check(req->pageUrl, config->get_refer(req->vhost))) != ERROR_SUCCESS) {
  105 + srs_error("check refer failed. ret=%d", ret);
  106 + return ret;
  107 + }
  108 + srs_verbose("check refer success.");
  109 +
  110 + if ((ret = rtmp->set_window_ack_size(2.5 * 1000 * 1000)) != ERROR_SUCCESS) {
  111 + srs_error("set window acknowledgement size failed. ret=%d", ret);
  112 + return ret;
  113 + }
  114 + srs_verbose("set window acknowledgement size success");
  115 +
  116 + if ((ret = rtmp->set_peer_bandwidth(2.5 * 1000 * 1000, 2)) != ERROR_SUCCESS) {
  117 + srs_error("set peer bandwidth failed. ret=%d", ret);
  118 + return ret;
  119 + }
  120 + srs_verbose("set peer bandwidth success");
  121 +
  122 + if ((ret = rtmp->response_connect_app(req)) != ERROR_SUCCESS) {
  123 + srs_error("response connect app failed. ret=%d", ret);
  124 + return ret;
  125 + }
  126 + srs_verbose("response connect app success");
  127 +
  128 + if ((ret = rtmp->on_bw_done()) != ERROR_SUCCESS) {
  129 + srs_error("on_bw_done failed. ret=%d", ret);
  130 + return ret;
  131 + }
  132 + srs_verbose("on_bw_done success");
  133 +
  134 + SrsClientType type;
  135 + if ((ret = rtmp->identify_client(res->stream_id, type, req->stream)) != ERROR_SUCCESS) {
  136 + srs_error("identify client failed. ret=%d", ret);
  137 + return ret;
  138 + }
  139 + req->strip();
  140 + srs_trace("identify client success. type=%d, stream_name=%s", type, req->stream.c_str());
  141 +
  142 + int chunk_size = 4096;
  143 + SrsConfDirective* conf = config->get_chunk_size();
  144 + if (conf && !conf->arg0().empty()) {
  145 + chunk_size = ::atoi(conf->arg0().c_str());
  146 + }
  147 + if ((ret = rtmp->set_chunk_size(chunk_size)) != ERROR_SUCCESS) {
  148 + srs_error("set chunk_size=%d failed. ret=%d", chunk_size, ret);
  149 + return ret;
  150 + }
  151 + srs_trace("set chunk_size=%d success", chunk_size);
  152 +
  153 + // find a source to publish.
  154 + SrsSource* source = SrsSource::find(req->get_stream_url());
  155 + srs_assert(source != NULL);
  156 +
  157 + // check publish available.
  158 + if (type != SrsClientPlay && !source->can_publish()) {
  159 + ret = ERROR_SYSTEM_STREAM_BUSY;
  160 + srs_warn("stream %s is already publishing. ret=%d",
  161 + req->get_stream_url().c_str(), ret);
  162 + // to delay request
  163 + st_usleep(SRS_STREAM_BUSY_SLEEP_MS * 1000);
  164 + return ret;
  165 + }
  166 +
  167 + bool enabled_cache = true;
  168 + conf = config->get_gop_cache(req->vhost);
  169 + if (conf && conf->arg0() == "off") {
  170 + enabled_cache = false;
  171 + }
  172 + source->set_cache(enabled_cache);
  173 +
  174 + srs_info("source found, url=%s, enabled_cache=%d", req->get_stream_url().c_str(), enabled_cache);
  175 +
  176 + switch (type) {
  177 + case SrsClientPlay: {
  178 + srs_verbose("start to play stream %s.", req->stream.c_str());
  179 +
  180 + if ((ret = rtmp->start_play(res->stream_id)) != ERROR_SUCCESS) {
  181 + srs_error("start to play stream failed. ret=%d", ret);
  182 + return ret;
  183 + }
  184 + srs_info("start to play stream %s success", req->stream.c_str());
  185 + return playing(source);
  186 + }
  187 + case SrsClientFMLEPublish: {
  188 + srs_verbose("FMLE start to publish stream %s.", req->stream.c_str());
  189 +
  190 + if ((ret = rtmp->start_fmle_publish(res->stream_id)) != ERROR_SUCCESS) {
  191 + srs_error("start to publish stream failed. ret=%d", ret);
  192 + return ret;
  193 + }
  194 + srs_info("start to publish stream %s success", req->stream.c_str());
  195 + ret = publish(source, true);
  196 + source->on_unpublish();
  197 + return ret;
  198 + }
  199 + case SrsClientFlashPublish: {
  200 + srs_verbose("flash start to publish stream %s.", req->stream.c_str());
  201 +
  202 + if ((ret = rtmp->start_flash_publish(res->stream_id)) != ERROR_SUCCESS) {
  203 + srs_error("flash start to publish stream failed. ret=%d", ret);
  204 + return ret;
  205 + }
  206 + srs_info("flash start to publish stream %s success", req->stream.c_str());
  207 + ret = publish(source, false);
  208 + source->on_unpublish();
  209 + return ret;
  210 + }
  211 + default: {
  212 + ret = ERROR_SYSTEM_CLIENT_INVALID;
  213 + srs_info("invalid client type=%d. ret=%d", type, ret);
  214 + return ret;
  215 + }
  216 + }
  217 +
  218 + return ret;
  219 +}
  220 +
  221 +int SrsClient::check_vhost()
  222 +{
  223 + int ret = ERROR_SUCCESS;
  224 +
  225 + srs_assert(req != NULL);
  226 +
  227 + SrsConfDirective* vhost = config->get_vhost(req->vhost);
  228 + if (vhost == NULL) {
  229 + ret = ERROR_RTMP_VHOST_NOT_FOUND;
  230 + srs_error("vhost %s not found. ret=%d", req->vhost.c_str(), ret);
  231 + return ret;
  232 + }
  233 +
  234 + SrsConfDirective* conf = NULL;
  235 + if ((conf = config->get_vhost_enabled(req->vhost)) != NULL && conf->arg0() != "on") {
  236 + ret = ERROR_RTMP_VHOST_NOT_FOUND;
  237 + srs_error("vhost %s disabled. ret=%d", req->vhost.c_str(), ret);
  238 + return ret;
  239 + }
  240 +
  241 + if (req->vhost != vhost->arg0()) {
  242 + srs_trace("vhost change from %s to %s", req->vhost.c_str(), vhost->arg0().c_str());
  243 + req->vhost = vhost->arg0();
  244 + }
  245 +
  246 + return ret;
  247 +}
  248 +
  249 +int SrsClient::playing(SrsSource* source)
  250 +{
  251 + int ret = ERROR_SUCCESS;
  252 +
  253 + if ((ret = refer->check(req->pageUrl, config->get_refer_play(req->vhost))) != ERROR_SUCCESS) {
  254 + srs_error("check play_refer failed. ret=%d", ret);
  255 + return ret;
  256 + }
  257 + srs_verbose("check play_refer success.");
  258 +
  259 + SrsConsumer* consumer = NULL;
  260 + if ((ret = source->create_consumer(consumer)) != ERROR_SUCCESS) {
  261 + srs_error("create consumer failed. ret=%d", ret);
  262 + return ret;
  263 + }
  264 +
  265 + srs_assert(consumer != NULL);
  266 + SrsAutoFree(SrsConsumer, consumer, false);
  267 + srs_verbose("consumer created success.");
  268 +
  269 + rtmp->set_recv_timeout(SRS_PULSE_TIMEOUT_MS * 1000);
  270 +
  271 + SrsPithyPrint pithy_print(SRS_STAGE_PLAY_USER);
  272 +
  273 + while (true) {
  274 + pithy_print.elapse(SRS_PULSE_TIMEOUT_MS);
  275 +
  276 + // switch to other st-threads.
  277 + st_usleep(0);
  278 +
  279 + // read from client.
  280 + int ctl_msg_ret = ERROR_SUCCESS;
  281 + if (true) {
  282 + SrsCommonMessage* msg = NULL;
  283 + ctl_msg_ret = ret = rtmp->recv_message(&msg);
  284 +
  285 + srs_verbose("play loop recv message. ret=%d", ret);
  286 + if (ret != ERROR_SUCCESS && ret != ERROR_SOCKET_TIMEOUT) {
  287 + srs_error("recv client control message failed. ret=%d", ret);
  288 + return ret;
  289 + }
  290 + if ((ret = process_play_control_msg(consumer, msg)) != ERROR_SUCCESS) {
  291 + srs_error("process play control message failed. ret=%d", ret);
  292 + return ret;
  293 + }
  294 + }
  295 +
  296 + // get messages from consumer.
  297 + SrsSharedPtrMessage** msgs = NULL;
  298 + int count = 0;
  299 + if ((ret = consumer->get_packets(0, msgs, count)) != ERROR_SUCCESS) {
  300 + srs_error("get messages from consumer failed. ret=%d", ret);
  301 + return ret;
  302 + }
  303 +
  304 + // reportable
  305 + if (pithy_print.can_print()) {
  306 + srs_trace("-> clock=%u, time=%"PRId64", cmr=%d, msgs=%d, obytes=%"PRId64", ibytes=%"PRId64", okbps=%d, ikbps=%d",
  307 + (int)(srs_get_system_time_ms()/1000), pithy_print.get_age(), ctl_msg_ret, count, rtmp->get_send_bytes(), rtmp->get_recv_bytes(), rtmp->get_send_kbps(), rtmp->get_recv_kbps());
  308 + }
  309 +
  310 + if (count <= 0) {
  311 + srs_verbose("no packets in queue.");
  312 + continue;
  313 + }
  314 + SrsAutoFree(SrsSharedPtrMessage*, msgs, true);
  315 +
  316 + // sendout messages
  317 + for (int i = 0; i < count; i++) {
  318 + SrsSharedPtrMessage* msg = msgs[i];
  319 +
  320 + // the send_message will free the msg,
  321 + // so set the msgs[i] to NULL.
  322 + msgs[i] = NULL;
  323 +
  324 + if ((ret = rtmp->send_message(msg)) != ERROR_SUCCESS) {
  325 + srs_error("send message to client failed. ret=%d", ret);
  326 + return ret;
  327 + }
  328 + }
  329 + }
  330 +
  331 + return ret;
  332 +}
  333 +
  334 +int SrsClient::publish(SrsSource* source, bool is_fmle)
  335 +{
  336 + int ret = ERROR_SUCCESS;
  337 +
  338 + if ((ret = refer->check(req->pageUrl, config->get_refer_publish(req->vhost))) != ERROR_SUCCESS) {
  339 + srs_error("check publish_refer failed. ret=%d", ret);
  340 + return ret;
  341 + }
  342 + srs_verbose("check publish_refer success.");
  343 +
  344 + SrsPithyPrint pithy_print(SRS_STAGE_PUBLISH_USER);
  345 +
  346 + // notify the hls to prepare when publish start.
  347 + if ((ret = source->on_publish(req->vhost, req->app, req->stream)) != ERROR_SUCCESS) {
  348 + srs_error("hls on_publish failed. ret=%d", ret);
  349 + return ret;
  350 + }
  351 + srs_verbose("hls on_publish success.");
  352 +
  353 + while (true) {
  354 + // switch to other st-threads.
  355 + st_usleep(0);
  356 +
  357 + SrsCommonMessage* msg = NULL;
  358 + if ((ret = rtmp->recv_message(&msg)) != ERROR_SUCCESS) {
  359 + srs_error("recv identify client message failed. ret=%d", ret);
  360 + return ret;
  361 + }
  362 +
  363 + SrsAutoFree(SrsCommonMessage, msg, false);
  364 +
  365 + pithy_print.set_age(msg->header.timestamp);
  366 +
  367 + // reportable
  368 + if (pithy_print.can_print()) {
  369 + srs_trace("<- clock=%u, time=%"PRId64", obytes=%"PRId64", ibytes=%"PRId64", okbps=%d, ikbps=%d",
  370 + (int)(srs_get_system_time_ms()/1000), pithy_print.get_age(), rtmp->get_send_bytes(), rtmp->get_recv_bytes(), rtmp->get_send_kbps(), rtmp->get_recv_kbps());
  371 + }
  372 +
  373 + if ((ret = process_publish_message(source, msg, is_fmle)) != ERROR_SUCCESS) {
  374 + srs_error("process publish message failed. ret=%d", ret);
  375 + return ret;
  376 + }
  377 + }
  378 +
  379 + return ret;
  380 +}
  381 +
  382 +int SrsClient::process_publish_message(SrsSource* source, SrsCommonMessage* msg, bool is_fmle)
  383 +{
  384 + int ret = ERROR_SUCCESS;
  385 +
  386 + // process audio packet
  387 + if (msg->header.is_audio()) {
  388 + if ((ret = source->on_audio(msg)) != ERROR_SUCCESS) {
  389 + srs_error("source process audio message failed. ret=%d", ret);
  390 + return ret;
  391 + }
  392 + }
  393 + // process video packet
  394 + if (msg->header.is_video()) {
  395 + if ((ret = source->on_video(msg)) != ERROR_SUCCESS) {
  396 + srs_error("source process video message failed. ret=%d", ret);
  397 + return ret;
  398 + }
  399 + }
  400 +
  401 + // process onMetaData
  402 + if (msg->header.is_amf0_data() || msg->header.is_amf3_data()) {
  403 + if ((ret = msg->decode_packet(rtmp->get_protocol())) != ERROR_SUCCESS) {
  404 + srs_error("decode onMetaData message failed. ret=%d", ret);
  405 + return ret;
  406 + }
  407 +
  408 + SrsPacket* pkt = msg->get_packet();
  409 + if (dynamic_cast<SrsOnMetaDataPacket*>(pkt)) {
  410 + SrsOnMetaDataPacket* metadata = dynamic_cast<SrsOnMetaDataPacket*>(pkt);
  411 + if ((ret = source->on_meta_data(msg, metadata)) != ERROR_SUCCESS) {
  412 + srs_error("source process onMetaData message failed. ret=%d", ret);
  413 + return ret;
  414 + }
  415 + srs_trace("process onMetaData message success.");
  416 + return ret;
  417 + }
  418 +
  419 + srs_trace("ignore AMF0/AMF3 data message.");
  420 + return ret;
  421 + }
  422 +
  423 + // process UnPublish event.
  424 + if (msg->header.is_amf0_command() || msg->header.is_amf3_command()) {
  425 + if ((ret = msg->decode_packet(rtmp->get_protocol())) != ERROR_SUCCESS) {
  426 + srs_error("decode unpublish message failed. ret=%d", ret);
  427 + return ret;
  428 + }
  429 +
  430 + // flash unpublish.
  431 + if (!is_fmle) {
  432 + srs_trace("flash publish finished.");
  433 + return ret;
  434 + }
  435 +
  436 + SrsPacket* pkt = msg->get_packet();
  437 + if (dynamic_cast<SrsFMLEStartPacket*>(pkt)) {
  438 + SrsFMLEStartPacket* unpublish = dynamic_cast<SrsFMLEStartPacket*>(pkt);
  439 + return rtmp->fmle_unpublish(res->stream_id, unpublish->transaction_id);
  440 + }
  441 +
  442 + srs_trace("ignore AMF0/AMF3 command message.");
  443 + return ret;
  444 + }
  445 +
  446 + return ret;
  447 +}
  448 +
  449 +int SrsClient::get_peer_ip()
  450 +{
  451 + int ret = ERROR_SUCCESS;
  452 +
  453 + int fd = st_netfd_fileno(stfd);
  454 +
  455 + // discovery client information
  456 + sockaddr_in addr;
  457 + socklen_t addrlen = sizeof(addr);
  458 + if (getpeername(fd, (sockaddr*)&addr, &addrlen) == -1) {
  459 + ret = ERROR_SOCKET_GET_PEER_NAME;
  460 + srs_error("discovery client information failed. ret=%d", ret);
  461 + return ret;
  462 + }
  463 + srs_verbose("get peer name success.");
  464 +
  465 + // ip v4 or v6
  466 + char buf[INET6_ADDRSTRLEN];
  467 + memset(buf, 0, sizeof(buf));
  468 +
  469 + if ((inet_ntop(addr.sin_family, &addr.sin_addr, buf, sizeof(buf))) == NULL) {
  470 + ret = ERROR_SOCKET_GET_PEER_IP;
  471 + srs_error("convert client information failed. ret=%d", ret);
  472 + return ret;
  473 + }
  474 + srs_verbose("get peer ip of client ip=%s, fd=%d", buf, fd);
  475 +
  476 + ip = new char[strlen(buf) + 1];
  477 + strcpy(ip, buf);
  478 +
  479 + srs_verbose("get peer ip success. ip=%s, fd=%d", ip, fd);
  480 +
  481 + return ret;
  482 +}
  483 +
  484 +int SrsClient::process_play_control_msg(SrsConsumer* consumer, SrsCommonMessage* msg)
  485 +{
  486 + int ret = ERROR_SUCCESS;
  487 +
  488 + if (!msg) {
  489 + srs_verbose("ignore all empty message.");
  490 + return ret;
  491 + }
  492 + SrsAutoFree(SrsCommonMessage, msg, false);
  493 +
  494 + if (!msg->header.is_amf0_command() && !msg->header.is_amf3_command()) {
  495 + srs_info("ignore all message except amf0/amf3 command.");
  496 + return ret;
  497 + }
  498 +
  499 + if ((ret = msg->decode_packet(rtmp->get_protocol())) != ERROR_SUCCESS) {
  500 + srs_error("decode the amf0/amf3 command packet failed. ret=%d", ret);
  501 + return ret;
  502 + }
  503 + srs_info("decode the amf0/amf3 command packet success.");
  504 +
  505 + SrsPausePacket* pause = dynamic_cast<SrsPausePacket*>(msg->get_packet());
  506 + if (!pause) {
  507 + srs_info("ignore all amf0/amf3 command except pause.");
  508 + return ret;
  509 + }
  510 +
  511 + if ((ret = rtmp->on_play_client_pause(res->stream_id, pause->is_pause)) != ERROR_SUCCESS) {
  512 + srs_error("rtmp process play client pause failed. ret=%d", ret);
  513 + return ret;
  514 + }
  515 +
  516 + if ((ret = consumer->on_play_client_pause(pause->is_pause)) != ERROR_SUCCESS) {
  517 + srs_error("consumer process play client pause failed. ret=%d", ret);
  518 + return ret;
  519 + }
  520 + srs_info("process pause success, is_pause=%d, time=%d.", pause->is_pause, pause->time_ms);
  521 +
  522 + return ret;
  523 +}
  524 +
1 -/*  
2 -The MIT License (MIT)  
3 -  
4 -Copyright (c) 2013 winlin  
5 -  
6 -Permission is hereby granted, free of charge, to any person obtaining a copy of  
7 -this software and associated documentation files (the "Software"), to deal in  
8 -the Software without restriction, including without limitation the rights to  
9 -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of  
10 -the Software, and to permit persons to whom the Software is furnished to do so,  
11 -subject to the following conditions:  
12 -  
13 -The above copyright notice and this permission notice shall be included in all  
14 -copies or substantial portions of the Software.  
15 -  
16 -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  
17 -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS  
18 -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR  
19 -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER  
20 -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN  
21 -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  
22 -*/  
23 -  
24 -#include <srs_core_config.hpp>  
25 -  
26 -#include <stdio.h>  
27 -#include <stdlib.h>  
28 -#include <errno.h>  
29 -#include <string.h>  
30 -// file operations.  
31 -#include <unistd.h>  
32 -#include <sys/types.h>  
33 -#include <sys/stat.h>  
34 -#include <fcntl.h>  
35 -  
36 -#include <vector>  
37 -#include <algorithm>  
38 -  
39 -#include <srs_core_error.hpp>  
40 -#include <srs_core_log.hpp>  
41 -#include <srs_core_autofree.hpp>  
42 -  
43 -#define FILE_OFFSET(fd) lseek(fd, 0, SEEK_CUR)  
44 -  
45 -int64_t FILE_SIZE(int fd)  
46 -{  
47 - int64_t pre = FILE_OFFSET(fd);  
48 - int64_t pos = lseek(fd, 0, SEEK_END);  
49 - lseek(fd, pre, SEEK_SET);  
50 - return pos;  
51 -}  
52 -  
53 -#define LF (char)0x0a  
54 -#define CR (char)0x0d  
55 -  
56 -bool is_common_space(char ch)  
57 -{  
58 - return (ch == ' ' || ch == '\t' || ch == CR || ch == LF);  
59 -}  
60 -  
61 -#define CONF_BUFFER_SIZE 4096  
62 -  
63 -SrsFileBuffer::SrsFileBuffer()  
64 -{  
65 - fd = -1;  
66 - line = 0;  
67 -  
68 - pos = last = start = new char[CONF_BUFFER_SIZE];  
69 - end = start + CONF_BUFFER_SIZE;  
70 -}  
71 -  
72 -SrsFileBuffer::~SrsFileBuffer()  
73 -{  
74 - if (fd > 0) {  
75 - close(fd);  
76 - }  
77 - srs_freepa(start);  
78 -}  
79 -  
80 -int SrsFileBuffer::open(const char* filename)  
81 -{  
82 - assert(fd == -1);  
83 -  
84 - if ((fd = ::open(filename, O_RDONLY, 0)) < 0) {  
85 - srs_error("open conf file error. errno=%d(%s)", errno, strerror(errno));  
86 - return ERROR_SYSTEM_CONFIG_INVALID;  
87 - }  
88 -  
89 - line = 1;  
90 -  
91 - return ERROR_SUCCESS;  
92 -}  
93 -  
94 -SrsConfDirective::SrsConfDirective()  
95 -{  
96 -}  
97 -  
98 -SrsConfDirective::~SrsConfDirective()  
99 -{  
100 - std::vector<SrsConfDirective*>::iterator it;  
101 - for (it = directives.begin(); it != directives.end(); ++it) {  
102 - SrsConfDirective* directive = *it;  
103 - srs_freep(directive);  
104 - }  
105 - directives.clear();  
106 -}  
107 -  
108 -std::string SrsConfDirective::arg0()  
109 -{  
110 - if (args.size() > 0) {  
111 - return args.at(0);  
112 - }  
113 -  
114 - return "";  
115 -}  
116 -  
117 -std::string SrsConfDirective::arg1()  
118 -{  
119 - if (args.size() > 1) {  
120 - return args.at(1);  
121 - }  
122 -  
123 - return "";  
124 -}  
125 -  
126 -std::string SrsConfDirective::arg2()  
127 -{  
128 - if (args.size() > 2) {  
129 - return args.at(2);  
130 - }  
131 -  
132 - return "";  
133 -}  
134 -  
135 -SrsConfDirective* SrsConfDirective::at(int index)  
136 -{  
137 - return directives.at(index);  
138 -}  
139 -  
140 -SrsConfDirective* SrsConfDirective::get(std::string _name)  
141 -{  
142 - std::vector<SrsConfDirective*>::iterator it;  
143 - for (it = directives.begin(); it != directives.end(); ++it) {  
144 - SrsConfDirective* directive = *it;  
145 - if (directive->name == _name) {  
146 - return directive;  
147 - }  
148 - }  
149 -  
150 - return NULL;  
151 -}  
152 -  
153 -int SrsConfDirective::parse(const char* filename)  
154 -{  
155 - int ret = ERROR_SUCCESS;  
156 -  
157 - SrsFileBuffer buffer;  
158 -  
159 - if ((ret = buffer.open(filename)) != ERROR_SUCCESS) {  
160 - return ret;  
161 - }  
162 -  
163 - return parse_conf(&buffer, parse_file);  
164 -}  
165 -  
166 -// see: ngx_conf_parse  
167 -int SrsConfDirective::parse_conf(SrsFileBuffer* buffer, SrsDirectiveType type)  
168 -{  
169 - int ret = ERROR_SUCCESS;  
170 -  
171 - while (true) {  
172 - std::vector<std::string> args;  
173 - ret = read_token(buffer, args);  
174 -  
175 - /**  
176 - * ret maybe:  
177 - * ERROR_SYSTEM_CONFIG_INVALID error.  
178 - * ERROR_SYSTEM_CONFIG_DIRECTIVE directive terminated by ';' found  
179 - * ERROR_SYSTEM_CONFIG_BLOCK_START token terminated by '{' found  
180 - * ERROR_SYSTEM_CONFIG_BLOCK_END the '}' found  
181 - * ERROR_SYSTEM_CONFIG_EOF the config file is done  
182 - */  
183 - if (ret == ERROR_SYSTEM_CONFIG_INVALID) {  
184 - return ret;  
185 - }  
186 - if (ret == ERROR_SYSTEM_CONFIG_BLOCK_END) {  
187 - if (type != parse_block) {  
188 - srs_error("line %d: unexpected \"}\"", buffer->line);  
189 - return ret;  
190 - }  
191 - return ERROR_SUCCESS;  
192 - }  
193 - if (ret == ERROR_SYSTEM_CONFIG_EOF) {  
194 - if (type == parse_block) {  
195 - srs_error("line %d: unexpected end of file, expecting \"}\"", buffer->line);  
196 - return ret;  
197 - }  
198 - return ERROR_SUCCESS;  
199 - }  
200 -  
201 - if (args.empty()) {  
202 - srs_error("line %d: empty directive.", buffer->line);  
203 - return ret;  
204 - }  
205 -  
206 - // build directive tree.  
207 - SrsConfDirective* directive = new SrsConfDirective();  
208 -  
209 - directive->conf_line = buffer->line;  
210 - directive->name = args[0];  
211 - args.erase(args.begin());  
212 - directive->args.swap(args);  
213 -  
214 - directives.push_back(directive);  
215 -  
216 - if (ret == ERROR_SYSTEM_CONFIG_BLOCK_START) {  
217 - if ((ret = directive->parse_conf(buffer, parse_block)) != ERROR_SUCCESS) {  
218 - return ret;  
219 - }  
220 - }  
221 - }  
222 -  
223 - return ret;  
224 -}  
225 -  
226 -// see: ngx_conf_read_token  
227 -int SrsConfDirective::read_token(SrsFileBuffer* buffer, std::vector<std::string>& args)  
228 -{  
229 - int ret = ERROR_SUCCESS;  
230 -  
231 - char* pstart = buffer->pos;  
232 - int startline = buffer->line;  
233 -  
234 - bool sharp_comment = false;  
235 -  
236 - bool d_quoted = false;  
237 - bool s_quoted = false;  
238 -  
239 - bool need_space = false;  
240 - bool last_space = true;  
241 -  
242 - while (true) {  
243 - if ((ret = refill_buffer(buffer, d_quoted, s_quoted, startline, pstart)) != ERROR_SUCCESS) {  
244 - if (!args.empty() || !last_space) {  
245 - srs_error("line %d: unexpected end of file, expecting ; or \"}\"", buffer->line);  
246 - return ERROR_SYSTEM_CONFIG_INVALID;  
247 - }  
248 - return ret;  
249 - }  
250 -  
251 - char ch = *buffer->pos++;  
252 -  
253 - if (ch == LF) {  
254 - buffer->line++;  
255 - sharp_comment = false;  
256 - }  
257 -  
258 - if (sharp_comment) {  
259 - continue;  
260 - }  
261 -  
262 - if (need_space) {  
263 - if (is_common_space(ch)) {  
264 - last_space = true;  
265 - need_space = false;  
266 - continue;  
267 - }  
268 - if (ch == ';') {  
269 - return ERROR_SYSTEM_CONFIG_DIRECTIVE;  
270 - }  
271 - if (ch == '{') {  
272 - return ERROR_SYSTEM_CONFIG_BLOCK_START;  
273 - }  
274 - srs_error("line %d: unexpected '%c'", buffer->line, ch);  
275 - return ERROR_SYSTEM_CONFIG_INVALID;  
276 - }  
277 -  
278 - // last charecter is space.  
279 - if (last_space) {  
280 - if (is_common_space(ch)) {  
281 - continue;  
282 - }  
283 - pstart = buffer->pos - 1;  
284 - startline = buffer->line;  
285 - switch (ch) {  
286 - case ';':  
287 - if (args.size() == 0) {  
288 - srs_error("line %d: unexpected ';'", buffer->line);  
289 - return ERROR_SYSTEM_CONFIG_INVALID;  
290 - }  
291 - return ERROR_SYSTEM_CONFIG_DIRECTIVE;  
292 - case '{':  
293 - if (args.size() == 0) {  
294 - srs_error("line %d: unexpected '{'", buffer->line);  
295 - return ERROR_SYSTEM_CONFIG_INVALID;  
296 - }  
297 - return ERROR_SYSTEM_CONFIG_BLOCK_START;  
298 - case '}':  
299 - if (args.size() != 0) {  
300 - srs_error("line %d: unexpected '}'", buffer->line);  
301 - return ERROR_SYSTEM_CONFIG_INVALID;  
302 - }  
303 - return ERROR_SYSTEM_CONFIG_BLOCK_END;  
304 - case '#':  
305 - sharp_comment = 1;  
306 - continue;  
307 - case '"':  
308 - pstart++;  
309 - d_quoted = true;  
310 - last_space = 0;  
311 - continue;  
312 - case '\'':  
313 - pstart++;  
314 - s_quoted = true;  
315 - last_space = 0;  
316 - continue;  
317 - default:  
318 - last_space = 0;  
319 - continue;  
320 - }  
321 - } else {  
322 - // last charecter is not space  
323 - bool found = false;  
324 - if (d_quoted) {  
325 - if (ch == '"') {  
326 - d_quoted = false;  
327 - need_space = true;  
328 - found = true;  
329 - }  
330 - } else if (s_quoted) {  
331 - if (ch == '\'') {  
332 - s_quoted = false;  
333 - need_space = true;  
334 - found = true;  
335 - }  
336 - } else if (is_common_space(ch) || ch == ';' || ch == '{') {  
337 - last_space = true;  
338 - found = 1;  
339 - }  
340 -  
341 - if (found) {  
342 - int len = buffer->pos - pstart;  
343 - char* word = new char[len];  
344 - memcpy(word, pstart, len);  
345 - word[len - 1] = 0;  
346 -  
347 - args.push_back(word);  
348 - srs_freepa(word);  
349 -  
350 - if (ch == ';') {  
351 - return ERROR_SYSTEM_CONFIG_DIRECTIVE;  
352 - }  
353 - if (ch == '{') {  
354 - return ERROR_SYSTEM_CONFIG_BLOCK_START;  
355 - }  
356 - }  
357 - }  
358 - }  
359 -  
360 - return ret;  
361 -}  
362 -  
363 -int SrsConfDirective::refill_buffer(SrsFileBuffer* buffer, bool d_quoted, bool s_quoted, int startline, char*& pstart)  
364 -{  
365 - int ret = ERROR_SUCCESS;  
366 -  
367 - if (buffer->pos < buffer->last) {  
368 - return ret;  
369 - }  
370 -  
371 - int size = FILE_SIZE(buffer->fd) - FILE_OFFSET(buffer->fd);  
372 -  
373 - if (size <= 0) {  
374 - return ERROR_SYSTEM_CONFIG_EOF;  
375 - }  
376 -  
377 - int len = buffer->pos - buffer->start;  
378 - if (len >= CONF_BUFFER_SIZE) {  
379 - buffer->line = startline;  
380 -  
381 - if (!d_quoted && !s_quoted) {  
382 - srs_error("line %d: too long parameter \"%*s...\" started",  
383 - buffer->line, 10, buffer->start);  
384 -  
385 - } else {  
386 - srs_error("line %d: too long parameter, "  
387 - "probably missing terminating '%c' character", buffer->line, d_quoted? '"':'\'');  
388 - }  
389 - return ERROR_SYSTEM_CONFIG_INVALID;  
390 - }  
391 -  
392 - if (len) {  
393 - memmove(buffer->start, pstart, len);  
394 - }  
395 -  
396 - size = srs_min(size, buffer->end - (buffer->start + len));  
397 - int n = read(buffer->fd, buffer->start + len, size);  
398 - if (n != size) {  
399 - srs_error("read file read error. expect %d, actual %d bytes.", size, n);  
400 - return ERROR_SYSTEM_CONFIG_INVALID;  
401 - }  
402 -  
403 - buffer->pos = buffer->start + len;  
404 - buffer->last = buffer->pos + n;  
405 - pstart = buffer->start;  
406 -  
407 - return ret;  
408 -}  
409 -  
410 -SrsConfig* config = new SrsConfig();  
411 -  
412 -SrsConfig::SrsConfig()  
413 -{  
414 - show_help = false;  
415 - show_version = false;  
416 -  
417 - root = new SrsConfDirective();  
418 - root->conf_line = 0;  
419 - root->name = "root";  
420 -}  
421 -  
422 -SrsConfig::~SrsConfig()  
423 -{  
424 - srs_freep(root);  
425 -}  
426 -  
427 -int SrsConfig::reload()  
428 -{  
429 - int ret = ERROR_SUCCESS;  
430 -  
431 - SrsConfig conf;  
432 - if ((ret = conf.parse_file(config_file.c_str())) != ERROR_SUCCESS) {  
433 - srs_error("config reloader parse file failed. ret=%d", ret);  
434 - return ret;  
435 - }  
436 - srs_info("config reloader parse file success.");  
437 -  
438 - // store current root to old_root,  
439 - // and reap the root from conf to current root.  
440 - SrsConfDirective* old_root = root;  
441 - SrsAutoFree(SrsConfDirective, old_root, false);  
442 -  
443 - root = conf.root;  
444 - conf.root = NULL;  
445 -  
446 - // merge config.  
447 - std::vector<SrsReloadHandler*>::iterator it;  
448 -  
449 - // merge config: listen  
450 - if (!srs_directive_equals(root->get("listen"), old_root->get("listen"))) {  
451 - for (it = subscribes.begin(); it != subscribes.end(); ++it) {  
452 - SrsReloadHandler* subscribe = *it;  
453 - if ((ret = subscribe->on_reload_listen()) != ERROR_SUCCESS) {  
454 - srs_error("notify subscribes reload listen failed. ret=%d", ret);  
455 - return ret;  
456 - }  
457 - }  
458 - srs_trace("reload listen success.");  
459 - }  
460 - // merge config: pithy_print  
461 - if (!srs_directive_equals(root->get("pithy_print"), old_root->get("pithy_print"))) {  
462 - for (it = subscribes.begin(); it != subscribes.end(); ++it) {  
463 - SrsReloadHandler* subscribe = *it;  
464 - if ((ret = subscribe->on_reload_pithy_print()) != ERROR_SUCCESS) {  
465 - srs_error("notify subscribes pithy_print listen failed. ret=%d", ret);  
466 - return ret;  
467 - }  
468 - }  
469 - srs_trace("reload pithy_print success.");  
470 - }  
471 -  
472 - return ret;  
473 -}  
474 -  
475 -void SrsConfig::subscribe(SrsReloadHandler* handler)  
476 -{  
477 - std::vector<SrsReloadHandler*>::iterator it;  
478 -  
479 - it = std::find(subscribes.begin(), subscribes.end(), handler);  
480 - if (it != subscribes.end()) {  
481 - return;  
482 - }  
483 -  
484 - subscribes.push_back(handler);  
485 -}  
486 -  
487 -void SrsConfig::unsubscribe(SrsReloadHandler* handler)  
488 -{  
489 - std::vector<SrsReloadHandler*>::iterator it;  
490 -  
491 - it = std::find(subscribes.begin(), subscribes.end(), handler);  
492 - if (it == subscribes.end()) {  
493 - return;  
494 - }  
495 -  
496 - subscribes.erase(it);  
497 -}  
498 -  
499 -// see: ngx_get_options  
500 -int SrsConfig::parse_options(int argc, char** argv)  
501 -{  
502 - int ret = ERROR_SUCCESS;  
503 -  
504 - for (int i = 1; i < argc; i++) {  
505 - if ((ret = parse_argv(i, argv)) != ERROR_SUCCESS) {  
506 - return ret;  
507 - }  
508 - }  
509 -  
510 - if (show_help) {  
511 - print_help(argv);  
512 - }  
513 -  
514 - if (show_version) {  
515 - printf("%s\n", RTMP_SIG_SRS_VERSION);  
516 - }  
517 -  
518 - if (show_help || show_version) {  
519 - exit(0);  
520 - }  
521 -  
522 - if (config_file.empty()) {  
523 - ret = ERROR_SYSTEM_CONFIG_INVALID;  
524 - srs_error("config file not specified, see help: %s -h, ret=%d", argv[0], ret);  
525 - return ret;  
526 - }  
527 -  
528 - return parse_file(config_file.c_str());  
529 -}  
530 -  
531 -SrsConfDirective* SrsConfig::get_vhost(std::string vhost)  
532 -{  
533 - srs_assert(root);  
534 -  
535 - for (int i = 0; i < (int)root->directives.size(); i++) {  
536 - SrsConfDirective* conf = root->at(i);  
537 -  
538 - if (conf->name != "vhost") {  
539 - continue;  
540 - }  
541 -  
542 - if (conf->arg0() == vhost) {  
543 - return conf;  
544 - }  
545 - }  
546 -  
547 - if (vhost != RTMP_VHOST_DEFAULT) {  
548 - return get_vhost(RTMP_VHOST_DEFAULT);  
549 - }  
550 -  
551 - return NULL;  
552 -}  
553 -  
554 -SrsConfDirective* SrsConfig::get_vhost_enabled(std::string vhost)  
555 -{  
556 - SrsConfDirective* conf = get_vhost(vhost);  
557 -  
558 - if (!conf) {  
559 - return NULL;  
560 - }  
561 -  
562 - return conf->get("enabled");  
563 -}  
564 -  
565 -SrsConfDirective* SrsConfig::get_gop_cache(std::string vhost)  
566 -{  
567 - SrsConfDirective* conf = get_vhost(vhost);  
568 -  
569 - if (!conf) {  
570 - return NULL;  
571 - }  
572 -  
573 - return conf->get("gop_cache");  
574 -}  
575 -  
576 -SrsConfDirective* SrsConfig::get_forward(std::string vhost)  
577 -{  
578 - SrsConfDirective* conf = get_vhost(vhost);  
579 -  
580 - if (!conf) {  
581 - return NULL;  
582 - }  
583 -  
584 - return conf->get("forward");  
585 -}  
586 -  
587 -SrsConfDirective* SrsConfig::get_hls(std::string vhost)  
588 -{  
589 - SrsConfDirective* conf = get_vhost(vhost);  
590 -  
591 - if (!conf) {  
592 - return NULL;  
593 - }  
594 -  
595 - return conf->get("hls");  
596 -}  
597 -  
598 -SrsConfDirective* SrsConfig::get_hls_path(std::string vhost)  
599 -{  
600 - SrsConfDirective* conf = get_vhost(vhost);  
601 -  
602 - if (!conf) {  
603 - return NULL;  
604 - }  
605 -  
606 - return conf->get("hls_path");  
607 -}  
608 -  
609 -SrsConfDirective* SrsConfig::get_hls_fragment(std::string vhost)  
610 -{  
611 - SrsConfDirective* conf = get_vhost(vhost);  
612 -  
613 - if (!conf) {  
614 - return NULL;  
615 - }  
616 -  
617 - return conf->get("hls_fragment");  
618 -}  
619 -  
620 -SrsConfDirective* SrsConfig::get_hls_window(std::string vhost)  
621 -{  
622 - SrsConfDirective* conf = get_vhost(vhost);  
623 -  
624 - if (!conf) {  
625 - return NULL;  
626 - }  
627 -  
628 - return conf->get("hls_window");  
629 -}  
630 -  
631 -SrsConfDirective* SrsConfig::get_refer(std::string vhost)  
632 -{  
633 - SrsConfDirective* conf = get_vhost(vhost);  
634 -  
635 - if (!conf) {  
636 - return NULL;  
637 - }  
638 -  
639 - return conf->get("refer");  
640 -}  
641 -  
642 -SrsConfDirective* SrsConfig::get_refer_play(std::string vhost)  
643 -{  
644 - SrsConfDirective* conf = get_vhost(vhost);  
645 -  
646 - if (!conf) {  
647 - return NULL;  
648 - }  
649 -  
650 - return conf->get("refer_play");  
651 -}  
652 -  
653 -SrsConfDirective* SrsConfig::get_refer_publish(std::string vhost)  
654 -{  
655 - SrsConfDirective* conf = get_vhost(vhost);  
656 -  
657 - if (!conf) {  
658 - return NULL;  
659 - }  
660 -  
661 - return conf->get("refer_publish");  
662 -}  
663 -  
664 -SrsConfDirective* SrsConfig::get_listen()  
665 -{  
666 - return root->get("listen");  
667 -}  
668 -  
669 -SrsConfDirective* SrsConfig::get_chunk_size()  
670 -{  
671 - return root->get("chunk_size");  
672 -}  
673 -  
674 -SrsConfDirective* SrsConfig::get_pithy_print_publish()  
675 -{  
676 - SrsConfDirective* pithy = root->get("pithy_print");  
677 - if (!pithy) {  
678 - return NULL;  
679 - }  
680 -  
681 - return pithy->get("publish");  
682 -}  
683 -  
684 -SrsConfDirective* SrsConfig::get_pithy_print_play()  
685 -{  
686 - SrsConfDirective* pithy = root->get("pithy_print");  
687 - if (!pithy) {  
688 - return NULL;  
689 - }  
690 -  
691 - return pithy->get("play");  
692 -}  
693 -  
694 -int SrsConfig::parse_file(const char* filename)  
695 -{  
696 - int ret = ERROR_SUCCESS;  
697 -  
698 - config_file = filename;  
699 -  
700 - if (config_file.empty()) {  
701 - return ERROR_SYSTEM_CONFIG_INVALID;  
702 - }  
703 -  
704 - if ((ret = root->parse(config_file.c_str())) != ERROR_SUCCESS) {  
705 - return ret;  
706 - }  
707 -  
708 - SrsConfDirective* conf = NULL;  
709 - if ((conf = get_listen()) == NULL || conf->args.size() == 0) {  
710 - ret = ERROR_SYSTEM_CONFIG_INVALID;  
711 - srs_error("line %d: conf error, "  
712 - "directive \"listen\" is empty, ret=%d", (conf? conf->conf_line:0), ret);  
713 - return ret;  
714 - }  
715 - // TODO: check the hls.  
716 - // TODO: check other config.  
717 - // TODO: check hls.  
718 - // TODO: check ssl.  
719 -  
720 - return ret;  
721 -}  
722 -  
723 -int SrsConfig::parse_argv(int& i, char** argv)  
724 -{  
725 - int ret = ERROR_SUCCESS;  
726 -  
727 - char* p = argv[i];  
728 -  
729 - if (*p++ != '-') {  
730 - ret = ERROR_SYSTEM_CONFIG_INVALID;  
731 - srs_error("invalid options(index=%d, value=%s), "  
732 - "must starts with -, see help: %s -h, ret=%d", i, argv[i], argv[0], ret);  
733 - return ret;  
734 - }  
735 -  
736 - while (*p) {  
737 - switch (*p++) {  
738 - case '?':  
739 - case 'h':  
740 - show_help = true;  
741 - break;  
742 - case 'v':  
743 - case 'V':  
744 - show_version = true;  
745 - break;  
746 - case 'c':  
747 - if (*p) {  
748 - config_file = p;  
749 - return ret;  
750 - }  
751 - if (argv[++i]) {  
752 - config_file = argv[i];  
753 - return ret;  
754 - }  
755 - ret = ERROR_SYSTEM_CONFIG_INVALID;  
756 - srs_error("option \"-c\" requires parameter, ret=%d", ret);  
757 - return ret;  
758 - default:  
759 - ret = ERROR_SYSTEM_CONFIG_INVALID;  
760 - srs_error("invalid option: \"%c\", see help: %s -h, ret=%d", *(p - 1), argv[0], ret);  
761 - return ret;  
762 - }  
763 - }  
764 -  
765 - return ret;  
766 -}  
767 -  
768 -void SrsConfig::print_help(char** argv)  
769 -{  
770 - printf(RTMP_SIG_SRS_NAME" "RTMP_SIG_SRS_VERSION  
771 - " Copyright (c) 2013 winlin\n"  
772 - "configuration: "SRS_CONFIGURE"\n"  
773 - "Usage: %s [-h?vV] [-c <filename>]\n"  
774 - "\n"  
775 - "Options:\n"  
776 - " -?-h : show help\n"  
777 - " -v-V : show version and exit\n"  
778 - " -c filename : set configuration file\n"  
779 - "\n"  
780 - RTMP_SIG_SRS_WEB"\n"  
781 - RTMP_SIG_SRS_URL"\n"  
782 - "Email: "RTMP_SIG_SRS_EMAIL"\n"  
783 - "\n",  
784 - argv[0]);  
785 -}  
786 -  
787 -bool srs_directive_equals(SrsConfDirective* a, SrsConfDirective* b)  
788 -{  
789 - if (!a || !b) {  
790 - return false;  
791 - }  
792 -  
793 - if (a->name != b->name) {  
794 - return false;  
795 - }  
796 -  
797 - if (a->args.size() != b->args.size()) {  
798 - return false;  
799 - }  
800 -  
801 - for (int i = 0; i < (int)a->args.size(); i++) {  
802 - if (a->args.at(i) != b->args.at(i)) {  
803 - return false;  
804 - }  
805 - }  
806 -  
807 - if (a->directives.size() != b->directives.size()) {  
808 - return false;  
809 - }  
810 -  
811 - for (int i = 0; i < (int)a->directives.size(); i++) {  
812 - SrsConfDirective* a0 = a->at(i);  
813 - SrsConfDirective* b0 = b->at(i);  
814 -  
815 - if (!srs_directive_equals(a0, b0)) {  
816 - return false;  
817 - }  
818 - }  
819 -  
820 - return true;  
821 -}  
822 - 1 +/*
  2 +The MIT License (MIT)
  3 +
  4 +Copyright (c) 2013 winlin
  5 +
  6 +Permission is hereby granted, free of charge, to any person obtaining a copy of
  7 +this software and associated documentation files (the "Software"), to deal in
  8 +the Software without restriction, including without limitation the rights to
  9 +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  10 +the Software, and to permit persons to whom the Software is furnished to do so,
  11 +subject to the following conditions:
  12 +
  13 +The above copyright notice and this permission notice shall be included in all
  14 +copies or substantial portions of the Software.
  15 +
  16 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  18 +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  19 +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  20 +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21 +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22 +*/
  23 +
  24 +#include <srs_core_config.hpp>
  25 +
  26 +#include <stdio.h>
  27 +#include <stdlib.h>
  28 +#include <errno.h>
  29 +#include <string.h>
  30 +// file operations.
  31 +#include <unistd.h>
  32 +#include <sys/types.h>
  33 +#include <sys/stat.h>
  34 +#include <fcntl.h>
  35 +
  36 +#include <vector>
  37 +#include <algorithm>
  38 +
  39 +#include <srs_core_error.hpp>
  40 +#include <srs_core_log.hpp>
  41 +#include <srs_core_autofree.hpp>
  42 +
  43 +#define FILE_OFFSET(fd) lseek(fd, 0, SEEK_CUR)
  44 +
  45 +int64_t FILE_SIZE(int fd)
  46 +{
  47 + int64_t pre = FILE_OFFSET(fd);
  48 + int64_t pos = lseek(fd, 0, SEEK_END);
  49 + lseek(fd, pre, SEEK_SET);
  50 + return pos;
  51 +}
  52 +
  53 +#define LF (char)0x0a
  54 +#define CR (char)0x0d
  55 +
  56 +bool is_common_space(char ch)
  57 +{
  58 + return (ch == ' ' || ch == '\t' || ch == CR || ch == LF);
  59 +}
  60 +
  61 +#define CONF_BUFFER_SIZE 4096
  62 +
  63 +SrsFileBuffer::SrsFileBuffer()
  64 +{
  65 + fd = -1;
  66 + line = 0;
  67 +
  68 + pos = last = start = new char[CONF_BUFFER_SIZE];
  69 + end = start + CONF_BUFFER_SIZE;
  70 +}
  71 +
  72 +SrsFileBuffer::~SrsFileBuffer()
  73 +{
  74 + if (fd > 0) {
  75 + close(fd);
  76 + }
  77 + srs_freepa(start);
  78 +}
  79 +
  80 +int SrsFileBuffer::open(const char* filename)
  81 +{
  82 + assert(fd == -1);
  83 +
  84 + if ((fd = ::open(filename, O_RDONLY, 0)) < 0) {
  85 + srs_error("open conf file error. errno=%d(%s)", errno, strerror(errno));
  86 + return ERROR_SYSTEM_CONFIG_INVALID;
  87 + }
  88 +
  89 + line = 1;
  90 +
  91 + return ERROR_SUCCESS;
  92 +}
  93 +
  94 +SrsConfDirective::SrsConfDirective()
  95 +{
  96 +}
  97 +
  98 +SrsConfDirective::~SrsConfDirective()
  99 +{
  100 + std::vector<SrsConfDirective*>::iterator it;
  101 + for (it = directives.begin(); it != directives.end(); ++it) {
  102 + SrsConfDirective* directive = *it;
  103 + srs_freep(directive);
  104 + }
  105 + directives.clear();
  106 +}
  107 +
  108 +std::string SrsConfDirective::arg0()
  109 +{
  110 + if (args.size() > 0) {
  111 + return args.at(0);
  112 + }
  113 +
  114 + return "";
  115 +}
  116 +
  117 +std::string SrsConfDirective::arg1()
  118 +{
  119 + if (args.size() > 1) {
  120 + return args.at(1);
  121 + }
  122 +
  123 + return "";
  124 +}
  125 +
  126 +std::string SrsConfDirective::arg2()
  127 +{
  128 + if (args.size() > 2) {
  129 + return args.at(2);
  130 + }
  131 +
  132 + return "";
  133 +}
  134 +
  135 +SrsConfDirective* SrsConfDirective::at(int index)
  136 +{
  137 + return directives.at(index);
  138 +}
  139 +
  140 +SrsConfDirective* SrsConfDirective::get(std::string _name)
  141 +{
  142 + std::vector<SrsConfDirective*>::iterator it;
  143 + for (it = directives.begin(); it != directives.end(); ++it) {
  144 + SrsConfDirective* directive = *it;
  145 + if (directive->name == _name) {
  146 + return directive;
  147 + }
  148 + }
  149 +
  150 + return NULL;
  151 +}
  152 +
  153 +int SrsConfDirective::parse(const char* filename)
  154 +{
  155 + int ret = ERROR_SUCCESS;
  156 +
  157 + SrsFileBuffer buffer;
  158 +
  159 + if ((ret = buffer.open(filename)) != ERROR_SUCCESS) {
  160 + return ret;
  161 + }
  162 +
  163 + return parse_conf(&buffer, parse_file);
  164 +}
  165 +
  166 +// see: ngx_conf_parse
  167 +int SrsConfDirective::parse_conf(SrsFileBuffer* buffer, SrsDirectiveType type)
  168 +{
  169 + int ret = ERROR_SUCCESS;
  170 +
  171 + while (true) {
  172 + std::vector<std::string> args;
  173 + ret = read_token(buffer, args);
  174 +
  175 + /**
  176 + * ret maybe:
  177 + * ERROR_SYSTEM_CONFIG_INVALID error.
  178 + * ERROR_SYSTEM_CONFIG_DIRECTIVE directive terminated by ';' found
  179 + * ERROR_SYSTEM_CONFIG_BLOCK_START token terminated by '{' found
  180 + * ERROR_SYSTEM_CONFIG_BLOCK_END the '}' found
  181 + * ERROR_SYSTEM_CONFIG_EOF the config file is done
  182 + */
  183 + if (ret == ERROR_SYSTEM_CONFIG_INVALID) {
  184 + return ret;
  185 + }
  186 + if (ret == ERROR_SYSTEM_CONFIG_BLOCK_END) {
  187 + if (type != parse_block) {
  188 + srs_error("line %d: unexpected \"}\"", buffer->line);
  189 + return ret;
  190 + }
  191 + return ERROR_SUCCESS;
  192 + }
  193 + if (ret == ERROR_SYSTEM_CONFIG_EOF) {
  194 + if (type == parse_block) {
  195 + srs_error("line %d: unexpected end of file, expecting \"}\"", buffer->line);
  196 + return ret;
  197 + }
  198 + return ERROR_SUCCESS;
  199 + }
  200 +
  201 + if (args.empty()) {
  202 + srs_error("line %d: empty directive.", buffer->line);
  203 + return ret;
  204 + }
  205 +
  206 + // build directive tree.
  207 + SrsConfDirective* directive = new SrsConfDirective();
  208 +
  209 + directive->conf_line = buffer->line;
  210 + directive->name = args[0];
  211 + args.erase(args.begin());
  212 + directive->args.swap(args);
  213 +
  214 + directives.push_back(directive);
  215 +
  216 + if (ret == ERROR_SYSTEM_CONFIG_BLOCK_START) {
  217 + if ((ret = directive->parse_conf(buffer, parse_block)) != ERROR_SUCCESS) {
  218 + return ret;
  219 + }
  220 + }
  221 + }
  222 +
  223 + return ret;
  224 +}
  225 +
  226 +// see: ngx_conf_read_token
  227 +int SrsConfDirective::read_token(SrsFileBuffer* buffer, std::vector<std::string>& args)
  228 +{
  229 + int ret = ERROR_SUCCESS;
  230 +
  231 + char* pstart = buffer->pos;
  232 + int startline = buffer->line;
  233 +
  234 + bool sharp_comment = false;
  235 +
  236 + bool d_quoted = false;
  237 + bool s_quoted = false;
  238 +
  239 + bool need_space = false;
  240 + bool last_space = true;
  241 +
  242 + while (true) {
  243 + if ((ret = refill_buffer(buffer, d_quoted, s_quoted, startline, pstart)) != ERROR_SUCCESS) {
  244 + if (!args.empty() || !last_space) {
  245 + srs_error("line %d: unexpected end of file, expecting ; or \"}\"", buffer->line);
  246 + return ERROR_SYSTEM_CONFIG_INVALID;
  247 + }
  248 + return ret;
  249 + }
  250 +
  251 + char ch = *buffer->pos++;
  252 +
  253 + if (ch == LF) {
  254 + buffer->line++;
  255 + sharp_comment = false;
  256 + }
  257 +
  258 + if (sharp_comment) {
  259 + continue;
  260 + }
  261 +
  262 + if (need_space) {
  263 + if (is_common_space(ch)) {
  264 + last_space = true;
  265 + need_space = false;
  266 + continue;
  267 + }
  268 + if (ch == ';') {
  269 + return ERROR_SYSTEM_CONFIG_DIRECTIVE;
  270 + }
  271 + if (ch == '{') {
  272 + return ERROR_SYSTEM_CONFIG_BLOCK_START;
  273 + }
  274 + srs_error("line %d: unexpected '%c'", buffer->line, ch);
  275 + return ERROR_SYSTEM_CONFIG_INVALID;
  276 + }
  277 +
  278 + // last charecter is space.
  279 + if (last_space) {
  280 + if (is_common_space(ch)) {
  281 + continue;
  282 + }
  283 + pstart = buffer->pos - 1;
  284 + startline = buffer->line;
  285 + switch (ch) {
  286 + case ';':
  287 + if (args.size() == 0) {
  288 + srs_error("line %d: unexpected ';'", buffer->line);
  289 + return ERROR_SYSTEM_CONFIG_INVALID;
  290 + }
  291 + return ERROR_SYSTEM_CONFIG_DIRECTIVE;
  292 + case '{':
  293 + if (args.size() == 0) {
  294 + srs_error("line %d: unexpected '{'", buffer->line);
  295 + return ERROR_SYSTEM_CONFIG_INVALID;
  296 + }
  297 + return ERROR_SYSTEM_CONFIG_BLOCK_START;
  298 + case '}':
  299 + if (args.size() != 0) {
  300 + srs_error("line %d: unexpected '}'", buffer->line);
  301 + return ERROR_SYSTEM_CONFIG_INVALID;
  302 + }
  303 + return ERROR_SYSTEM_CONFIG_BLOCK_END;
  304 + case '#':
  305 + sharp_comment = 1;
  306 + continue;
  307 + case '"':
  308 + pstart++;
  309 + d_quoted = true;
  310 + last_space = 0;
  311 + continue;
  312 + case '\'':
  313 + pstart++;
  314 + s_quoted = true;
  315 + last_space = 0;
  316 + continue;
  317 + default:
  318 + last_space = 0;
  319 + continue;
  320 + }
  321 + } else {
  322 + // last charecter is not space
  323 + bool found = false;
  324 + if (d_quoted) {
  325 + if (ch == '"') {
  326 + d_quoted = false;
  327 + need_space = true;
  328 + found = true;
  329 + }
  330 + } else if (s_quoted) {
  331 + if (ch == '\'') {
  332 + s_quoted = false;
  333 + need_space = true;
  334 + found = true;
  335 + }
  336 + } else if (is_common_space(ch) || ch == ';' || ch == '{') {
  337 + last_space = true;
  338 + found = 1;
  339 + }
  340 +
  341 + if (found) {
  342 + int len = buffer->pos - pstart;
  343 + char* word = new char[len];
  344 + memcpy(word, pstart, len);
  345 + word[len - 1] = 0;
  346 +
  347 + args.push_back(word);
  348 + srs_freepa(word);
  349 +
  350 + if (ch == ';') {
  351 + return ERROR_SYSTEM_CONFIG_DIRECTIVE;
  352 + }
  353 + if (ch == '{') {
  354 + return ERROR_SYSTEM_CONFIG_BLOCK_START;
  355 + }
  356 + }
  357 + }
  358 + }
  359 +
  360 + return ret;
  361 +}
  362 +
  363 +int SrsConfDirective::refill_buffer(SrsFileBuffer* buffer, bool d_quoted, bool s_quoted, int startline, char*& pstart)
  364 +{
  365 + int ret = ERROR_SUCCESS;
  366 +
  367 + if (buffer->pos < buffer->last) {
  368 + return ret;
  369 + }
  370 +
  371 + int size = FILE_SIZE(buffer->fd) - FILE_OFFSET(buffer->fd);
  372 +
  373 + if (size <= 0) {
  374 + return ERROR_SYSTEM_CONFIG_EOF;
  375 + }
  376 +
  377 + int len = buffer->pos - buffer->start;
  378 + if (len >= CONF_BUFFER_SIZE) {
  379 + buffer->line = startline;
  380 +
  381 + if (!d_quoted && !s_quoted) {
  382 + srs_error("line %d: too long parameter \"%*s...\" started",
  383 + buffer->line, 10, buffer->start);
  384 +
  385 + } else {
  386 + srs_error("line %d: too long parameter, "
  387 + "probably missing terminating '%c' character", buffer->line, d_quoted? '"':'\'');
  388 + }
  389 + return ERROR_SYSTEM_CONFIG_INVALID;
  390 + }
  391 +
  392 + if (len) {
  393 + memmove(buffer->start, pstart, len);
  394 + }
  395 +
  396 + size = srs_min(size, buffer->end - (buffer->start + len));
  397 + int n = read(buffer->fd, buffer->start + len, size);
  398 + if (n != size) {
  399 + srs_error("read file read error. expect %d, actual %d bytes.", size, n);
  400 + return ERROR_SYSTEM_CONFIG_INVALID;
  401 + }
  402 +
  403 + buffer->pos = buffer->start + len;
  404 + buffer->last = buffer->pos + n;
  405 + pstart = buffer->start;
  406 +
  407 + return ret;
  408 +}
  409 +
  410 +SrsConfig* config = new SrsConfig();
  411 +
  412 +SrsConfig::SrsConfig()
  413 +{
  414 + show_help = false;
  415 + show_version = false;
  416 +
  417 + root = new SrsConfDirective();
  418 + root->conf_line = 0;
  419 + root->name = "root";
  420 +}
  421 +
  422 +SrsConfig::~SrsConfig()
  423 +{
  424 + srs_freep(root);
  425 +}
  426 +
  427 +int SrsConfig::reload()
  428 +{
  429 + int ret = ERROR_SUCCESS;
  430 +
  431 + SrsConfig conf;
  432 + if ((ret = conf.parse_file(config_file.c_str())) != ERROR_SUCCESS) {
  433 + srs_error("config reloader parse file failed. ret=%d", ret);
  434 + return ret;
  435 + }
  436 + srs_info("config reloader parse file success.");
  437 +
  438 + // store current root to old_root,
  439 + // and reap the root from conf to current root.
  440 + SrsConfDirective* old_root = root;
  441 + SrsAutoFree(SrsConfDirective, old_root, false);
  442 +
  443 + root = conf.root;
  444 + conf.root = NULL;
  445 +
  446 + // merge config.
  447 + std::vector<SrsReloadHandler*>::iterator it;
  448 +
  449 + // merge config: listen
  450 + if (!srs_directive_equals(root->get("listen"), old_root->get("listen"))) {
  451 + for (it = subscribes.begin(); it != subscribes.end(); ++it) {
  452 + SrsReloadHandler* subscribe = *it;
  453 + if ((ret = subscribe->on_reload_listen()) != ERROR_SUCCESS) {
  454 + srs_error("notify subscribes reload listen failed. ret=%d", ret);
  455 + return ret;
  456 + }
  457 + }
  458 + srs_trace("reload listen success.");
  459 + }
  460 + // merge config: pithy_print
  461 + if (!srs_directive_equals(root->get("pithy_print"), old_root->get("pithy_print"))) {
  462 + for (it = subscribes.begin(); it != subscribes.end(); ++it) {
  463 + SrsReloadHandler* subscribe = *it;
  464 + if ((ret = subscribe->on_reload_pithy_print()) != ERROR_SUCCESS) {
  465 + srs_error("notify subscribes pithy_print listen failed. ret=%d", ret);
  466 + return ret;
  467 + }
  468 + }
  469 + srs_trace("reload pithy_print success.");
  470 + }
  471 +
  472 + return ret;
  473 +}
  474 +
  475 +void SrsConfig::subscribe(SrsReloadHandler* handler)
  476 +{
  477 + std::vector<SrsReloadHandler*>::iterator it;
  478 +
  479 + it = std::find(subscribes.begin(), subscribes.end(), handler);
  480 + if (it != subscribes.end()) {
  481 + return;
  482 + }
  483 +
  484 + subscribes.push_back(handler);
  485 +}
  486 +
  487 +void SrsConfig::unsubscribe(SrsReloadHandler* handler)
  488 +{
  489 + std::vector<SrsReloadHandler*>::iterator it;
  490 +
  491 + it = std::find(subscribes.begin(), subscribes.end(), handler);
  492 + if (it == subscribes.end()) {
  493 + return;
  494 + }
  495 +
  496 + subscribes.erase(it);
  497 +}
  498 +
  499 +// see: ngx_get_options
  500 +int SrsConfig::parse_options(int argc, char** argv)
  501 +{
  502 + int ret = ERROR_SUCCESS;
  503 +
  504 + for (int i = 1; i < argc; i++) {
  505 + if ((ret = parse_argv(i, argv)) != ERROR_SUCCESS) {
  506 + return ret;
  507 + }
  508 + }
  509 +
  510 + if (show_help) {
  511 + print_help(argv);
  512 + }
  513 +
  514 + if (show_version) {
  515 + printf("%s\n", RTMP_SIG_SRS_VERSION);
  516 + }
  517 +
  518 + if (show_help || show_version) {
  519 + exit(0);
  520 + }
  521 +
  522 + if (config_file.empty()) {
  523 + ret = ERROR_SYSTEM_CONFIG_INVALID;
  524 + srs_error("config file not specified, see help: %s -h, ret=%d", argv[0], ret);
  525 + return ret;
  526 + }
  527 +
  528 + return parse_file(config_file.c_str());
  529 +}
  530 +
  531 +SrsConfDirective* SrsConfig::get_vhost(std::string vhost)
  532 +{
  533 + srs_assert(root);
  534 +
  535 + for (int i = 0; i < (int)root->directives.size(); i++) {
  536 + SrsConfDirective* conf = root->at(i);
  537 +
  538 + if (conf->name != "vhost") {
  539 + continue;
  540 + }
  541 +
  542 + if (conf->arg0() == vhost) {
  543 + return conf;
  544 + }
  545 + }
  546 +
  547 + if (vhost != RTMP_VHOST_DEFAULT) {
  548 + return get_vhost(RTMP_VHOST_DEFAULT);
  549 + }
  550 +
  551 + return NULL;
  552 +}
  553 +
  554 +SrsConfDirective* SrsConfig::get_vhost_enabled(std::string vhost)
  555 +{
  556 + SrsConfDirective* conf = get_vhost(vhost);
  557 +
  558 + if (!conf) {
  559 + return NULL;
  560 + }
  561 +
  562 + return conf->get("enabled");
  563 +}
  564 +
  565 +SrsConfDirective* SrsConfig::get_gop_cache(std::string vhost)
  566 +{
  567 + SrsConfDirective* conf = get_vhost(vhost);
  568 +
  569 + if (!conf) {
  570 + return NULL;
  571 + }
  572 +
  573 + return conf->get("gop_cache");
  574 +}
  575 +
  576 +SrsConfDirective* SrsConfig::get_forward(std::string vhost)
  577 +{
  578 + SrsConfDirective* conf = get_vhost(vhost);
  579 +
  580 + if (!conf) {
  581 + return NULL;
  582 + }
  583 +
  584 + return conf->get("forward");
  585 +}
  586 +
  587 +SrsConfDirective* SrsConfig::get_hls(std::string vhost)
  588 +{
  589 + SrsConfDirective* conf = get_vhost(vhost);
  590 +
  591 + if (!conf) {
  592 + return NULL;
  593 + }
  594 +
  595 + return conf->get("hls");
  596 +}
  597 +
  598 +SrsConfDirective* SrsConfig::get_hls_path(std::string vhost)
  599 +{
  600 + SrsConfDirective* conf = get_vhost(vhost);
  601 +
  602 + if (!conf) {
  603 + return NULL;
  604 + }
  605 +
  606 + return conf->get("hls_path");
  607 +}
  608 +
  609 +SrsConfDirective* SrsConfig::get_hls_fragment(std::string vhost)
  610 +{
  611 + SrsConfDirective* conf = get_vhost(vhost);
  612 +
  613 + if (!conf) {
  614 + return NULL;
  615 + }
  616 +
  617 + return conf->get("hls_fragment");
  618 +}
  619 +
  620 +SrsConfDirective* SrsConfig::get_hls_window(std::string vhost)
  621 +{
  622 + SrsConfDirective* conf = get_vhost(vhost);
  623 +
  624 + if (!conf) {
  625 + return NULL;
  626 + }
  627 +
  628 + return conf->get("hls_window");
  629 +}
  630 +
  631 +SrsConfDirective* SrsConfig::get_refer(std::string vhost)
  632 +{
  633 + SrsConfDirective* conf = get_vhost(vhost);
  634 +
  635 + if (!conf) {
  636 + return NULL;
  637 + }
  638 +
  639 + return conf->get("refer");
  640 +}
  641 +
  642 +SrsConfDirective* SrsConfig::get_refer_play(std::string vhost)
  643 +{
  644 + SrsConfDirective* conf = get_vhost(vhost);
  645 +
  646 + if (!conf) {
  647 + return NULL;
  648 + }
  649 +
  650 + return conf->get("refer_play");
  651 +}
  652 +
  653 +SrsConfDirective* SrsConfig::get_refer_publish(std::string vhost)
  654 +{
  655 + SrsConfDirective* conf = get_vhost(vhost);
  656 +
  657 + if (!conf) {
  658 + return NULL;
  659 + }
  660 +
  661 + return conf->get("refer_publish");
  662 +}
  663 +
  664 +SrsConfDirective* SrsConfig::get_listen()
  665 +{
  666 + return root->get("listen");
  667 +}
  668 +
  669 +SrsConfDirective* SrsConfig::get_chunk_size()
  670 +{
  671 + return root->get("chunk_size");
  672 +}
  673 +
  674 +SrsConfDirective* SrsConfig::get_pithy_print_publish()
  675 +{
  676 + SrsConfDirective* pithy = root->get("pithy_print");
  677 + if (!pithy) {
  678 + return NULL;
  679 + }
  680 +
  681 + return pithy->get("publish");
  682 +}
  683 +
  684 +SrsConfDirective* SrsConfig::get_pithy_print_forwarder()
  685 +{
  686 + SrsConfDirective* pithy = root->get("pithy_print");
  687 + if (!pithy) {
  688 + return NULL;
  689 + }
  690 +
  691 + return pithy->get("forwarder");
  692 +}
  693 +
  694 +SrsConfDirective* SrsConfig::get_pithy_print_play()
  695 +{
  696 + SrsConfDirective* pithy = root->get("pithy_print");
  697 + if (!pithy) {
  698 + return NULL;
  699 + }
  700 +
  701 + return pithy->get("play");
  702 +}
  703 +
  704 +int SrsConfig::parse_file(const char* filename)
  705 +{
  706 + int ret = ERROR_SUCCESS;
  707 +
  708 + config_file = filename;
  709 +
  710 + if (config_file.empty()) {
  711 + return ERROR_SYSTEM_CONFIG_INVALID;
  712 + }
  713 +
  714 + if ((ret = root->parse(config_file.c_str())) != ERROR_SUCCESS) {
  715 + return ret;
  716 + }
  717 +
  718 + SrsConfDirective* conf = NULL;
  719 + if ((conf = get_listen()) == NULL || conf->args.size() == 0) {
  720 + ret = ERROR_SYSTEM_CONFIG_INVALID;
  721 + srs_error("line %d: conf error, "
  722 + "directive \"listen\" is empty, ret=%d", (conf? conf->conf_line:0), ret);
  723 + return ret;
  724 + }
  725 + // TODO: check the hls.
  726 + // TODO: check other config.
  727 + // TODO: check hls.
  728 + // TODO: check ssl.
  729 +
  730 + return ret;
  731 +}
  732 +
  733 +int SrsConfig::parse_argv(int& i, char** argv)
  734 +{
  735 + int ret = ERROR_SUCCESS;
  736 +
  737 + char* p = argv[i];
  738 +
  739 + if (*p++ != '-') {
  740 + ret = ERROR_SYSTEM_CONFIG_INVALID;
  741 + srs_error("invalid options(index=%d, value=%s), "
  742 + "must starts with -, see help: %s -h, ret=%d", i, argv[i], argv[0], ret);
  743 + return ret;
  744 + }
  745 +
  746 + while (*p) {
  747 + switch (*p++) {
  748 + case '?':
  749 + case 'h':
  750 + show_help = true;
  751 + break;
  752 + case 'v':
  753 + case 'V':
  754 + show_version = true;
  755 + break;
  756 + case 'c':
  757 + if (*p) {
  758 + config_file = p;
  759 + return ret;
  760 + }
  761 + if (argv[++i]) {
  762 + config_file = argv[i];
  763 + return ret;
  764 + }
  765 + ret = ERROR_SYSTEM_CONFIG_INVALID;
  766 + srs_error("option \"-c\" requires parameter, ret=%d", ret);
  767 + return ret;
  768 + default:
  769 + ret = ERROR_SYSTEM_CONFIG_INVALID;
  770 + srs_error("invalid option: \"%c\", see help: %s -h, ret=%d", *(p - 1), argv[0], ret);
  771 + return ret;
  772 + }
  773 + }
  774 +
  775 + return ret;
  776 +}
  777 +
  778 +void SrsConfig::print_help(char** argv)
  779 +{
  780 + printf(RTMP_SIG_SRS_NAME" "RTMP_SIG_SRS_VERSION
  781 + " Copyright (c) 2013 winlin\n"
  782 + "configuration: "SRS_CONFIGURE"\n"
  783 + "Usage: %s [-h?vV] [-c <filename>]\n"
  784 + "\n"
  785 + "Options:\n"
  786 + " -?-h : show help\n"
  787 + " -v-V : show version and exit\n"
  788 + " -c filename : set configuration file\n"
  789 + "\n"
  790 + RTMP_SIG_SRS_WEB"\n"
  791 + RTMP_SIG_SRS_URL"\n"
  792 + "Email: "RTMP_SIG_SRS_EMAIL"\n"
  793 + "\n",
  794 + argv[0]);
  795 +}
  796 +
  797 +bool srs_directive_equals(SrsConfDirective* a, SrsConfDirective* b)
  798 +{
  799 + if (!a || !b) {
  800 + return false;
  801 + }
  802 +
  803 + if (a->name != b->name) {
  804 + return false;
  805 + }
  806 +
  807 + if (a->args.size() != b->args.size()) {
  808 + return false;
  809 + }
  810 +
  811 + for (int i = 0; i < (int)a->args.size(); i++) {
  812 + if (a->args.at(i) != b->args.at(i)) {
  813 + return false;
  814 + }
  815 + }
  816 +
  817 + if (a->directives.size() != b->directives.size()) {
  818 + return false;
  819 + }
  820 +
  821 + for (int i = 0; i < (int)a->directives.size(); i++) {
  822 + SrsConfDirective* a0 = a->at(i);
  823 + SrsConfDirective* b0 = b->at(i);
  824 +
  825 + if (!srs_directive_equals(a0, b0)) {
  826 + return false;
  827 + }
  828 + }
  829 +
  830 + return true;
  831 +}
  832 +
1 -/*  
2 -The MIT License (MIT)  
3 -  
4 -Copyright (c) 2013 winlin  
5 -  
6 -Permission is hereby granted, free of charge, to any person obtaining a copy of  
7 -this software and associated documentation files (the "Software"), to deal in  
8 -the Software without restriction, including without limitation the rights to  
9 -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of  
10 -the Software, and to permit persons to whom the Software is furnished to do so,  
11 -subject to the following conditions:  
12 -  
13 -The above copyright notice and this permission notice shall be included in all  
14 -copies or substantial portions of the Software.  
15 -  
16 -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  
17 -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS  
18 -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR  
19 -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER  
20 -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN  
21 -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  
22 -*/  
23 -  
24 -#ifndef SRS_CORE_CONIFG_HPP  
25 -#define SRS_CORE_CONIFG_HPP  
26 -  
27 -/*  
28 -#include <srs_core_config.hpp>  
29 -*/  
30 -#include <srs_core.hpp>  
31 -  
32 -#include <vector>  
33 -#include <string>  
34 -  
35 -#include <srs_core_reload.hpp>  
36 -  
37 -// default vhost for rtmp  
38 -#define RTMP_VHOST_DEFAULT "__defaultVhost__"  
39 -  
40 -#define SRS_CONF_DEFAULT_HLS_PATH "./objs/nginx/html"  
41 -#define SRS_CONF_DEFAULT_HLS_FRAGMENT 10  
42 -#define SRS_CONF_DEFAULT_HLS_WINDOW 60  
43 -// in ms, for HLS aac sync time.  
44 -#define SRS_CONF_DEFAULT_AAC_SYNC 100  
45 -// in ms, for HLS aac flush the audio  
46 -#define SRS_CONF_DEFAULT_AAC_DELAY 300  
47 -  
48 -class SrsFileBuffer  
49 -{  
50 -public:  
51 - int fd;  
52 - int line;  
53 - // start of buffer.  
54 - char* start;  
55 - // end of buffer.  
56 - char* end;  
57 - // current consumed position.  
58 - char* pos;  
59 - // last available position.  
60 - char* last;  
61 -  
62 - SrsFileBuffer();  
63 - virtual ~SrsFileBuffer();  
64 - virtual int open(const char* filename);  
65 -};  
66 -  
67 -class SrsConfDirective  
68 -{  
69 -public:  
70 - int conf_line;  
71 - std::string name;  
72 - std::vector<std::string> args;  
73 - std::vector<SrsConfDirective*> directives;  
74 -public:  
75 - SrsConfDirective();  
76 - virtual ~SrsConfDirective();  
77 - std::string arg0();  
78 - std::string arg1();  
79 - std::string arg2();  
80 - SrsConfDirective* at(int index);  
81 - SrsConfDirective* get(std::string _name);  
82 -public:  
83 - virtual int parse(const char* filename);  
84 -public:  
85 - enum SrsDirectiveType{parse_file, parse_block};  
86 - virtual int parse_conf(SrsFileBuffer* buffer, SrsDirectiveType type);  
87 - virtual int read_token(SrsFileBuffer* buffer, std::vector<std::string>& args);  
88 - virtual int refill_buffer(SrsFileBuffer* buffer, bool d_quoted, bool s_quoted, int startline, char*& pstart);  
89 -};  
90 -  
91 -/**  
92 -* the config parser.  
93 -* for the config supports reload, so never keep the reference cross st-thread,  
94 -* that is, never save the SrsConfDirective* get by any api of config,  
95 -* for it maybe free in the reload st-thread cycle.  
96 -* you can keep it before st-thread switch, or simply never keep it.  
97 -*/  
98 -class SrsConfig  
99 -{  
100 -private:  
101 - bool show_help;  
102 - bool show_version;  
103 - std::string config_file;  
104 - SrsConfDirective* root;  
105 - std::vector<SrsReloadHandler*> subscribes;  
106 -public:  
107 - SrsConfig();  
108 - virtual ~SrsConfig();  
109 -public:  
110 - virtual int reload();  
111 - virtual void subscribe(SrsReloadHandler* handler);  
112 - virtual void unsubscribe(SrsReloadHandler* handler);  
113 -public:  
114 - virtual int parse_options(int argc, char** argv);  
115 - virtual SrsConfDirective* get_vhost(std::string vhost);  
116 - virtual SrsConfDirective* get_vhost_enabled(std::string vhost);  
117 - virtual SrsConfDirective* get_gop_cache(std::string vhost);  
118 - virtual SrsConfDirective* get_forward(std::string vhost);  
119 - virtual SrsConfDirective* get_hls(std::string vhost);  
120 - virtual SrsConfDirective* get_hls_path(std::string vhost);  
121 - virtual SrsConfDirective* get_hls_fragment(std::string vhost);  
122 - virtual SrsConfDirective* get_hls_window(std::string vhost);  
123 - virtual SrsConfDirective* get_refer(std::string vhost);  
124 - virtual SrsConfDirective* get_refer_play(std::string vhost);  
125 - virtual SrsConfDirective* get_refer_publish(std::string vhost);  
126 - virtual SrsConfDirective* get_listen();  
127 - virtual SrsConfDirective* get_chunk_size();  
128 - virtual SrsConfDirective* get_pithy_print_publish();  
129 - virtual SrsConfDirective* get_pithy_print_play();  
130 -private:  
131 - virtual int parse_file(const char* filename);  
132 - virtual int parse_argv(int& i, char** argv);  
133 - virtual void print_help(char** argv);  
134 -};  
135 -  
136 -/**  
137 -* deep compare directive.  
138 -*/  
139 -bool srs_directive_equals(SrsConfDirective* a, SrsConfDirective* b);  
140 -  
141 -// global config  
142 -extern SrsConfig* config;  
143 - 1 +/*
  2 +The MIT License (MIT)
  3 +
  4 +Copyright (c) 2013 winlin
  5 +
  6 +Permission is hereby granted, free of charge, to any person obtaining a copy of
  7 +this software and associated documentation files (the "Software"), to deal in
  8 +the Software without restriction, including without limitation the rights to
  9 +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  10 +the Software, and to permit persons to whom the Software is furnished to do so,
  11 +subject to the following conditions:
  12 +
  13 +The above copyright notice and this permission notice shall be included in all
  14 +copies or substantial portions of the Software.
  15 +
  16 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  18 +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  19 +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  20 +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21 +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22 +*/
  23 +
  24 +#ifndef SRS_CORE_CONIFG_HPP
  25 +#define SRS_CORE_CONIFG_HPP
  26 +
  27 +/*
  28 +#include <srs_core_config.hpp>
  29 +*/
  30 +#include <srs_core.hpp>
  31 +
  32 +#include <vector>
  33 +#include <string>
  34 +
  35 +#include <srs_core_reload.hpp>
  36 +
  37 +// default vhost for rtmp
  38 +#define RTMP_VHOST_DEFAULT "__defaultVhost__"
  39 +
  40 +#define SRS_CONF_DEFAULT_HLS_PATH "./objs/nginx/html"
  41 +#define SRS_CONF_DEFAULT_HLS_FRAGMENT 10
  42 +#define SRS_CONF_DEFAULT_HLS_WINDOW 60
  43 +// in ms, for HLS aac sync time.
  44 +#define SRS_CONF_DEFAULT_AAC_SYNC 100
  45 +// in ms, for HLS aac flush the audio
  46 +#define SRS_CONF_DEFAULT_AAC_DELAY 300
  47 +
  48 +class SrsFileBuffer
  49 +{
  50 +public:
  51 + int fd;
  52 + int line;
  53 + // start of buffer.
  54 + char* start;
  55 + // end of buffer.
  56 + char* end;
  57 + // current consumed position.
  58 + char* pos;
  59 + // last available position.
  60 + char* last;
  61 +
  62 + SrsFileBuffer();
  63 + virtual ~SrsFileBuffer();
  64 + virtual int open(const char* filename);
  65 +};
  66 +
  67 +class SrsConfDirective
  68 +{
  69 +public:
  70 + int conf_line;
  71 + std::string name;
  72 + std::vector<std::string> args;
  73 + std::vector<SrsConfDirective*> directives;
  74 +public:
  75 + SrsConfDirective();
  76 + virtual ~SrsConfDirective();
  77 + std::string arg0();
  78 + std::string arg1();
  79 + std::string arg2();
  80 + SrsConfDirective* at(int index);
  81 + SrsConfDirective* get(std::string _name);
  82 +public:
  83 + virtual int parse(const char* filename);
  84 +public:
  85 + enum SrsDirectiveType{parse_file, parse_block};
  86 + virtual int parse_conf(SrsFileBuffer* buffer, SrsDirectiveType type);
  87 + virtual int read_token(SrsFileBuffer* buffer, std::vector<std::string>& args);
  88 + virtual int refill_buffer(SrsFileBuffer* buffer, bool d_quoted, bool s_quoted, int startline, char*& pstart);
  89 +};
  90 +
  91 +/**
  92 +* the config parser.
  93 +* for the config supports reload, so never keep the reference cross st-thread,
  94 +* that is, never save the SrsConfDirective* get by any api of config,
  95 +* for it maybe free in the reload st-thread cycle.
  96 +* you can keep it before st-thread switch, or simply never keep it.
  97 +*/
  98 +class SrsConfig
  99 +{
  100 +private:
  101 + bool show_help;
  102 + bool show_version;
  103 + std::string config_file;
  104 + SrsConfDirective* root;
  105 + std::vector<SrsReloadHandler*> subscribes;
  106 +public:
  107 + SrsConfig();
  108 + virtual ~SrsConfig();
  109 +public:
  110 + virtual int reload();
  111 + virtual void subscribe(SrsReloadHandler* handler);
  112 + virtual void unsubscribe(SrsReloadHandler* handler);
  113 +public:
  114 + virtual int parse_options(int argc, char** argv);
  115 + virtual SrsConfDirective* get_vhost(std::string vhost);
  116 + virtual SrsConfDirective* get_vhost_enabled(std::string vhost);
  117 + virtual SrsConfDirective* get_gop_cache(std::string vhost);
  118 + virtual SrsConfDirective* get_forward(std::string vhost);
  119 + virtual SrsConfDirective* get_hls(std::string vhost);
  120 + virtual SrsConfDirective* get_hls_path(std::string vhost);
  121 + virtual SrsConfDirective* get_hls_fragment(std::string vhost);
  122 + virtual SrsConfDirective* get_hls_window(std::string vhost);
  123 + virtual SrsConfDirective* get_refer(std::string vhost);
  124 + virtual SrsConfDirective* get_refer_play(std::string vhost);
  125 + virtual SrsConfDirective* get_refer_publish(std::string vhost);
  126 + virtual SrsConfDirective* get_listen();
  127 + virtual SrsConfDirective* get_chunk_size();
  128 + virtual SrsConfDirective* get_pithy_print_publish();
  129 + virtual SrsConfDirective* get_pithy_print_forwarder();
  130 + virtual SrsConfDirective* get_pithy_print_play();
  131 +private:
  132 + virtual int parse_file(const char* filename);
  133 + virtual int parse_argv(int& i, char** argv);
  134 + virtual void print_help(char** argv);
  135 +};
  136 +
  137 +/**
  138 +* deep compare directive.
  139 +*/
  140 +bool srs_directive_equals(SrsConfDirective* a, SrsConfDirective* b);
  141 +
  142 +// global config
  143 +extern SrsConfig* config;
  144 +
144 #endif 145 #endif
1 -/*  
2 -The MIT License (MIT)  
3 -  
4 -Copyright (c) 2013 winlin  
5 -  
6 -Permission is hereby granted, free of charge, to any person obtaining a copy of  
7 -this software and associated documentation files (the "Software"), to deal in  
8 -the Software without restriction, including without limitation the rights to  
9 -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of  
10 -the Software, and to permit persons to whom the Software is furnished to do so,  
11 -subject to the following conditions:  
12 -  
13 -The above copyright notice and this permission notice shall be included in all  
14 -copies or substantial portions of the Software.  
15 -  
16 -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  
17 -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS  
18 -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR  
19 -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER  
20 -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN  
21 -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  
22 -*/  
23 -  
24 -#include <srs_core_forward.hpp>  
25 -  
26 -#include <stdlib.h>  
27 -#include <sys/socket.h>  
28 -#include <netinet/in.h>  
29 -#include <arpa/inet.h>  
30 -#include <netdb.h>  
31 -  
32 -#include <srs_core_error.hpp>  
33 -#include <srs_core_rtmp.hpp>  
34 -#include <srs_core_log.hpp>  
35 -  
36 -#define SRS_FORWARDER_SLEEP_MS 2000  
37 -#define SRS_SEND_TIMEOUT_US 3000000L  
38 -#define SRS_RECV_TIMEOUT_US SRS_SEND_TIMEOUT_US  
39 -  
40 -SrsForwarder::SrsForwarder()  
41 -{  
42 - client = NULL;  
43 - tid = NULL;  
44 - stfd = NULL;  
45 - loop = false;  
46 - stream_id = 0;  
47 -}  
48 -  
49 -SrsForwarder::~SrsForwarder()  
50 -{  
51 - on_unpublish();  
52 -}  
53 -  
54 -int SrsForwarder::on_publish(std::string vhost, std::string _app, std::string stream, std::string forward_server)  
55 -{  
56 - int ret = ERROR_SUCCESS;  
57 -  
58 - app = _app;  
59 -  
60 - tc_url = "rtmp://";  
61 - tc_url += vhost;  
62 - tc_url += "/";  
63 - tc_url += app;  
64 -  
65 - stream_name = stream;  
66 - server = forward_server;  
67 - port = 1935;  
68 -  
69 - size_t pos = forward_server.find(":");  
70 - if (pos != std::string::npos) {  
71 - port = ::atoi(forward_server.substr(pos + 1).c_str());  
72 - server = forward_server.substr(0, pos);  
73 - }  
74 -  
75 - if ((ret = open_socket()) != ERROR_SUCCESS) {  
76 - return ret;  
77 - }  
78 -  
79 - srs_assert(!tid);  
80 - if((tid = st_thread_create(forward_thread, this, 1, 0)) == NULL){  
81 - ret = ERROR_ST_CREATE_FORWARD_THREAD;  
82 - srs_error("st_thread_create failed. ret=%d", ret);  
83 - return ret;  
84 - }  
85 -  
86 - return ret;  
87 -}  
88 -  
89 -void SrsForwarder::on_unpublish()  
90 -{  
91 - if (tid) {  
92 - loop = false;  
93 - st_thread_interrupt(tid);  
94 - st_thread_join(tid, NULL);  
95 - tid = NULL;  
96 - }  
97 -  
98 - if (stfd) {  
99 - int fd = st_netfd_fileno(stfd);  
100 - st_netfd_close(stfd);  
101 - stfd = NULL;  
102 -  
103 - // st does not close it sometimes,  
104 - // close it manually.  
105 - close(fd);  
106 - }  
107 -  
108 - srs_freep(client);  
109 -}  
110 -  
111 -int SrsForwarder::on_meta_data(SrsSharedPtrMessage* metadata)  
112 -{  
113 - int ret = ERROR_SUCCESS;  
114 - return ret;  
115 -}  
116 -  
117 -int SrsForwarder::on_audio(SrsSharedPtrMessage* msg)  
118 -{  
119 - int ret = ERROR_SUCCESS;  
120 - return ret;  
121 -}  
122 -  
123 -int SrsForwarder::on_video(SrsSharedPtrMessage* msg)  
124 -{  
125 - int ret = ERROR_SUCCESS;  
126 - return ret;  
127 -}  
128 -  
129 -int SrsForwarder::open_socket()  
130 -{  
131 - int ret = ERROR_SUCCESS;  
132 -  
133 - srs_trace("forward stream=%s, tcUrl=%s to server=%s, port=%d",  
134 - stream_name.c_str(), tc_url.c_str(), server.c_str(), port);  
135 -  
136 - int sock = socket(AF_INET, SOCK_STREAM, 0);  
137 - if(sock == -1){  
138 - ret = ERROR_SOCKET_CREATE;  
139 - srs_error("create socket error. ret=%d", ret);  
140 - return ret;  
141 - }  
142 -  
143 - stfd = st_netfd_open_socket(sock);  
144 - if(stfd == NULL){  
145 - ret = ERROR_ST_OPEN_SOCKET;  
146 - srs_error("st_netfd_open_socket failed. ret=%d", ret);  
147 - return ret;  
148 - }  
149 -  
150 - srs_freep(client);  
151 - client = new SrsRtmpClient(stfd);  
152 -  
153 - return ret;  
154 -}  
155 -  
156 -int SrsForwarder::connect_server()  
157 -{  
158 - int ret = ERROR_SUCCESS;  
159 -  
160 - std::string ip = parse_server(server);  
161 - if (ip.empty()) {  
162 - ret = ERROR_SYSTEM_IP_INVALID;  
163 - srs_error("dns resolve server error, ip empty. ret=%d", ret);  
164 - return ret;  
165 - }  
166 -  
167 - sockaddr_in addr;  
168 - addr.sin_family = AF_INET;  
169 - addr.sin_port = htons(port);  
170 - addr.sin_addr.s_addr = inet_addr(ip.c_str());  
171 -  
172 - if (st_connect(stfd, (const struct sockaddr*)&addr, sizeof(sockaddr_in), ST_UTIME_NO_TIMEOUT) == -1){  
173 - ret = ERROR_ST_CONNECT;  
174 - srs_error("connect to server error. ip=%s, port=%d, ret=%d", ip.c_str(), port, ret);  
175 - return ret;  
176 - }  
177 - srs_trace("connect to server success. server=%s, ip=%s, port=%d", server.c_str(), ip.c_str(), port);  
178 -  
179 - return ret;  
180 -}  
181 -  
182 -std::string SrsForwarder::parse_server(std::string host)  
183 -{  
184 - if (inet_addr(host.c_str()) != INADDR_NONE) {  
185 - return host;  
186 - }  
187 -  
188 - hostent* answer = gethostbyname(host.c_str());  
189 - if (answer == NULL) {  
190 - srs_error("dns resolve host %s error.", host.c_str());  
191 - return "";  
192 - }  
193 -  
194 - char ipv4[16];  
195 - memset(ipv4, 0, sizeof(ipv4));  
196 - for (int i = 0; i < answer->h_length; i++) {  
197 - inet_ntop(AF_INET, answer->h_addr_list[i], ipv4, sizeof(ipv4));  
198 - srs_info("dns resolve host %s to %s.", host.c_str(), ipv4);  
199 - break;  
200 - }  
201 -  
202 - return ipv4;  
203 -}  
204 -  
205 -int SrsForwarder::forward_cycle_imp()  
206 -{  
207 - int ret = ERROR_SUCCESS;  
208 -  
209 - client->set_recv_timeout(SRS_RECV_TIMEOUT_US);  
210 - client->set_send_timeout(SRS_SEND_TIMEOUT_US);  
211 -  
212 - if ((ret = connect_server()) != ERROR_SUCCESS) {  
213 - return ret;  
214 - }  
215 - srs_assert(client);  
216 -  
217 - if ((ret = client->handshake()) != ERROR_SUCCESS) {  
218 - srs_error("handshake with server failed. ret=%d", ret);  
219 - return ret;  
220 - }  
221 - if ((ret = client->connect_app(app, tc_url)) != ERROR_SUCCESS) {  
222 - srs_error("connect with server failed, tcUrl=%s. ret=%d", tc_url.c_str(), ret);  
223 - return ret;  
224 - }  
225 - if ((ret = client->create_stream(stream_id)) != ERROR_SUCCESS) {  
226 - srs_error("connect with server failed, stream_id=%d. ret=%d", stream_id, ret);  
227 - return ret;  
228 - }  
229 - if ((ret = client->publish(stream_name, stream_id)) != ERROR_SUCCESS) {  
230 - srs_error("connect with server failed, stream_name=%s, stream_id=%d. ret=%d",  
231 - stream_name.c_str(), stream_id, ret);  
232 - return ret;  
233 - }  
234 -  
235 - return ret;  
236 -}  
237 -  
238 -void SrsForwarder::forward_cycle()  
239 -{  
240 - int ret = ERROR_SUCCESS;  
241 -  
242 - log_context->generate_id();  
243 - srs_trace("forward cycle start");  
244 -  
245 - while (loop) {  
246 - if ((ret = forward_cycle_imp()) != ERROR_SUCCESS) {  
247 - srs_warn("forward cycle failed, ignored and retry, ret=%d", ret);  
248 - } else {  
249 - srs_info("forward cycle success, retry");  
250 - }  
251 -  
252 - if (!loop) {  
253 - break;  
254 - }  
255 -  
256 - st_usleep(SRS_FORWARDER_SLEEP_MS * 1000);  
257 -  
258 - if ((ret = open_socket()) != ERROR_SUCCESS) {  
259 - srs_warn("forward cycle reopen failed, ignored and retry, ret=%d", ret);  
260 - } else {  
261 - srs_info("forward cycle reopen success");  
262 - }  
263 - }  
264 - srs_trace("forward cycle finished");  
265 -}  
266 -  
267 -void* SrsForwarder::forward_thread(void* arg)  
268 -{  
269 - SrsForwarder* obj = (SrsForwarder*)arg;  
270 - srs_assert(obj != NULL);  
271 -  
272 - obj->loop = true;  
273 - obj->forward_cycle();  
274 -  
275 - return NULL;  
276 -}  
277 - 1 +/*
  2 +The MIT License (MIT)
  3 +
  4 +Copyright (c) 2013 winlin
  5 +
  6 +Permission is hereby granted, free of charge, to any person obtaining a copy of
  7 +this software and associated documentation files (the "Software"), to deal in
  8 +the Software without restriction, including without limitation the rights to
  9 +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  10 +the Software, and to permit persons to whom the Software is furnished to do so,
  11 +subject to the following conditions:
  12 +
  13 +The above copyright notice and this permission notice shall be included in all
  14 +copies or substantial portions of the Software.
  15 +
  16 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  18 +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  19 +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  20 +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21 +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22 +*/
  23 +
  24 +#include <srs_core_forward.hpp>
  25 +
  26 +#include <stdlib.h>
  27 +#include <sys/socket.h>
  28 +#include <netinet/in.h>
  29 +#include <arpa/inet.h>
  30 +#include <netdb.h>
  31 +
  32 +#include <srs_core_error.hpp>
  33 +#include <srs_core_rtmp.hpp>
  34 +#include <srs_core_log.hpp>
  35 +#include <srs_core_protocol.hpp>
  36 +#include <srs_core_pithy_print.hpp>
  37 +
  38 +#define SRS_PULSE_TIMEOUT_MS 100
  39 +#define SRS_FORWARDER_SLEEP_MS 2000
  40 +#define SRS_SEND_TIMEOUT_US 3000000L
  41 +#define SRS_RECV_TIMEOUT_US SRS_SEND_TIMEOUT_US
  42 +
  43 +SrsForwarder::SrsForwarder()
  44 +{
  45 + client = NULL;
  46 + tid = NULL;
  47 + stfd = NULL;
  48 + loop = false;
  49 + stream_id = 0;
  50 +}
  51 +
  52 +SrsForwarder::~SrsForwarder()
  53 +{
  54 + on_unpublish();
  55 +
  56 + std::vector<SrsSharedPtrMessage*>::iterator it;
  57 + for (it = msgs.begin(); it != msgs.end(); ++it) {
  58 + SrsSharedPtrMessage* msg = *it;
  59 + srs_freep(msg);
  60 + }
  61 + msgs.clear();
  62 +}
  63 +
  64 +int SrsForwarder::on_publish(std::string vhost, std::string _app, std::string stream, std::string forward_server)
  65 +{
  66 + int ret = ERROR_SUCCESS;
  67 +
  68 + app = _app;
  69 +
  70 + tc_url = "rtmp://";
  71 + tc_url += vhost;
  72 + tc_url += "/";
  73 + tc_url += app;
  74 +
  75 + stream_name = stream;
  76 + server = forward_server;
  77 + port = 1935;
  78 +
  79 + size_t pos = forward_server.find(":");
  80 + if (pos != std::string::npos) {
  81 + port = ::atoi(forward_server.substr(pos + 1).c_str());
  82 + server = forward_server.substr(0, pos);
  83 + }
  84 +
  85 + if ((ret = open_socket()) != ERROR_SUCCESS) {
  86 + return ret;
  87 + }
  88 +
  89 + srs_assert(!tid);
  90 + if((tid = st_thread_create(forward_thread, this, 1, 0)) == NULL){
  91 + ret = ERROR_ST_CREATE_FORWARD_THREAD;
  92 + srs_error("st_thread_create failed. ret=%d", ret);
  93 + return ret;
  94 + }
  95 +
  96 + return ret;
  97 +}
  98 +
  99 +void SrsForwarder::on_unpublish()
  100 +{
  101 + if (tid) {
  102 + loop = false;
  103 + st_thread_interrupt(tid);
  104 + st_thread_join(tid, NULL);
  105 + tid = NULL;
  106 + }
  107 +
  108 + if (stfd) {
  109 + int fd = st_netfd_fileno(stfd);
  110 + st_netfd_close(stfd);
  111 + stfd = NULL;
  112 +
  113 + // st does not close it sometimes,
  114 + // close it manually.
  115 + close(fd);
  116 + }
  117 +
  118 + srs_freep(client);
  119 +}
  120 +
  121 +int SrsForwarder::on_meta_data(SrsSharedPtrMessage* metadata)
  122 +{
  123 + int ret = ERROR_SUCCESS;
  124 +
  125 + msgs.push_back(metadata);
  126 +
  127 + return ret;
  128 +}
  129 +
  130 +int SrsForwarder::on_audio(SrsSharedPtrMessage* msg)
  131 +{
  132 + int ret = ERROR_SUCCESS;
  133 +
  134 + msgs.push_back(msg);
  135 +
  136 + return ret;
  137 +}
  138 +
  139 +int SrsForwarder::on_video(SrsSharedPtrMessage* msg)
  140 +{
  141 + int ret = ERROR_SUCCESS;
  142 +
  143 + msgs.push_back(msg);
  144 +
  145 + return ret;
  146 +}
  147 +
  148 +int SrsForwarder::open_socket()
  149 +{
  150 + int ret = ERROR_SUCCESS;
  151 +
  152 + srs_trace("forward stream=%s, tcUrl=%s to server=%s, port=%d",
  153 + stream_name.c_str(), tc_url.c_str(), server.c_str(), port);
  154 +
  155 + int sock = socket(AF_INET, SOCK_STREAM, 0);
  156 + if(sock == -1){
  157 + ret = ERROR_SOCKET_CREATE;
  158 + srs_error("create socket error. ret=%d", ret);
  159 + return ret;
  160 + }
  161 +
  162 + stfd = st_netfd_open_socket(sock);
  163 + if(stfd == NULL){
  164 + ret = ERROR_ST_OPEN_SOCKET;
  165 + srs_error("st_netfd_open_socket failed. ret=%d", ret);
  166 + return ret;
  167 + }
  168 +
  169 + srs_freep(client);
  170 + client = new SrsRtmpClient(stfd);
  171 +
  172 + return ret;
  173 +}
  174 +
  175 +int SrsForwarder::connect_server()
  176 +{
  177 + int ret = ERROR_SUCCESS;
  178 +
  179 + std::string ip = parse_server(server);
  180 + if (ip.empty()) {
  181 + ret = ERROR_SYSTEM_IP_INVALID;
  182 + srs_error("dns resolve server error, ip empty. ret=%d", ret);
  183 + return ret;
  184 + }
  185 +
  186 + sockaddr_in addr;
  187 + addr.sin_family = AF_INET;
  188 + addr.sin_port = htons(port);
  189 + addr.sin_addr.s_addr = inet_addr(ip.c_str());
  190 +
  191 + if (st_connect(stfd, (const struct sockaddr*)&addr, sizeof(sockaddr_in), ST_UTIME_NO_TIMEOUT) == -1){
  192 + ret = ERROR_ST_CONNECT;
  193 + srs_error("connect to server error. ip=%s, port=%d, ret=%d", ip.c_str(), port, ret);
  194 + return ret;
  195 + }
  196 + srs_trace("connect to server success. server=%s, ip=%s, port=%d", server.c_str(), ip.c_str(), port);
  197 +
  198 + return ret;
  199 +}
  200 +
  201 +std::string SrsForwarder::parse_server(std::string host)
  202 +{
  203 + if (inet_addr(host.c_str()) != INADDR_NONE) {
  204 + return host;
  205 + }
  206 +
  207 + hostent* answer = gethostbyname(host.c_str());
  208 + if (answer == NULL) {
  209 + srs_error("dns resolve host %s error.", host.c_str());
  210 + return "";
  211 + }
  212 +
  213 + char ipv4[16];
  214 + memset(ipv4, 0, sizeof(ipv4));
  215 + for (int i = 0; i < answer->h_length; i++) {
  216 + inet_ntop(AF_INET, answer->h_addr_list[i], ipv4, sizeof(ipv4));
  217 + srs_info("dns resolve host %s to %s.", host.c_str(), ipv4);
  218 + break;
  219 + }
  220 +
  221 + return ipv4;
  222 +}
  223 +
  224 +int SrsForwarder::forward_cycle_imp()
  225 +{
  226 + int ret = ERROR_SUCCESS;
  227 +
  228 + client->set_recv_timeout(SRS_RECV_TIMEOUT_US);
  229 + client->set_send_timeout(SRS_SEND_TIMEOUT_US);
  230 +
  231 + if ((ret = connect_server()) != ERROR_SUCCESS) {
  232 + return ret;
  233 + }
  234 + srs_assert(client);
  235 +
  236 + if ((ret = client->handshake()) != ERROR_SUCCESS) {
  237 + srs_error("handshake with server failed. ret=%d", ret);
  238 + return ret;
  239 + }
  240 + if ((ret = client->connect_app(app, tc_url)) != ERROR_SUCCESS) {
  241 + srs_error("connect with server failed, tcUrl=%s. ret=%d", tc_url.c_str(), ret);
  242 + return ret;
  243 + }
  244 + if ((ret = client->create_stream(stream_id)) != ERROR_SUCCESS) {
  245 + srs_error("connect with server failed, stream_id=%d. ret=%d", stream_id, ret);
  246 + return ret;
  247 + }
  248 + if ((ret = client->publish(stream_name, stream_id)) != ERROR_SUCCESS) {
  249 + srs_error("connect with server failed, stream_name=%s, stream_id=%d. ret=%d",
  250 + stream_name.c_str(), stream_id, ret);
  251 + return ret;
  252 + }
  253 +
  254 + if ((ret = forward()) != ERROR_SUCCESS) {
  255 + return ret;
  256 + }
  257 +
  258 + return ret;
  259 +}
  260 +
  261 +int SrsForwarder::forward()
  262 +{
  263 + int ret = ERROR_SUCCESS;
  264 +
  265 + client->set_recv_timeout(SRS_PULSE_TIMEOUT_MS * 1000);
  266 +
  267 + SrsPithyPrint pithy_print(SRS_STAGE_FORWARDER);
  268 +
  269 + while (loop) {
  270 + pithy_print.elapse(SRS_PULSE_TIMEOUT_MS);
  271 +
  272 + // switch to other st-threads.
  273 + st_usleep(0);
  274 +
  275 + // read from client.
  276 + if (true) {
  277 + SrsCommonMessage* msg = NULL;
  278 + ret = client->recv_message(&msg);
  279 +
  280 + srs_verbose("play loop recv message. ret=%d", ret);
  281 + if (ret != ERROR_SUCCESS && ret != ERROR_SOCKET_TIMEOUT) {
  282 + srs_error("recv server control message failed. ret=%d", ret);
  283 + return ret;
  284 + }
  285 + }
  286 +
  287 + int count = (int)msgs.size();
  288 +
  289 + // reportable
  290 + if (pithy_print.can_print()) {
  291 + srs_trace("-> clock=%u, time=%"PRId64", msgs=%d, obytes=%"PRId64", ibytes=%"PRId64", okbps=%d, ikbps=%d",
  292 + (int)(srs_get_system_time_ms()/1000), pithy_print.get_age(), count, client->get_send_bytes(), client->get_recv_bytes(), client->get_send_kbps(), client->get_recv_kbps());
  293 + }
  294 +
  295 + // all msgs to forward.
  296 + for (int i = 0; i < count; i++) {
  297 + SrsSharedPtrMessage* msg = msgs[i];
  298 + msgs[i] = NULL;
  299 +
  300 + if ((ret = client->send_message(msg)) != ERROR_SUCCESS) {
  301 + srs_error("forwarder send message to server failed. ret=%d", ret);
  302 + return ret;
  303 + }
  304 + }
  305 + msgs.clear();
  306 + }
  307 +
  308 + return ret;
  309 +}
  310 +
  311 +void SrsForwarder::forward_cycle()
  312 +{
  313 + int ret = ERROR_SUCCESS;
  314 +
  315 + log_context->generate_id();
  316 + srs_trace("forward cycle start");
  317 +
  318 + while (loop) {
  319 + if ((ret = forward_cycle_imp()) != ERROR_SUCCESS) {
  320 + srs_warn("forward cycle failed, ignored and retry, ret=%d", ret);
  321 + } else {
  322 + srs_info("forward cycle success, retry");
  323 + }
  324 +
  325 + if (!loop) {
  326 + break;
  327 + }
  328 +
  329 + st_usleep(SRS_FORWARDER_SLEEP_MS * 1000);
  330 +
  331 + if ((ret = open_socket()) != ERROR_SUCCESS) {
  332 + srs_warn("forward cycle reopen failed, ignored and retry, ret=%d", ret);
  333 + } else {
  334 + srs_info("forward cycle reopen success");
  335 + }
  336 + }
  337 + srs_trace("forward cycle finished");
  338 +}
  339 +
  340 +void* SrsForwarder::forward_thread(void* arg)
  341 +{
  342 + SrsForwarder* obj = (SrsForwarder*)arg;
  343 + srs_assert(obj != NULL);
  344 +
  345 + obj->loop = true;
  346 + obj->forward_cycle();
  347 +
  348 + return NULL;
  349 +}
  350 +
1 -/*  
2 -The MIT License (MIT)  
3 -  
4 -Copyright (c) 2013 winlin  
5 -  
6 -Permission is hereby granted, free of charge, to any person obtaining a copy of  
7 -this software and associated documentation files (the "Software"), to deal in  
8 -the Software without restriction, including without limitation the rights to  
9 -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of  
10 -the Software, and to permit persons to whom the Software is furnished to do so,  
11 -subject to the following conditions:  
12 -  
13 -The above copyright notice and this permission notice shall be included in all  
14 -copies or substantial portions of the Software.  
15 -  
16 -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  
17 -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS  
18 -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR  
19 -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER  
20 -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN  
21 -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  
22 -*/  
23 -  
24 -#ifndef SRS_CORE_FORWARD_HPP  
25 -#define SRS_CORE_FORWARD_HPP  
26 -  
27 -/*  
28 -#include <srs_core_forward.hpp>  
29 -*/  
30 -#include <srs_core.hpp>  
31 -  
32 -#include <string>  
33 -  
34 -#include <st.h>  
35 -  
36 -class SrsSharedPtrMessage;  
37 -class SrsOnMetaDataPacket;  
38 -class SrsRtmpClient;  
39 -  
40 -/**  
41 -* forward the stream to other servers.  
42 -*/  
43 -class SrsForwarder  
44 -{  
45 -private:  
46 - std::string app;  
47 - std::string tc_url;  
48 - std::string stream_name;  
49 - int stream_id;  
50 - std::string server;  
51 - int port;  
52 -private:  
53 - st_netfd_t stfd;  
54 - st_thread_t tid;  
55 - bool loop;  
56 -private:  
57 - SrsRtmpClient* client;  
58 -public:  
59 - SrsForwarder();  
60 - virtual ~SrsForwarder();  
61 -public:  
62 - virtual int on_publish(std::string vhost, std::string app, std::string stream, std::string forward_server);  
63 - virtual void on_unpublish();  
64 - virtual int on_meta_data(SrsSharedPtrMessage* metadata);  
65 - virtual int on_audio(SrsSharedPtrMessage* msg);  
66 - virtual int on_video(SrsSharedPtrMessage* msg);  
67 -private:  
68 - virtual int open_socket();  
69 - virtual int connect_server();  
70 - std::string parse_server(std::string host);  
71 -private:  
72 - virtual int forward_cycle_imp();  
73 - virtual void forward_cycle();  
74 - static void* forward_thread(void* arg);  
75 -};  
76 -  
77 -#endif 1 +/*
  2 +The MIT License (MIT)
  3 +
  4 +Copyright (c) 2013 winlin
  5 +
  6 +Permission is hereby granted, free of charge, to any person obtaining a copy of
  7 +this software and associated documentation files (the "Software"), to deal in
  8 +the Software without restriction, including without limitation the rights to
  9 +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  10 +the Software, and to permit persons to whom the Software is furnished to do so,
  11 +subject to the following conditions:
  12 +
  13 +The above copyright notice and this permission notice shall be included in all
  14 +copies or substantial portions of the Software.
  15 +
  16 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  18 +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  19 +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  20 +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21 +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22 +*/
  23 +
  24 +#ifndef SRS_CORE_FORWARD_HPP
  25 +#define SRS_CORE_FORWARD_HPP
  26 +
  27 +/*
  28 +#include <srs_core_forward.hpp>
  29 +*/
  30 +#include <srs_core.hpp>
  31 +
  32 +#include <string>
  33 +#include <vector>
  34 +
  35 +#include <st.h>
  36 +
  37 +class SrsSharedPtrMessage;
  38 +class SrsOnMetaDataPacket;
  39 +class SrsRtmpClient;
  40 +
  41 +/**
  42 +* forward the stream to other servers.
  43 +*/
  44 +class SrsForwarder
  45 +{
  46 +private:
  47 + std::string app;
  48 + std::string tc_url;
  49 + std::string stream_name;
  50 + int stream_id;
  51 + std::string server;
  52 + int port;
  53 +private:
  54 + st_netfd_t stfd;
  55 + st_thread_t tid;
  56 + bool loop;
  57 +private:
  58 + SrsRtmpClient* client;
  59 + std::vector<SrsSharedPtrMessage*> msgs;
  60 +public:
  61 + SrsForwarder();
  62 + virtual ~SrsForwarder();
  63 +public:
  64 + virtual int on_publish(std::string vhost, std::string app, std::string stream, std::string forward_server);
  65 + virtual void on_unpublish();
  66 + virtual int on_meta_data(SrsSharedPtrMessage* metadata);
  67 + virtual int on_audio(SrsSharedPtrMessage* msg);
  68 + virtual int on_video(SrsSharedPtrMessage* msg);
  69 +private:
  70 + virtual int open_socket();
  71 + virtual int connect_server();
  72 + std::string parse_server(std::string host);
  73 +private:
  74 + virtual int forward_cycle_imp();
  75 + virtual int forward();
  76 + virtual void forward_cycle();
  77 + static void* forward_thread(void* arg);
  78 +};
  79 +
  80 +#endif
1 -/*  
2 -The MIT License (MIT)  
3 -  
4 -Copyright (c) 2013 winlin  
5 -  
6 -Permission is hereby granted, free of charge, to any person obtaining a copy of  
7 -this software and associated documentation files (the "Software"), to deal in  
8 -the Software without restriction, including without limitation the rights to  
9 -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of  
10 -the Software, and to permit persons to whom the Software is furnished to do so,  
11 -subject to the following conditions:  
12 -  
13 -The above copyright notice and this permission notice shall be included in all  
14 -copies or substantial portions of the Software.  
15 -  
16 -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  
17 -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS  
18 -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR  
19 -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER  
20 -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN  
21 -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  
22 -*/  
23 -  
24 -#include <srs_core_pithy_print.hpp>  
25 -  
26 -#include <stdlib.h>  
27 -#include <map>  
28 -  
29 -#include <srs_core_log.hpp>  
30 -#include <srs_core_config.hpp>  
31 -#include <srs_core_reload.hpp>  
32 -#include <srs_core_error.hpp>  
33 -  
34 -#define SRS_STAGE_DEFAULT_INTERVAL_MS 1200  
35 -#define SRS_STAGE_PLAY_USER_INTERVAL_MS 1300  
36 -#define SRS_STAGE_PUBLISH_USER_INTERVAL_MS 1100  
37 -  
38 -struct SrsStageInfo : public SrsReloadHandler  
39 -{  
40 - int stage_id;  
41 - int pithy_print_time_ms;  
42 - int nb_clients;  
43 -  
44 - SrsStageInfo(int _stage_id)  
45 - {  
46 - stage_id = _stage_id;  
47 - nb_clients = 0;  
48 -  
49 - update_print_time();  
50 -  
51 - config->subscribe(this);  
52 - }  
53 - virtual ~SrsStageInfo()  
54 - {  
55 - config->unsubscribe(this);  
56 - }  
57 - void update_print_time()  
58 - {  
59 - switch (stage_id) {  
60 - case SRS_STAGE_PLAY_USER: {  
61 - pithy_print_time_ms = SRS_STAGE_PLAY_USER_INTERVAL_MS;  
62 - SrsConfDirective* conf = config->get_pithy_print_play();  
63 - if (conf && !conf->arg0().empty()) {  
64 - pithy_print_time_ms = ::atoi(conf->arg0().c_str());  
65 - }  
66 - break;  
67 - }  
68 - case SRS_STAGE_PUBLISH_USER: {  
69 - pithy_print_time_ms = SRS_STAGE_PUBLISH_USER_INTERVAL_MS;  
70 - SrsConfDirective* conf = config->get_pithy_print_publish();  
71 - if (conf && !conf->arg0().empty()) {  
72 - pithy_print_time_ms = ::atoi(conf->arg0().c_str());  
73 - }  
74 - break;  
75 - }  
76 - default: {  
77 - pithy_print_time_ms = SRS_STAGE_DEFAULT_INTERVAL_MS;  
78 - break;  
79 - }  
80 - }  
81 - }  
82 -public:  
83 - virtual int on_reload_pithy_print()  
84 - {  
85 - update_print_time();  
86 - return ERROR_SUCCESS;  
87 - }  
88 -};  
89 -static std::map<int, SrsStageInfo*> _srs_stages;  
90 -  
91 -SrsPithyPrint::SrsPithyPrint(int _stage_id)  
92 -{  
93 - stage_id = _stage_id;  
94 - client_id = enter_stage();  
95 - printed_age = age = 0;  
96 -}  
97 -  
98 -SrsPithyPrint::~SrsPithyPrint()  
99 -{  
100 - leave_stage();  
101 -}  
102 -  
103 -int SrsPithyPrint::enter_stage()  
104 -{  
105 - SrsStageInfo* stage = NULL;  
106 -  
107 - std::map<int, SrsStageInfo*>::iterator it = _srs_stages.find(stage_id);  
108 - if (it == _srs_stages.end()) {  
109 - stage = _srs_stages[stage_id] = new SrsStageInfo(stage_id);  
110 - } else {  
111 - stage = it->second;  
112 - }  
113 -  
114 - srs_assert(stage != NULL);  
115 - client_id = stage->nb_clients++;  
116 -  
117 - srs_verbose("enter stage, stage_id=%d, client_id=%d, nb_clients=%d, time_ms=%d",  
118 - stage->stage_id, client_id, stage->nb_clients, stage->pithy_print_time_ms);  
119 -  
120 - return client_id;  
121 -}  
122 -  
123 -void SrsPithyPrint::leave_stage()  
124 -{  
125 - SrsStageInfo* stage = _srs_stages[stage_id];  
126 - srs_assert(stage != NULL);  
127 -  
128 - stage->nb_clients--;  
129 -  
130 - srs_verbose("leave stage, stage_id=%d, client_id=%d, nb_clients=%d, time_ms=%d",  
131 - stage->stage_id, client_id, stage->nb_clients, stage->pithy_print_time_ms);  
132 -}  
133 -  
134 -void SrsPithyPrint::elapse(int64_t time_ms)  
135 -{  
136 - age += time_ms;  
137 -}  
138 -  
139 -bool SrsPithyPrint::can_print()  
140 -{  
141 - SrsStageInfo* stage = _srs_stages[stage_id];  
142 - srs_assert(stage != NULL);  
143 -  
144 - int64_t alive_age = age - printed_age;  
145 - int64_t can_print_age = stage->nb_clients * stage->pithy_print_time_ms;  
146 -  
147 - bool can_print = alive_age >= can_print_age;  
148 - if (can_print) {  
149 - printed_age = age;  
150 - }  
151 -  
152 - return can_print;  
153 -}  
154 -  
155 -int64_t SrsPithyPrint::get_age()  
156 -{  
157 - return age;  
158 -}  
159 -  
160 -void SrsPithyPrint::set_age(int64_t _age)  
161 -{  
162 - age = _age;  
163 -}  
164 - 1 +/*
  2 +The MIT License (MIT)
  3 +
  4 +Copyright (c) 2013 winlin
  5 +
  6 +Permission is hereby granted, free of charge, to any person obtaining a copy of
  7 +this software and associated documentation files (the "Software"), to deal in
  8 +the Software without restriction, including without limitation the rights to
  9 +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  10 +the Software, and to permit persons to whom the Software is furnished to do so,
  11 +subject to the following conditions:
  12 +
  13 +The above copyright notice and this permission notice shall be included in all
  14 +copies or substantial portions of the Software.
  15 +
  16 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  18 +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  19 +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  20 +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21 +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22 +*/
  23 +
  24 +#include <srs_core_pithy_print.hpp>
  25 +
  26 +#include <stdlib.h>
  27 +#include <map>
  28 +
  29 +#include <srs_core_log.hpp>
  30 +#include <srs_core_config.hpp>
  31 +#include <srs_core_reload.hpp>
  32 +#include <srs_core_error.hpp>
  33 +
  34 +#define SRS_STAGE_DEFAULT_INTERVAL_MS 1200
  35 +#define SRS_STAGE_PLAY_USER_INTERVAL_MS 1300
  36 +#define SRS_STAGE_PUBLISH_USER_INTERVAL_MS 1100
  37 +#define SRS_STAGE_FORWARDER_INTERVAL_MS 2000
  38 +
  39 +struct SrsStageInfo : public SrsReloadHandler
  40 +{
  41 + int stage_id;
  42 + int pithy_print_time_ms;
  43 + int nb_clients;
  44 +
  45 + SrsStageInfo(int _stage_id)
  46 + {
  47 + stage_id = _stage_id;
  48 + nb_clients = 0;
  49 +
  50 + update_print_time();
  51 +
  52 + config->subscribe(this);
  53 + }
  54 + virtual ~SrsStageInfo()
  55 + {
  56 + config->unsubscribe(this);
  57 + }
  58 + void update_print_time()
  59 + {
  60 + switch (stage_id) {
  61 + case SRS_STAGE_PLAY_USER: {
  62 + pithy_print_time_ms = SRS_STAGE_PLAY_USER_INTERVAL_MS;
  63 + SrsConfDirective* conf = config->get_pithy_print_play();
  64 + if (conf && !conf->arg0().empty()) {
  65 + pithy_print_time_ms = ::atoi(conf->arg0().c_str());
  66 + }
  67 + break;
  68 + }
  69 + case SRS_STAGE_PUBLISH_USER: {
  70 + pithy_print_time_ms = SRS_STAGE_PUBLISH_USER_INTERVAL_MS;
  71 + SrsConfDirective* conf = config->get_pithy_print_publish();
  72 + if (conf && !conf->arg0().empty()) {
  73 + pithy_print_time_ms = ::atoi(conf->arg0().c_str());
  74 + }
  75 + break;
  76 + }
  77 + case SRS_STAGE_FORWARDER: {
  78 + pithy_print_time_ms = SRS_STAGE_FORWARDER_INTERVAL_MS;
  79 + SrsConfDirective* conf = config->get_pithy_print_forwarder();
  80 + if (conf && !conf->arg0().empty()) {
  81 + pithy_print_time_ms = ::atoi(conf->arg0().c_str());
  82 + }
  83 + break;
  84 + }
  85 + default: {
  86 + pithy_print_time_ms = SRS_STAGE_DEFAULT_INTERVAL_MS;
  87 + break;
  88 + }
  89 + }
  90 + }
  91 +public:
  92 + virtual int on_reload_pithy_print()
  93 + {
  94 + update_print_time();
  95 + return ERROR_SUCCESS;
  96 + }
  97 +};
  98 +static std::map<int, SrsStageInfo*> _srs_stages;
  99 +
  100 +SrsPithyPrint::SrsPithyPrint(int _stage_id)
  101 +{
  102 + stage_id = _stage_id;
  103 + client_id = enter_stage();
  104 + printed_age = age = 0;
  105 +}
  106 +
  107 +SrsPithyPrint::~SrsPithyPrint()
  108 +{
  109 + leave_stage();
  110 +}
  111 +
  112 +int SrsPithyPrint::enter_stage()
  113 +{
  114 + SrsStageInfo* stage = NULL;
  115 +
  116 + std::map<int, SrsStageInfo*>::iterator it = _srs_stages.find(stage_id);
  117 + if (it == _srs_stages.end()) {
  118 + stage = _srs_stages[stage_id] = new SrsStageInfo(stage_id);
  119 + } else {
  120 + stage = it->second;
  121 + }
  122 +
  123 + srs_assert(stage != NULL);
  124 + client_id = stage->nb_clients++;
  125 +
  126 + srs_verbose("enter stage, stage_id=%d, client_id=%d, nb_clients=%d, time_ms=%d",
  127 + stage->stage_id, client_id, stage->nb_clients, stage->pithy_print_time_ms);
  128 +
  129 + return client_id;
  130 +}
  131 +
  132 +void SrsPithyPrint::leave_stage()
  133 +{
  134 + SrsStageInfo* stage = _srs_stages[stage_id];
  135 + srs_assert(stage != NULL);
  136 +
  137 + stage->nb_clients--;
  138 +
  139 + srs_verbose("leave stage, stage_id=%d, client_id=%d, nb_clients=%d, time_ms=%d",
  140 + stage->stage_id, client_id, stage->nb_clients, stage->pithy_print_time_ms);
  141 +}
  142 +
  143 +void SrsPithyPrint::elapse(int64_t time_ms)
  144 +{
  145 + age += time_ms;
  146 +}
  147 +
  148 +bool SrsPithyPrint::can_print()
  149 +{
  150 + SrsStageInfo* stage = _srs_stages[stage_id];
  151 + srs_assert(stage != NULL);
  152 +
  153 + int64_t alive_age = age - printed_age;
  154 + int64_t can_print_age = stage->nb_clients * stage->pithy_print_time_ms;
  155 +
  156 + bool can_print = alive_age >= can_print_age;
  157 + if (can_print) {
  158 + printed_age = age;
  159 + }
  160 +
  161 + return can_print;
  162 +}
  163 +
  164 +int64_t SrsPithyPrint::get_age()
  165 +{
  166 + return age;
  167 +}
  168 +
  169 +void SrsPithyPrint::set_age(int64_t _age)
  170 +{
  171 + age = _age;
  172 +}
  173 +
1 -/*  
2 -The MIT License (MIT)  
3 -  
4 -Copyright (c) 2013 winlin  
5 -  
6 -Permission is hereby granted, free of charge, to any person obtaining a copy of  
7 -this software and associated documentation files (the "Software"), to deal in  
8 -the Software without restriction, including without limitation the rights to  
9 -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of  
10 -the Software, and to permit persons to whom the Software is furnished to do so,  
11 -subject to the following conditions:  
12 -  
13 -The above copyright notice and this permission notice shall be included in all  
14 -copies or substantial portions of the Software.  
15 -  
16 -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  
17 -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS  
18 -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR  
19 -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER  
20 -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN  
21 -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  
22 -*/  
23 -  
24 -#ifndef SRS_CORE_PITHY_PRINT_HPP  
25 -#define SRS_CORE_PITHY_PRINT_HPP  
26 -  
27 -/*  
28 -#include <srs_core_pithy_print.hpp>  
29 -*/  
30 -  
31 -#include <srs_core.hpp>  
32 -  
33 -// the pithy stage for all play clients.  
34 -#define SRS_STAGE_PLAY_USER 1  
35 -// the pithy stage for all publish clients.  
36 -#define SRS_STAGE_PUBLISH_USER 2  
37 -  
38 -/**  
39 -* the stage is used for a collection of object to do print,  
40 -* the print time in a stage is constant and not changed.  
41 -* for example, stage #1 for all play clients, print time is 3s,  
42 -* if there is 10clients, then all clients should print in 10*3s.  
43 -*/  
44 -class SrsPithyPrint  
45 -{  
46 -private:  
47 - int client_id;  
48 - int stage_id;  
49 - int64_t age;  
50 - int64_t printed_age;  
51 -public:  
52 - /**  
53 - * @param _stage_id defined in SRS_STAGE_xxx, eg. SRS_STAGE_PLAY_USER.  
54 - */  
55 - SrsPithyPrint(int _stage_id);  
56 - virtual ~SrsPithyPrint();  
57 -private:  
58 - /**  
59 - * enter the specified stage, return the client id.  
60 - */  
61 - virtual int enter_stage();  
62 - /**  
63 - * leave the specified stage, release the client id.  
64 - */  
65 - virtual void leave_stage();  
66 -public:  
67 - /**  
68 - * specified client elapse some time.  
69 - */  
70 - virtual void elapse(int64_t time_ms);  
71 - /**  
72 - * whether current client can print.  
73 - */  
74 - virtual bool can_print();  
75 - /**  
76 - * get the elapsed time in ms.  
77 - */  
78 - virtual int64_t get_age();  
79 - virtual void set_age(int64_t _age);  
80 -};  
81 - 1 +/*
  2 +The MIT License (MIT)
  3 +
  4 +Copyright (c) 2013 winlin
  5 +
  6 +Permission is hereby granted, free of charge, to any person obtaining a copy of
  7 +this software and associated documentation files (the "Software"), to deal in
  8 +the Software without restriction, including without limitation the rights to
  9 +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  10 +the Software, and to permit persons to whom the Software is furnished to do so,
  11 +subject to the following conditions:
  12 +
  13 +The above copyright notice and this permission notice shall be included in all
  14 +copies or substantial portions of the Software.
  15 +
  16 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  18 +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  19 +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  20 +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  21 +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22 +*/
  23 +
  24 +#ifndef SRS_CORE_PITHY_PRINT_HPP
  25 +#define SRS_CORE_PITHY_PRINT_HPP
  26 +
  27 +/*
  28 +#include <srs_core_pithy_print.hpp>
  29 +*/
  30 +
  31 +#include <srs_core.hpp>
  32 +
  33 +// the pithy stage for all play clients.
  34 +#define SRS_STAGE_PLAY_USER 1
  35 +// the pithy stage for all publish clients.
  36 +#define SRS_STAGE_PUBLISH_USER 2
  37 +// the pithy stage for all forward clients.
  38 +#define SRS_STAGE_FORWARDER 3
  39 +
  40 +/**
  41 +* the stage is used for a collection of object to do print,
  42 +* the print time in a stage is constant and not changed.
  43 +* for example, stage #1 for all play clients, print time is 3s,
  44 +* if there is 10clients, then all clients should print in 10*3s.
  45 +*/
  46 +class SrsPithyPrint
  47 +{
  48 +private:
  49 + int client_id;
  50 + int stage_id;
  51 + int64_t age;
  52 + int64_t printed_age;
  53 +public:
  54 + /**
  55 + * @param _stage_id defined in SRS_STAGE_xxx, eg. SRS_STAGE_PLAY_USER.
  56 + */
  57 + SrsPithyPrint(int _stage_id);
  58 + virtual ~SrsPithyPrint();
  59 +private:
  60 + /**
  61 + * enter the specified stage, return the client id.
  62 + */
  63 + virtual int enter_stage();
  64 + /**
  65 + * leave the specified stage, release the client id.
  66 + */
  67 + virtual void leave_stage();
  68 +public:
  69 + /**
  70 + * specified client elapse some time.
  71 + */
  72 + virtual void elapse(int64_t time_ms);
  73 + /**
  74 + * whether current client can print.
  75 + */
  76 + virtual bool can_print();
  77 + /**
  78 + * get the elapsed time in ms.
  79 + */
  80 + virtual int64_t get_age();
  81 + virtual void set_age(int64_t _age);
  82 +};
  83 +
82 #endif 84 #endif