winlin

refine readme.

要显示太多修改。

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

@@ -21,52 +21,52 @@ people who have submitted patches, reported bugs, added translations, helped<br/ @@ -21,52 +21,52 @@ people who have submitted patches, reported bugs, added translations, helped<br/
21 answer newbie questions, and generally made SRS that much better: [AUTHORS.txt](https://github.com/winlinvip/simple-rtmp-server/blob/master/AUTHORS.txt) 21 answer newbie questions, and generally made SRS that much better: [AUTHORS.txt](https://github.com/winlinvip/simple-rtmp-server/blob/master/AUTHORS.txt)
22 22
23 ### Usage(simple) 23 ### Usage(simple)
24 -<strong>step -1:</strong> get SRS<br/> 24 +<strong>Step -1:</strong> get SRS<br/>
25 <pre> 25 <pre>
26 git clone https://github.com/winlinvip/simple-rtmp-server && 26 git clone https://github.com/winlinvip/simple-rtmp-server &&
27 cd simple-rtmp-server/trunk 27 cd simple-rtmp-server/trunk
28 </pre> 28 </pre>
29 -<strong>step 0:</strong> build SRS system.<br/> 29 +<strong>Step 0:</strong> build SRS system.<br/>
30 <pre> 30 <pre>
31 bash scripts/build.sh 31 bash scripts/build.sh
32 </pre> 32 </pre>
33 -<strong>step 1:</strong> start SRS all demo features.<br/> 33 +<strong>Step 1:</strong> start SRS all demo features.<br/>
34 <pre> 34 <pre>
35 bash scripts/run.sh 35 bash scripts/run.sh
36 </pre> 36 </pre>
37 -<strong>step 2:</strong> SRS live show: [http://your-server-ip](http://your-server-ip) <br/>  
38 -<strong>step 3:</strong> stop SRS demo<br/> 37 +<strong>Step 2:</strong> SRS live show: [http://your-server-ip](http://your-server-ip) <br/>
  38 +<strong>Step 3:</strong> stop SRS demo<br/>
39 <pre> 39 <pre>
40 bash scripts/stop.sh 40 bash scripts/stop.sh
41 </pre> 41 </pre>
42 42
43 ### Usage(detail) 43 ### Usage(detail)
44 -<strong>step 0:</strong> get SRS <br/> 44 +<strong>Step 0:</strong> get SRS <br/>
45 <pre> 45 <pre>
46 git clone https://github.com/winlinvip/simple-rtmp-server && 46 git clone https://github.com/winlinvip/simple-rtmp-server &&
47 cd simple-rtmp-server/trunk 47 cd simple-rtmp-server/trunk
48 </pre> 48 </pre>
49 -<strong>step 1:</strong> build SRS <br/> 49 +<strong>Step 1:</strong> build SRS <br/>
50 <pre> 50 <pre>
51 ./configure --with-ssl --with-hls --with-ffmpeg --with-http && make 51 ./configure --with-ssl --with-hls --with-ffmpeg --with-http && make
52 </pre> 52 </pre>
53 -<strong>step 2:</strong> start SRS <br/> 53 +<strong>Step 2:</strong> start SRS <br/>
54 <pre> 54 <pre>
55 ./objs/srs -c conf/srs.conf 55 ./objs/srs -c conf/srs.conf
56 </pre> 56 </pre>
57 -<strong>step 3(optinal):</strong> start SRS listen at 19350 to forward to<br/> 57 +<strong>Step 3(optinal):</strong> start SRS listen at 19350 to forward to<br/>
58 <pre> 58 <pre>
59 ./objs/srs -c conf/srs.19350.conf 59 ./objs/srs -c conf/srs.19350.conf
60 </pre> 60 </pre>
61 -<strong>step 4(optinal):</strong> start nginx for HLS <br/> 61 +<strong>Step 4(optinal):</strong> start nginx for HLS <br/>
62 <pre> 62 <pre>
63 sudo ./objs/nginx/sbin/nginx 63 sudo ./objs/nginx/sbin/nginx
64 </pre> 64 </pre>
65 -<strong>step 5(optinal):</strong> start http hooks for SRS callback <br/> 65 +<strong>Step 5(optinal):</strong> start http hooks for SRS callback <br/>
66 <pre> 66 <pre>
67 python ./research/api-server/server.py 8085 67 python ./research/api-server/server.py 8085
68 </pre> 68 </pre>
69 -<strong>step 6:</strong> publish demo live stream <br/> 69 +<strong>Step 6:</strong> publish demo live stream <br/>
70 <pre> 70 <pre>
71 FMS URL: rtmp://127.0.0.1/live?vhost=demo.srs.com 71 FMS URL: rtmp://127.0.0.1/live?vhost=demo.srs.com
72 Stream: livestream 72 Stream: livestream
@@ -78,7 +78,7 @@ FFMPEG to publish the default demo stream: @@ -78,7 +78,7 @@ FFMPEG to publish the default demo stream:
78 sleep 1; \ 78 sleep 1; \
79 done 79 done
80 </pre> 80 </pre>
81 -<strong>step 7:</strong> publish players live stream <br/> 81 +<strong>Step 7:</strong> publish players live stream <br/>
82 <pre> 82 <pre>
83 FMS URL: rtmp://127.0.0.1/live?vhost=players 83 FMS URL: rtmp://127.0.0.1/live?vhost=players
84 Stream: livestream 84 Stream: livestream
@@ -90,7 +90,7 @@ FFMPEG to publish the players demo stream: @@ -90,7 +90,7 @@ FFMPEG to publish the players demo stream:
90 sleep 1; \ 90 sleep 1; \
91 done 91 done
92 </pre> 92 </pre>
93 -<strong>step 8:</strong> add server ip to client hosts as demo. <br/> 93 +<strong>Step 8:</strong> add server ip to client hosts as demo. <br/>
94 <pre> 94 <pre>
95 # edit the folowing file: 95 # edit the folowing file:
96 # linux: /etc/hosts 96 # linux: /etc/hosts
@@ -98,14 +98,14 @@ FFMPEG to publish the players demo stream: @@ -98,14 +98,14 @@ FFMPEG to publish the players demo stream:
98 # where server ip is 192.168.2.111 98 # where server ip is 192.168.2.111
99 192.168.2.111 demo.srs.com 99 192.168.2.111 demo.srs.com
100 </pre> 100 </pre>
101 -<strong>step 9:</strong> play live stream. <br/> 101 +<strong>Step 9:</strong> play live stream. <br/>
102 <pre> 102 <pre>
103 players: http://demo.srs.com/players 103 players: http://demo.srs.com/players
104 rtmp url: rtmp://demo.srs.com/live/livestream 104 rtmp url: rtmp://demo.srs.com/live/livestream
105 m3u8 url: http://demo.srs.com/live/livestream.m3u8 105 m3u8 url: http://demo.srs.com/live/livestream.m3u8
106 for android: http://demo.srs.com/live/livestream.html 106 for android: http://demo.srs.com/live/livestream.html
107 </pre> 107 </pre>
108 -<strong>step 10(optinal):</strong> play live stream auto transcoded<br/> 108 +<strong>Step 10(optinal):</strong> play live stream auto transcoded<br/>
109 <pre> 109 <pre>
110 rtmp url: rtmp://demo.srs.com/live/livestream_ld 110 rtmp url: rtmp://demo.srs.com/live/livestream_ld
111 m3u8 url: http://demo.srs.com/live/livestream_ld.m3u8 111 m3u8 url: http://demo.srs.com/live/livestream_ld.m3u8
@@ -114,7 +114,7 @@ rtmp url: rtmp://demo.srs.com/live/livestream_sd @@ -114,7 +114,7 @@ rtmp url: rtmp://demo.srs.com/live/livestream_sd
114 m3u8 url: http://demo.srs.com/live/livestream_sd.m3u8 114 m3u8 url: http://demo.srs.com/live/livestream_sd.m3u8
115 for android: http://demo.srs.com/live/livestream_sd.html 115 for android: http://demo.srs.com/live/livestream_sd.html
116 </pre> 116 </pre>
117 -<strong>step 11(optinal):</strong> play live stream auto forwarded, the hls dir change to /forward<br/> 117 +<strong>Step 11(optinal):</strong> play live stream auto forwarded, the hls dir change to /forward<br/>
118 <pre> 118 <pre>
119 rtmp url: rtmp://demo.srs.com:19350/live/livestream 119 rtmp url: rtmp://demo.srs.com:19350/live/livestream
120 m3u8 url: http://demo.srs.com/forward/live/livestream.m3u8 120 m3u8 url: http://demo.srs.com/forward/live/livestream.m3u8
@@ -126,7 +126,7 @@ rtmp url: rtmp://demo.srs.com:19350/live/livestream_sd @@ -126,7 +126,7 @@ rtmp url: rtmp://demo.srs.com:19350/live/livestream_sd
126 m3u8 url: http://demo.srs.com/forward/live/livestream_sd.m3u8 126 m3u8 url: http://demo.srs.com/forward/live/livestream_sd.m3u8
127 for android: http://demo.srs.com/forward/live/livestream_sd.html 127 for android: http://demo.srs.com/forward/live/livestream_sd.html
128 </pre> 128 </pre>
129 -<strong>step 12(optinal):</strong> modify the config and reload it (all features support reload)<br/> 129 +<strong>Step 12(optinal):</strong> modify the config and reload it (all features support reload)<br/>
130 <pre> 130 <pre>
131 killall -1 srs 131 killall -1 srs
132 </pre> 132 </pre>
@@ -190,7 +190,7 @@ Bandwidth Test Workflow: @@ -190,7 +190,7 @@ Bandwidth Test Workflow:
190 | final(2)-----------------> | 190 | final(2)-----------------> |
191 | &lt;END> | 191 | &lt;END> |
192 192
193 -@see: class SrsBandwidth comments. 193 +@See: class SrsBandwidth comments.
194 </pre> 194 </pre>
195 195
196 ### System Requirements 196 ### System Requirements
@@ -199,37 +199,38 @@ Supported operating systems and hardware: @@ -199,37 +199,38 @@ Supported operating systems and hardware:
199 * All handware. 199 * All handware.
200 200
201 ### Summary 201 ### Summary
202 -1. simple: also stable enough.<br/>  
203 -2. high-performance: single-thread, async socket, event/st-thread driven.<br/>  
204 -3. no edge server, origin server only.<br/>  
205 -4. no vod streaming, live streaming only.<br/>  
206 -5. no multiple processes, single process only.<br/>  
207 -6. support vhost, support \_\_defaultVhost\_\_.<br/>  
208 -7. support adobe rtmp live streaming.<br/>  
209 -8. support apple hls(m3u8) live streaming.<br/>  
210 -9. support reload config to enable changes.<br/>  
211 -10. support cache last gop for flash player to fast startup.<br/>  
212 -11. support listen at multiple ports.<br/>  
213 -12. support long time(>4.6hours) publish/play.<br/>  
214 -13. high performace, 1800 connections(500kbps), 900Mbps, CPU 90.2%, 41MB<br/>  
215 -14. support forward publish stream to build active-standby cluster.<br/>  
216 -15. support broadcast by forward the stream to other servers(origin/edge).<br/>  
217 -16. support live stream transcoding by ffmpeg.<br/>  
218 -17. support live stream forward(acopy/vcopy) by ffmpeg.<br/>  
219 -18. support ffmpeg filters(logo/overlay/crop), x264 params.<br/>  
220 -19. support audio transcode only, speex/mp3 to aac<br/>  
221 -20. support http callback api hooks(for authentication and injection).<br/>  
222 -21. support bandwidth test api and flash client.<br/>  
223 -22. player, publisher(encoder), and demo pages(jquery+bootstrap). <br/>  
224 -23. demo video meeting or chat(SRS+cherrypy+jquery+bootstrap). <br/>  
225 -24. [plan] support network based cli and json result.<br/>  
226 -25. [plan] support adobe flash refer/token/swf verification.<br/>  
227 -26. [plan] support adobe amf3 codec.<br/>  
228 -27. [plan] support dvr(record live to vod file)<br/>  
229 -28. [plan] support FMS edge protocol<br/>  
230 -29. [plan] support encryption: RTMPE/RTMPS, HLS DRM<br/>  
231 -30. [plan] support RTMPT, http to tranverse firewalls<br/>  
232 -31. [plan] support file source, transcoding file to live stream<br/> 202 +1. Simple: also stable enough.<br/>
  203 +2. High-performance: single-thread, async socket, event/st-thread driven.<br/>
  204 +3. NO edge server, origin server only.<br/>
  205 +4. NO vod streaming, live streaming only.<br/>
  206 +5. NO multiple processes, single process only.<br/>
  207 +6. Support vhost, support \_\_defaultVhost\_\_.<br/>
  208 +7. Support adobe rtmp live streaming.<br/>
  209 +8. Support apple hls(m3u8) live streaming.<br/>
  210 +9. Support reload config to enable changes.<br/>
  211 +10. Support cache last gop for flash player to fast startup.<br/>
  212 +11. Support listen at multiple ports.<br/>
  213 +12. Support long time(>4.6hours) publish/play.<br/>
  214 +13. High performace, 1800 connections(500kbps), 900Mbps, CPU 90.2%, 41MB<br/>
  215 +14. Support forward publish stream to build active-standby cluster.<br/>
  216 +15. Support broadcast by forward the stream to other servers(origin/edge).<br/>
  217 +16. Support live stream transcoding by ffmpeg.<br/>
  218 +17. Support live stream forward(acopy/vcopy) by ffmpeg.<br/>
  219 +18. Support ffmpeg filters(logo/overlay/crop), x264 params.<br/>
  220 +19. Support audio transcode only, speex/mp3 to aac<br/>
  221 +20. Support http callback api hooks(for authentication and injection).<br/>
  222 +21. Support bandwidth test api and flash client.<br/>
  223 +22. Player, publisher(encoder), and demo pages(jquery+bootstrap). <br/>
  224 +23. Demo video meeting or chat(SRS+cherrypy+jquery+bootstrap). <br/>
  225 +24. [dev] Full documents in wiki, in chineses. <br/>
  226 +25. [plan] Support network based cli and json result.<br/>
  227 +26. [plan] Support adobe flash refer/token/swf verification.<br/>
  228 +27. [plan] Support adobe amf3 codec.<br/>
  229 +28. [plan] Support dvr(record live to vod file)<br/>
  230 +29. [plan] Support FMS edge protocol<br/>
  231 +30. [plan] Support encryption: RTMPE/RTMPS, HLS DRM<br/>
  232 +31. [plan] Support RTMPT, http to tranverse firewalls<br/>
  233 +32. [plan] Support file source, transcoding file to live stream<br/>
233 234
234 ### Performance 235 ### Performance
235 1. 300 connections, 150Mbps, 500kbps, CPU 18.8%, 5956KB. 236 1. 300 connections, 150Mbps, 500kbps, CPU 18.8%, 5956KB.
@@ -239,6 +240,7 @@ Supported operating systems and hardware: @@ -239,6 +240,7 @@ Supported operating systems and hardware:
239 5. 1500 connections, 750Mbps, 500kbps, CPU 81.9%, 28MB. 240 5. 1500 connections, 750Mbps, 500kbps, CPU 81.9%, 28MB.
240 6. 1800 connections, 900Mbps, 500kbps, CPU 90.2%, 41MB. 241 6. 1800 connections, 900Mbps, 500kbps, CPU 90.2%, 41MB.
241 <pre> 242 <pre>
  243 +[winlin@dev6 srs]$ dstat
242 ----total-cpu-usage---- -dsk/total- ---net/lo-- ---paging-- ---system-- 244 ----total-cpu-usage---- -dsk/total- ---net/lo-- ---paging-- ---system--
243 usr sys idl wai hiq siq| read writ| recv send| in out | int csw 245 usr sys idl wai hiq siq| read writ| recv send| in out | int csw
244 58 9 32 0 0 1| 0 4168k| 277M 277M| 0 0 | 29k 25k 246 58 9 32 0 0 1| 0 4168k| 277M 277M| 0 0 | 29k 25k
@@ -257,16 +259,16 @@ usr sys idl wai hiq siq| read writ| recv send| in out | int csw @@ -257,16 +259,16 @@ usr sys idl wai hiq siq| read writ| recv send| in out | int csw
257 </pre> 259 </pre>
258 260
259 ### Releases 261 ### Releases
260 -* 2013-12-25, [release v0.9](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.9), support bandwidth test, add player/encoder/chat demos. 20926 lines.<br/>  
261 -* 2013-12-08, [release v0.8](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.8), support http hooks callback, update [st_load](https://github.com/winlinvip/st-load). 19186 lines.<br/>  
262 -* 2013-12-03, [release v0.7](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.7), support live stream transcoding. 17605 lines.<br/>  
263 -* 2013-11-29, [release v0.6](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.6), support forward stream to origin/edge. 16094 lines.<br/>  
264 -* 2013-11-26, [release v0.5](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.5), support HLS(m3u8), fragment and window. 14449 lines.<br/>  
265 -* 2013-11-10, [release v0.4](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.4), support reload config, pause, longtime publish/play. 12500 lines.<br/>  
266 -* 2013-11-04, [release v0.3](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.3), support vhost, refer, gop cache, listen multiple ports. 11773 lines.<br/>  
267 -* 2013-10-25, [release v0.2](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.2), support rtmp flash publish, h264, time jitter correct. 10125 lines.<br/>  
268 -* 2013-10-23, [release v0.1](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.1), support rtmp FMLE/FFMPEG publish, vp6. 8287 lines.<br/>  
269 -* 2013-10-17, created.<br/> 262 +* 2013-12-25, [Release v0.9](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.9), support bandwidth test, add player/encoder/chat demos. 20926 lines.<br/>
  263 +* 2013-12-08, [Release v0.8](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.8), support http hooks callback, update [st_load](https://github.com/winlinvip/st-load). 19186 lines.<br/>
  264 +* 2013-12-03, [Release v0.7](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.7), support live stream transcoding. 17605 lines.<br/>
  265 +* 2013-11-29, [Release v0.6](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.6), support forward stream to origin/edge. 16094 lines.<br/>
  266 +* 2013-11-26, [Release v0.5](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.5), support HLS(m3u8), fragment and window. 14449 lines.<br/>
  267 +* 2013-11-10, [Release v0.4](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.4), support reload config, pause, longtime publish/play. 12500 lines.<br/>
  268 +* 2013-11-04, [Release v0.3](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.3), support vhost, refer, gop cache, listen multiple ports. 11773 lines.<br/>
  269 +* 2013-10-25, [Release v0.2](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.2), support rtmp flash publish, h264, time jitter correct. 10125 lines.<br/>
  270 +* 2013-10-23, [Release v0.1](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.1), support rtmp FMLE/FFMPEG publish, vp6. 8287 lines.<br/>
  271 +* 2013-10-17, Created.<br/>
270 272
271 ### Compare 273 ### Compare
272 * SRS v0.9: 20926 lines. player/encoder/chat demos. bandwidth test for encoder/CDN.<br/> 274 * SRS v0.9: 20926 lines. player/encoder/chat demos. bandwidth test for encoder/CDN.<br/>
@@ -76,7 +76,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -76,7 +76,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
76 #define RTMP_SIG_SRS_URL "https://"RTMP_SIG_SRS_URL_SHORT 76 #define RTMP_SIG_SRS_URL "https://"RTMP_SIG_SRS_URL_SHORT
77 #define RTMP_SIG_SRS_URL_SHORT "github.com/winlinvip/simple-rtmp-server" 77 #define RTMP_SIG_SRS_URL_SHORT "github.com/winlinvip/simple-rtmp-server"
78 #define RTMP_SIG_SRS_WEB "http://blog.csdn.net/win_lin" 78 #define RTMP_SIG_SRS_WEB "http://blog.csdn.net/win_lin"
79 -#define RTMP_SIG_SRS_EMAIL "winterserver@126.com" 79 +#define RTMP_SIG_SRS_EMAIL "winlin@vip.126.com"
80 #define RTMP_SIG_SRS_LICENSE "The MIT License (MIT)" 80 #define RTMP_SIG_SRS_LICENSE "The MIT License (MIT)"
81 #define RTMP_SIG_SRS_COPYRIGHT "Copyright (c) 2013-2014 winlin" 81 #define RTMP_SIG_SRS_COPYRIGHT "Copyright (c) 2013-2014 winlin"
82 #define RTMP_SIG_SRS_PRIMARY_AUTHROS "winlin,wenjiegit" 82 #define RTMP_SIG_SRS_PRIMARY_AUTHROS "winlin,wenjiegit"
1 -/*  
2 -The MIT License (MIT)  
3 -  
4 -Copyright (c) 2013-2014 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 -using namespace std;  
39 -  
40 -#include <srs_core_error.hpp>  
41 -#include <srs_core_log.hpp>  
42 -#include <srs_core_autofree.hpp>  
43 -  
44 -#define FILE_OFFSET(fd) lseek(fd, 0, SEEK_CUR)  
45 -  
46 -int64_t FILE_SIZE(int fd)  
47 -{  
48 - int64_t pre = FILE_OFFSET(fd);  
49 - int64_t pos = lseek(fd, 0, SEEK_END);  
50 - lseek(fd, pre, SEEK_SET);  
51 - return pos;  
52 -}  
53 -  
54 -#define LF (char)0x0a  
55 -#define CR (char)0x0d  
56 -  
57 -bool is_common_space(char ch)  
58 -{  
59 - return (ch == ' ' || ch == '\t' || ch == CR || ch == LF);  
60 -}  
61 -  
62 -class SrsFileBuffer  
63 -{  
64 -private:  
65 - // last available position.  
66 - char* last;  
67 - // end of buffer.  
68 - char* end;  
69 - // start of buffer.  
70 - char* start;  
71 -public:  
72 - // current consumed position.  
73 - char* pos;  
74 - // current parsed line.  
75 - int line;  
76 -  
77 - SrsFileBuffer();  
78 - virtual ~SrsFileBuffer();  
79 - virtual int fullfill(const char* filename);  
80 - virtual bool empty();  
81 -};  
82 -  
83 -SrsFileBuffer::SrsFileBuffer()  
84 -{  
85 - line = 0;  
86 -  
87 - pos = last = start = NULL;  
88 - end = start;  
89 -}  
90 -  
91 -SrsFileBuffer::~SrsFileBuffer()  
92 -{  
93 - srs_freepa(start);  
94 -}  
95 -  
96 -int SrsFileBuffer::fullfill(const char* filename)  
97 -{  
98 - int ret = ERROR_SUCCESS;  
99 -  
100 - int fd = -1;  
101 - int nread = 0;  
102 - int filesize = 0;  
103 -  
104 - if ((fd = ::open(filename, O_RDONLY, 0)) < 0) {  
105 - ret = ERROR_SYSTEM_CONFIG_INVALID;  
106 - srs_error("open conf file error. ret=%d", ret);  
107 - goto finish;  
108 - }  
109 -  
110 - if ((filesize = FILE_SIZE(fd) - FILE_OFFSET(fd)) <= 0) {  
111 - ret = ERROR_SYSTEM_CONFIG_EOF;  
112 - srs_error("read conf file error. ret=%d", ret);  
113 - goto finish;  
114 - }  
115 -  
116 - srs_freepa(start);  
117 - pos = last = start = new char[filesize];  
118 - end = start + filesize;  
119 -  
120 - if ((nread = read(fd, start, filesize)) != filesize) {  
121 - ret = ERROR_SYSTEM_CONFIG_INVALID;  
122 - srs_error("read file read error. expect %d, actual %d bytes, ret=%d",  
123 - filesize, nread, ret);  
124 - goto finish;  
125 - }  
126 -  
127 - line = 1;  
128 -  
129 -finish:  
130 - if (fd > 0) {  
131 - ::close(fd);  
132 - }  
133 -  
134 - return ret;  
135 -}  
136 -  
137 -bool SrsFileBuffer::empty()  
138 -{  
139 - return pos >= end;  
140 -}  
141 -  
142 -SrsConfDirective::SrsConfDirective()  
143 -{  
144 -}  
145 -  
146 -SrsConfDirective::~SrsConfDirective()  
147 -{  
148 - std::vector<SrsConfDirective*>::iterator it;  
149 - for (it = directives.begin(); it != directives.end(); ++it) {  
150 - SrsConfDirective* directive = *it;  
151 - srs_freep(directive);  
152 - }  
153 - directives.clear();  
154 -}  
155 -  
156 -string SrsConfDirective::arg0()  
157 -{  
158 - if (args.size() > 0) {  
159 - return args.at(0);  
160 - }  
161 -  
162 - return "";  
163 -}  
164 -  
165 -string SrsConfDirective::arg1()  
166 -{  
167 - if (args.size() > 1) {  
168 - return args.at(1);  
169 - }  
170 -  
171 - return "";  
172 -}  
173 -  
174 -string SrsConfDirective::arg2()  
175 -{  
176 - if (args.size() > 2) {  
177 - return args.at(2);  
178 - }  
179 -  
180 - return "";  
181 -}  
182 -  
183 -SrsConfDirective* SrsConfDirective::at(int index)  
184 -{  
185 - return directives.at(index);  
186 -}  
187 -  
188 -SrsConfDirective* SrsConfDirective::get(string _name)  
189 -{  
190 - std::vector<SrsConfDirective*>::iterator it;  
191 - for (it = directives.begin(); it != directives.end(); ++it) {  
192 - SrsConfDirective* directive = *it;  
193 - if (directive->name == _name) {  
194 - return directive;  
195 - }  
196 - }  
197 -  
198 - return NULL;  
199 -}  
200 -  
201 -SrsConfDirective* SrsConfDirective::get(string _name, string _arg0)  
202 -{  
203 - std::vector<SrsConfDirective*>::iterator it;  
204 - for (it = directives.begin(); it != directives.end(); ++it) {  
205 - SrsConfDirective* directive = *it;  
206 - if (directive->name == _name && directive->arg0() == _arg0) {  
207 - return directive;  
208 - }  
209 - }  
210 -  
211 - return NULL;  
212 -}  
213 -  
214 -int SrsConfDirective::parse(const char* filename)  
215 -{  
216 - int ret = ERROR_SUCCESS;  
217 -  
218 - SrsFileBuffer buffer;  
219 -  
220 - if ((ret = buffer.fullfill(filename)) != ERROR_SUCCESS) {  
221 - return ret;  
222 - }  
223 -  
224 - return parse_conf(&buffer, parse_file);  
225 -}  
226 -  
227 -// see: ngx_conf_parse  
228 -int SrsConfDirective::parse_conf(SrsFileBuffer* buffer, SrsDirectiveType type)  
229 -{  
230 - int ret = ERROR_SUCCESS;  
231 -  
232 - while (true) {  
233 - std::vector<string> args;  
234 - ret = read_token(buffer, args);  
235 -  
236 - /**  
237 - * ret maybe:  
238 - * ERROR_SYSTEM_CONFIG_INVALID error.  
239 - * ERROR_SYSTEM_CONFIG_DIRECTIVE directive terminated by ';' found  
240 - * ERROR_SYSTEM_CONFIG_BLOCK_START token terminated by '{' found  
241 - * ERROR_SYSTEM_CONFIG_BLOCK_END the '}' found  
242 - * ERROR_SYSTEM_CONFIG_EOF the config file is done  
243 - */  
244 - if (ret == ERROR_SYSTEM_CONFIG_INVALID) {  
245 - return ret;  
246 - }  
247 - if (ret == ERROR_SYSTEM_CONFIG_BLOCK_END) {  
248 - if (type != parse_block) {  
249 - srs_error("line %d: unexpected \"}\"", buffer->line);  
250 - return ret;  
251 - }  
252 - return ERROR_SUCCESS;  
253 - }  
254 - if (ret == ERROR_SYSTEM_CONFIG_EOF) {  
255 - if (type == parse_block) {  
256 - srs_error("line %d: unexpected end of file, expecting \"}\"", buffer->line);  
257 - return ret;  
258 - }  
259 - return ERROR_SUCCESS;  
260 - }  
261 -  
262 - if (args.empty()) {  
263 - srs_error("line %d: empty directive.", buffer->line);  
264 - return ret;  
265 - }  
266 -  
267 - // build directive tree.  
268 - SrsConfDirective* directive = new SrsConfDirective();  
269 -  
270 - directive->conf_line = buffer->line;  
271 - directive->name = args[0];  
272 - args.erase(args.begin());  
273 - directive->args.swap(args);  
274 -  
275 - directives.push_back(directive);  
276 -  
277 - if (ret == ERROR_SYSTEM_CONFIG_BLOCK_START) {  
278 - if ((ret = directive->parse_conf(buffer, parse_block)) != ERROR_SUCCESS) {  
279 - return ret;  
280 - }  
281 - }  
282 - }  
283 -  
284 - return ret;  
285 -}  
286 -  
287 -// see: ngx_conf_read_token  
288 -int SrsConfDirective::read_token(SrsFileBuffer* buffer, std::vector<string>& args)  
289 -{  
290 - int ret = ERROR_SUCCESS;  
291 -  
292 - char* pstart = buffer->pos;  
293 - int startline = buffer->line;  
294 -  
295 - bool sharp_comment = false;  
296 -  
297 - bool d_quoted = false;  
298 - bool s_quoted = false;  
299 -  
300 - bool need_space = false;  
301 - bool last_space = true;  
302 -  
303 - while (true) {  
304 - if (buffer->empty()) {  
305 - ret = ERROR_SYSTEM_CONFIG_EOF;  
306 -  
307 - if (!args.empty() || !last_space) {  
308 - srs_error("line %d: unexpected end of file, expecting ; or \"}\"", buffer->line);  
309 - return ERROR_SYSTEM_CONFIG_INVALID;  
310 - }  
311 - srs_error("end of file. ret=%d", ret);  
312 -  
313 - return ret;  
314 - }  
315 -  
316 - char ch = *buffer->pos++;  
317 -  
318 - if (ch == LF) {  
319 - buffer->line++;  
320 - sharp_comment = false;  
321 - }  
322 -  
323 - if (sharp_comment) {  
324 - continue;  
325 - }  
326 -  
327 - if (need_space) {  
328 - if (is_common_space(ch)) {  
329 - last_space = true;  
330 - need_space = false;  
331 - continue;  
332 - }  
333 - if (ch == ';') {  
334 - return ERROR_SYSTEM_CONFIG_DIRECTIVE;  
335 - }  
336 - if (ch == '{') {  
337 - return ERROR_SYSTEM_CONFIG_BLOCK_START;  
338 - }  
339 - srs_error("line %d: unexpected '%c'", buffer->line, ch);  
340 - return ERROR_SYSTEM_CONFIG_INVALID;  
341 - }  
342 -  
343 - // last charecter is space.  
344 - if (last_space) {  
345 - if (is_common_space(ch)) {  
346 - continue;  
347 - }  
348 - pstart = buffer->pos - 1;  
349 - startline = buffer->line;  
350 - switch (ch) {  
351 - case ';':  
352 - if (args.size() == 0) {  
353 - srs_error("line %d: unexpected ';'", buffer->line);  
354 - return ERROR_SYSTEM_CONFIG_INVALID;  
355 - }  
356 - return ERROR_SYSTEM_CONFIG_DIRECTIVE;  
357 - case '{':  
358 - if (args.size() == 0) {  
359 - srs_error("line %d: unexpected '{'", buffer->line);  
360 - return ERROR_SYSTEM_CONFIG_INVALID;  
361 - }  
362 - return ERROR_SYSTEM_CONFIG_BLOCK_START;  
363 - case '}':  
364 - if (args.size() != 0) {  
365 - srs_error("line %d: unexpected '}'", buffer->line);  
366 - return ERROR_SYSTEM_CONFIG_INVALID;  
367 - }  
368 - return ERROR_SYSTEM_CONFIG_BLOCK_END;  
369 - case '#':  
370 - sharp_comment = 1;  
371 - continue;  
372 - case '"':  
373 - pstart++;  
374 - d_quoted = true;  
375 - last_space = 0;  
376 - continue;  
377 - case '\'':  
378 - pstart++;  
379 - s_quoted = true;  
380 - last_space = 0;  
381 - continue;  
382 - default:  
383 - last_space = 0;  
384 - continue;  
385 - }  
386 - } else {  
387 - // last charecter is not space  
388 - bool found = false;  
389 - if (d_quoted) {  
390 - if (ch == '"') {  
391 - d_quoted = false;  
392 - need_space = true;  
393 - found = true;  
394 - }  
395 - } else if (s_quoted) {  
396 - if (ch == '\'') {  
397 - s_quoted = false;  
398 - need_space = true;  
399 - found = true;  
400 - }  
401 - } else if (is_common_space(ch) || ch == ';' || ch == '{') {  
402 - last_space = true;  
403 - found = 1;  
404 - }  
405 -  
406 - if (found) {  
407 - int len = buffer->pos - pstart;  
408 - char* word = new char[len];  
409 - memcpy(word, pstart, len);  
410 - word[len - 1] = 0;  
411 -  
412 - string word_str = word;  
413 - if (!word_str.empty()) {  
414 - args.push_back(word_str);  
415 - }  
416 - srs_freepa(word);  
417 -  
418 - if (ch == ';') {  
419 - return ERROR_SYSTEM_CONFIG_DIRECTIVE;  
420 - }  
421 - if (ch == '{') {  
422 - return ERROR_SYSTEM_CONFIG_BLOCK_START;  
423 - }  
424 - }  
425 - }  
426 - }  
427 -  
428 - return ret;  
429 -}  
430 -  
431 -SrsConfig* config = new SrsConfig();  
432 -  
433 -SrsConfig::SrsConfig()  
434 -{  
435 - show_help = false;  
436 - show_version = false;  
437 -  
438 - root = new SrsConfDirective();  
439 - root->conf_line = 0;  
440 - root->name = "root";  
441 -}  
442 -  
443 -SrsConfig::~SrsConfig()  
444 -{  
445 - srs_freep(root);  
446 -}  
447 -  
448 -int SrsConfig::reload()  
449 -{  
450 - int ret = ERROR_SUCCESS;  
451 -  
452 - SrsConfig conf;  
453 - if ((ret = conf.parse_file(config_file.c_str())) != ERROR_SUCCESS) {  
454 - srs_error("config reloader parse file failed. ret=%d", ret);  
455 - return ret;  
456 - }  
457 - srs_info("config reloader parse file success.");  
458 -  
459 - // store current root to old_root,  
460 - // and reap the root from conf to current root.  
461 - SrsConfDirective* old_root = root;  
462 - SrsAutoFree(SrsConfDirective, old_root, false);  
463 -  
464 - root = conf.root;  
465 - conf.root = NULL;  
466 -  
467 - // merge config.  
468 - std::vector<ISrsReloadHandler*>::iterator it;  
469 -  
470 - // merge config: listen  
471 - if (!srs_directive_equals(root->get("listen"), old_root->get("listen"))) {  
472 - for (it = subscribes.begin(); it != subscribes.end(); ++it) {  
473 - ISrsReloadHandler* subscribe = *it;  
474 - if ((ret = subscribe->on_reload_listen()) != ERROR_SUCCESS) {  
475 - srs_error("notify subscribes reload listen failed. ret=%d", ret);  
476 - return ret;  
477 - }  
478 - }  
479 - srs_trace("reload listen success.");  
480 - }  
481 -  
482 - // merge config: pithy_print  
483 - if (!srs_directive_equals(root->get("pithy_print"), old_root->get("pithy_print"))) {  
484 - for (it = subscribes.begin(); it != subscribes.end(); ++it) {  
485 - ISrsReloadHandler* subscribe = *it;  
486 - if ((ret = subscribe->on_reload_pithy_print()) != ERROR_SUCCESS) {  
487 - srs_error("notify subscribes pithy_print listen failed. ret=%d", ret);  
488 - return ret;  
489 - }  
490 - }  
491 - srs_trace("reload pithy_print success.");  
492 - }  
493 -  
494 - // merge config: vhost added, directly supported.  
495 -  
496 - // merge config: vhost removed/disabled/modified.  
497 - for (int i = 0; i < (int)old_root->directives.size(); i++) {  
498 - SrsConfDirective* old_vhost = old_root->at(i);  
499 - // only process vhost directives.  
500 - if (old_vhost->name != "vhost") {  
501 - continue;  
502 - }  
503 -  
504 - std::string vhost = old_vhost->arg0();  
505 -  
506 - SrsConfDirective* new_vhost = root->get("vhost", vhost);  
507 - // ignore if absolutely equal  
508 - if (new_vhost && srs_directive_equals(old_vhost, new_vhost)) {  
509 - srs_trace("vhost %s absolutely equal, ignore.", vhost.c_str());  
510 - continue;  
511 - }  
512 - // ignore if enable the new vhost when old vhost is disabled.  
513 - if (get_vhost_enabled(new_vhost) && !get_vhost_enabled(old_vhost)) {  
514 - srs_trace("vhost %s disabled=>enabled, ignore.", vhost.c_str());  
515 - continue;  
516 - }  
517 - // ignore if both old and new vhost are disabled.  
518 - if (!get_vhost_enabled(new_vhost) && !get_vhost_enabled(old_vhost)) {  
519 - srs_trace("vhost %s disabled=>disabled, ignore.", vhost.c_str());  
520 - continue;  
521 - }  
522 -  
523 - // merge config: vhost removed/disabled.  
524 - if (!get_vhost_enabled(new_vhost) && get_vhost_enabled(old_vhost)) {  
525 - srs_trace("vhost %s disabled, reload it.", vhost.c_str());  
526 - for (it = subscribes.begin(); it != subscribes.end(); ++it) {  
527 - ISrsReloadHandler* subscribe = *it;  
528 - if ((ret = subscribe->on_reload_vhost_removed(vhost)) != ERROR_SUCCESS) {  
529 - srs_error("notify subscribes pithy_print remove "  
530 - "vhost %s failed. ret=%d", vhost.c_str(), ret);  
531 - return ret;  
532 - }  
533 - }  
534 - srs_trace("reload remove vhost %s success.", vhost.c_str());  
535 - }  
536 -  
537 - // merge config: vhost modified.  
538 - srs_trace("vhost %s modified, reload its detail.", vhost.c_str());  
539 - if (get_vhost_enabled(new_vhost) && get_vhost_enabled(old_vhost)) {  
540 - // gop_cache  
541 - if (!srs_directive_equals(new_vhost->get("gop_cache"), old_vhost->get("gop_cache"))) {  
542 - for (it = subscribes.begin(); it != subscribes.end(); ++it) {  
543 - ISrsReloadHandler* subscribe = *it;  
544 - if ((ret = subscribe->on_reload_gop_cache(vhost)) != ERROR_SUCCESS) {  
545 - srs_error("vhost %s notify subscribes gop_cache failed. ret=%d", vhost.c_str(), ret);  
546 - return ret;  
547 - }  
548 - }  
549 - srs_trace("vhost %s reload gop_cache success.", vhost.c_str());  
550 - }  
551 - // queue_length  
552 - if (!srs_directive_equals(new_vhost->get("queue_length"), old_vhost->get("queue_length"))) {  
553 - for (it = subscribes.begin(); it != subscribes.end(); ++it) {  
554 - ISrsReloadHandler* subscribe = *it;  
555 - if ((ret = subscribe->on_reload_queue_length(vhost)) != ERROR_SUCCESS) {  
556 - srs_error("vhost %s notify subscribes queue_length failed. ret=%d", vhost.c_str(), ret);  
557 - return ret;  
558 - }  
559 - }  
560 - srs_trace("vhost %s reload queue_length success.", vhost.c_str());  
561 - }  
562 - // forward  
563 - if (!srs_directive_equals(new_vhost->get("forward"), old_vhost->get("forward"))) {  
564 - for (it = subscribes.begin(); it != subscribes.end(); ++it) {  
565 - ISrsReloadHandler* subscribe = *it;  
566 - if ((ret = subscribe->on_reload_forward(vhost)) != ERROR_SUCCESS) {  
567 - srs_error("vhost %s notify subscribes forward failed. ret=%d", vhost.c_str(), ret);  
568 - return ret;  
569 - }  
570 - }  
571 - srs_trace("vhost %s reload forward success.", vhost.c_str());  
572 - }  
573 - // hls  
574 - if (!srs_directive_equals(new_vhost->get("hls"), old_vhost->get("hls"))) {  
575 - for (it = subscribes.begin(); it != subscribes.end(); ++it) {  
576 - ISrsReloadHandler* subscribe = *it;  
577 - if ((ret = subscribe->on_reload_hls(vhost)) != ERROR_SUCCESS) {  
578 - srs_error("vhost %s notify subscribes hls failed. ret=%d", vhost.c_str(), ret);  
579 - return ret;  
580 - }  
581 - }  
582 - srs_trace("vhost %s reload hls success.", vhost.c_str());  
583 - }  
584 - // transcode  
585 - if (!srs_directive_equals(new_vhost->get("transcode"), old_vhost->get("transcode"))) {  
586 - for (it = subscribes.begin(); it != subscribes.end(); ++it) {  
587 - ISrsReloadHandler* subscribe = *it;  
588 - if ((ret = subscribe->on_reload_transcode(vhost)) != ERROR_SUCCESS) {  
589 - srs_error("vhost %s notify subscribes transcode failed. ret=%d", vhost.c_str(), ret);  
590 - return ret;  
591 - }  
592 - }  
593 - srs_trace("vhost %s reload transcode success.", vhost.c_str());  
594 - }  
595 - // TODO: suppor reload hls/forward/ffmpeg/http  
596 - continue;  
597 - }  
598 - srs_warn("invalid reload path, enabled old: %d, new: %d",  
599 - get_vhost_enabled(old_vhost), get_vhost_enabled(new_vhost));  
600 - }  
601 -  
602 - return ret;  
603 -}  
604 -  
605 -void SrsConfig::subscribe(ISrsReloadHandler* handler)  
606 -{  
607 - std::vector<ISrsReloadHandler*>::iterator it;  
608 -  
609 - it = std::find(subscribes.begin(), subscribes.end(), handler);  
610 - if (it != subscribes.end()) {  
611 - return;  
612 - }  
613 -  
614 - subscribes.push_back(handler);  
615 -}  
616 -  
617 -void SrsConfig::unsubscribe(ISrsReloadHandler* handler)  
618 -{  
619 - std::vector<ISrsReloadHandler*>::iterator it;  
620 -  
621 - it = std::find(subscribes.begin(), subscribes.end(), handler);  
622 - if (it == subscribes.end()) {  
623 - return;  
624 - }  
625 -  
626 - subscribes.erase(it);  
627 -}  
628 -  
629 -// see: ngx_get_options  
630 -int SrsConfig::parse_options(int argc, char** argv)  
631 -{  
632 - int ret = ERROR_SUCCESS;  
633 -  
634 - for (int i = 1; i < argc; i++) {  
635 - if ((ret = parse_argv(i, argv)) != ERROR_SUCCESS) {  
636 - return ret;  
637 - }  
638 - }  
639 -  
640 - if (show_help) {  
641 - print_help(argv);  
642 - }  
643 -  
644 - if (show_version) {  
645 - printf("%s\n", RTMP_SIG_SRS_VERSION);  
646 - }  
647 -  
648 - if (show_help || show_version) {  
649 - exit(0);  
650 - }  
651 -  
652 - if (config_file.empty()) {  
653 - ret = ERROR_SYSTEM_CONFIG_INVALID;  
654 - srs_error("config file not specified, see help: %s -h, ret=%d", argv[0], ret);  
655 - return ret;  
656 - }  
657 -  
658 - return parse_file(config_file.c_str());  
659 -}  
660 -  
661 -int SrsConfig::parse_file(const char* filename)  
662 -{  
663 - int ret = ERROR_SUCCESS;  
664 -  
665 - config_file = filename;  
666 -  
667 - if (config_file.empty()) {  
668 - return ERROR_SYSTEM_CONFIG_INVALID;  
669 - }  
670 -  
671 - if ((ret = root->parse(config_file.c_str())) != ERROR_SUCCESS) {  
672 - return ret;  
673 - }  
674 -  
675 - SrsConfDirective* conf = NULL;  
676 - if ((conf = get_listen()) == NULL || conf->args.size() == 0) {  
677 - ret = ERROR_SYSTEM_CONFIG_INVALID;  
678 - srs_error("line %d: conf error, "  
679 - "directive \"listen\" is empty, ret=%d", (conf? conf->conf_line:0), ret);  
680 - return ret;  
681 - }  
682 -  
683 - // TODO: check the hls.  
684 - // TODO: check forward.  
685 - // TODO: check ffmpeg.  
686 - // TODO: check http.  
687 -  
688 - return ret;  
689 -}  
690 -  
691 -int SrsConfig::parse_argv(int& i, char** argv)  
692 -{  
693 - int ret = ERROR_SUCCESS;  
694 -  
695 - char* p = argv[i];  
696 -  
697 - if (*p++ != '-') {  
698 - ret = ERROR_SYSTEM_CONFIG_INVALID;  
699 - srs_error("invalid options(index=%d, value=%s), "  
700 - "must starts with -, see help: %s -h, ret=%d", i, argv[i], argv[0], ret);  
701 - return ret;  
702 - }  
703 -  
704 - while (*p) {  
705 - switch (*p++) {  
706 - case '?':  
707 - case 'h':  
708 - show_help = true;  
709 - break;  
710 - case 'v':  
711 - case 'V':  
712 - show_version = true;  
713 - break;  
714 - case 'c':  
715 - if (*p) {  
716 - config_file = p;  
717 - return ret;  
718 - }  
719 - if (argv[++i]) {  
720 - config_file = argv[i];  
721 - return ret;  
722 - }  
723 - ret = ERROR_SYSTEM_CONFIG_INVALID;  
724 - srs_error("option \"-c\" requires parameter, ret=%d", ret);  
725 - return ret;  
726 - default:  
727 - ret = ERROR_SYSTEM_CONFIG_INVALID;  
728 - srs_error("invalid option: \"%c\", see help: %s -h, ret=%d", *(p - 1), argv[0], ret);  
729 - return ret;  
730 - }  
731 - }  
732 -  
733 - return ret;  
734 -}  
735 -  
736 -void SrsConfig::print_help(char** argv)  
737 -{  
738 - printf(  
739 - RTMP_SIG_SRS_NAME" "RTMP_SIG_SRS_VERSION" "RTMP_SIG_SRS_COPYRIGHT"\n"  
740 - "Primary Authors: "RTMP_SIG_SRS_PRIMARY_AUTHROS"\n"  
741 - "Build: "SRS_BUILD_DATE" Configuration: "SRS_CONFIGURE"\n"  
742 - "Usage: %s [-h?vV] [-c <filename>]\n"  
743 - "\n"  
744 - "Options:\n"  
745 - " -?-h : show help\n"  
746 - " -v-V : show version and exit\n"  
747 - " -c filename : set configuration file\n"  
748 - "\n"  
749 - RTMP_SIG_SRS_WEB"\n"  
750 - RTMP_SIG_SRS_URL"\n"  
751 - "Email: "RTMP_SIG_SRS_EMAIL"\n"  
752 - "\n",  
753 - argv[0]);  
754 -}  
755 -  
756 -SrsConfDirective* SrsConfig::get_vhost(string vhost)  
757 -{  
758 - srs_assert(root);  
759 -  
760 - for (int i = 0; i < (int)root->directives.size(); i++) {  
761 - SrsConfDirective* conf = root->at(i);  
762 -  
763 - if (conf->name != "vhost") {  
764 - continue;  
765 - }  
766 -  
767 - if (conf->arg0() == vhost) {  
768 - return conf;  
769 - }  
770 - }  
771 -  
772 - if (vhost != RTMP_VHOST_DEFAULT) {  
773 - return get_vhost(RTMP_VHOST_DEFAULT);  
774 - }  
775 -  
776 - return NULL;  
777 -}  
778 -  
779 -SrsConfDirective* SrsConfig::get_vhost_on_connect(string vhost)  
780 -{  
781 - SrsConfDirective* conf = get_vhost(vhost);  
782 -  
783 - if (!conf) {  
784 - return NULL;  
785 - }  
786 -  
787 - conf = conf->get("http_hooks");  
788 - if (!conf) {  
789 - return NULL;  
790 - }  
791 -  
792 - SrsConfDirective* enabled = conf->get("enabled");  
793 - if (!enabled || enabled->arg0() != "on") {  
794 - return NULL;  
795 - }  
796 -  
797 - return conf->get("on_connect");  
798 -}  
799 -  
800 -SrsConfDirective* SrsConfig::get_vhost_on_close(string vhost)  
801 -{  
802 - SrsConfDirective* conf = get_vhost(vhost);  
803 -  
804 - if (!conf) {  
805 - return NULL;  
806 - }  
807 -  
808 - conf = conf->get("http_hooks");  
809 - if (!conf) {  
810 - return NULL;  
811 - }  
812 -  
813 - SrsConfDirective* enabled = conf->get("enabled");  
814 - if (!enabled || enabled->arg0() != "on") {  
815 - return NULL;  
816 - }  
817 -  
818 - return conf->get("on_close");  
819 -}  
820 -  
821 -SrsConfDirective* SrsConfig::get_vhost_on_publish(string vhost)  
822 -{  
823 - SrsConfDirective* conf = get_vhost(vhost);  
824 -  
825 - if (!conf) {  
826 - return NULL;  
827 - }  
828 -  
829 - conf = conf->get("http_hooks");  
830 - if (!conf) {  
831 - return NULL;  
832 - }  
833 -  
834 - SrsConfDirective* enabled = conf->get("enabled");  
835 - if (!enabled || enabled->arg0() != "on") {  
836 - return NULL;  
837 - }  
838 -  
839 - return conf->get("on_publish");  
840 -}  
841 -  
842 -SrsConfDirective* SrsConfig::get_vhost_on_unpublish(string vhost)  
843 -{  
844 - SrsConfDirective* conf = get_vhost(vhost);  
845 -  
846 - if (!conf) {  
847 - return NULL;  
848 - }  
849 -  
850 - conf = conf->get("http_hooks");  
851 - if (!conf) {  
852 - return NULL;  
853 - }  
854 -  
855 - SrsConfDirective* enabled = conf->get("enabled");  
856 - if (!enabled || enabled->arg0() != "on") {  
857 - return NULL;  
858 - }  
859 -  
860 - return conf->get("on_unpublish");  
861 -}  
862 -  
863 -SrsConfDirective* SrsConfig::get_vhost_on_play(string vhost)  
864 -{  
865 - SrsConfDirective* conf = get_vhost(vhost);  
866 -  
867 - if (!conf) {  
868 - return NULL;  
869 - }  
870 -  
871 - conf = conf->get("http_hooks");  
872 - if (!conf) {  
873 - return NULL;  
874 - }  
875 -  
876 - SrsConfDirective* enabled = conf->get("enabled");  
877 - if (!enabled || enabled->arg0() != "on") {  
878 - return NULL;  
879 - }  
880 -  
881 - return conf->get("on_play");  
882 -}  
883 -  
884 -SrsConfDirective* SrsConfig::get_vhost_on_stop(string vhost)  
885 -{  
886 - SrsConfDirective* conf = get_vhost(vhost);  
887 -  
888 - if (!conf) {  
889 - return NULL;  
890 - }  
891 -  
892 - conf = conf->get("http_hooks");  
893 - if (!conf) {  
894 - return NULL;  
895 - }  
896 -  
897 - SrsConfDirective* enabled = conf->get("enabled");  
898 - if (!enabled || enabled->arg0() != "on") {  
899 - return NULL;  
900 - }  
901 -  
902 - return conf->get("on_stop");  
903 -}  
904 -  
905 -bool SrsConfig::get_vhost_enabled(string vhost)  
906 -{  
907 - SrsConfDirective* vhost_conf = get_vhost(vhost);  
908 -  
909 - return get_vhost_enabled(vhost_conf);  
910 -}  
911 -  
912 -bool SrsConfig::get_vhost_enabled(SrsConfDirective* vhost)  
913 -{  
914 - if (!vhost) {  
915 - return false;  
916 - }  
917 -  
918 - SrsConfDirective* conf = vhost->get("enabled");  
919 - if (!conf) {  
920 - return true;  
921 - }  
922 -  
923 - if (conf->arg0() == "off") {  
924 - return false;  
925 - }  
926 -  
927 - return true;  
928 -}  
929 -  
930 -SrsConfDirective* SrsConfig::get_transcode(string vhost, string scope)  
931 -{  
932 - SrsConfDirective* conf = get_vhost(vhost);  
933 -  
934 - if (!conf) {  
935 - return NULL;  
936 - }  
937 -  
938 - SrsConfDirective* transcode = conf->get("transcode");  
939 - if (!transcode) {  
940 - return NULL;  
941 - }  
942 -  
943 - if (transcode->arg0() == scope) {  
944 - return transcode;  
945 - }  
946 -  
947 - return NULL;  
948 -}  
949 -  
950 -bool SrsConfig::get_transcode_enabled(SrsConfDirective* transcode)  
951 -{  
952 - if (!transcode) {  
953 - return false;  
954 - }  
955 -  
956 - SrsConfDirective* conf = transcode->get("enabled");  
957 - if (!conf || conf->arg0() != "on") {  
958 - return false;  
959 - }  
960 -  
961 - return true;  
962 -}  
963 -  
964 -string SrsConfig::get_transcode_ffmpeg(SrsConfDirective* transcode)  
965 -{  
966 - if (!transcode) {  
967 - return "";  
968 - }  
969 -  
970 - SrsConfDirective* conf = transcode->get("ffmpeg");  
971 - if (!conf) {  
972 - return "";  
973 - }  
974 -  
975 - return conf->arg0();  
976 -}  
977 -  
978 -void SrsConfig::get_transcode_engines(SrsConfDirective* transcode, std::vector<SrsConfDirective*>& engines)  
979 -{  
980 - if (!transcode) {  
981 - return;  
982 - }  
983 -  
984 - for (int i = 0; i < (int)transcode->directives.size(); i++) {  
985 - SrsConfDirective* conf = transcode->directives[i];  
986 -  
987 - if (conf->name == "engine") {  
988 - engines.push_back(conf);  
989 - }  
990 - }  
991 -  
992 - return;  
993 -}  
994 -  
995 -bool SrsConfig::get_engine_enabled(SrsConfDirective* engine)  
996 -{  
997 - if (!engine) {  
998 - return false;  
999 - }  
1000 -  
1001 - SrsConfDirective* conf = engine->get("enabled");  
1002 - if (!conf || conf->arg0() != "on") {  
1003 - return false;  
1004 - }  
1005 -  
1006 - return true;  
1007 -}  
1008 -  
1009 -string SrsConfig::get_engine_vcodec(SrsConfDirective* engine)  
1010 -{  
1011 - if (!engine) {  
1012 - return "";  
1013 - }  
1014 -  
1015 - SrsConfDirective* conf = engine->get("vcodec");  
1016 - if (!conf) {  
1017 - return "";  
1018 - }  
1019 -  
1020 - return conf->arg0();  
1021 -}  
1022 -  
1023 -int SrsConfig::get_engine_vbitrate(SrsConfDirective* engine)  
1024 -{  
1025 - if (!engine) {  
1026 - return 0;  
1027 - }  
1028 -  
1029 - SrsConfDirective* conf = engine->get("vbitrate");  
1030 - if (!conf) {  
1031 - return 0;  
1032 - }  
1033 -  
1034 - return ::atoi(conf->arg0().c_str());  
1035 -}  
1036 -  
1037 -double SrsConfig::get_engine_vfps(SrsConfDirective* engine)  
1038 -{  
1039 - if (!engine) {  
1040 - return 0;  
1041 - }  
1042 -  
1043 - SrsConfDirective* conf = engine->get("vfps");  
1044 - if (!conf) {  
1045 - return 0;  
1046 - }  
1047 -  
1048 - return ::atof(conf->arg0().c_str());  
1049 -}  
1050 -  
1051 -int SrsConfig::get_engine_vwidth(SrsConfDirective* engine)  
1052 -{  
1053 - if (!engine) {  
1054 - return 0;  
1055 - }  
1056 -  
1057 - SrsConfDirective* conf = engine->get("vwidth");  
1058 - if (!conf) {  
1059 - return 0;  
1060 - }  
1061 -  
1062 - return ::atoi(conf->arg0().c_str());  
1063 -}  
1064 -  
1065 -int SrsConfig::get_engine_vheight(SrsConfDirective* engine)  
1066 -{  
1067 - if (!engine) {  
1068 - return 0;  
1069 - }  
1070 -  
1071 - SrsConfDirective* conf = engine->get("vheight");  
1072 - if (!conf) {  
1073 - return 0;  
1074 - }  
1075 -  
1076 - return ::atoi(conf->arg0().c_str());  
1077 -}  
1078 -  
1079 -int SrsConfig::get_engine_vthreads(SrsConfDirective* engine)  
1080 -{  
1081 - if (!engine) {  
1082 - return 0;  
1083 - }  
1084 -  
1085 - SrsConfDirective* conf = engine->get("vthreads");  
1086 - if (!conf) {  
1087 - return 0;  
1088 - }  
1089 -  
1090 - return ::atoi(conf->arg0().c_str());  
1091 -}  
1092 -  
1093 -string SrsConfig::get_engine_vprofile(SrsConfDirective* engine)  
1094 -{  
1095 - if (!engine) {  
1096 - return "";  
1097 - }  
1098 -  
1099 - SrsConfDirective* conf = engine->get("vprofile");  
1100 - if (!conf) {  
1101 - return "";  
1102 - }  
1103 -  
1104 - return conf->arg0();  
1105 -}  
1106 -  
1107 -string SrsConfig::get_engine_vpreset(SrsConfDirective* engine)  
1108 -{  
1109 - if (!engine) {  
1110 - return "";  
1111 - }  
1112 -  
1113 - SrsConfDirective* conf = engine->get("vpreset");  
1114 - if (!conf) {  
1115 - return "";  
1116 - }  
1117 -  
1118 - return conf->arg0();  
1119 -}  
1120 -  
1121 -void SrsConfig::get_engine_vparams(SrsConfDirective* engine, std::vector<string>& vparams)  
1122 -{  
1123 - if (!engine) {  
1124 - return;  
1125 - }  
1126 -  
1127 - SrsConfDirective* conf = engine->get("vparams");  
1128 - if (!conf) {  
1129 - return;  
1130 - }  
1131 -  
1132 - for (int i = 0; i < (int)conf->directives.size(); i++) {  
1133 - SrsConfDirective* p = conf->directives[i];  
1134 - if (!p) {  
1135 - continue;  
1136 - }  
1137 -  
1138 - vparams.push_back("-" + p->name);  
1139 - vparams.push_back(p->arg0());  
1140 - }  
1141 -}  
1142 -  
1143 -void SrsConfig::get_engine_vfilter(SrsConfDirective* engine, std::vector<string>& vfilter)  
1144 -{  
1145 - if (!engine) {  
1146 - return;  
1147 - }  
1148 -  
1149 - SrsConfDirective* conf = engine->get("vfilter");  
1150 - if (!conf) {  
1151 - return;  
1152 - }  
1153 -  
1154 - for (int i = 0; i < (int)conf->directives.size(); i++) {  
1155 - SrsConfDirective* p = conf->directives[i];  
1156 - if (!p) {  
1157 - continue;  
1158 - }  
1159 -  
1160 - vfilter.push_back("-" + p->name);  
1161 - vfilter.push_back(p->arg0());  
1162 - }  
1163 -}  
1164 -  
1165 -string SrsConfig::get_engine_acodec(SrsConfDirective* engine)  
1166 -{  
1167 - if (!engine) {  
1168 - return "";  
1169 - }  
1170 -  
1171 - SrsConfDirective* conf = engine->get("acodec");  
1172 - if (!conf) {  
1173 - return "";  
1174 - }  
1175 -  
1176 - return conf->arg0();  
1177 -}  
1178 -  
1179 -int SrsConfig::get_engine_abitrate(SrsConfDirective* engine)  
1180 -{  
1181 - if (!engine) {  
1182 - return 0;  
1183 - }  
1184 -  
1185 - SrsConfDirective* conf = engine->get("abitrate");  
1186 - if (!conf) {  
1187 - return 0;  
1188 - }  
1189 -  
1190 - return ::atoi(conf->arg0().c_str());  
1191 -}  
1192 -  
1193 -int SrsConfig::get_engine_asample_rate(SrsConfDirective* engine)  
1194 -{  
1195 - if (!engine) {  
1196 - return 0;  
1197 - }  
1198 -  
1199 - SrsConfDirective* conf = engine->get("asample_rate");  
1200 - if (!conf) {  
1201 - return 0;  
1202 - }  
1203 -  
1204 - return ::atoi(conf->arg0().c_str());  
1205 -}  
1206 -  
1207 -int SrsConfig::get_engine_achannels(SrsConfDirective* engine)  
1208 -{  
1209 - if (!engine) {  
1210 - return 0;  
1211 - }  
1212 -  
1213 - SrsConfDirective* conf = engine->get("achannels");  
1214 - if (!conf) {  
1215 - return 0;  
1216 - }  
1217 -  
1218 - return ::atoi(conf->arg0().c_str());  
1219 -}  
1220 -  
1221 -void SrsConfig::get_engine_aparams(SrsConfDirective* engine, std::vector<string>& aparams)  
1222 -{  
1223 - if (!engine) {  
1224 - return;  
1225 - }  
1226 -  
1227 - SrsConfDirective* conf = engine->get("aparams");  
1228 - if (!conf) {  
1229 - return;  
1230 - }  
1231 -  
1232 - for (int i = 0; i < (int)conf->directives.size(); i++) {  
1233 - SrsConfDirective* p = conf->directives[i];  
1234 - if (!p) {  
1235 - continue;  
1236 - }  
1237 -  
1238 - aparams.push_back("-" + p->name);  
1239 - aparams.push_back(p->arg0());  
1240 - }  
1241 -}  
1242 -  
1243 -string SrsConfig::get_engine_output(SrsConfDirective* engine)  
1244 -{  
1245 - if (!engine) {  
1246 - return "";  
1247 - }  
1248 -  
1249 - SrsConfDirective* conf = engine->get("output");  
1250 - if (!conf) {  
1251 - return "";  
1252 - }  
1253 -  
1254 - return conf->arg0();  
1255 -}  
1256 -  
1257 -string SrsConfig::get_log_dir()  
1258 -{  
1259 - srs_assert(root);  
1260 -  
1261 - SrsConfDirective* conf = root->get("log_dir");  
1262 - if (!conf || conf->arg0().empty()) {  
1263 - return "./objs/logs";  
1264 - }  
1265 -  
1266 - return conf->arg0();  
1267 -}  
1268 -  
1269 -int SrsConfig::get_max_connections()  
1270 -{  
1271 - srs_assert(root);  
1272 -  
1273 - SrsConfDirective* conf = root->get("max_connections");  
1274 - if (!conf || conf->arg0().empty()) {  
1275 - return 2000;  
1276 - }  
1277 -  
1278 - return ::atoi(conf->arg0().c_str());  
1279 -}  
1280 -  
1281 -bool SrsConfig::get_gop_cache(string vhost)  
1282 -{  
1283 - SrsConfDirective* conf = get_vhost(vhost);  
1284 -  
1285 - if (!conf) {  
1286 - return true;  
1287 - }  
1288 -  
1289 - conf = conf->get("gop_cache");  
1290 - if (conf && conf->arg0() == "off") {  
1291 - return false;  
1292 - }  
1293 -  
1294 - return true;  
1295 -}  
1296 -  
1297 -double SrsConfig::get_queue_length(string vhost)  
1298 -{  
1299 - SrsConfDirective* conf = get_vhost(vhost);  
1300 -  
1301 - if (!conf) {  
1302 - return SRS_CONF_DEFAULT_QUEUE_LENGTH;  
1303 - }  
1304 -  
1305 - conf = conf->get("queue_length");  
1306 - if (!conf || conf->arg0().empty()) {  
1307 - return SRS_CONF_DEFAULT_QUEUE_LENGTH;  
1308 - }  
1309 -  
1310 - return ::atoi(conf->arg0().c_str());  
1311 -}  
1312 -  
1313 -SrsConfDirective* SrsConfig::get_forward(string vhost)  
1314 -{  
1315 - SrsConfDirective* conf = get_vhost(vhost);  
1316 -  
1317 - if (!conf) {  
1318 - return NULL;  
1319 - }  
1320 -  
1321 - return conf->get("forward");  
1322 -}  
1323 -  
1324 -SrsConfDirective* SrsConfig::get_hls(string vhost)  
1325 -{  
1326 - SrsConfDirective* conf = get_vhost(vhost);  
1327 -  
1328 - if (!conf) {  
1329 - return NULL;  
1330 - }  
1331 -  
1332 - return conf->get("hls");  
1333 -}  
1334 -  
1335 -bool SrsConfig::get_hls_enabled(string vhost)  
1336 -{  
1337 - SrsConfDirective* hls = get_hls(vhost);  
1338 -  
1339 - if (!hls) {  
1340 - return false;  
1341 - }  
1342 -  
1343 - SrsConfDirective* conf = hls->get("enabled");  
1344 -  
1345 - if (!conf) {  
1346 - return false;  
1347 - }  
1348 -  
1349 - if (conf->arg0() == "on") {  
1350 - return true;  
1351 - }  
1352 -  
1353 - return false;  
1354 -}  
1355 -  
1356 -string SrsConfig::get_hls_path(string vhost)  
1357 -{  
1358 - SrsConfDirective* hls = get_hls(vhost);  
1359 -  
1360 - if (!hls) {  
1361 - return SRS_CONF_DEFAULT_HLS_PATH;  
1362 - }  
1363 -  
1364 - SrsConfDirective* conf = hls->get("hls_path");  
1365 -  
1366 - if (!conf) {  
1367 - return SRS_CONF_DEFAULT_HLS_PATH;  
1368 - }  
1369 -  
1370 - return conf->arg0();  
1371 -}  
1372 -  
1373 -double SrsConfig::get_hls_fragment(string vhost)  
1374 -{  
1375 - SrsConfDirective* hls = get_hls(vhost);  
1376 -  
1377 - if (!hls) {  
1378 - return SRS_CONF_DEFAULT_HLS_FRAGMENT;  
1379 - }  
1380 -  
1381 - SrsConfDirective* conf = hls->get("hls_fragment");  
1382 -  
1383 - if (!conf) {  
1384 - return SRS_CONF_DEFAULT_HLS_FRAGMENT;  
1385 - }  
1386 -  
1387 - return ::atof(conf->arg0().c_str());  
1388 -}  
1389 -  
1390 -double SrsConfig::get_hls_window(string vhost)  
1391 -{  
1392 - SrsConfDirective* hls = get_hls(vhost);  
1393 -  
1394 - if (!hls) {  
1395 - return SRS_CONF_DEFAULT_HLS_WINDOW;  
1396 - }  
1397 -  
1398 - SrsConfDirective* conf = hls->get("hls_window");  
1399 -  
1400 - if (!conf) {  
1401 - return SRS_CONF_DEFAULT_HLS_WINDOW;  
1402 - }  
1403 -  
1404 - return ::atof(conf->arg0().c_str());  
1405 -}  
1406 -  
1407 -SrsConfDirective* SrsConfig::get_refer(string vhost)  
1408 -{  
1409 - SrsConfDirective* conf = get_vhost(vhost);  
1410 -  
1411 - if (!conf) {  
1412 - return NULL;  
1413 - }  
1414 -  
1415 - return conf->get("refer");  
1416 -}  
1417 -  
1418 -SrsConfDirective* SrsConfig::get_refer_play(string vhost)  
1419 -{  
1420 - SrsConfDirective* conf = get_vhost(vhost);  
1421 -  
1422 - if (!conf) {  
1423 - return NULL;  
1424 - }  
1425 -  
1426 - return conf->get("refer_play");  
1427 -}  
1428 -  
1429 -SrsConfDirective* SrsConfig::get_refer_publish(string vhost)  
1430 -{  
1431 - SrsConfDirective* conf = get_vhost(vhost);  
1432 -  
1433 - if (!conf) {  
1434 - return NULL;  
1435 - }  
1436 -  
1437 - return conf->get("refer_publish");  
1438 -}  
1439 -  
1440 -SrsConfDirective* SrsConfig::get_listen()  
1441 -{  
1442 - return root->get("listen");  
1443 -}  
1444 -  
1445 -int SrsConfig::get_chunk_size(const std::string &vhost)  
1446 -{  
1447 - SrsConfDirective* conf = get_vhost(vhost);  
1448 -  
1449 - if (!conf) {  
1450 - return SRS_CONF_DEFAULT_CHUNK_SIZE;  
1451 - }  
1452 -  
1453 - conf = conf->get("chunk_size");  
1454 - if (!conf) {  
1455 - // vhost does not specify the chunk size,  
1456 - // use the global instead.  
1457 - conf = root->get("chunk_size");  
1458 - if (!conf) {  
1459 - return SRS_CONF_DEFAULT_CHUNK_SIZE;  
1460 - }  
1461 -  
1462 - return ::atoi(conf->arg0().c_str());  
1463 - }  
1464 -  
1465 - return ::atoi(conf->arg0().c_str());  
1466 -}  
1467 -  
1468 -int SrsConfig::get_pithy_print_publish()  
1469 -{  
1470 - SrsConfDirective* pithy = root->get("pithy_print");  
1471 - if (!pithy) {  
1472 - return SRS_STAGE_PUBLISH_USER_INTERVAL_MS;  
1473 - }  
1474 -  
1475 - pithy = pithy->get("publish");  
1476 - if (!pithy) {  
1477 - return SRS_STAGE_PUBLISH_USER_INTERVAL_MS;  
1478 - }  
1479 -  
1480 - return ::atoi(pithy->arg0().c_str());  
1481 -}  
1482 -  
1483 -int SrsConfig::get_pithy_print_forwarder()  
1484 -{  
1485 - SrsConfDirective* pithy = root->get("pithy_print");  
1486 - if (!pithy) {  
1487 - return SRS_STAGE_FORWARDER_INTERVAL_MS;  
1488 - }  
1489 -  
1490 - pithy = pithy->get("forwarder");  
1491 - if (!pithy) {  
1492 - return SRS_STAGE_FORWARDER_INTERVAL_MS;  
1493 - }  
1494 -  
1495 - return ::atoi(pithy->arg0().c_str());  
1496 -}  
1497 -  
1498 -int SrsConfig::get_pithy_print_hls()  
1499 -{  
1500 - SrsConfDirective* pithy = root->get("pithy_print");  
1501 - if (!pithy) {  
1502 - return SRS_STAGE_HLS_INTERVAL_MS;  
1503 - }  
1504 -  
1505 - pithy = pithy->get("hls");  
1506 - if (!pithy) {  
1507 - return SRS_STAGE_HLS_INTERVAL_MS;  
1508 - }  
1509 -  
1510 - return ::atoi(pithy->arg0().c_str());  
1511 -}  
1512 -  
1513 -bool SrsConfig::get_bw_check_enabled(const string &vhost)  
1514 -{  
1515 - SrsConfDirective* conf = get_vhost(vhost);  
1516 -  
1517 - if (!conf) {  
1518 - return false;  
1519 - }  
1520 -  
1521 - conf = conf->get("bandcheck");  
1522 - if (!conf) {  
1523 - return false;  
1524 - }  
1525 -  
1526 - conf = conf->get("enabled");  
1527 - if (!conf || conf->arg0() != "on") {  
1528 - return false;  
1529 - }  
1530 -  
1531 - return true;  
1532 -}  
1533 -  
1534 -string SrsConfig::get_bw_check_key(const string &vhost)  
1535 -{  
1536 - SrsConfDirective* conf = get_vhost(vhost);  
1537 -  
1538 - if (!conf) {  
1539 - return "";  
1540 - }  
1541 -  
1542 - conf = conf->get("bandcheck");  
1543 - if (!conf) {  
1544 - return "";  
1545 - }  
1546 -  
1547 - conf = conf->get("key");  
1548 - if (!conf) {  
1549 - return "";  
1550 - }  
1551 -  
1552 - return conf->arg0();  
1553 -}  
1554 -  
1555 -int SrsConfig::get_bw_check_interval_ms(const string &vhost)  
1556 -{  
1557 - SrsConfDirective* conf = get_vhost(vhost);  
1558 -  
1559 - if (!conf) {  
1560 - return SRS_CONF_DEFAULT_BANDWIDTH_INTERVAL;  
1561 - }  
1562 -  
1563 - conf = conf->get("bandcheck");  
1564 - if (!conf) {  
1565 - return SRS_CONF_DEFAULT_BANDWIDTH_INTERVAL;  
1566 - }  
1567 -  
1568 - conf = conf->get("interval_ms");  
1569 - if (!conf) {  
1570 - return SRS_CONF_DEFAULT_BANDWIDTH_INTERVAL;  
1571 - }  
1572 -  
1573 - return ::atoi(conf->arg0().c_str()) * 1000;  
1574 -}  
1575 -  
1576 -int SrsConfig::get_bw_check_limit_kbps(const string &vhost)  
1577 -{  
1578 - SrsConfDirective* conf = get_vhost(vhost);  
1579 -  
1580 - if (!conf) {  
1581 - return SRS_CONF_DEFAULT_BANDWIDTH_LIMIT_KBPS;  
1582 - }  
1583 -  
1584 - conf = conf->get("bandcheck");  
1585 - if (!conf) {  
1586 - return SRS_CONF_DEFAULT_BANDWIDTH_LIMIT_KBPS;  
1587 - }  
1588 -  
1589 - conf = conf->get("limit_kbps");  
1590 - if (!conf) {  
1591 - return SRS_CONF_DEFAULT_BANDWIDTH_LIMIT_KBPS;  
1592 - }  
1593 -  
1594 - return ::atoi(conf->arg0().c_str());  
1595 -}  
1596 -  
1597 -int SrsConfig::get_pithy_print_encoder()  
1598 -{  
1599 - SrsConfDirective* pithy = root->get("encoder");  
1600 - if (!pithy) {  
1601 - return SRS_STAGE_ENCODER_INTERVAL_MS;  
1602 - }  
1603 -  
1604 - pithy = pithy->get("forwarder");  
1605 - if (!pithy) {  
1606 - return SRS_STAGE_ENCODER_INTERVAL_MS;  
1607 - }  
1608 -  
1609 - return ::atoi(pithy->arg0().c_str());  
1610 -}  
1611 -  
1612 -int SrsConfig::get_pithy_print_play()  
1613 -{  
1614 - SrsConfDirective* pithy = root->get("pithy_print");  
1615 - if (!pithy) {  
1616 - return SRS_STAGE_PLAY_USER_INTERVAL_MS;  
1617 - }  
1618 -  
1619 - pithy = pithy->get("play");  
1620 - if (!pithy) {  
1621 - return SRS_STAGE_PLAY_USER_INTERVAL_MS;  
1622 - }  
1623 -  
1624 - return ::atoi(pithy->arg0().c_str());  
1625 -}  
1626 -  
1627 -bool srs_directive_equals(SrsConfDirective* a, SrsConfDirective* b)  
1628 -{  
1629 - // both NULL, equal.  
1630 - if (!a && !b) {  
1631 - return true;  
1632 - }  
1633 -  
1634 - if (!a || !b) {  
1635 - return false;  
1636 - }  
1637 -  
1638 - if (a->name != b->name) {  
1639 - return false;  
1640 - }  
1641 -  
1642 - if (a->args.size() != b->args.size()) {  
1643 - return false;  
1644 - }  
1645 -  
1646 - for (int i = 0; i < (int)a->args.size(); i++) {  
1647 - if (a->args.at(i) != b->args.at(i)) {  
1648 - return false;  
1649 - }  
1650 - }  
1651 -  
1652 - if (a->directives.size() != b->directives.size()) {  
1653 - return false;  
1654 - }  
1655 -  
1656 - for (int i = 0; i < (int)a->directives.size(); i++) {  
1657 - SrsConfDirective* a0 = a->at(i);  
1658 - SrsConfDirective* b0 = b->at(i);  
1659 -  
1660 - if (!srs_directive_equals(a0, b0)) {  
1661 - return false;  
1662 - }  
1663 - }  
1664 -  
1665 - return true;  
1666 -}  
1667 - 1 +/*
  2 +The MIT License (MIT)
  3 +
  4 +Copyright (c) 2013-2014 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 +using namespace std;
  39 +
  40 +#include <srs_core_error.hpp>
  41 +#include <srs_core_log.hpp>
  42 +#include <srs_core_autofree.hpp>
  43 +
  44 +#define FILE_OFFSET(fd) lseek(fd, 0, SEEK_CUR)
  45 +
  46 +int64_t FILE_SIZE(int fd)
  47 +{
  48 + int64_t pre = FILE_OFFSET(fd);
  49 + int64_t pos = lseek(fd, 0, SEEK_END);
  50 + lseek(fd, pre, SEEK_SET);
  51 + return pos;
  52 +}
  53 +
  54 +#define LF (char)0x0a
  55 +#define CR (char)0x0d
  56 +
  57 +bool is_common_space(char ch)
  58 +{
  59 + return (ch == ' ' || ch == '\t' || ch == CR || ch == LF);
  60 +}
  61 +
  62 +class SrsFileBuffer
  63 +{
  64 +private:
  65 + // last available position.
  66 + char* last;
  67 + // end of buffer.
  68 + char* end;
  69 + // start of buffer.
  70 + char* start;
  71 +public:
  72 + // current consumed position.
  73 + char* pos;
  74 + // current parsed line.
  75 + int line;
  76 +
  77 + SrsFileBuffer();
  78 + virtual ~SrsFileBuffer();
  79 + virtual int fullfill(const char* filename);
  80 + virtual bool empty();
  81 +};
  82 +
  83 +SrsFileBuffer::SrsFileBuffer()
  84 +{
  85 + line = 0;
  86 +
  87 + pos = last = start = NULL;
  88 + end = start;
  89 +}
  90 +
  91 +SrsFileBuffer::~SrsFileBuffer()
  92 +{
  93 + srs_freepa(start);
  94 +}
  95 +
  96 +int SrsFileBuffer::fullfill(const char* filename)
  97 +{
  98 + int ret = ERROR_SUCCESS;
  99 +
  100 + int fd = -1;
  101 + int nread = 0;
  102 + int filesize = 0;
  103 +
  104 + if ((fd = ::open(filename, O_RDONLY, 0)) < 0) {
  105 + ret = ERROR_SYSTEM_CONFIG_INVALID;
  106 + srs_error("open conf file error. ret=%d", ret);
  107 + goto finish;
  108 + }
  109 +
  110 + if ((filesize = FILE_SIZE(fd) - FILE_OFFSET(fd)) <= 0) {
  111 + ret = ERROR_SYSTEM_CONFIG_EOF;
  112 + srs_error("read conf file error. ret=%d", ret);
  113 + goto finish;
  114 + }
  115 +
  116 + srs_freepa(start);
  117 + pos = last = start = new char[filesize];
  118 + end = start + filesize;
  119 +
  120 + if ((nread = read(fd, start, filesize)) != filesize) {
  121 + ret = ERROR_SYSTEM_CONFIG_INVALID;
  122 + srs_error("read file read error. expect %d, actual %d bytes, ret=%d",
  123 + filesize, nread, ret);
  124 + goto finish;
  125 + }
  126 +
  127 + line = 1;
  128 +
  129 +finish:
  130 + if (fd > 0) {
  131 + ::close(fd);
  132 + }
  133 +
  134 + return ret;
  135 +}
  136 +
  137 +bool SrsFileBuffer::empty()
  138 +{
  139 + return pos >= end;
  140 +}
  141 +
  142 +SrsConfDirective::SrsConfDirective()
  143 +{
  144 +}
  145 +
  146 +SrsConfDirective::~SrsConfDirective()
  147 +{
  148 + std::vector<SrsConfDirective*>::iterator it;
  149 + for (it = directives.begin(); it != directives.end(); ++it) {
  150 + SrsConfDirective* directive = *it;
  151 + srs_freep(directive);
  152 + }
  153 + directives.clear();
  154 +}
  155 +
  156 +string SrsConfDirective::arg0()
  157 +{
  158 + if (args.size() > 0) {
  159 + return args.at(0);
  160 + }
  161 +
  162 + return "";
  163 +}
  164 +
  165 +string SrsConfDirective::arg1()
  166 +{
  167 + if (args.size() > 1) {
  168 + return args.at(1);
  169 + }
  170 +
  171 + return "";
  172 +}
  173 +
  174 +string SrsConfDirective::arg2()
  175 +{
  176 + if (args.size() > 2) {
  177 + return args.at(2);
  178 + }
  179 +
  180 + return "";
  181 +}
  182 +
  183 +SrsConfDirective* SrsConfDirective::at(int index)
  184 +{
  185 + return directives.at(index);
  186 +}
  187 +
  188 +SrsConfDirective* SrsConfDirective::get(string _name)
  189 +{
  190 + std::vector<SrsConfDirective*>::iterator it;
  191 + for (it = directives.begin(); it != directives.end(); ++it) {
  192 + SrsConfDirective* directive = *it;
  193 + if (directive->name == _name) {
  194 + return directive;
  195 + }
  196 + }
  197 +
  198 + return NULL;
  199 +}
  200 +
  201 +SrsConfDirective* SrsConfDirective::get(string _name, string _arg0)
  202 +{
  203 + std::vector<SrsConfDirective*>::iterator it;
  204 + for (it = directives.begin(); it != directives.end(); ++it) {
  205 + SrsConfDirective* directive = *it;
  206 + if (directive->name == _name && directive->arg0() == _arg0) {
  207 + return directive;
  208 + }
  209 + }
  210 +
  211 + return NULL;
  212 +}
  213 +
  214 +int SrsConfDirective::parse(const char* filename)
  215 +{
  216 + int ret = ERROR_SUCCESS;
  217 +
  218 + SrsFileBuffer buffer;
  219 +
  220 + if ((ret = buffer.fullfill(filename)) != ERROR_SUCCESS) {
  221 + return ret;
  222 + }
  223 +
  224 + return parse_conf(&buffer, parse_file);
  225 +}
  226 +
  227 +// see: ngx_conf_parse
  228 +int SrsConfDirective::parse_conf(SrsFileBuffer* buffer, SrsDirectiveType type)
  229 +{
  230 + int ret = ERROR_SUCCESS;
  231 +
  232 + while (true) {
  233 + std::vector<string> args;
  234 + ret = read_token(buffer, args);
  235 +
  236 + /**
  237 + * ret maybe:
  238 + * ERROR_SYSTEM_CONFIG_INVALID error.
  239 + * ERROR_SYSTEM_CONFIG_DIRECTIVE directive terminated by ';' found
  240 + * ERROR_SYSTEM_CONFIG_BLOCK_START token terminated by '{' found
  241 + * ERROR_SYSTEM_CONFIG_BLOCK_END the '}' found
  242 + * ERROR_SYSTEM_CONFIG_EOF the config file is done
  243 + */
  244 + if (ret == ERROR_SYSTEM_CONFIG_INVALID) {
  245 + return ret;
  246 + }
  247 + if (ret == ERROR_SYSTEM_CONFIG_BLOCK_END) {
  248 + if (type != parse_block) {
  249 + srs_error("line %d: unexpected \"}\"", buffer->line);
  250 + return ret;
  251 + }
  252 + return ERROR_SUCCESS;
  253 + }
  254 + if (ret == ERROR_SYSTEM_CONFIG_EOF) {
  255 + if (type == parse_block) {
  256 + srs_error("line %d: unexpected end of file, expecting \"}\"", buffer->line);
  257 + return ret;
  258 + }
  259 + return ERROR_SUCCESS;
  260 + }
  261 +
  262 + if (args.empty()) {
  263 + srs_error("line %d: empty directive.", buffer->line);
  264 + return ret;
  265 + }
  266 +
  267 + // build directive tree.
  268 + SrsConfDirective* directive = new SrsConfDirective();
  269 +
  270 + directive->conf_line = buffer->line;
  271 + directive->name = args[0];
  272 + args.erase(args.begin());
  273 + directive->args.swap(args);
  274 +
  275 + directives.push_back(directive);
  276 +
  277 + if (ret == ERROR_SYSTEM_CONFIG_BLOCK_START) {
  278 + if ((ret = directive->parse_conf(buffer, parse_block)) != ERROR_SUCCESS) {
  279 + return ret;
  280 + }
  281 + }
  282 + }
  283 +
  284 + return ret;
  285 +}
  286 +
  287 +// see: ngx_conf_read_token
  288 +int SrsConfDirective::read_token(SrsFileBuffer* buffer, std::vector<string>& args)
  289 +{
  290 + int ret = ERROR_SUCCESS;
  291 +
  292 + char* pstart = buffer->pos;
  293 + int startline = buffer->line;
  294 +
  295 + bool sharp_comment = false;
  296 +
  297 + bool d_quoted = false;
  298 + bool s_quoted = false;
  299 +
  300 + bool need_space = false;
  301 + bool last_space = true;
  302 +
  303 + while (true) {
  304 + if (buffer->empty()) {
  305 + ret = ERROR_SYSTEM_CONFIG_EOF;
  306 +
  307 + if (!args.empty() || !last_space) {
  308 + srs_error("line %d: unexpected end of file, expecting ; or \"}\"", buffer->line);
  309 + return ERROR_SYSTEM_CONFIG_INVALID;
  310 + }
  311 + srs_error("end of file. ret=%d", ret);
  312 +
  313 + return ret;
  314 + }
  315 +
  316 + char ch = *buffer->pos++;
  317 +
  318 + if (ch == LF) {
  319 + buffer->line++;
  320 + sharp_comment = false;
  321 + }
  322 +
  323 + if (sharp_comment) {
  324 + continue;
  325 + }
  326 +
  327 + if (need_space) {
  328 + if (is_common_space(ch)) {
  329 + last_space = true;
  330 + need_space = false;
  331 + continue;
  332 + }
  333 + if (ch == ';') {
  334 + return ERROR_SYSTEM_CONFIG_DIRECTIVE;
  335 + }
  336 + if (ch == '{') {
  337 + return ERROR_SYSTEM_CONFIG_BLOCK_START;
  338 + }
  339 + srs_error("line %d: unexpected '%c'", buffer->line, ch);
  340 + return ERROR_SYSTEM_CONFIG_INVALID;
  341 + }
  342 +
  343 + // last charecter is space.
  344 + if (last_space) {
  345 + if (is_common_space(ch)) {
  346 + continue;
  347 + }
  348 + pstart = buffer->pos - 1;
  349 + startline = buffer->line;
  350 + switch (ch) {
  351 + case ';':
  352 + if (args.size() == 0) {
  353 + srs_error("line %d: unexpected ';'", buffer->line);
  354 + return ERROR_SYSTEM_CONFIG_INVALID;
  355 + }
  356 + return ERROR_SYSTEM_CONFIG_DIRECTIVE;
  357 + case '{':
  358 + if (args.size() == 0) {
  359 + srs_error("line %d: unexpected '{'", buffer->line);
  360 + return ERROR_SYSTEM_CONFIG_INVALID;
  361 + }
  362 + return ERROR_SYSTEM_CONFIG_BLOCK_START;
  363 + case '}':
  364 + if (args.size() != 0) {
  365 + srs_error("line %d: unexpected '}'", buffer->line);
  366 + return ERROR_SYSTEM_CONFIG_INVALID;
  367 + }
  368 + return ERROR_SYSTEM_CONFIG_BLOCK_END;
  369 + case '#':
  370 + sharp_comment = 1;
  371 + continue;
  372 + case '"':
  373 + pstart++;
  374 + d_quoted = true;
  375 + last_space = 0;
  376 + continue;
  377 + case '\'':
  378 + pstart++;
  379 + s_quoted = true;
  380 + last_space = 0;
  381 + continue;
  382 + default:
  383 + last_space = 0;
  384 + continue;
  385 + }
  386 + } else {
  387 + // last charecter is not space
  388 + bool found = false;
  389 + if (d_quoted) {
  390 + if (ch == '"') {
  391 + d_quoted = false;
  392 + need_space = true;
  393 + found = true;
  394 + }
  395 + } else if (s_quoted) {
  396 + if (ch == '\'') {
  397 + s_quoted = false;
  398 + need_space = true;
  399 + found = true;
  400 + }
  401 + } else if (is_common_space(ch) || ch == ';' || ch == '{') {
  402 + last_space = true;
  403 + found = 1;
  404 + }
  405 +
  406 + if (found) {
  407 + int len = buffer->pos - pstart;
  408 + char* word = new char[len];
  409 + memcpy(word, pstart, len);
  410 + word[len - 1] = 0;
  411 +
  412 + string word_str = word;
  413 + if (!word_str.empty()) {
  414 + args.push_back(word_str);
  415 + }
  416 + srs_freepa(word);
  417 +
  418 + if (ch == ';') {
  419 + return ERROR_SYSTEM_CONFIG_DIRECTIVE;
  420 + }
  421 + if (ch == '{') {
  422 + return ERROR_SYSTEM_CONFIG_BLOCK_START;
  423 + }
  424 + }
  425 + }
  426 + }
  427 +
  428 + return ret;
  429 +}
  430 +
  431 +SrsConfig* config = new SrsConfig();
  432 +
  433 +SrsConfig::SrsConfig()
  434 +{
  435 + show_help = false;
  436 + show_version = false;
  437 +
  438 + root = new SrsConfDirective();
  439 + root->conf_line = 0;
  440 + root->name = "root";
  441 +}
  442 +
  443 +SrsConfig::~SrsConfig()
  444 +{
  445 + srs_freep(root);
  446 +}
  447 +
  448 +int SrsConfig::reload()
  449 +{
  450 + int ret = ERROR_SUCCESS;
  451 +
  452 + SrsConfig conf;
  453 + if ((ret = conf.parse_file(config_file.c_str())) != ERROR_SUCCESS) {
  454 + srs_error("config reloader parse file failed. ret=%d", ret);
  455 + return ret;
  456 + }
  457 + srs_info("config reloader parse file success.");
  458 +
  459 + // store current root to old_root,
  460 + // and reap the root from conf to current root.
  461 + SrsConfDirective* old_root = root;
  462 + SrsAutoFree(SrsConfDirective, old_root, false);
  463 +
  464 + root = conf.root;
  465 + conf.root = NULL;
  466 +
  467 + // merge config.
  468 + std::vector<ISrsReloadHandler*>::iterator it;
  469 +
  470 + // merge config: listen
  471 + if (!srs_directive_equals(root->get("listen"), old_root->get("listen"))) {
  472 + for (it = subscribes.begin(); it != subscribes.end(); ++it) {
  473 + ISrsReloadHandler* subscribe = *it;
  474 + if ((ret = subscribe->on_reload_listen()) != ERROR_SUCCESS) {
  475 + srs_error("notify subscribes reload listen failed. ret=%d", ret);
  476 + return ret;
  477 + }
  478 + }
  479 + srs_trace("reload listen success.");
  480 + }
  481 +
  482 + // merge config: pithy_print
  483 + if (!srs_directive_equals(root->get("pithy_print"), old_root->get("pithy_print"))) {
  484 + for (it = subscribes.begin(); it != subscribes.end(); ++it) {
  485 + ISrsReloadHandler* subscribe = *it;
  486 + if ((ret = subscribe->on_reload_pithy_print()) != ERROR_SUCCESS) {
  487 + srs_error("notify subscribes pithy_print listen failed. ret=%d", ret);
  488 + return ret;
  489 + }
  490 + }
  491 + srs_trace("reload pithy_print success.");
  492 + }
  493 +
  494 + // merge config: vhost added, directly supported.
  495 +
  496 + // merge config: vhost removed/disabled/modified.
  497 + for (int i = 0; i < (int)old_root->directives.size(); i++) {
  498 + SrsConfDirective* old_vhost = old_root->at(i);
  499 + // only process vhost directives.
  500 + if (old_vhost->name != "vhost") {
  501 + continue;
  502 + }
  503 +
  504 + std::string vhost = old_vhost->arg0();
  505 +
  506 + SrsConfDirective* new_vhost = root->get("vhost", vhost);
  507 + // ignore if absolutely equal
  508 + if (new_vhost && srs_directive_equals(old_vhost, new_vhost)) {
  509 + srs_trace("vhost %s absolutely equal, ignore.", vhost.c_str());
  510 + continue;
  511 + }
  512 + // ignore if enable the new vhost when old vhost is disabled.
  513 + if (get_vhost_enabled(new_vhost) && !get_vhost_enabled(old_vhost)) {
  514 + srs_trace("vhost %s disabled=>enabled, ignore.", vhost.c_str());
  515 + continue;
  516 + }
  517 + // ignore if both old and new vhost are disabled.
  518 + if (!get_vhost_enabled(new_vhost) && !get_vhost_enabled(old_vhost)) {
  519 + srs_trace("vhost %s disabled=>disabled, ignore.", vhost.c_str());
  520 + continue;
  521 + }
  522 +
  523 + // merge config: vhost removed/disabled.
  524 + if (!get_vhost_enabled(new_vhost) && get_vhost_enabled(old_vhost)) {
  525 + srs_trace("vhost %s disabled, reload it.", vhost.c_str());
  526 + for (it = subscribes.begin(); it != subscribes.end(); ++it) {
  527 + ISrsReloadHandler* subscribe = *it;
  528 + if ((ret = subscribe->on_reload_vhost_removed(vhost)) != ERROR_SUCCESS) {
  529 + srs_error("notify subscribes pithy_print remove "
  530 + "vhost %s failed. ret=%d", vhost.c_str(), ret);
  531 + return ret;
  532 + }
  533 + }
  534 + srs_trace("reload remove vhost %s success.", vhost.c_str());
  535 + }
  536 +
  537 + // merge config: vhost modified.
  538 + srs_trace("vhost %s modified, reload its detail.", vhost.c_str());
  539 + if (get_vhost_enabled(new_vhost) && get_vhost_enabled(old_vhost)) {
  540 + // gop_cache
  541 + if (!srs_directive_equals(new_vhost->get("gop_cache"), old_vhost->get("gop_cache"))) {
  542 + for (it = subscribes.begin(); it != subscribes.end(); ++it) {
  543 + ISrsReloadHandler* subscribe = *it;
  544 + if ((ret = subscribe->on_reload_gop_cache(vhost)) != ERROR_SUCCESS) {
  545 + srs_error("vhost %s notify subscribes gop_cache failed. ret=%d", vhost.c_str(), ret);
  546 + return ret;
  547 + }
  548 + }
  549 + srs_trace("vhost %s reload gop_cache success.", vhost.c_str());
  550 + }
  551 + // queue_length
  552 + if (!srs_directive_equals(new_vhost->get("queue_length"), old_vhost->get("queue_length"))) {
  553 + for (it = subscribes.begin(); it != subscribes.end(); ++it) {
  554 + ISrsReloadHandler* subscribe = *it;
  555 + if ((ret = subscribe->on_reload_queue_length(vhost)) != ERROR_SUCCESS) {
  556 + srs_error("vhost %s notify subscribes queue_length failed. ret=%d", vhost.c_str(), ret);
  557 + return ret;
  558 + }
  559 + }
  560 + srs_trace("vhost %s reload queue_length success.", vhost.c_str());
  561 + }
  562 + // forward
  563 + if (!srs_directive_equals(new_vhost->get("forward"), old_vhost->get("forward"))) {
  564 + for (it = subscribes.begin(); it != subscribes.end(); ++it) {
  565 + ISrsReloadHandler* subscribe = *it;
  566 + if ((ret = subscribe->on_reload_forward(vhost)) != ERROR_SUCCESS) {
  567 + srs_error("vhost %s notify subscribes forward failed. ret=%d", vhost.c_str(), ret);
  568 + return ret;
  569 + }
  570 + }
  571 + srs_trace("vhost %s reload forward success.", vhost.c_str());
  572 + }
  573 + // hls
  574 + if (!srs_directive_equals(new_vhost->get("hls"), old_vhost->get("hls"))) {
  575 + for (it = subscribes.begin(); it != subscribes.end(); ++it) {
  576 + ISrsReloadHandler* subscribe = *it;
  577 + if ((ret = subscribe->on_reload_hls(vhost)) != ERROR_SUCCESS) {
  578 + srs_error("vhost %s notify subscribes hls failed. ret=%d", vhost.c_str(), ret);
  579 + return ret;
  580 + }
  581 + }
  582 + srs_trace("vhost %s reload hls success.", vhost.c_str());
  583 + }
  584 + // transcode
  585 + if (!srs_directive_equals(new_vhost->get("transcode"), old_vhost->get("transcode"))) {
  586 + for (it = subscribes.begin(); it != subscribes.end(); ++it) {
  587 + ISrsReloadHandler* subscribe = *it;
  588 + if ((ret = subscribe->on_reload_transcode(vhost)) != ERROR_SUCCESS) {
  589 + srs_error("vhost %s notify subscribes transcode failed. ret=%d", vhost.c_str(), ret);
  590 + return ret;
  591 + }
  592 + }
  593 + srs_trace("vhost %s reload transcode success.", vhost.c_str());
  594 + }
  595 + // TODO: suppor reload hls/forward/ffmpeg/http
  596 + continue;
  597 + }
  598 + srs_warn("invalid reload path, enabled old: %d, new: %d",
  599 + get_vhost_enabled(old_vhost), get_vhost_enabled(new_vhost));
  600 + }
  601 +
  602 + return ret;
  603 +}
  604 +
  605 +void SrsConfig::subscribe(ISrsReloadHandler* handler)
  606 +{
  607 + std::vector<ISrsReloadHandler*>::iterator it;
  608 +
  609 + it = std::find(subscribes.begin(), subscribes.end(), handler);
  610 + if (it != subscribes.end()) {
  611 + return;
  612 + }
  613 +
  614 + subscribes.push_back(handler);
  615 +}
  616 +
  617 +void SrsConfig::unsubscribe(ISrsReloadHandler* handler)
  618 +{
  619 + std::vector<ISrsReloadHandler*>::iterator it;
  620 +
  621 + it = std::find(subscribes.begin(), subscribes.end(), handler);
  622 + if (it == subscribes.end()) {
  623 + return;
  624 + }
  625 +
  626 + subscribes.erase(it);
  627 +}
  628 +
  629 +// see: ngx_get_options
  630 +int SrsConfig::parse_options(int argc, char** argv)
  631 +{
  632 + int ret = ERROR_SUCCESS;
  633 +
  634 + for (int i = 1; i < argc; i++) {
  635 + if ((ret = parse_argv(i, argv)) != ERROR_SUCCESS) {
  636 + return ret;
  637 + }
  638 + }
  639 +
  640 + if (show_help) {
  641 + print_help(argv);
  642 + }
  643 +
  644 + if (show_version) {
  645 + printf("%s\n", RTMP_SIG_SRS_VERSION);
  646 + }
  647 +
  648 + if (show_help || show_version) {
  649 + exit(0);
  650 + }
  651 +
  652 + if (config_file.empty()) {
  653 + ret = ERROR_SYSTEM_CONFIG_INVALID;
  654 + srs_error("config file not specified, see help: %s -h, ret=%d", argv[0], ret);
  655 + return ret;
  656 + }
  657 +
  658 + return parse_file(config_file.c_str());
  659 +}
  660 +
  661 +int SrsConfig::parse_file(const char* filename)
  662 +{
  663 + int ret = ERROR_SUCCESS;
  664 +
  665 + config_file = filename;
  666 +
  667 + if (config_file.empty()) {
  668 + return ERROR_SYSTEM_CONFIG_INVALID;
  669 + }
  670 +
  671 + if ((ret = root->parse(config_file.c_str())) != ERROR_SUCCESS) {
  672 + return ret;
  673 + }
  674 +
  675 + SrsConfDirective* conf = NULL;
  676 + if ((conf = get_listen()) == NULL || conf->args.size() == 0) {
  677 + ret = ERROR_SYSTEM_CONFIG_INVALID;
  678 + srs_error("line %d: conf error, "
  679 + "directive \"listen\" is empty, ret=%d", (conf? conf->conf_line:0), ret);
  680 + return ret;
  681 + }
  682 +
  683 + // TODO: check the hls.
  684 + // TODO: check forward.
  685 + // TODO: check ffmpeg.
  686 + // TODO: check http.
  687 +
  688 + return ret;
  689 +}
  690 +
  691 +int SrsConfig::parse_argv(int& i, char** argv)
  692 +{
  693 + int ret = ERROR_SUCCESS;
  694 +
  695 + char* p = argv[i];
  696 +
  697 + if (*p++ != '-') {
  698 + ret = ERROR_SYSTEM_CONFIG_INVALID;
  699 + srs_error("invalid options(index=%d, value=%s), "
  700 + "must starts with -, see help: %s -h, ret=%d", i, argv[i], argv[0], ret);
  701 + return ret;
  702 + }
  703 +
  704 + while (*p) {
  705 + switch (*p++) {
  706 + case '?':
  707 + case 'h':
  708 + show_help = true;
  709 + break;
  710 + case 'v':
  711 + case 'V':
  712 + show_version = true;
  713 + break;
  714 + case 'c':
  715 + if (*p) {
  716 + config_file = p;
  717 + return ret;
  718 + }
  719 + if (argv[++i]) {
  720 + config_file = argv[i];
  721 + return ret;
  722 + }
  723 + ret = ERROR_SYSTEM_CONFIG_INVALID;
  724 + srs_error("option \"-c\" requires parameter, ret=%d", ret);
  725 + return ret;
  726 + default:
  727 + ret = ERROR_SYSTEM_CONFIG_INVALID;
  728 + srs_error("invalid option: \"%c\", see help: %s -h, ret=%d", *(p - 1), argv[0], ret);
  729 + return ret;
  730 + }
  731 + }
  732 +
  733 + return ret;
  734 +}
  735 +
  736 +void SrsConfig::print_help(char** argv)
  737 +{
  738 + printf(
  739 + RTMP_SIG_SRS_NAME" "RTMP_SIG_SRS_VERSION" "RTMP_SIG_SRS_COPYRIGHT"\n"
  740 + "Primary Authors: "RTMP_SIG_SRS_PRIMARY_AUTHROS"\n"
  741 + "Build: "SRS_BUILD_DATE" Configuration: "SRS_CONFIGURE"\n"
  742 + "Usage: %s [-h?vV] [-c <filename>]\n"
  743 + "\n"
  744 + "Options:\n"
  745 + " -?-h : show help\n"
  746 + " -v-V : show version and exit\n"
  747 + " -c filename : set configuration file\n"
  748 + "\n"
  749 + RTMP_SIG_SRS_WEB"\n"
  750 + RTMP_SIG_SRS_URL"\n"
  751 + "Email: "RTMP_SIG_SRS_EMAIL"\n"
  752 + "\n",
  753 + argv[0]);
  754 +}
  755 +
  756 +SrsConfDirective* SrsConfig::get_vhost(string vhost)
  757 +{
  758 + srs_assert(root);
  759 +
  760 + for (int i = 0; i < (int)root->directives.size(); i++) {
  761 + SrsConfDirective* conf = root->at(i);
  762 +
  763 + if (conf->name != "vhost") {
  764 + continue;
  765 + }
  766 +
  767 + if (conf->arg0() == vhost) {
  768 + return conf;
  769 + }
  770 + }
  771 +
  772 + if (vhost != RTMP_VHOST_DEFAULT) {
  773 + return get_vhost(RTMP_VHOST_DEFAULT);
  774 + }
  775 +
  776 + return NULL;
  777 +}
  778 +
  779 +SrsConfDirective* SrsConfig::get_vhost_on_connect(string vhost)
  780 +{
  781 + SrsConfDirective* conf = get_vhost(vhost);
  782 +
  783 + if (!conf) {
  784 + return NULL;
  785 + }
  786 +
  787 + conf = conf->get("http_hooks");
  788 + if (!conf) {
  789 + return NULL;
  790 + }
  791 +
  792 + SrsConfDirective* enabled = conf->get("enabled");
  793 + if (!enabled || enabled->arg0() != "on") {
  794 + return NULL;
  795 + }
  796 +
  797 + return conf->get("on_connect");
  798 +}
  799 +
  800 +SrsConfDirective* SrsConfig::get_vhost_on_close(string vhost)
  801 +{
  802 + SrsConfDirective* conf = get_vhost(vhost);
  803 +
  804 + if (!conf) {
  805 + return NULL;
  806 + }
  807 +
  808 + conf = conf->get("http_hooks");
  809 + if (!conf) {
  810 + return NULL;
  811 + }
  812 +
  813 + SrsConfDirective* enabled = conf->get("enabled");
  814 + if (!enabled || enabled->arg0() != "on") {
  815 + return NULL;
  816 + }
  817 +
  818 + return conf->get("on_close");
  819 +}
  820 +
  821 +SrsConfDirective* SrsConfig::get_vhost_on_publish(string vhost)
  822 +{
  823 + SrsConfDirective* conf = get_vhost(vhost);
  824 +
  825 + if (!conf) {
  826 + return NULL;
  827 + }
  828 +
  829 + conf = conf->get("http_hooks");
  830 + if (!conf) {
  831 + return NULL;
  832 + }
  833 +
  834 + SrsConfDirective* enabled = conf->get("enabled");
  835 + if (!enabled || enabled->arg0() != "on") {
  836 + return NULL;
  837 + }
  838 +
  839 + return conf->get("on_publish");
  840 +}
  841 +
  842 +SrsConfDirective* SrsConfig::get_vhost_on_unpublish(string vhost)
  843 +{
  844 + SrsConfDirective* conf = get_vhost(vhost);
  845 +
  846 + if (!conf) {
  847 + return NULL;
  848 + }
  849 +
  850 + conf = conf->get("http_hooks");
  851 + if (!conf) {
  852 + return NULL;
  853 + }
  854 +
  855 + SrsConfDirective* enabled = conf->get("enabled");
  856 + if (!enabled || enabled->arg0() != "on") {
  857 + return NULL;
  858 + }
  859 +
  860 + return conf->get("on_unpublish");
  861 +}
  862 +
  863 +SrsConfDirective* SrsConfig::get_vhost_on_play(string vhost)
  864 +{
  865 + SrsConfDirective* conf = get_vhost(vhost);
  866 +
  867 + if (!conf) {
  868 + return NULL;
  869 + }
  870 +
  871 + conf = conf->get("http_hooks");
  872 + if (!conf) {
  873 + return NULL;
  874 + }
  875 +
  876 + SrsConfDirective* enabled = conf->get("enabled");
  877 + if (!enabled || enabled->arg0() != "on") {
  878 + return NULL;
  879 + }
  880 +
  881 + return conf->get("on_play");
  882 +}
  883 +
  884 +SrsConfDirective* SrsConfig::get_vhost_on_stop(string vhost)
  885 +{
  886 + SrsConfDirective* conf = get_vhost(vhost);
  887 +
  888 + if (!conf) {
  889 + return NULL;
  890 + }
  891 +
  892 + conf = conf->get("http_hooks");
  893 + if (!conf) {
  894 + return NULL;
  895 + }
  896 +
  897 + SrsConfDirective* enabled = conf->get("enabled");
  898 + if (!enabled || enabled->arg0() != "on") {
  899 + return NULL;
  900 + }
  901 +
  902 + return conf->get("on_stop");
  903 +}
  904 +
  905 +bool SrsConfig::get_vhost_enabled(string vhost)
  906 +{
  907 + SrsConfDirective* vhost_conf = get_vhost(vhost);
  908 +
  909 + return get_vhost_enabled(vhost_conf);
  910 +}
  911 +
  912 +bool SrsConfig::get_vhost_enabled(SrsConfDirective* vhost)
  913 +{
  914 + if (!vhost) {
  915 + return false;
  916 + }
  917 +
  918 + SrsConfDirective* conf = vhost->get("enabled");
  919 + if (!conf) {
  920 + return true;
  921 + }
  922 +
  923 + if (conf->arg0() == "off") {
  924 + return false;
  925 + }
  926 +
  927 + return true;
  928 +}
  929 +
  930 +SrsConfDirective* SrsConfig::get_transcode(string vhost, string scope)
  931 +{
  932 + SrsConfDirective* conf = get_vhost(vhost);
  933 +
  934 + if (!conf) {
  935 + return NULL;
  936 + }
  937 +
  938 + SrsConfDirective* transcode = conf->get("transcode");
  939 + if (!transcode) {
  940 + return NULL;
  941 + }
  942 +
  943 + if (transcode->arg0() == scope) {
  944 + return transcode;
  945 + }
  946 +
  947 + return NULL;
  948 +}
  949 +
  950 +bool SrsConfig::get_transcode_enabled(SrsConfDirective* transcode)
  951 +{
  952 + if (!transcode) {
  953 + return false;
  954 + }
  955 +
  956 + SrsConfDirective* conf = transcode->get("enabled");
  957 + if (!conf || conf->arg0() != "on") {
  958 + return false;
  959 + }
  960 +
  961 + return true;
  962 +}
  963 +
  964 +string SrsConfig::get_transcode_ffmpeg(SrsConfDirective* transcode)
  965 +{
  966 + if (!transcode) {
  967 + return "";
  968 + }
  969 +
  970 + SrsConfDirective* conf = transcode->get("ffmpeg");
  971 + if (!conf) {
  972 + return "";
  973 + }
  974 +
  975 + return conf->arg0();
  976 +}
  977 +
  978 +void SrsConfig::get_transcode_engines(SrsConfDirective* transcode, std::vector<SrsConfDirective*>& engines)
  979 +{
  980 + if (!transcode) {
  981 + return;
  982 + }
  983 +
  984 + for (int i = 0; i < (int)transcode->directives.size(); i++) {
  985 + SrsConfDirective* conf = transcode->directives[i];
  986 +
  987 + if (conf->name == "engine") {
  988 + engines.push_back(conf);
  989 + }
  990 + }
  991 +
  992 + return;
  993 +}
  994 +
  995 +bool SrsConfig::get_engine_enabled(SrsConfDirective* engine)
  996 +{
  997 + if (!engine) {
  998 + return false;
  999 + }
  1000 +
  1001 + SrsConfDirective* conf = engine->get("enabled");
  1002 + if (!conf || conf->arg0() != "on") {
  1003 + return false;
  1004 + }
  1005 +
  1006 + return true;
  1007 +}
  1008 +
  1009 +string SrsConfig::get_engine_vcodec(SrsConfDirective* engine)
  1010 +{
  1011 + if (!engine) {
  1012 + return "";
  1013 + }
  1014 +
  1015 + SrsConfDirective* conf = engine->get("vcodec");
  1016 + if (!conf) {
  1017 + return "";
  1018 + }
  1019 +
  1020 + return conf->arg0();
  1021 +}
  1022 +
  1023 +int SrsConfig::get_engine_vbitrate(SrsConfDirective* engine)
  1024 +{
  1025 + if (!engine) {
  1026 + return 0;
  1027 + }
  1028 +
  1029 + SrsConfDirective* conf = engine->get("vbitrate");
  1030 + if (!conf) {
  1031 + return 0;
  1032 + }
  1033 +
  1034 + return ::atoi(conf->arg0().c_str());
  1035 +}
  1036 +
  1037 +double SrsConfig::get_engine_vfps(SrsConfDirective* engine)
  1038 +{
  1039 + if (!engine) {
  1040 + return 0;
  1041 + }
  1042 +
  1043 + SrsConfDirective* conf = engine->get("vfps");
  1044 + if (!conf) {
  1045 + return 0;
  1046 + }
  1047 +
  1048 + return ::atof(conf->arg0().c_str());
  1049 +}
  1050 +
  1051 +int SrsConfig::get_engine_vwidth(SrsConfDirective* engine)
  1052 +{
  1053 + if (!engine) {
  1054 + return 0;
  1055 + }
  1056 +
  1057 + SrsConfDirective* conf = engine->get("vwidth");
  1058 + if (!conf) {
  1059 + return 0;
  1060 + }
  1061 +
  1062 + return ::atoi(conf->arg0().c_str());
  1063 +}
  1064 +
  1065 +int SrsConfig::get_engine_vheight(SrsConfDirective* engine)
  1066 +{
  1067 + if (!engine) {
  1068 + return 0;
  1069 + }
  1070 +
  1071 + SrsConfDirective* conf = engine->get("vheight");
  1072 + if (!conf) {
  1073 + return 0;
  1074 + }
  1075 +
  1076 + return ::atoi(conf->arg0().c_str());
  1077 +}
  1078 +
  1079 +int SrsConfig::get_engine_vthreads(SrsConfDirective* engine)
  1080 +{
  1081 + if (!engine) {
  1082 + return 0;
  1083 + }
  1084 +
  1085 + SrsConfDirective* conf = engine->get("vthreads");
  1086 + if (!conf) {
  1087 + return 0;
  1088 + }
  1089 +
  1090 + return ::atoi(conf->arg0().c_str());
  1091 +}
  1092 +
  1093 +string SrsConfig::get_engine_vprofile(SrsConfDirective* engine)
  1094 +{
  1095 + if (!engine) {
  1096 + return "";
  1097 + }
  1098 +
  1099 + SrsConfDirective* conf = engine->get("vprofile");
  1100 + if (!conf) {
  1101 + return "";
  1102 + }
  1103 +
  1104 + return conf->arg0();
  1105 +}
  1106 +
  1107 +string SrsConfig::get_engine_vpreset(SrsConfDirective* engine)
  1108 +{
  1109 + if (!engine) {
  1110 + return "";
  1111 + }
  1112 +
  1113 + SrsConfDirective* conf = engine->get("vpreset");
  1114 + if (!conf) {
  1115 + return "";
  1116 + }
  1117 +
  1118 + return conf->arg0();
  1119 +}
  1120 +
  1121 +void SrsConfig::get_engine_vparams(SrsConfDirective* engine, std::vector<string>& vparams)
  1122 +{
  1123 + if (!engine) {
  1124 + return;
  1125 + }
  1126 +
  1127 + SrsConfDirective* conf = engine->get("vparams");
  1128 + if (!conf) {
  1129 + return;
  1130 + }
  1131 +
  1132 + for (int i = 0; i < (int)conf->directives.size(); i++) {
  1133 + SrsConfDirective* p = conf->directives[i];
  1134 + if (!p) {
  1135 + continue;
  1136 + }
  1137 +
  1138 + vparams.push_back("-" + p->name);
  1139 + vparams.push_back(p->arg0());
  1140 + }
  1141 +}
  1142 +
  1143 +void SrsConfig::get_engine_vfilter(SrsConfDirective* engine, std::vector<string>& vfilter)
  1144 +{
  1145 + if (!engine) {
  1146 + return;
  1147 + }
  1148 +
  1149 + SrsConfDirective* conf = engine->get("vfilter");
  1150 + if (!conf) {
  1151 + return;
  1152 + }
  1153 +
  1154 + for (int i = 0; i < (int)conf->directives.size(); i++) {
  1155 + SrsConfDirective* p = conf->directives[i];
  1156 + if (!p) {
  1157 + continue;
  1158 + }
  1159 +
  1160 + vfilter.push_back("-" + p->name);
  1161 + vfilter.push_back(p->arg0());
  1162 + }
  1163 +}
  1164 +
  1165 +string SrsConfig::get_engine_acodec(SrsConfDirective* engine)
  1166 +{
  1167 + if (!engine) {
  1168 + return "";
  1169 + }
  1170 +
  1171 + SrsConfDirective* conf = engine->get("acodec");
  1172 + if (!conf) {
  1173 + return "";
  1174 + }
  1175 +
  1176 + return conf->arg0();
  1177 +}
  1178 +
  1179 +int SrsConfig::get_engine_abitrate(SrsConfDirective* engine)
  1180 +{
  1181 + if (!engine) {
  1182 + return 0;
  1183 + }
  1184 +
  1185 + SrsConfDirective* conf = engine->get("abitrate");
  1186 + if (!conf) {
  1187 + return 0;
  1188 + }
  1189 +
  1190 + return ::atoi(conf->arg0().c_str());
  1191 +}
  1192 +
  1193 +int SrsConfig::get_engine_asample_rate(SrsConfDirective* engine)
  1194 +{
  1195 + if (!engine) {
  1196 + return 0;
  1197 + }
  1198 +
  1199 + SrsConfDirective* conf = engine->get("asample_rate");
  1200 + if (!conf) {
  1201 + return 0;
  1202 + }
  1203 +
  1204 + return ::atoi(conf->arg0().c_str());
  1205 +}
  1206 +
  1207 +int SrsConfig::get_engine_achannels(SrsConfDirective* engine)
  1208 +{
  1209 + if (!engine) {
  1210 + return 0;
  1211 + }
  1212 +
  1213 + SrsConfDirective* conf = engine->get("achannels");
  1214 + if (!conf) {
  1215 + return 0;
  1216 + }
  1217 +
  1218 + return ::atoi(conf->arg0().c_str());
  1219 +}
  1220 +
  1221 +void SrsConfig::get_engine_aparams(SrsConfDirective* engine, std::vector<string>& aparams)
  1222 +{
  1223 + if (!engine) {
  1224 + return;
  1225 + }
  1226 +
  1227 + SrsConfDirective* conf = engine->get("aparams");
  1228 + if (!conf) {
  1229 + return;
  1230 + }
  1231 +
  1232 + for (int i = 0; i < (int)conf->directives.size(); i++) {
  1233 + SrsConfDirective* p = conf->directives[i];
  1234 + if (!p) {
  1235 + continue;
  1236 + }
  1237 +
  1238 + aparams.push_back("-" + p->name);
  1239 + aparams.push_back(p->arg0());
  1240 + }
  1241 +}
  1242 +
  1243 +string SrsConfig::get_engine_output(SrsConfDirective* engine)
  1244 +{
  1245 + if (!engine) {
  1246 + return "";
  1247 + }
  1248 +
  1249 + SrsConfDirective* conf = engine->get("output");
  1250 + if (!conf) {
  1251 + return "";
  1252 + }
  1253 +
  1254 + return conf->arg0();
  1255 +}
  1256 +
  1257 +string SrsConfig::get_log_dir()
  1258 +{
  1259 + srs_assert(root);
  1260 +
  1261 + SrsConfDirective* conf = root->get("log_dir");
  1262 + if (!conf || conf->arg0().empty()) {
  1263 + return "./objs/logs";
  1264 + }
  1265 +
  1266 + return conf->arg0();
  1267 +}
  1268 +
  1269 +int SrsConfig::get_max_connections()
  1270 +{
  1271 + srs_assert(root);
  1272 +
  1273 + SrsConfDirective* conf = root->get("max_connections");
  1274 + if (!conf || conf->arg0().empty()) {
  1275 + return 2000;
  1276 + }
  1277 +
  1278 + return ::atoi(conf->arg0().c_str());
  1279 +}
  1280 +
  1281 +bool SrsConfig::get_gop_cache(string vhost)
  1282 +{
  1283 + SrsConfDirective* conf = get_vhost(vhost);
  1284 +
  1285 + if (!conf) {
  1286 + return true;
  1287 + }
  1288 +
  1289 + conf = conf->get("gop_cache");
  1290 + if (conf && conf->arg0() == "off") {
  1291 + return false;
  1292 + }
  1293 +
  1294 + return true;
  1295 +}
  1296 +
  1297 +double SrsConfig::get_queue_length(string vhost)
  1298 +{
  1299 + SrsConfDirective* conf = get_vhost(vhost);
  1300 +
  1301 + if (!conf) {
  1302 + return SRS_CONF_DEFAULT_QUEUE_LENGTH;
  1303 + }
  1304 +
  1305 + conf = conf->get("queue_length");
  1306 + if (!conf || conf->arg0().empty()) {
  1307 + return SRS_CONF_DEFAULT_QUEUE_LENGTH;
  1308 + }
  1309 +
  1310 + return ::atoi(conf->arg0().c_str());
  1311 +}
  1312 +
  1313 +SrsConfDirective* SrsConfig::get_forward(string vhost)
  1314 +{
  1315 + SrsConfDirective* conf = get_vhost(vhost);
  1316 +
  1317 + if (!conf) {
  1318 + return NULL;
  1319 + }
  1320 +
  1321 + return conf->get("forward");
  1322 +}
  1323 +
  1324 +SrsConfDirective* SrsConfig::get_hls(string vhost)
  1325 +{
  1326 + SrsConfDirective* conf = get_vhost(vhost);
  1327 +
  1328 + if (!conf) {
  1329 + return NULL;
  1330 + }
  1331 +
  1332 + return conf->get("hls");
  1333 +}
  1334 +
  1335 +bool SrsConfig::get_hls_enabled(string vhost)
  1336 +{
  1337 + SrsConfDirective* hls = get_hls(vhost);
  1338 +
  1339 + if (!hls) {
  1340 + return false;
  1341 + }
  1342 +
  1343 + SrsConfDirective* conf = hls->get("enabled");
  1344 +
  1345 + if (!conf) {
  1346 + return false;
  1347 + }
  1348 +
  1349 + if (conf->arg0() == "on") {
  1350 + return true;
  1351 + }
  1352 +
  1353 + return false;
  1354 +}
  1355 +
  1356 +string SrsConfig::get_hls_path(string vhost)
  1357 +{
  1358 + SrsConfDirective* hls = get_hls(vhost);
  1359 +
  1360 + if (!hls) {
  1361 + return SRS_CONF_DEFAULT_HLS_PATH;
  1362 + }
  1363 +
  1364 + SrsConfDirective* conf = hls->get("hls_path");
  1365 +
  1366 + if (!conf) {
  1367 + return SRS_CONF_DEFAULT_HLS_PATH;
  1368 + }
  1369 +
  1370 + return conf->arg0();
  1371 +}
  1372 +
  1373 +double SrsConfig::get_hls_fragment(string vhost)
  1374 +{
  1375 + SrsConfDirective* hls = get_hls(vhost);
  1376 +
  1377 + if (!hls) {
  1378 + return SRS_CONF_DEFAULT_HLS_FRAGMENT;
  1379 + }
  1380 +
  1381 + SrsConfDirective* conf = hls->get("hls_fragment");
  1382 +
  1383 + if (!conf) {
  1384 + return SRS_CONF_DEFAULT_HLS_FRAGMENT;
  1385 + }
  1386 +
  1387 + return ::atof(conf->arg0().c_str());
  1388 +}
  1389 +
  1390 +double SrsConfig::get_hls_window(string vhost)
  1391 +{
  1392 + SrsConfDirective* hls = get_hls(vhost);
  1393 +
  1394 + if (!hls) {
  1395 + return SRS_CONF_DEFAULT_HLS_WINDOW;
  1396 + }
  1397 +
  1398 + SrsConfDirective* conf = hls->get("hls_window");
  1399 +
  1400 + if (!conf) {
  1401 + return SRS_CONF_DEFAULT_HLS_WINDOW;
  1402 + }
  1403 +
  1404 + return ::atof(conf->arg0().c_str());
  1405 +}
  1406 +
  1407 +SrsConfDirective* SrsConfig::get_refer(string vhost)
  1408 +{
  1409 + SrsConfDirective* conf = get_vhost(vhost);
  1410 +
  1411 + if (!conf) {
  1412 + return NULL;
  1413 + }
  1414 +
  1415 + return conf->get("refer");
  1416 +}
  1417 +
  1418 +SrsConfDirective* SrsConfig::get_refer_play(string vhost)
  1419 +{
  1420 + SrsConfDirective* conf = get_vhost(vhost);
  1421 +
  1422 + if (!conf) {
  1423 + return NULL;
  1424 + }
  1425 +
  1426 + return conf->get("refer_play");
  1427 +}
  1428 +
  1429 +SrsConfDirective* SrsConfig::get_refer_publish(string vhost)
  1430 +{
  1431 + SrsConfDirective* conf = get_vhost(vhost);
  1432 +
  1433 + if (!conf) {
  1434 + return NULL;
  1435 + }
  1436 +
  1437 + return conf->get("refer_publish");
  1438 +}
  1439 +
  1440 +SrsConfDirective* SrsConfig::get_listen()
  1441 +{
  1442 + return root->get("listen");
  1443 +}
  1444 +
  1445 +int SrsConfig::get_chunk_size(const std::string &vhost)
  1446 +{
  1447 + SrsConfDirective* conf = get_vhost(vhost);
  1448 +
  1449 + if (!conf) {
  1450 + return SRS_CONF_DEFAULT_CHUNK_SIZE;
  1451 + }
  1452 +
  1453 + conf = conf->get("chunk_size");
  1454 + if (!conf) {
  1455 + // vhost does not specify the chunk size,
  1456 + // use the global instead.
  1457 + conf = root->get("chunk_size");
  1458 + if (!conf) {
  1459 + return SRS_CONF_DEFAULT_CHUNK_SIZE;
  1460 + }
  1461 +
  1462 + return ::atoi(conf->arg0().c_str());
  1463 + }
  1464 +
  1465 + return ::atoi(conf->arg0().c_str());
  1466 +}
  1467 +
  1468 +int SrsConfig::get_pithy_print_publish()
  1469 +{
  1470 + SrsConfDirective* pithy = root->get("pithy_print");
  1471 + if (!pithy) {
  1472 + return SRS_STAGE_PUBLISH_USER_INTERVAL_MS;
  1473 + }
  1474 +
  1475 + pithy = pithy->get("publish");
  1476 + if (!pithy) {
  1477 + return SRS_STAGE_PUBLISH_USER_INTERVAL_MS;
  1478 + }
  1479 +
  1480 + return ::atoi(pithy->arg0().c_str());
  1481 +}
  1482 +
  1483 +int SrsConfig::get_pithy_print_forwarder()
  1484 +{
  1485 + SrsConfDirective* pithy = root->get("pithy_print");
  1486 + if (!pithy) {
  1487 + return SRS_STAGE_FORWARDER_INTERVAL_MS;
  1488 + }
  1489 +
  1490 + pithy = pithy->get("forwarder");
  1491 + if (!pithy) {
  1492 + return SRS_STAGE_FORWARDER_INTERVAL_MS;
  1493 + }
  1494 +
  1495 + return ::atoi(pithy->arg0().c_str());
  1496 +}
  1497 +
  1498 +int SrsConfig::get_pithy_print_hls()
  1499 +{
  1500 + SrsConfDirective* pithy = root->get("pithy_print");
  1501 + if (!pithy) {
  1502 + return SRS_STAGE_HLS_INTERVAL_MS;
  1503 + }
  1504 +
  1505 + pithy = pithy->get("hls");
  1506 + if (!pithy) {
  1507 + return SRS_STAGE_HLS_INTERVAL_MS;
  1508 + }
  1509 +
  1510 + return ::atoi(pithy->arg0().c_str());
  1511 +}
  1512 +
  1513 +bool SrsConfig::get_bw_check_enabled(const string &vhost)
  1514 +{
  1515 + SrsConfDirective* conf = get_vhost(vhost);
  1516 +
  1517 + if (!conf) {
  1518 + return false;
  1519 + }
  1520 +
  1521 + conf = conf->get("bandcheck");
  1522 + if (!conf) {
  1523 + return false;
  1524 + }
  1525 +
  1526 + conf = conf->get("enabled");
  1527 + if (!conf || conf->arg0() != "on") {
  1528 + return false;
  1529 + }
  1530 +
  1531 + return true;
  1532 +}
  1533 +
  1534 +string SrsConfig::get_bw_check_key(const string &vhost)
  1535 +{
  1536 + SrsConfDirective* conf = get_vhost(vhost);
  1537 +
  1538 + if (!conf) {
  1539 + return "";
  1540 + }
  1541 +
  1542 + conf = conf->get("bandcheck");
  1543 + if (!conf) {
  1544 + return "";
  1545 + }
  1546 +
  1547 + conf = conf->get("key");
  1548 + if (!conf) {
  1549 + return "";
  1550 + }
  1551 +
  1552 + return conf->arg0();
  1553 +}
  1554 +
  1555 +int SrsConfig::get_bw_check_interval_ms(const string &vhost)
  1556 +{
  1557 + SrsConfDirective* conf = get_vhost(vhost);
  1558 +
  1559 + if (!conf) {
  1560 + return SRS_CONF_DEFAULT_BANDWIDTH_INTERVAL;
  1561 + }
  1562 +
  1563 + conf = conf->get("bandcheck");
  1564 + if (!conf) {
  1565 + return SRS_CONF_DEFAULT_BANDWIDTH_INTERVAL;
  1566 + }
  1567 +
  1568 + conf = conf->get("interval_ms");
  1569 + if (!conf) {
  1570 + return SRS_CONF_DEFAULT_BANDWIDTH_INTERVAL;
  1571 + }
  1572 +
  1573 + return ::atoi(conf->arg0().c_str()) * 1000;
  1574 +}
  1575 +
  1576 +int SrsConfig::get_bw_check_limit_kbps(const string &vhost)
  1577 +{
  1578 + SrsConfDirective* conf = get_vhost(vhost);
  1579 +
  1580 + if (!conf) {
  1581 + return SRS_CONF_DEFAULT_BANDWIDTH_LIMIT_KBPS;
  1582 + }
  1583 +
  1584 + conf = conf->get("bandcheck");
  1585 + if (!conf) {
  1586 + return SRS_CONF_DEFAULT_BANDWIDTH_LIMIT_KBPS;
  1587 + }
  1588 +
  1589 + conf = conf->get("limit_kbps");
  1590 + if (!conf) {
  1591 + return SRS_CONF_DEFAULT_BANDWIDTH_LIMIT_KBPS;
  1592 + }
  1593 +
  1594 + return ::atoi(conf->arg0().c_str());
  1595 +}
  1596 +
  1597 +int SrsConfig::get_pithy_print_encoder()
  1598 +{
  1599 + SrsConfDirective* pithy = root->get("encoder");
  1600 + if (!pithy) {
  1601 + return SRS_STAGE_ENCODER_INTERVAL_MS;
  1602 + }
  1603 +
  1604 + pithy = pithy->get("forwarder");
  1605 + if (!pithy) {
  1606 + return SRS_STAGE_ENCODER_INTERVAL_MS;
  1607 + }
  1608 +
  1609 + return ::atoi(pithy->arg0().c_str());
  1610 +}
  1611 +
  1612 +int SrsConfig::get_pithy_print_play()
  1613 +{
  1614 + SrsConfDirective* pithy = root->get("pithy_print");
  1615 + if (!pithy) {
  1616 + return SRS_STAGE_PLAY_USER_INTERVAL_MS;
  1617 + }
  1618 +
  1619 + pithy = pithy->get("play");
  1620 + if (!pithy) {
  1621 + return SRS_STAGE_PLAY_USER_INTERVAL_MS;
  1622 + }
  1623 +
  1624 + return ::atoi(pithy->arg0().c_str());
  1625 +}
  1626 +
  1627 +bool srs_directive_equals(SrsConfDirective* a, SrsConfDirective* b)
  1628 +{
  1629 + // both NULL, equal.
  1630 + if (!a && !b) {
  1631 + return true;
  1632 + }
  1633 +
  1634 + if (!a || !b) {
  1635 + return false;
  1636 + }
  1637 +
  1638 + if (a->name != b->name) {
  1639 + return false;
  1640 + }
  1641 +
  1642 + if (a->args.size() != b->args.size()) {
  1643 + return false;
  1644 + }
  1645 +
  1646 + for (int i = 0; i < (int)a->args.size(); i++) {
  1647 + if (a->args.at(i) != b->args.at(i)) {
  1648 + return false;
  1649 + }
  1650 + }
  1651 +
  1652 + if (a->directives.size() != b->directives.size()) {
  1653 + return false;
  1654 + }
  1655 +
  1656 + for (int i = 0; i < (int)a->directives.size(); i++) {
  1657 + SrsConfDirective* a0 = a->at(i);
  1658 + SrsConfDirective* b0 = b->at(i);
  1659 +
  1660 + if (!srs_directive_equals(a0, b0)) {
  1661 + return false;
  1662 + }
  1663 + }
  1664 +
  1665 + return true;
  1666 +}