winlin

refine the authors and license

  1 +Authors ordered by first contribution.
  2 +
  3 +* winlin <winlin@vip.126.com>
  4 +* wenjie
1 -simple-rtmp-server 1 +Simple-RTMP-Server
2 ================== 2 ==================
3 3
4 -srs(simple rtmp origin live server) over state-threads.<br/>  
5 -srs is a simple, high-performance, running in single process, origin live server.<br/>  
6 -srs supports vhost, rtmp, HLS, transcoding, forward, http hooks. <br/>  
7 -blog: [http://blog.csdn.net/win_lin](http://blog.csdn.net/win_lin) <br/>  
8 -see also: [https://github.com/winlinvip/simple-rtmp-server](https://github.com/winlinvip/simple-rtmp-server) <br/>  
9 -see also: [http://winlinvip.github.io/simple-rtmp-server](http://winlinvip.github.io/simple-rtmp-server) <br/> 4 +SRS(SIMPLE RTMP Server) over state-threads created in 2013.<br/>
  5 +SRS is a simple, high-performance, running in single process, origin live server.<br/>
  6 +SRS supports vhost, rtmp, HLS, transcoding, forward, http hooks. <br/>
  7 +Blog: [http://blog.csdn.net/win_lin](http://blog.csdn.net/win_lin) <br/>
  8 +See also: [https://github.com/winlinvip/simple-rtmp-server](https://github.com/winlinvip/simple-rtmp-server) <br/>
  9 +See also: [http://winlinvip.github.io/simple-rtmp-server](http://winlinvip.github.io/simple-rtmp-server) <br/>
10 TencentQQ: [http://url.cn/WAHICw](http://url.cn/WAHICw) (Group: 212189142) 10 TencentQQ: [http://url.cn/WAHICw](http://url.cn/WAHICw) (Group: 212189142)
11 11
12 -### Contributors  
13 -winlin([winterserver](#)): [http://blog.csdn.net/win_lin](http://blog.csdn.net/win_lin) <br/>  
14 -wenjie([wenjiegit](https://github.com/wenjiegit/simple-rtmp-server)): [http://blog.chinaunix.net/uid/25006789.html](http://blog.chinaunix.net/uid/25006789.html) <br/>  
15 -about the contributors: <br/>  
16 -1. contribute important features to srs. <br/>  
17 -2. the name of all contributors will send in the response of NetConnection.connect and metadata. 12 +### AUTHORS
  13 +The PRIMARY AUTHORS are (and/or have been)(Authors ordered by first contribution): <br/>
  14 +* winlin([winterserver](#)): [http://blog.csdn.net/win_lin](http://blog.csdn.net/win_lin) <br/>
  15 +* wenjie([wenjiegit](https://github.com/wenjiegit/simple-rtmp-server)): [http://blog.chinaunix.net/uid/25006789.html](http://blog.chinaunix.net/uid/25006789.html) <br/>
  16 +About the primary AUTHORS: <br/>
  17 +* Contribute important features to SRS. <br/>
  18 +* Names of all PRIMARY AUTHORS response in NetConnection.connect and metadata. <br/>
  19 +And here is an inevitably incomplete list of MUCH-APPRECIATED CONTRIBUTORS --<br/>
  20 +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)
18 22
19 ### Usage(simple) 23 ### Usage(simple)
20 -<strong>step -1:</strong> get srs<br/> 24 +<strong>step -1:</strong> get SRS<br/>
21 <pre> 25 <pre>
22 git clone https://github.com/winlinvip/simple-rtmp-server && 26 git clone https://github.com/winlinvip/simple-rtmp-server &&
23 cd simple-rtmp-server/trunk 27 cd simple-rtmp-server/trunk
24 </pre> 28 </pre>
25 -<strong>step 0:</strong> build srs system.<br/> 29 +<strong>step 0:</strong> build SRS system.<br/>
26 <pre> 30 <pre>
27 bash scripts/build.sh 31 bash scripts/build.sh
28 </pre> 32 </pre>
29 -<strong>step 1:</strong> start srs all demo features.<br/> 33 +<strong>step 1:</strong> start SRS all demo features.<br/>
30 <pre> 34 <pre>
31 bash scripts/run.sh 35 bash scripts/run.sh
32 </pre> 36 </pre>
33 -<strong>step 2:</strong> srs live show: [http://your-server-ip](http://your-server-ip) <br/>  
34 -<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/>
35 <pre> 39 <pre>
36 bash scripts/stop.sh 40 bash scripts/stop.sh
37 </pre> 41 </pre>
38 42
39 ### Usage(detail) 43 ### Usage(detail)
40 -<strong>step 0:</strong> get srs <br/> 44 +<strong>step 0:</strong> get SRS <br/>
41 <pre> 45 <pre>
42 git clone https://github.com/winlinvip/simple-rtmp-server && 46 git clone https://github.com/winlinvip/simple-rtmp-server &&
43 cd simple-rtmp-server/trunk 47 cd simple-rtmp-server/trunk
44 </pre> 48 </pre>
45 -<strong>step 1:</strong> build srs <br/> 49 +<strong>step 1:</strong> build SRS <br/>
46 <pre> 50 <pre>
47 ./configure --with-ssl --with-hls --with-ffmpeg --with-http && make 51 ./configure --with-ssl --with-hls --with-ffmpeg --with-http && make
48 </pre> 52 </pre>
49 -<strong>step 2:</strong> start srs <br/> 53 +<strong>step 2:</strong> start SRS <br/>
50 <pre> 54 <pre>
51 ./objs/srs -c conf/srs.conf 55 ./objs/srs -c conf/srs.conf
52 </pre> 56 </pre>
53 -<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/>
54 <pre> 58 <pre>
55 ./objs/srs -c conf/srs.19350.conf 59 ./objs/srs -c conf/srs.19350.conf
56 </pre> 60 </pre>
@@ -58,7 +62,7 @@ cd simple-rtmp-server/trunk @@ -58,7 +62,7 @@ cd simple-rtmp-server/trunk
58 <pre> 62 <pre>
59 sudo ./objs/nginx/sbin/nginx 63 sudo ./objs/nginx/sbin/nginx
60 </pre> 64 </pre>
61 -<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/>
62 <pre> 66 <pre>
63 python ./research/api-server/server.py 8085 67 python ./research/api-server/server.py 8085
64 </pre> 68 </pre>
@@ -135,7 +139,7 @@ killall -s SIGHUP srs @@ -135,7 +139,7 @@ killall -s SIGHUP srs
135 System Architecture: 139 System Architecture:
136 <pre> 140 <pre>
137 +------------------------------------------------------+ 141 +------------------------------------------------------+
138 -| SRS(Simple Rtmp Server) | 142 +| SRS(Simple RTMP Server) |
139 +---------------+---------------+-----------+----------+ 143 +---------------+---------------+-----------+----------+
140 | API/hook | Transcoder | HLS | RTMP | 144 | API/hook | Transcoder | HLS | RTMP |
141 | http-parser | FFMPEG/x264 | NGINX/ts | protocol | 145 | http-parser | FFMPEG/x264 | NGINX/ts | protocol |
@@ -151,7 +155,7 @@ Stream Architecture: @@ -151,7 +155,7 @@ Stream Architecture:
151 + Publish + + Deliver | 155 + Publish + + Deliver |
152 +---|-----+ +----|-----+ 156 +---|-----+ +----|-----+
153 +-----------+-------------------------+----------------+ 157 +-----------+-------------------------+----------------+
154 -| Encoder | SRS(Simple Rtmp Server) | Client | 158 +| Encoder | SRS(Simple RTMP Server) | Client |
155 +-----------+-------------------------+----------------+ 159 +-----------+-------------------------+----------------+
156 | (FMLE, | +-> RTMP protocol ----+-> Flash Player | 160 | (FMLE, | +-> RTMP protocol ----+-> Flash Player |
157 | FFMPEG, --+-> +-> HLS/NGINX --------+-> m3u8 player | 161 | FFMPEG, --+-> +-> HLS/NGINX --------+-> m3u8 player |
@@ -217,7 +221,7 @@ Supported operating systems and hardware: @@ -217,7 +221,7 @@ Supported operating systems and hardware:
217 20. support http callback api hooks(for authentication and injection).<br/> 221 20. support http callback api hooks(for authentication and injection).<br/>
218 21. support bandwidth test api and flash client.<br/> 222 21. support bandwidth test api and flash client.<br/>
219 22. player, publisher(encoder), and demo pages(jquery+bootstrap). <br/> 223 22. player, publisher(encoder), and demo pages(jquery+bootstrap). <br/>
220 -23. demo video meeting or chat(srs+cherrypy+jquery+bootstrap). <br/> 224 +23. demo video meeting or chat(SRS+cherrypy+jquery+bootstrap). <br/>
221 24. [plan] support network based cli and json result.<br/> 225 24. [plan] support network based cli and json result.<br/>
222 25. [plan] support adobe flash refer/token/swf verification.<br/> 226 25. [plan] support adobe flash refer/token/swf verification.<br/>
223 26. [plan] support adobe amf3 codec.<br/> 227 26. [plan] support adobe amf3 codec.<br/>
@@ -265,15 +269,15 @@ usr sys idl wai hiq siq| read writ| recv send| in out | int csw @@ -265,15 +269,15 @@ usr sys idl wai hiq siq| read writ| recv send| in out | int csw
265 * 2013-10-17, created.<br/> 269 * 2013-10-17, created.<br/>
266 270
267 ### Compare 271 ### Compare
268 -* srs v0.9: 20926 lines. player/encoder/chat demos. bandwidth test for encoder/CDN.<br/>  
269 -* srs v0.8: 19186 lines. implements http hooks refer to [nginx-rtmp](https://github.com/arut/nginx-rtmp-module). <br/>  
270 -* srs v0.7: 17605 lines. implements transcoding(FFMPEG) feature refer to [wowza](http://www.wowza.com). <br/>  
271 -* srs v0.6: 16094 lines. important feature forward for CDN. <br/>  
272 -* srs v0.5: 14449 lines. implements HLS feature refer to [nginx-rtmp](https://github.com/arut/nginx-rtmp-module). <br/>  
273 -* srs v0.4: 12500 lines. important feature reload for CDN. <br/>  
274 -* srs v0.3: 11773 lines. implements vhost feature refer to [FMS](http://www.adobe.com/products/adobe-media-server-family.html). <br/>  
275 -* srs v0.2: 10125 lines. implements rtmp protocol stack refer to [nginx-rtmp](https://github.com/arut/nginx-rtmp-module). <br/>  
276 -* srs v0.1: 8287 lines. base on state-threads. <br/> 272 +* SRS v0.9: 20926 lines. player/encoder/chat demos. bandwidth test for encoder/CDN.<br/>
  273 +* SRS v0.8: 19186 lines. implements http hooks refer to [nginx-rtmp](https://github.com/arut/nginx-rtmp-module). <br/>
  274 +* SRS v0.7: 17605 lines. implements transcoding(FFMPEG) feature refer to [wowza](http://www.wowza.com). <br/>
  275 +* SRS v0.6: 16094 lines. important feature forward for CDN. <br/>
  276 +* SRS v0.5: 14449 lines. implements HLS feature refer to [nginx-rtmp](https://github.com/arut/nginx-rtmp-module). <br/>
  277 +* SRS v0.4: 12500 lines. important feature reload for CDN. <br/>
  278 +* SRS v0.3: 11773 lines. implements vhost feature refer to [FMS](http://www.adobe.com/products/adobe-media-server-family.html). <br/>
  279 +* SRS v0.2: 10125 lines. implements rtmp protocol stack refer to [nginx-rtmp](https://github.com/arut/nginx-rtmp-module). <br/>
  280 +* SRS v0.1: 8287 lines. base on state-threads. <br/>
277 * nginx-rtmp v1.0.4: 26786 lines <br/> 281 * nginx-rtmp v1.0.4: 26786 lines <br/>
278 * nginx v1.5.0: 139524 lines <br/> 282 * nginx v1.5.0: 139524 lines <br/>
279 283
@@ -281,7 +285,7 @@ usr sys idl wai hiq siq| read writ| recv send| in out | int csw @@ -281,7 +285,7 @@ usr sys idl wai hiq siq| read writ| recv send| in out | int csw
281 * v1.0, 2013-12-27, merge from wenjie, the bandwidth test feature. 285 * v1.0, 2013-12-27, merge from wenjie, the bandwidth test feature.
282 * v0.9, 2013-12-25, [v0.9](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.9) released. 20926 lines. 286 * v0.9, 2013-12-25, [v0.9](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.9) released. 20926 lines.
283 * v0.9, 2013-12-25, fix the bitrate bug(in Bps), use enhanced microphone. 287 * v0.9, 2013-12-25, fix the bitrate bug(in Bps), use enhanced microphone.
284 -* v0.9, 2013-12-22, demo video meeting or chat(srs+cherrypy+jquery+bootstrap). 288 +* v0.9, 2013-12-22, demo video meeting or chat(SRS+cherrypy+jquery+bootstrap).
285 * v0.9, 2013-12-22, merge from wenjie, support banwidth test. 289 * v0.9, 2013-12-22, merge from wenjie, support banwidth test.
286 * v0.9, 2013-12-22, merge from wenjie: support set chunk size at vhost level 290 * v0.9, 2013-12-22, merge from wenjie: support set chunk size at vhost level
287 * v0.9, 2013-12-21, add [players](http://demo.srs.com/players) for play and publish. 291 * v0.9, 2013-12-21, add [players](http://demo.srs.com/players) for play and publish.
@@ -298,7 +302,7 @@ usr sys idl wai hiq siq| read writ| recv send| in out | int csw @@ -298,7 +302,7 @@ usr sys idl wai hiq siq| read writ| recv send| in out | int csw
298 * v0.8, 2013-12-08, support multiple http hooks for a event. 302 * v0.8, 2013-12-08, support multiple http hooks for a event.
299 * v0.8, 2013-12-07, support http callback hooks, on_connect. 303 * v0.8, 2013-12-07, support http callback hooks, on_connect.
300 * v0.8, 2013-12-07, support network based cli and json result, add CherryPy 3.2.4. 304 * v0.8, 2013-12-07, support network based cli and json result, add CherryPy 3.2.4.
301 -* v0.8, 2013-12-07, update http/hls/rtmp load test tool [st_load](https://github.com/winlinvip/st-load), use srs rtmp sdk. 305 +* v0.8, 2013-12-07, update http/hls/rtmp load test tool [st_load](https://github.com/winlinvip/st-load), use SRS rtmp sdk.
302 * v0.8, 2013-12-06, support max_connections, drop if exceed. 306 * v0.8, 2013-12-06, support max_connections, drop if exceed.
303 * v0.8, 2013-12-05, support log_dir, write ffmpeg log to file. 307 * v0.8, 2013-12-05, support log_dir, write ffmpeg log to file.
304 * v0.8, 2013-12-05, fix the forward/hls/encoder bug. 308 * v0.8, 2013-12-05, fix the forward/hls/encoder bug.
@@ -79,7 +79,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -79,7 +79,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
79 #define RTMP_SIG_SRS_EMAIL "winterserver@126.com" 79 #define RTMP_SIG_SRS_EMAIL "winterserver@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_CONTRIBUTOR "winlin,wenjiegit" 82 +#define RTMP_SIG_SRS_PRIMARY_AUTHROS "winlin,wenjiegit"
83 83
84 // compare 84 // compare
85 #define srs_min(a, b) (((a) < (b))? (a) : (b)) 85 #define srs_min(a, b) (((a) < (b))? (a) : (b))
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(RTMP_SIG_SRS_NAME" "RTMP_SIG_SRS_VERSION  
739 - " Copyright (c) 2013-2014 winlin\n"  
740 - "Contributors: "RTMP_SIG_SRS_CONTRIBUTOR"\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 +}
  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_rtmp.hpp>  
25 -  
26 -#include <srs_core_log.hpp>  
27 -#include <srs_core_error.hpp>  
28 -#include <srs_core_socket.hpp>  
29 -#include <srs_core_protocol.hpp>  
30 -#include <srs_core_autofree.hpp>  
31 -#include <srs_core_amf0.hpp>  
32 -#include <srs_core_handshake.hpp>  
33 -#include <srs_core_config.hpp>  
34 -  
35 -using namespace std;  
36 -  
37 -/**  
38 -* the signature for packets to client.  
39 -*/  
40 -#define RTMP_SIG_FMS_VER "3,5,3,888"  
41 -#define RTMP_SIG_AMF0_VER 0  
42 -#define RTMP_SIG_CLIENT_ID "ASAICiss"  
43 -  
44 -/**  
45 -* onStatus consts.  
46 -*/  
47 -#define StatusLevel "level"  
48 -#define StatusCode "code"  
49 -#define StatusDescription "description"  
50 -#define StatusDetails "details"  
51 -#define StatusClientId "clientid"  
52 -// status value  
53 -#define StatusLevelStatus "status"  
54 -// status error  
55 -#define StatusLevelError "error"  
56 -// code value  
57 -#define StatusCodeConnectSuccess "NetConnection.Connect.Success"  
58 -#define StatusCodeConnectRejected "NetConnection.Connect.Rejected"  
59 -#define StatusCodeStreamReset "NetStream.Play.Reset"  
60 -#define StatusCodeStreamStart "NetStream.Play.Start"  
61 -#define StatusCodeStreamPause "NetStream.Pause.Notify"  
62 -#define StatusCodeStreamUnpause "NetStream.Unpause.Notify"  
63 -#define StatusCodePublishStart "NetStream.Publish.Start"  
64 -#define StatusCodeDataStart "NetStream.Data.Start"  
65 -#define StatusCodeUnpublishSuccess "NetStream.Unpublish.Success"  
66 -  
67 -// FMLE  
68 -#define RTMP_AMF0_COMMAND_ON_FC_PUBLISH "onFCPublish"  
69 -#define RTMP_AMF0_COMMAND_ON_FC_UNPUBLISH "onFCUnpublish"  
70 -  
71 -// default stream id for response the createStream request.  
72 -#define SRS_DEFAULT_SID 1  
73 -  
74 -SrsRequest::SrsRequest()  
75 -{  
76 - objectEncoding = RTMP_SIG_AMF0_VER;  
77 -}  
78 -  
79 -SrsRequest::~SrsRequest()  
80 -{  
81 -}  
82 -  
83 -SrsRequest* SrsRequest::copy()  
84 -{  
85 - SrsRequest* cp = new SrsRequest();  
86 -  
87 - cp->app = app;  
88 - cp->objectEncoding = objectEncoding;  
89 - cp->pageUrl = pageUrl;  
90 - cp->port = port;  
91 - cp->schema = schema;  
92 - cp->stream = stream;  
93 - cp->swfUrl = swfUrl;  
94 - cp->tcUrl = tcUrl;  
95 - cp->vhost = vhost;  
96 -  
97 - return cp;  
98 -}  
99 -  
100 -int SrsRequest::discovery_app()  
101 -{  
102 - int ret = ERROR_SUCCESS;  
103 -  
104 - size_t pos = std::string::npos;  
105 - std::string url = tcUrl;  
106 -  
107 - if ((pos = url.find("://")) != std::string::npos) {  
108 - schema = url.substr(0, pos);  
109 - url = url.substr(schema.length() + 3);  
110 - srs_verbose("discovery schema=%s", schema.c_str());  
111 - }  
112 -  
113 - if ((pos = url.find("/")) != std::string::npos) {  
114 - vhost = url.substr(0, pos);  
115 - url = url.substr(vhost.length() + 1);  
116 - srs_verbose("discovery vhost=%s", vhost.c_str());  
117 - }  
118 -  
119 - port = RTMP_DEFAULT_PORTS;  
120 - if ((pos = vhost.find(":")) != std::string::npos) {  
121 - port = vhost.substr(pos + 1);  
122 - vhost = vhost.substr(0, pos);  
123 - srs_verbose("discovery vhost=%s, port=%s", vhost.c_str(), port.c_str());  
124 - }  
125 -  
126 - app = url;  
127 - srs_vhost_resolve(vhost, app);  
128 - strip();  
129 -  
130 - // resolve the vhost from config  
131 - SrsConfDirective* parsed_vhost = config->get_vhost(vhost);  
132 - if (parsed_vhost) {  
133 - vhost = parsed_vhost->arg0();  
134 - }  
135 -  
136 - // TODO: discovery the params of vhost.  
137 -  
138 - srs_info("discovery app success. schema=%s, vhost=%s, port=%s, app=%s",  
139 - schema.c_str(), vhost.c_str(), port.c_str(), app.c_str());  
140 -  
141 - if (schema.empty() || vhost.empty() || port.empty() || app.empty()) {  
142 - ret = ERROR_RTMP_REQ_TCURL;  
143 - srs_error("discovery tcUrl failed. "  
144 - "tcUrl=%s, schema=%s, vhost=%s, port=%s, app=%s, ret=%d",  
145 - tcUrl.c_str(), schema.c_str(), vhost.c_str(), port.c_str(), app.c_str(), ret);  
146 - return ret;  
147 - }  
148 -  
149 - strip();  
150 -  
151 - return ret;  
152 -}  
153 -  
154 -string SrsRequest::get_stream_url()  
155 -{  
156 - std::string url = "";  
157 -  
158 - url += vhost;  
159 - url += "/";  
160 - url += app;  
161 - url += "/";  
162 - url += stream;  
163 -  
164 - return url;  
165 -}  
166 -  
167 -void SrsRequest::strip()  
168 -{  
169 - trim(vhost, "/ \n\r\t");  
170 - trim(app, "/ \n\r\t");  
171 - trim(stream, "/ \n\r\t");  
172 -}  
173 -  
174 -std::string& SrsRequest::trim(string& str, string chs)  
175 -{  
176 - for (int i = 0; i < (int)chs.length(); i++) {  
177 - char ch = chs.at(i);  
178 -  
179 - for (std::string::iterator it = str.begin(); it != str.end();) {  
180 - if (ch == *it) {  
181 - it = str.erase(it);  
182 - } else {  
183 - ++it;  
184 - }  
185 - }  
186 - }  
187 -  
188 - return str;  
189 -}  
190 -  
191 -SrsResponse::SrsResponse()  
192 -{  
193 - stream_id = SRS_DEFAULT_SID;  
194 -}  
195 -  
196 -SrsResponse::~SrsResponse()  
197 -{  
198 -}  
199 -  
200 -SrsRtmpClient::SrsRtmpClient(st_netfd_t _stfd)  
201 -{  
202 - stfd = _stfd;  
203 - protocol = new SrsProtocol(stfd);  
204 -}  
205 -  
206 -SrsRtmpClient::~SrsRtmpClient()  
207 -{  
208 - srs_freep(protocol);  
209 -}  
210 -  
211 -void SrsRtmpClient::set_recv_timeout(int64_t timeout_us)  
212 -{  
213 - protocol->set_recv_timeout(timeout_us);  
214 -}  
215 -  
216 -void SrsRtmpClient::set_send_timeout(int64_t timeout_us)  
217 -{  
218 - protocol->set_send_timeout(timeout_us);  
219 -}  
220 -  
221 -int64_t SrsRtmpClient::get_recv_bytes()  
222 -{  
223 - return protocol->get_recv_bytes();  
224 -}  
225 -  
226 -int64_t SrsRtmpClient::get_send_bytes()  
227 -{  
228 - return protocol->get_send_bytes();  
229 -}  
230 -  
231 -int SrsRtmpClient::get_recv_kbps()  
232 -{  
233 - return protocol->get_recv_kbps();  
234 -}  
235 -  
236 -int SrsRtmpClient::get_send_kbps()  
237 -{  
238 - return protocol->get_send_kbps();  
239 -}  
240 -  
241 -int SrsRtmpClient::recv_message(SrsCommonMessage** pmsg)  
242 -{  
243 - return protocol->recv_message(pmsg);  
244 -}  
245 -  
246 -int SrsRtmpClient::send_message(ISrsMessage* msg)  
247 -{  
248 - return protocol->send_message(msg);  
249 -}  
250 -  
251 -int SrsRtmpClient::handshake()  
252 -{  
253 - int ret = ERROR_SUCCESS;  
254 -  
255 - SrsSocket skt(stfd);  
256 -  
257 - skt.set_recv_timeout(protocol->get_recv_timeout());  
258 - skt.set_send_timeout(protocol->get_send_timeout());  
259 -  
260 - SrsComplexHandshake complex_hs;  
261 - SrsSimpleHandshake simple_hs;  
262 - if ((ret = simple_hs.handshake_with_server(skt, complex_hs)) != ERROR_SUCCESS) {  
263 - return ret;  
264 - }  
265 -  
266 - return ret;  
267 -}  
268 -  
269 -int SrsRtmpClient::connect_app(string app, string tc_url)  
270 -{  
271 - int ret = ERROR_SUCCESS;  
272 -  
273 - // Connect(vhost, app)  
274 - if (true) {  
275 - SrsCommonMessage* msg = new SrsCommonMessage();  
276 - SrsConnectAppPacket* pkt = new SrsConnectAppPacket();  
277 - msg->set_packet(pkt, 0);  
278 -  
279 - pkt->command_object = new SrsAmf0Object();  
280 - pkt->command_object->set("app", new SrsAmf0String(app.c_str()));  
281 - pkt->command_object->set("swfUrl", new SrsAmf0String());  
282 - pkt->command_object->set("tcUrl", new SrsAmf0String(tc_url.c_str()));  
283 - pkt->command_object->set("fpad", new SrsAmf0Boolean(false));  
284 - pkt->command_object->set("capabilities", new SrsAmf0Number(239));  
285 - pkt->command_object->set("audioCodecs", new SrsAmf0Number(3575));  
286 - pkt->command_object->set("videoCodecs", new SrsAmf0Number(252));  
287 - pkt->command_object->set("videoFunction", new SrsAmf0Number(1));  
288 - pkt->command_object->set("pageUrl", new SrsAmf0String());  
289 - pkt->command_object->set("objectEncoding", new SrsAmf0Number(0));  
290 -  
291 - if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {  
292 - return ret;  
293 - }  
294 - }  
295 -  
296 - // Set Window Acknowledgement size(2500000)  
297 - if (true) {  
298 - SrsCommonMessage* msg = new SrsCommonMessage();  
299 - SrsSetWindowAckSizePacket* pkt = new SrsSetWindowAckSizePacket();  
300 -  
301 - pkt->ackowledgement_window_size = 2500000;  
302 - msg->set_packet(pkt, 0);  
303 -  
304 - if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {  
305 - return ret;  
306 - }  
307 - }  
308 -  
309 - // expect connect _result  
310 - SrsCommonMessage* msg = NULL;  
311 - SrsConnectAppResPacket* pkt = NULL;  
312 - if ((ret = srs_rtmp_expect_message<SrsConnectAppResPacket>(protocol, &msg, &pkt)) != ERROR_SUCCESS) {  
313 - srs_error("expect connect app response message failed. ret=%d", ret);  
314 - return ret;  
315 - }  
316 - SrsAutoFree(SrsCommonMessage, msg, false);  
317 - srs_info("get connect app response message");  
318 -  
319 - return ret;  
320 -}  
321 -  
322 -int SrsRtmpClient::create_stream(int& stream_id)  
323 -{  
324 - int ret = ERROR_SUCCESS;  
325 -  
326 - // CreateStream  
327 - if (true) {  
328 - SrsCommonMessage* msg = new SrsCommonMessage();  
329 - SrsCreateStreamPacket* pkt = new SrsCreateStreamPacket();  
330 -  
331 - msg->set_packet(pkt, 0);  
332 -  
333 - if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {  
334 - return ret;  
335 - }  
336 - }  
337 -  
338 - // CreateStream _result.  
339 - if (true) {  
340 - SrsCommonMessage* msg = NULL;  
341 - SrsCreateStreamResPacket* pkt = NULL;  
342 - if ((ret = srs_rtmp_expect_message<SrsCreateStreamResPacket>(protocol, &msg, &pkt)) != ERROR_SUCCESS) {  
343 - srs_error("expect create stream response message failed. ret=%d", ret);  
344 - return ret;  
345 - }  
346 - SrsAutoFree(SrsCommonMessage, msg, false);  
347 - srs_info("get create stream response message");  
348 -  
349 - stream_id = (int)pkt->stream_id;  
350 - }  
351 -  
352 - return ret;  
353 -}  
354 -  
355 -int SrsRtmpClient::play(string stream, int stream_id)  
356 -{  
357 - int ret = ERROR_SUCCESS;  
358 -  
359 - // Play(stream)  
360 - if (true) {  
361 - SrsCommonMessage* msg = new SrsCommonMessage();  
362 - SrsPlayPacket* pkt = new SrsPlayPacket();  
363 -  
364 - pkt->stream_name = stream;  
365 - msg->set_packet(pkt, stream_id);  
366 -  
367 - if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {  
368 - srs_error("send play stream failed. "  
369 - "stream=%s, stream_id=%d, ret=%d",  
370 - stream.c_str(), stream_id, ret);  
371 - return ret;  
372 - }  
373 - }  
374 -  
375 - // SetBufferLength(1000ms)  
376 - int buffer_length_ms = 1000;  
377 - if (true) {  
378 - SrsCommonMessage* msg = new SrsCommonMessage();  
379 - SrsUserControlPacket* pkt = new SrsUserControlPacket();  
380 -  
381 - pkt->event_type = SrcPCUCSetBufferLength;  
382 - pkt->event_data = stream_id;  
383 - pkt->extra_data = buffer_length_ms;  
384 - msg->set_packet(pkt, 0);  
385 -  
386 - if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {  
387 - srs_error("send set buffer length failed. "  
388 - "stream=%s, stream_id=%d, bufferLength=%d, ret=%d",  
389 - stream.c_str(), stream_id, buffer_length_ms, ret);  
390 - return ret;  
391 - }  
392 - }  
393 -  
394 - return ret;  
395 -}  
396 -  
397 -int SrsRtmpClient::publish(string stream, int stream_id)  
398 -{  
399 - int ret = ERROR_SUCCESS;  
400 -  
401 - // publish(stream)  
402 - if (true) {  
403 - SrsCommonMessage* msg = new SrsCommonMessage();  
404 - SrsPublishPacket* pkt = new SrsPublishPacket();  
405 -  
406 - pkt->stream_name = stream;  
407 - msg->set_packet(pkt, stream_id);  
408 -  
409 - if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {  
410 - srs_error("send publish message failed. "  
411 - "stream=%s, stream_id=%d, ret=%d",  
412 - stream.c_str(), stream_id, ret);  
413 - return ret;  
414 - }  
415 - }  
416 -  
417 - return ret;  
418 -}  
419 -  
420 -SrsRtmp::SrsRtmp(st_netfd_t client_stfd)  
421 -{  
422 - protocol = new SrsProtocol(client_stfd);  
423 - stfd = client_stfd;  
424 -}  
425 -  
426 -SrsRtmp::~SrsRtmp()  
427 -{  
428 - srs_freep(protocol);  
429 -}  
430 -  
431 -SrsProtocol* SrsRtmp::get_protocol()  
432 -{  
433 - return protocol;  
434 -}  
435 -  
436 -void SrsRtmp::set_recv_timeout(int64_t timeout_us)  
437 -{  
438 - protocol->set_recv_timeout(timeout_us);  
439 -}  
440 -  
441 -int64_t SrsRtmp::get_recv_timeout()  
442 -{  
443 - return protocol->get_recv_timeout();  
444 -}  
445 -  
446 -void SrsRtmp::set_send_timeout(int64_t timeout_us)  
447 -{  
448 - protocol->set_send_timeout(timeout_us);  
449 -}  
450 -  
451 -int64_t SrsRtmp::get_send_timeout()  
452 -{  
453 - return protocol->get_send_timeout();  
454 -}  
455 -  
456 -int64_t SrsRtmp::get_recv_bytes()  
457 -{  
458 - return protocol->get_recv_bytes();  
459 -}  
460 -  
461 -int64_t SrsRtmp::get_send_bytes()  
462 -{  
463 - return protocol->get_send_bytes();  
464 -}  
465 -  
466 -int SrsRtmp::get_recv_kbps()  
467 -{  
468 - return protocol->get_recv_kbps();  
469 -}  
470 -  
471 -int SrsRtmp::get_send_kbps()  
472 -{  
473 - return protocol->get_send_kbps();  
474 -}  
475 -  
476 -int SrsRtmp::recv_message(SrsCommonMessage** pmsg)  
477 -{  
478 - return protocol->recv_message(pmsg);  
479 -}  
480 -  
481 -int SrsRtmp::send_message(ISrsMessage* msg)  
482 -{  
483 - return protocol->send_message(msg);  
484 -}  
485 -  
486 -int SrsRtmp::handshake()  
487 -{  
488 - int ret = ERROR_SUCCESS;  
489 -  
490 - SrsSocket skt(stfd);  
491 -  
492 - skt.set_recv_timeout(protocol->get_recv_timeout());  
493 - skt.set_send_timeout(protocol->get_send_timeout());  
494 -  
495 - SrsComplexHandshake complex_hs;  
496 - SrsSimpleHandshake simple_hs;  
497 - if ((ret = simple_hs.handshake_with_client(skt, complex_hs)) != ERROR_SUCCESS) {  
498 - return ret;  
499 - }  
500 -  
501 - return ret;  
502 -}  
503 -  
504 -int SrsRtmp::connect_app(SrsRequest* req)  
505 -{  
506 - int ret = ERROR_SUCCESS;  
507 -  
508 - SrsCommonMessage* msg = NULL;  
509 - SrsConnectAppPacket* pkt = NULL;  
510 - if ((ret = srs_rtmp_expect_message<SrsConnectAppPacket>(protocol, &msg, &pkt)) != ERROR_SUCCESS) {  
511 - srs_error("expect connect app message failed. ret=%d", ret);  
512 - return ret;  
513 - }  
514 - SrsAutoFree(SrsCommonMessage, msg, false);  
515 - srs_info("get connect app message");  
516 -  
517 - SrsAmf0Any* prop = NULL;  
518 -  
519 - if ((prop = pkt->command_object->ensure_property_string("tcUrl")) == NULL) {  
520 - ret = ERROR_RTMP_REQ_CONNECT;  
521 - srs_error("invalid request, must specifies the tcUrl. ret=%d", ret);  
522 - return ret;  
523 - }  
524 - req->tcUrl = srs_amf0_convert<SrsAmf0String>(prop)->value;  
525 -  
526 - if ((prop = pkt->command_object->ensure_property_string("pageUrl")) != NULL) {  
527 - req->pageUrl = srs_amf0_convert<SrsAmf0String>(prop)->value;  
528 - }  
529 -  
530 - if ((prop = pkt->command_object->ensure_property_string("swfUrl")) != NULL) {  
531 - req->swfUrl = srs_amf0_convert<SrsAmf0String>(prop)->value;  
532 - }  
533 -  
534 - if ((prop = pkt->command_object->ensure_property_number("objectEncoding")) != NULL) {  
535 - req->objectEncoding = srs_amf0_convert<SrsAmf0Number>(prop)->value;  
536 - }  
537 -  
538 - srs_info("get connect app message params success.");  
539 -  
540 - return req->discovery_app();  
541 -}  
542 -  
543 -int SrsRtmp::set_window_ack_size(int ack_size)  
544 -{  
545 - int ret = ERROR_SUCCESS;  
546 -  
547 - SrsCommonMessage* msg = new SrsCommonMessage();  
548 - SrsSetWindowAckSizePacket* pkt = new SrsSetWindowAckSizePacket();  
549 -  
550 - pkt->ackowledgement_window_size = ack_size;  
551 - msg->set_packet(pkt, 0);  
552 -  
553 - if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {  
554 - srs_error("send ack size message failed. ret=%d", ret);  
555 - return ret;  
556 - }  
557 - srs_info("send ack size message success. ack_size=%d", ack_size);  
558 -  
559 - return ret;  
560 -}  
561 -  
562 -int SrsRtmp::set_peer_bandwidth(int bandwidth, int type)  
563 -{  
564 - int ret = ERROR_SUCCESS;  
565 -  
566 - SrsCommonMessage* msg = new SrsCommonMessage();  
567 - SrsSetPeerBandwidthPacket* pkt = new SrsSetPeerBandwidthPacket();  
568 -  
569 - pkt->bandwidth = bandwidth;  
570 - pkt->type = type;  
571 - msg->set_packet(pkt, 0);  
572 -  
573 - if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {  
574 - srs_error("send set bandwidth message failed. ret=%d", ret);  
575 - return ret;  
576 - }  
577 - srs_info("send set bandwidth message "  
578 - "success. bandwidth=%d, type=%d", bandwidth, type);  
579 -  
580 - return ret;  
581 -}  
582 -  
583 -int SrsRtmp::response_connect_app(SrsRequest *req, const char* server_ip)  
584 -{  
585 - int ret = ERROR_SUCCESS;  
586 -  
587 - SrsCommonMessage* msg = new SrsCommonMessage();  
588 - SrsConnectAppResPacket* pkt = new SrsConnectAppResPacket();  
589 -  
590 - pkt->props->set("fmsVer", new SrsAmf0String("FMS/"RTMP_SIG_FMS_VER));  
591 - pkt->props->set("capabilities", new SrsAmf0Number(127));  
592 - pkt->props->set("mode", new SrsAmf0Number(1));  
593 -  
594 - pkt->info->set(StatusLevel, new SrsAmf0String(StatusLevelStatus));  
595 - pkt->info->set(StatusCode, new SrsAmf0String(StatusCodeConnectSuccess));  
596 - pkt->info->set(StatusDescription, new SrsAmf0String("Connection succeeded"));  
597 - pkt->info->set("objectEncoding", new SrsAmf0Number(req->objectEncoding));  
598 - SrsASrsAmf0EcmaArray* data = new SrsASrsAmf0EcmaArray();  
599 - pkt->info->set("data", data);  
600 -  
601 - data->set("srs_version", new SrsAmf0String(RTMP_SIG_FMS_VER));  
602 - data->set("srs_server", new SrsAmf0String(RTMP_SIG_SRS_KEY" "RTMP_SIG_SRS_VERSION" ("RTMP_SIG_SRS_URL_SHORT")"));  
603 - data->set("srs_license", new SrsAmf0String(RTMP_SIG_SRS_LICENSE));  
604 - data->set("srs_role", new SrsAmf0String(RTMP_SIG_SRS_ROLE));  
605 - data->set("srs_url", new SrsAmf0String(RTMP_SIG_SRS_URL));  
606 - data->set("srs_version", new SrsAmf0String(RTMP_SIG_SRS_VERSION));  
607 - data->set("srs_site", new SrsAmf0String(RTMP_SIG_SRS_WEB));  
608 - data->set("srs_email", new SrsAmf0String(RTMP_SIG_SRS_EMAIL));  
609 - data->set("srs_copyright", new SrsAmf0String(RTMP_SIG_SRS_COPYRIGHT));  
610 - data->set("srs_contributor", new SrsAmf0String(RTMP_SIG_SRS_CONTRIBUTOR));  
611 -  
612 - if (server_ip) {  
613 - data->set("srs_server_ip", new SrsAmf0String(server_ip));  
614 - }  
615 -  
616 - msg->set_packet(pkt, 0);  
617 -  
618 - if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {  
619 - srs_error("send connect app response message failed. ret=%d", ret);  
620 - return ret;  
621 - }  
622 - srs_info("send connect app response message success.");  
623 -  
624 - return ret;  
625 -}  
626 -  
627 -void SrsRtmp::response_connect_reject(SrsRequest *req, const char* desc)  
628 -{  
629 - int ret = ERROR_SUCCESS;  
630 -  
631 - SrsConnectAppResPacket* pkt = new SrsConnectAppResPacket();  
632 - pkt->command_name = "_error";  
633 - pkt->props->set(StatusLevel, new SrsAmf0String(StatusLevelError));  
634 - pkt->props->set(StatusCode, new SrsAmf0String(StatusCodeConnectRejected));  
635 - pkt->props->set(StatusDescription, new SrsAmf0String(desc));  
636 - //pkt->props->set("objectEncoding", new SrsAmf0Number(req->objectEncoding));  
637 -  
638 - SrsCommonMessage* msg = (new SrsCommonMessage())->set_packet(pkt, 0);  
639 - if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {  
640 - srs_error("send connect app response rejected message failed. ret=%d", ret);  
641 - return;  
642 - }  
643 - srs_info("send connect app response rejected message success.");  
644 -  
645 - return;  
646 -}  
647 -  
648 -int SrsRtmp::on_bw_done()  
649 -{  
650 - int ret = ERROR_SUCCESS;  
651 -  
652 - SrsCommonMessage* msg = new SrsCommonMessage();  
653 - SrsOnBWDonePacket* pkt = new SrsOnBWDonePacket();  
654 -  
655 - msg->set_packet(pkt, 0);  
656 -  
657 - if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {  
658 - srs_error("send onBWDone message failed. ret=%d", ret);  
659 - return ret;  
660 - }  
661 - srs_info("send onBWDone message success.");  
662 -  
663 - return ret;  
664 -}  
665 -  
666 -int SrsRtmp::identify_client(int stream_id, SrsClientType& type, std::string& stream_name)  
667 -{  
668 - type = SrsClientUnknown;  
669 - int ret = ERROR_SUCCESS;  
670 -  
671 - while (true) {  
672 - SrsCommonMessage* msg = NULL;  
673 - if ((ret = protocol->recv_message(&msg)) != ERROR_SUCCESS) {  
674 - srs_error("recv identify client message failed. ret=%d", ret);  
675 - return ret;  
676 - }  
677 -  
678 - SrsAutoFree(SrsCommonMessage, msg, false);  
679 -  
680 - if (!msg->header.is_amf0_command() && !msg->header.is_amf3_command()) {  
681 - srs_trace("identify ignore messages except "  
682 - "AMF0/AMF3 command message. type=%#x", msg->header.message_type);  
683 - continue;  
684 - }  
685 -  
686 - if ((ret = msg->decode_packet(protocol)) != ERROR_SUCCESS) {  
687 - srs_error("identify decode message failed. ret=%d", ret);  
688 - return ret;  
689 - }  
690 -  
691 - SrsPacket* pkt = msg->get_packet();  
692 - if (dynamic_cast<SrsCreateStreamPacket*>(pkt)) {  
693 - srs_info("identify client by create stream, play or flash publish.");  
694 - return identify_create_stream_client(  
695 - dynamic_cast<SrsCreateStreamPacket*>(pkt), stream_id, type, stream_name);  
696 - }  
697 - if (dynamic_cast<SrsFMLEStartPacket*>(pkt)) {  
698 - srs_info("identify client by releaseStream, fmle publish.");  
699 - return identify_fmle_publish_client(  
700 - dynamic_cast<SrsFMLEStartPacket*>(pkt), type, stream_name);  
701 - }  
702 -  
703 - srs_trace("ignore AMF0/AMF3 command message.");  
704 - }  
705 -  
706 - return ret;  
707 -}  
708 -  
709 -int SrsRtmp::set_chunk_size(int chunk_size)  
710 -{  
711 - int ret = ERROR_SUCCESS;  
712 -  
713 - SrsCommonMessage* msg = new SrsCommonMessage();  
714 - SrsSetChunkSizePacket* pkt = new SrsSetChunkSizePacket();  
715 -  
716 - pkt->chunk_size = chunk_size;  
717 - msg->set_packet(pkt, 0);  
718 -  
719 - if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {  
720 - srs_error("send set chunk size message failed. ret=%d", ret);  
721 - return ret;  
722 - }  
723 - srs_info("send set chunk size message success. chunk_size=%d", chunk_size);  
724 -  
725 - return ret;  
726 -}  
727 -  
728 -int SrsRtmp::start_play(int stream_id)  
729 -{  
730 - int ret = ERROR_SUCCESS;  
731 -  
732 - // StreamBegin  
733 - if (true) {  
734 - SrsCommonMessage* msg = new SrsCommonMessage();  
735 - SrsUserControlPacket* pkt = new SrsUserControlPacket();  
736 -  
737 - pkt->event_type = SrcPCUCStreamBegin;  
738 - pkt->event_data = stream_id;  
739 - msg->set_packet(pkt, 0);  
740 -  
741 - if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {  
742 - srs_error("send PCUC(StreamBegin) message failed. ret=%d", ret);  
743 - return ret;  
744 - }  
745 - srs_info("send PCUC(StreamBegin) message success.");  
746 - }  
747 -  
748 - // onStatus(NetStream.Play.Reset)  
749 - if (true) {  
750 - SrsCommonMessage* msg = new SrsCommonMessage();  
751 - SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket();  
752 -  
753 - pkt->data->set(StatusLevel, new SrsAmf0String(StatusLevelStatus));  
754 - pkt->data->set(StatusCode, new SrsAmf0String(StatusCodeStreamReset));  
755 - pkt->data->set(StatusDescription, new SrsAmf0String("Playing and resetting stream."));  
756 - pkt->data->set(StatusDetails, new SrsAmf0String("stream"));  
757 - pkt->data->set(StatusClientId, new SrsAmf0String(RTMP_SIG_CLIENT_ID));  
758 -  
759 - msg->set_packet(pkt, stream_id);  
760 -  
761 - if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {  
762 - srs_error("send onStatus(NetStream.Play.Reset) message failed. ret=%d", ret);  
763 - return ret;  
764 - }  
765 - srs_info("send onStatus(NetStream.Play.Reset) message success.");  
766 - }  
767 -  
768 - // onStatus(NetStream.Play.Start)  
769 - if (true) {  
770 - SrsCommonMessage* msg = new SrsCommonMessage();  
771 - SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket();  
772 -  
773 - pkt->data->set(StatusLevel, new SrsAmf0String(StatusLevelStatus));  
774 - pkt->data->set(StatusCode, new SrsAmf0String(StatusCodeStreamStart));  
775 - pkt->data->set(StatusDescription, new SrsAmf0String("Started playing stream."));  
776 - pkt->data->set(StatusDetails, new SrsAmf0String("stream"));  
777 - pkt->data->set(StatusClientId, new SrsAmf0String(RTMP_SIG_CLIENT_ID));  
778 -  
779 - msg->set_packet(pkt, stream_id);  
780 -  
781 - if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {  
782 - srs_error("send onStatus(NetStream.Play.Reset) message failed. ret=%d", ret);  
783 - return ret;  
784 - }  
785 - srs_info("send onStatus(NetStream.Play.Reset) message success.");  
786 - }  
787 -  
788 - // |RtmpSampleAccess(false, false)  
789 - if (true) {  
790 - SrsCommonMessage* msg = new SrsCommonMessage();  
791 - SrsSampleAccessPacket* pkt = new SrsSampleAccessPacket();  
792 -  
793 - msg->set_packet(pkt, stream_id);  
794 -  
795 - if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {  
796 - srs_error("send |RtmpSampleAccess(false, false) message failed. ret=%d", ret);  
797 - return ret;  
798 - }  
799 - srs_info("send |RtmpSampleAccess(false, false) message success.");  
800 - }  
801 -  
802 - // onStatus(NetStream.Data.Start)  
803 - if (true) {  
804 - SrsCommonMessage* msg = new SrsCommonMessage();  
805 - SrsOnStatusDataPacket* pkt = new SrsOnStatusDataPacket();  
806 -  
807 - pkt->data->set(StatusCode, new SrsAmf0String(StatusCodeDataStart));  
808 -  
809 - msg->set_packet(pkt, stream_id);  
810 -  
811 - if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {  
812 - srs_error("send onStatus(NetStream.Data.Start) message failed. ret=%d", ret);  
813 - return ret;  
814 - }  
815 - srs_info("send onStatus(NetStream.Data.Start) message success.");  
816 - }  
817 -  
818 - srs_info("start play success.");  
819 -  
820 - return ret;  
821 -}  
822 -  
823 -int SrsRtmp::on_play_client_pause(int stream_id, bool is_pause)  
824 -{  
825 - int ret = ERROR_SUCCESS;  
826 -  
827 - if (is_pause) {  
828 - // onStatus(NetStream.Pause.Notify)  
829 - if (true) {  
830 - SrsCommonMessage* msg = new SrsCommonMessage();  
831 - SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket();  
832 -  
833 - pkt->data->set(StatusLevel, new SrsAmf0String(StatusLevelStatus));  
834 - pkt->data->set(StatusCode, new SrsAmf0String(StatusCodeStreamPause));  
835 - pkt->data->set(StatusDescription, new SrsAmf0String("Paused stream."));  
836 -  
837 - msg->set_packet(pkt, stream_id);  
838 -  
839 - if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {  
840 - srs_error("send onStatus(NetStream.Pause.Notify) message failed. ret=%d", ret);  
841 - return ret;  
842 - }  
843 - srs_info("send onStatus(NetStream.Pause.Notify) message success.");  
844 - }  
845 - // StreamEOF  
846 - if (true) {  
847 - SrsCommonMessage* msg = new SrsCommonMessage();  
848 - SrsUserControlPacket* pkt = new SrsUserControlPacket();  
849 -  
850 - pkt->event_type = SrcPCUCStreamEOF;  
851 - pkt->event_data = stream_id;  
852 - msg->set_packet(pkt, 0);  
853 -  
854 - if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {  
855 - srs_error("send PCUC(StreamEOF) message failed. ret=%d", ret);  
856 - return ret;  
857 - }  
858 - srs_info("send PCUC(StreamEOF) message success.");  
859 - }  
860 - } else {  
861 - // onStatus(NetStream.Unpause.Notify)  
862 - if (true) {  
863 - SrsCommonMessage* msg = new SrsCommonMessage();  
864 - SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket();  
865 -  
866 - pkt->data->set(StatusLevel, new SrsAmf0String(StatusLevelStatus));  
867 - pkt->data->set(StatusCode, new SrsAmf0String(StatusCodeStreamUnpause));  
868 - pkt->data->set(StatusDescription, new SrsAmf0String("Unpaused stream."));  
869 -  
870 - msg->set_packet(pkt, stream_id);  
871 -  
872 - if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {  
873 - srs_error("send onStatus(NetStream.Unpause.Notify) message failed. ret=%d", ret);  
874 - return ret;  
875 - }  
876 - srs_info("send onStatus(NetStream.Unpause.Notify) message success.");  
877 - }  
878 - // StreanBegin  
879 - if (true) {  
880 - SrsCommonMessage* msg = new SrsCommonMessage();  
881 - SrsUserControlPacket* pkt = new SrsUserControlPacket();  
882 -  
883 - pkt->event_type = SrcPCUCStreamBegin;  
884 - pkt->event_data = stream_id;  
885 - msg->set_packet(pkt, 0);  
886 -  
887 - if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {  
888 - srs_error("send PCUC(StreanBegin) message failed. ret=%d", ret);  
889 - return ret;  
890 - }  
891 - srs_info("send PCUC(StreanBegin) message success.");  
892 - }  
893 - }  
894 -  
895 - return ret;  
896 -}  
897 -  
898 -int SrsRtmp::start_fmle_publish(int stream_id)  
899 -{  
900 - int ret = ERROR_SUCCESS;  
901 -  
902 - // FCPublish  
903 - double fc_publish_tid = 0;  
904 - if (true) {  
905 - SrsCommonMessage* msg = NULL;  
906 - SrsFMLEStartPacket* pkt = NULL;  
907 - if ((ret = srs_rtmp_expect_message<SrsFMLEStartPacket>(protocol, &msg, &pkt)) != ERROR_SUCCESS) {  
908 - srs_error("recv FCPublish message failed. ret=%d", ret);  
909 - return ret;  
910 - }  
911 - srs_info("recv FCPublish request message success.");  
912 -  
913 - SrsAutoFree(SrsCommonMessage, msg, false);  
914 - fc_publish_tid = pkt->transaction_id;  
915 - }  
916 - // FCPublish response  
917 - if (true) {  
918 - SrsCommonMessage* msg = new SrsCommonMessage();  
919 - SrsFMLEStartResPacket* pkt = new SrsFMLEStartResPacket(fc_publish_tid);  
920 -  
921 - msg->set_packet(pkt, 0);  
922 -  
923 - if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {  
924 - srs_error("send FCPublish response message failed. ret=%d", ret);  
925 - return ret;  
926 - }  
927 - srs_info("send FCPublish response message success.");  
928 - }  
929 -  
930 - // createStream  
931 - double create_stream_tid = 0;  
932 - if (true) {  
933 - SrsCommonMessage* msg = NULL;  
934 - SrsCreateStreamPacket* pkt = NULL;  
935 - if ((ret = srs_rtmp_expect_message<SrsCreateStreamPacket>(protocol, &msg, &pkt)) != ERROR_SUCCESS) {  
936 - srs_error("recv createStream message failed. ret=%d", ret);  
937 - return ret;  
938 - }  
939 - srs_info("recv createStream request message success.");  
940 -  
941 - SrsAutoFree(SrsCommonMessage, msg, false);  
942 - create_stream_tid = pkt->transaction_id;  
943 - }  
944 - // createStream response  
945 - if (true) {  
946 - SrsCommonMessage* msg = new SrsCommonMessage();  
947 - SrsCreateStreamResPacket* pkt = new SrsCreateStreamResPacket(create_stream_tid, stream_id);  
948 -  
949 - msg->set_packet(pkt, 0);  
950 -  
951 - if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {  
952 - srs_error("send createStream response message failed. ret=%d", ret);  
953 - return ret;  
954 - }  
955 - srs_info("send createStream response message success.");  
956 - }  
957 -  
958 - // publish  
959 - if (true) {  
960 - SrsCommonMessage* msg = NULL;  
961 - SrsPublishPacket* pkt = NULL;  
962 - if ((ret = srs_rtmp_expect_message<SrsPublishPacket>(protocol, &msg, &pkt)) != ERROR_SUCCESS) {  
963 - srs_error("recv publish message failed. ret=%d", ret);  
964 - return ret;  
965 - }  
966 - srs_info("recv publish request message success.");  
967 -  
968 - SrsAutoFree(SrsCommonMessage, msg, false);  
969 - }  
970 - // publish response onFCPublish(NetStream.Publish.Start)  
971 - if (true) {  
972 - SrsCommonMessage* msg = new SrsCommonMessage();  
973 - SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket();  
974 -  
975 - pkt->command_name = RTMP_AMF0_COMMAND_ON_FC_PUBLISH;  
976 - pkt->data->set(StatusCode, new SrsAmf0String(StatusCodePublishStart));  
977 - pkt->data->set(StatusDescription, new SrsAmf0String("Started publishing stream."));  
978 -  
979 - msg->set_packet(pkt, stream_id);  
980 -  
981 - if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {  
982 - srs_error("send onFCPublish(NetStream.Publish.Start) message failed. ret=%d", ret);  
983 - return ret;  
984 - }  
985 - srs_info("send onFCPublish(NetStream.Publish.Start) message success.");  
986 - }  
987 - // publish response onStatus(NetStream.Publish.Start)  
988 - if (true) {  
989 - SrsCommonMessage* msg = new SrsCommonMessage();  
990 - SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket();  
991 -  
992 - pkt->data->set(StatusLevel, new SrsAmf0String(StatusLevelStatus));  
993 - pkt->data->set(StatusCode, new SrsAmf0String(StatusCodePublishStart));  
994 - pkt->data->set(StatusDescription, new SrsAmf0String("Started publishing stream."));  
995 - pkt->data->set(StatusClientId, new SrsAmf0String(RTMP_SIG_CLIENT_ID));  
996 -  
997 - msg->set_packet(pkt, stream_id);  
998 -  
999 - if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {  
1000 - srs_error("send onStatus(NetStream.Publish.Start) message failed. ret=%d", ret);  
1001 - return ret;  
1002 - }  
1003 - srs_info("send onStatus(NetStream.Publish.Start) message success.");  
1004 - }  
1005 -  
1006 - srs_info("FMLE publish success.");  
1007 -  
1008 - return ret;  
1009 -}  
1010 -  
1011 -int SrsRtmp::fmle_unpublish(int stream_id, double unpublish_tid)  
1012 -{  
1013 - int ret = ERROR_SUCCESS;  
1014 -  
1015 - // publish response onFCUnpublish(NetStream.unpublish.Success)  
1016 - if (true) {  
1017 - SrsCommonMessage* msg = new SrsCommonMessage();  
1018 - SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket();  
1019 -  
1020 - pkt->command_name = RTMP_AMF0_COMMAND_ON_FC_UNPUBLISH;  
1021 - pkt->data->set(StatusCode, new SrsAmf0String(StatusCodeUnpublishSuccess));  
1022 - pkt->data->set(StatusDescription, new SrsAmf0String("Stop publishing stream."));  
1023 -  
1024 - msg->set_packet(pkt, stream_id);  
1025 -  
1026 - if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {  
1027 - srs_error("send onFCUnpublish(NetStream.unpublish.Success) message failed. ret=%d", ret);  
1028 - return ret;  
1029 - }  
1030 - srs_info("send onFCUnpublish(NetStream.unpublish.Success) message success.");  
1031 - }  
1032 - // FCUnpublish response  
1033 - if (true) {  
1034 - SrsCommonMessage* msg = new SrsCommonMessage();  
1035 - SrsFMLEStartResPacket* pkt = new SrsFMLEStartResPacket(unpublish_tid);  
1036 -  
1037 - msg->set_packet(pkt, stream_id);  
1038 -  
1039 - if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {  
1040 - srs_error("send FCUnpublish response message failed. ret=%d", ret);  
1041 - return ret;  
1042 - }  
1043 - srs_info("send FCUnpublish response message success.");  
1044 - }  
1045 - // publish response onStatus(NetStream.Unpublish.Success)  
1046 - if (true) {  
1047 - SrsCommonMessage* msg = new SrsCommonMessage();  
1048 - SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket();  
1049 -  
1050 - pkt->data->set(StatusLevel, new SrsAmf0String(StatusLevelStatus));  
1051 - pkt->data->set(StatusCode, new SrsAmf0String(StatusCodeUnpublishSuccess));  
1052 - pkt->data->set(StatusDescription, new SrsAmf0String("Stream is now unpublished"));  
1053 - pkt->data->set(StatusClientId, new SrsAmf0String(RTMP_SIG_CLIENT_ID));  
1054 -  
1055 - msg->set_packet(pkt, stream_id);  
1056 -  
1057 - if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {  
1058 - srs_error("send onStatus(NetStream.Unpublish.Success) message failed. ret=%d", ret);  
1059 - return ret;  
1060 - }  
1061 - srs_info("send onStatus(NetStream.Unpublish.Success) message success.");  
1062 - }  
1063 -  
1064 - srs_info("FMLE unpublish success.");  
1065 -  
1066 - return ret;  
1067 -}  
1068 -  
1069 -int SrsRtmp::start_flash_publish(int stream_id)  
1070 -{  
1071 - int ret = ERROR_SUCCESS;  
1072 -  
1073 - // publish response onStatus(NetStream.Publish.Start)  
1074 - if (true) {  
1075 - SrsCommonMessage* msg = new SrsCommonMessage();  
1076 - SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket();  
1077 -  
1078 - pkt->data->set(StatusLevel, new SrsAmf0String(StatusLevelStatus));  
1079 - pkt->data->set(StatusCode, new SrsAmf0String(StatusCodePublishStart));  
1080 - pkt->data->set(StatusDescription, new SrsAmf0String("Started publishing stream."));  
1081 - pkt->data->set(StatusClientId, new SrsAmf0String(RTMP_SIG_CLIENT_ID));  
1082 -  
1083 - msg->set_packet(pkt, stream_id);  
1084 -  
1085 - if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {  
1086 - srs_error("send onStatus(NetStream.Publish.Start) message failed. ret=%d", ret);  
1087 - return ret;  
1088 - }  
1089 - srs_info("send onStatus(NetStream.Publish.Start) message success.");  
1090 - }  
1091 -  
1092 - srs_info("flash publish success.");  
1093 -  
1094 - return ret;  
1095 -}  
1096 -  
1097 -int SrsRtmp::identify_create_stream_client(SrsCreateStreamPacket* req, int stream_id, SrsClientType& type, string& stream_name)  
1098 -{  
1099 - int ret = ERROR_SUCCESS;  
1100 -  
1101 - if (true) {  
1102 - SrsCommonMessage* msg = new SrsCommonMessage();  
1103 - SrsCreateStreamResPacket* pkt = new SrsCreateStreamResPacket(req->transaction_id, stream_id);  
1104 -  
1105 - msg->set_packet(pkt, 0);  
1106 -  
1107 - if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {  
1108 - srs_error("send createStream response message failed. ret=%d", ret);  
1109 - return ret;  
1110 - }  
1111 - srs_info("send createStream response message success.");  
1112 - }  
1113 -  
1114 - while (true) {  
1115 - SrsCommonMessage* msg = NULL;  
1116 - if ((ret = protocol->recv_message(&msg)) != ERROR_SUCCESS) {  
1117 - srs_error("recv identify client message failed. ret=%d", ret);  
1118 - return ret;  
1119 - }  
1120 -  
1121 - SrsAutoFree(SrsCommonMessage, msg, false);  
1122 -  
1123 - if (!msg->header.is_amf0_command() && !msg->header.is_amf3_command()) {  
1124 - srs_trace("identify ignore messages except "  
1125 - "AMF0/AMF3 command message. type=%#x", msg->header.message_type);  
1126 - continue;  
1127 - }  
1128 -  
1129 - if ((ret = msg->decode_packet(protocol)) != ERROR_SUCCESS) {  
1130 - srs_error("identify decode message failed. ret=%d", ret);  
1131 - return ret;  
1132 - }  
1133 -  
1134 - SrsPacket* pkt = msg->get_packet();  
1135 - if (dynamic_cast<SrsPlayPacket*>(pkt)) {  
1136 - SrsPlayPacket* play = dynamic_cast<SrsPlayPacket*>(pkt);  
1137 - type = SrsClientPlay;  
1138 - stream_name = play->stream_name;  
1139 - srs_trace("identity client type=play, stream_name=%s", stream_name.c_str());  
1140 - return ret;  
1141 - }  
1142 - if (dynamic_cast<SrsPublishPacket*>(pkt)) {  
1143 - srs_info("identify client by publish, falsh publish.");  
1144 - return identify_flash_publish_client(  
1145 - dynamic_cast<SrsPublishPacket*>(pkt), type, stream_name);  
1146 - }  
1147 -  
1148 - srs_trace("ignore AMF0/AMF3 command message.");  
1149 - }  
1150 -  
1151 - return ret;  
1152 -}  
1153 -  
1154 -int SrsRtmp::identify_fmle_publish_client(SrsFMLEStartPacket* req, SrsClientType& type, string& stream_name)  
1155 -{  
1156 - int ret = ERROR_SUCCESS;  
1157 -  
1158 - type = SrsClientFMLEPublish;  
1159 - stream_name = req->stream_name;  
1160 -  
1161 - // releaseStream response  
1162 - if (true) {  
1163 - SrsCommonMessage* msg = new SrsCommonMessage();  
1164 - SrsFMLEStartResPacket* pkt = new SrsFMLEStartResPacket(req->transaction_id);  
1165 -  
1166 - msg->set_packet(pkt, 0);  
1167 -  
1168 - if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {  
1169 - srs_error("send releaseStream response message failed. ret=%d", ret);  
1170 - return ret;  
1171 - }  
1172 - srs_info("send releaseStream response message success.");  
1173 - }  
1174 -  
1175 - return ret;  
1176 -}  
1177 -  
1178 -int SrsRtmp::identify_flash_publish_client(SrsPublishPacket* req, SrsClientType& type, string& stream_name)  
1179 -{  
1180 - int ret = ERROR_SUCCESS;  
1181 -  
1182 - type = SrsClientFlashPublish;  
1183 - stream_name = req->stream_name;  
1184 -  
1185 - return ret;  
1186 -}  
1187 - 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_rtmp.hpp>
  25 +
  26 +#include <srs_core_log.hpp>
  27 +#include <srs_core_error.hpp>
  28 +#include <srs_core_socket.hpp>
  29 +#include <srs_core_protocol.hpp>
  30 +#include <srs_core_autofree.hpp>
  31 +#include <srs_core_amf0.hpp>
  32 +#include <srs_core_handshake.hpp>
  33 +#include <srs_core_config.hpp>
  34 +
  35 +using namespace std;
  36 +
  37 +/**
  38 +* the signature for packets to client.
  39 +*/
  40 +#define RTMP_SIG_FMS_VER "3,5,3,888"
  41 +#define RTMP_SIG_AMF0_VER 0
  42 +#define RTMP_SIG_CLIENT_ID "ASAICiss"
  43 +
  44 +/**
  45 +* onStatus consts.
  46 +*/
  47 +#define StatusLevel "level"
  48 +#define StatusCode "code"
  49 +#define StatusDescription "description"
  50 +#define StatusDetails "details"
  51 +#define StatusClientId "clientid"
  52 +// status value
  53 +#define StatusLevelStatus "status"
  54 +// status error
  55 +#define StatusLevelError "error"
  56 +// code value
  57 +#define StatusCodeConnectSuccess "NetConnection.Connect.Success"
  58 +#define StatusCodeConnectRejected "NetConnection.Connect.Rejected"
  59 +#define StatusCodeStreamReset "NetStream.Play.Reset"
  60 +#define StatusCodeStreamStart "NetStream.Play.Start"
  61 +#define StatusCodeStreamPause "NetStream.Pause.Notify"
  62 +#define StatusCodeStreamUnpause "NetStream.Unpause.Notify"
  63 +#define StatusCodePublishStart "NetStream.Publish.Start"
  64 +#define StatusCodeDataStart "NetStream.Data.Start"
  65 +#define StatusCodeUnpublishSuccess "NetStream.Unpublish.Success"
  66 +
  67 +// FMLE
  68 +#define RTMP_AMF0_COMMAND_ON_FC_PUBLISH "onFCPublish"
  69 +#define RTMP_AMF0_COMMAND_ON_FC_UNPUBLISH "onFCUnpublish"
  70 +
  71 +// default stream id for response the createStream request.
  72 +#define SRS_DEFAULT_SID 1
  73 +
  74 +SrsRequest::SrsRequest()
  75 +{
  76 + objectEncoding = RTMP_SIG_AMF0_VER;
  77 +}
  78 +
  79 +SrsRequest::~SrsRequest()
  80 +{
  81 +}
  82 +
  83 +SrsRequest* SrsRequest::copy()
  84 +{
  85 + SrsRequest* cp = new SrsRequest();
  86 +
  87 + cp->app = app;
  88 + cp->objectEncoding = objectEncoding;
  89 + cp->pageUrl = pageUrl;
  90 + cp->port = port;
  91 + cp->schema = schema;
  92 + cp->stream = stream;
  93 + cp->swfUrl = swfUrl;
  94 + cp->tcUrl = tcUrl;
  95 + cp->vhost = vhost;
  96 +
  97 + return cp;
  98 +}
  99 +
  100 +int SrsRequest::discovery_app()
  101 +{
  102 + int ret = ERROR_SUCCESS;
  103 +
  104 + size_t pos = std::string::npos;
  105 + std::string url = tcUrl;
  106 +
  107 + if ((pos = url.find("://")) != std::string::npos) {
  108 + schema = url.substr(0, pos);
  109 + url = url.substr(schema.length() + 3);
  110 + srs_verbose("discovery schema=%s", schema.c_str());
  111 + }
  112 +
  113 + if ((pos = url.find("/")) != std::string::npos) {
  114 + vhost = url.substr(0, pos);
  115 + url = url.substr(vhost.length() + 1);
  116 + srs_verbose("discovery vhost=%s", vhost.c_str());
  117 + }
  118 +
  119 + port = RTMP_DEFAULT_PORTS;
  120 + if ((pos = vhost.find(":")) != std::string::npos) {
  121 + port = vhost.substr(pos + 1);
  122 + vhost = vhost.substr(0, pos);
  123 + srs_verbose("discovery vhost=%s, port=%s", vhost.c_str(), port.c_str());
  124 + }
  125 +
  126 + app = url;
  127 + srs_vhost_resolve(vhost, app);
  128 + strip();
  129 +
  130 + // resolve the vhost from config
  131 + SrsConfDirective* parsed_vhost = config->get_vhost(vhost);
  132 + if (parsed_vhost) {
  133 + vhost = parsed_vhost->arg0();
  134 + }
  135 +
  136 + // TODO: discovery the params of vhost.
  137 +
  138 + srs_info("discovery app success. schema=%s, vhost=%s, port=%s, app=%s",
  139 + schema.c_str(), vhost.c_str(), port.c_str(), app.c_str());
  140 +
  141 + if (schema.empty() || vhost.empty() || port.empty() || app.empty()) {
  142 + ret = ERROR_RTMP_REQ_TCURL;
  143 + srs_error("discovery tcUrl failed. "
  144 + "tcUrl=%s, schema=%s, vhost=%s, port=%s, app=%s, ret=%d",
  145 + tcUrl.c_str(), schema.c_str(), vhost.c_str(), port.c_str(), app.c_str(), ret);
  146 + return ret;
  147 + }
  148 +
  149 + strip();
  150 +
  151 + return ret;
  152 +}
  153 +
  154 +string SrsRequest::get_stream_url()
  155 +{
  156 + std::string url = "";
  157 +
  158 + url += vhost;
  159 + url += "/";
  160 + url += app;
  161 + url += "/";
  162 + url += stream;
  163 +
  164 + return url;
  165 +}
  166 +
  167 +void SrsRequest::strip()
  168 +{
  169 + trim(vhost, "/ \n\r\t");
  170 + trim(app, "/ \n\r\t");
  171 + trim(stream, "/ \n\r\t");
  172 +}
  173 +
  174 +std::string& SrsRequest::trim(string& str, string chs)
  175 +{
  176 + for (int i = 0; i < (int)chs.length(); i++) {
  177 + char ch = chs.at(i);
  178 +
  179 + for (std::string::iterator it = str.begin(); it != str.end();) {
  180 + if (ch == *it) {
  181 + it = str.erase(it);
  182 + } else {
  183 + ++it;
  184 + }
  185 + }
  186 + }
  187 +
  188 + return str;
  189 +}
  190 +
  191 +SrsResponse::SrsResponse()
  192 +{
  193 + stream_id = SRS_DEFAULT_SID;
  194 +}
  195 +
  196 +SrsResponse::~SrsResponse()
  197 +{
  198 +}
  199 +
  200 +SrsRtmpClient::SrsRtmpClient(st_netfd_t _stfd)
  201 +{
  202 + stfd = _stfd;
  203 + protocol = new SrsProtocol(stfd);
  204 +}
  205 +
  206 +SrsRtmpClient::~SrsRtmpClient()
  207 +{
  208 + srs_freep(protocol);
  209 +}
  210 +
  211 +void SrsRtmpClient::set_recv_timeout(int64_t timeout_us)
  212 +{
  213 + protocol->set_recv_timeout(timeout_us);
  214 +}
  215 +
  216 +void SrsRtmpClient::set_send_timeout(int64_t timeout_us)
  217 +{
  218 + protocol->set_send_timeout(timeout_us);
  219 +}
  220 +
  221 +int64_t SrsRtmpClient::get_recv_bytes()
  222 +{
  223 + return protocol->get_recv_bytes();
  224 +}
  225 +
  226 +int64_t SrsRtmpClient::get_send_bytes()
  227 +{
  228 + return protocol->get_send_bytes();
  229 +}
  230 +
  231 +int SrsRtmpClient::get_recv_kbps()
  232 +{
  233 + return protocol->get_recv_kbps();
  234 +}
  235 +
  236 +int SrsRtmpClient::get_send_kbps()
  237 +{
  238 + return protocol->get_send_kbps();
  239 +}
  240 +
  241 +int SrsRtmpClient::recv_message(SrsCommonMessage** pmsg)
  242 +{
  243 + return protocol->recv_message(pmsg);
  244 +}
  245 +
  246 +int SrsRtmpClient::send_message(ISrsMessage* msg)
  247 +{
  248 + return protocol->send_message(msg);
  249 +}
  250 +
  251 +int SrsRtmpClient::handshake()
  252 +{
  253 + int ret = ERROR_SUCCESS;
  254 +
  255 + SrsSocket skt(stfd);
  256 +
  257 + skt.set_recv_timeout(protocol->get_recv_timeout());
  258 + skt.set_send_timeout(protocol->get_send_timeout());
  259 +
  260 + SrsComplexHandshake complex_hs;
  261 + SrsSimpleHandshake simple_hs;
  262 + if ((ret = simple_hs.handshake_with_server(skt, complex_hs)) != ERROR_SUCCESS) {
  263 + return ret;
  264 + }
  265 +
  266 + return ret;
  267 +}
  268 +
  269 +int SrsRtmpClient::connect_app(string app, string tc_url)
  270 +{
  271 + int ret = ERROR_SUCCESS;
  272 +
  273 + // Connect(vhost, app)
  274 + if (true) {
  275 + SrsCommonMessage* msg = new SrsCommonMessage();
  276 + SrsConnectAppPacket* pkt = new SrsConnectAppPacket();
  277 + msg->set_packet(pkt, 0);
  278 +
  279 + pkt->command_object = new SrsAmf0Object();
  280 + pkt->command_object->set("app", new SrsAmf0String(app.c_str()));
  281 + pkt->command_object->set("swfUrl", new SrsAmf0String());
  282 + pkt->command_object->set("tcUrl", new SrsAmf0String(tc_url.c_str()));
  283 + pkt->command_object->set("fpad", new SrsAmf0Boolean(false));
  284 + pkt->command_object->set("capabilities", new SrsAmf0Number(239));
  285 + pkt->command_object->set("audioCodecs", new SrsAmf0Number(3575));
  286 + pkt->command_object->set("videoCodecs", new SrsAmf0Number(252));
  287 + pkt->command_object->set("videoFunction", new SrsAmf0Number(1));
  288 + pkt->command_object->set("pageUrl", new SrsAmf0String());
  289 + pkt->command_object->set("objectEncoding", new SrsAmf0Number(0));
  290 +
  291 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  292 + return ret;
  293 + }
  294 + }
  295 +
  296 + // Set Window Acknowledgement size(2500000)
  297 + if (true) {
  298 + SrsCommonMessage* msg = new SrsCommonMessage();
  299 + SrsSetWindowAckSizePacket* pkt = new SrsSetWindowAckSizePacket();
  300 +
  301 + pkt->ackowledgement_window_size = 2500000;
  302 + msg->set_packet(pkt, 0);
  303 +
  304 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  305 + return ret;
  306 + }
  307 + }
  308 +
  309 + // expect connect _result
  310 + SrsCommonMessage* msg = NULL;
  311 + SrsConnectAppResPacket* pkt = NULL;
  312 + if ((ret = srs_rtmp_expect_message<SrsConnectAppResPacket>(protocol, &msg, &pkt)) != ERROR_SUCCESS) {
  313 + srs_error("expect connect app response message failed. ret=%d", ret);
  314 + return ret;
  315 + }
  316 + SrsAutoFree(SrsCommonMessage, msg, false);
  317 + srs_info("get connect app response message");
  318 +
  319 + return ret;
  320 +}
  321 +
  322 +int SrsRtmpClient::create_stream(int& stream_id)
  323 +{
  324 + int ret = ERROR_SUCCESS;
  325 +
  326 + // CreateStream
  327 + if (true) {
  328 + SrsCommonMessage* msg = new SrsCommonMessage();
  329 + SrsCreateStreamPacket* pkt = new SrsCreateStreamPacket();
  330 +
  331 + msg->set_packet(pkt, 0);
  332 +
  333 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  334 + return ret;
  335 + }
  336 + }
  337 +
  338 + // CreateStream _result.
  339 + if (true) {
  340 + SrsCommonMessage* msg = NULL;
  341 + SrsCreateStreamResPacket* pkt = NULL;
  342 + if ((ret = srs_rtmp_expect_message<SrsCreateStreamResPacket>(protocol, &msg, &pkt)) != ERROR_SUCCESS) {
  343 + srs_error("expect create stream response message failed. ret=%d", ret);
  344 + return ret;
  345 + }
  346 + SrsAutoFree(SrsCommonMessage, msg, false);
  347 + srs_info("get create stream response message");
  348 +
  349 + stream_id = (int)pkt->stream_id;
  350 + }
  351 +
  352 + return ret;
  353 +}
  354 +
  355 +int SrsRtmpClient::play(string stream, int stream_id)
  356 +{
  357 + int ret = ERROR_SUCCESS;
  358 +
  359 + // Play(stream)
  360 + if (true) {
  361 + SrsCommonMessage* msg = new SrsCommonMessage();
  362 + SrsPlayPacket* pkt = new SrsPlayPacket();
  363 +
  364 + pkt->stream_name = stream;
  365 + msg->set_packet(pkt, stream_id);
  366 +
  367 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  368 + srs_error("send play stream failed. "
  369 + "stream=%s, stream_id=%d, ret=%d",
  370 + stream.c_str(), stream_id, ret);
  371 + return ret;
  372 + }
  373 + }
  374 +
  375 + // SetBufferLength(1000ms)
  376 + int buffer_length_ms = 1000;
  377 + if (true) {
  378 + SrsCommonMessage* msg = new SrsCommonMessage();
  379 + SrsUserControlPacket* pkt = new SrsUserControlPacket();
  380 +
  381 + pkt->event_type = SrcPCUCSetBufferLength;
  382 + pkt->event_data = stream_id;
  383 + pkt->extra_data = buffer_length_ms;
  384 + msg->set_packet(pkt, 0);
  385 +
  386 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  387 + srs_error("send set buffer length failed. "
  388 + "stream=%s, stream_id=%d, bufferLength=%d, ret=%d",
  389 + stream.c_str(), stream_id, buffer_length_ms, ret);
  390 + return ret;
  391 + }
  392 + }
  393 +
  394 + return ret;
  395 +}
  396 +
  397 +int SrsRtmpClient::publish(string stream, int stream_id)
  398 +{
  399 + int ret = ERROR_SUCCESS;
  400 +
  401 + // publish(stream)
  402 + if (true) {
  403 + SrsCommonMessage* msg = new SrsCommonMessage();
  404 + SrsPublishPacket* pkt = new SrsPublishPacket();
  405 +
  406 + pkt->stream_name = stream;
  407 + msg->set_packet(pkt, stream_id);
  408 +
  409 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  410 + srs_error("send publish message failed. "
  411 + "stream=%s, stream_id=%d, ret=%d",
  412 + stream.c_str(), stream_id, ret);
  413 + return ret;
  414 + }
  415 + }
  416 +
  417 + return ret;
  418 +}
  419 +
  420 +SrsRtmp::SrsRtmp(st_netfd_t client_stfd)
  421 +{
  422 + protocol = new SrsProtocol(client_stfd);
  423 + stfd = client_stfd;
  424 +}
  425 +
  426 +SrsRtmp::~SrsRtmp()
  427 +{
  428 + srs_freep(protocol);
  429 +}
  430 +
  431 +SrsProtocol* SrsRtmp::get_protocol()
  432 +{
  433 + return protocol;
  434 +}
  435 +
  436 +void SrsRtmp::set_recv_timeout(int64_t timeout_us)
  437 +{
  438 + protocol->set_recv_timeout(timeout_us);
  439 +}
  440 +
  441 +int64_t SrsRtmp::get_recv_timeout()
  442 +{
  443 + return protocol->get_recv_timeout();
  444 +}
  445 +
  446 +void SrsRtmp::set_send_timeout(int64_t timeout_us)
  447 +{
  448 + protocol->set_send_timeout(timeout_us);
  449 +}
  450 +
  451 +int64_t SrsRtmp::get_send_timeout()
  452 +{
  453 + return protocol->get_send_timeout();
  454 +}
  455 +
  456 +int64_t SrsRtmp::get_recv_bytes()
  457 +{
  458 + return protocol->get_recv_bytes();
  459 +}
  460 +
  461 +int64_t SrsRtmp::get_send_bytes()
  462 +{
  463 + return protocol->get_send_bytes();
  464 +}
  465 +
  466 +int SrsRtmp::get_recv_kbps()
  467 +{
  468 + return protocol->get_recv_kbps();
  469 +}
  470 +
  471 +int SrsRtmp::get_send_kbps()
  472 +{
  473 + return protocol->get_send_kbps();
  474 +}
  475 +
  476 +int SrsRtmp::recv_message(SrsCommonMessage** pmsg)
  477 +{
  478 + return protocol->recv_message(pmsg);
  479 +}
  480 +
  481 +int SrsRtmp::send_message(ISrsMessage* msg)
  482 +{
  483 + return protocol->send_message(msg);
  484 +}
  485 +
  486 +int SrsRtmp::handshake()
  487 +{
  488 + int ret = ERROR_SUCCESS;
  489 +
  490 + SrsSocket skt(stfd);
  491 +
  492 + skt.set_recv_timeout(protocol->get_recv_timeout());
  493 + skt.set_send_timeout(protocol->get_send_timeout());
  494 +
  495 + SrsComplexHandshake complex_hs;
  496 + SrsSimpleHandshake simple_hs;
  497 + if ((ret = simple_hs.handshake_with_client(skt, complex_hs)) != ERROR_SUCCESS) {
  498 + return ret;
  499 + }
  500 +
  501 + return ret;
  502 +}
  503 +
  504 +int SrsRtmp::connect_app(SrsRequest* req)
  505 +{
  506 + int ret = ERROR_SUCCESS;
  507 +
  508 + SrsCommonMessage* msg = NULL;
  509 + SrsConnectAppPacket* pkt = NULL;
  510 + if ((ret = srs_rtmp_expect_message<SrsConnectAppPacket>(protocol, &msg, &pkt)) != ERROR_SUCCESS) {
  511 + srs_error("expect connect app message failed. ret=%d", ret);
  512 + return ret;
  513 + }
  514 + SrsAutoFree(SrsCommonMessage, msg, false);
  515 + srs_info("get connect app message");
  516 +
  517 + SrsAmf0Any* prop = NULL;
  518 +
  519 + if ((prop = pkt->command_object->ensure_property_string("tcUrl")) == NULL) {
  520 + ret = ERROR_RTMP_REQ_CONNECT;
  521 + srs_error("invalid request, must specifies the tcUrl. ret=%d", ret);
  522 + return ret;
  523 + }
  524 + req->tcUrl = srs_amf0_convert<SrsAmf0String>(prop)->value;
  525 +
  526 + if ((prop = pkt->command_object->ensure_property_string("pageUrl")) != NULL) {
  527 + req->pageUrl = srs_amf0_convert<SrsAmf0String>(prop)->value;
  528 + }
  529 +
  530 + if ((prop = pkt->command_object->ensure_property_string("swfUrl")) != NULL) {
  531 + req->swfUrl = srs_amf0_convert<SrsAmf0String>(prop)->value;
  532 + }
  533 +
  534 + if ((prop = pkt->command_object->ensure_property_number("objectEncoding")) != NULL) {
  535 + req->objectEncoding = srs_amf0_convert<SrsAmf0Number>(prop)->value;
  536 + }
  537 +
  538 + srs_info("get connect app message params success.");
  539 +
  540 + return req->discovery_app();
  541 +}
  542 +
  543 +int SrsRtmp::set_window_ack_size(int ack_size)
  544 +{
  545 + int ret = ERROR_SUCCESS;
  546 +
  547 + SrsCommonMessage* msg = new SrsCommonMessage();
  548 + SrsSetWindowAckSizePacket* pkt = new SrsSetWindowAckSizePacket();
  549 +
  550 + pkt->ackowledgement_window_size = ack_size;
  551 + msg->set_packet(pkt, 0);
  552 +
  553 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  554 + srs_error("send ack size message failed. ret=%d", ret);
  555 + return ret;
  556 + }
  557 + srs_info("send ack size message success. ack_size=%d", ack_size);
  558 +
  559 + return ret;
  560 +}
  561 +
  562 +int SrsRtmp::set_peer_bandwidth(int bandwidth, int type)
  563 +{
  564 + int ret = ERROR_SUCCESS;
  565 +
  566 + SrsCommonMessage* msg = new SrsCommonMessage();
  567 + SrsSetPeerBandwidthPacket* pkt = new SrsSetPeerBandwidthPacket();
  568 +
  569 + pkt->bandwidth = bandwidth;
  570 + pkt->type = type;
  571 + msg->set_packet(pkt, 0);
  572 +
  573 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  574 + srs_error("send set bandwidth message failed. ret=%d", ret);
  575 + return ret;
  576 + }
  577 + srs_info("send set bandwidth message "
  578 + "success. bandwidth=%d, type=%d", bandwidth, type);
  579 +
  580 + return ret;
  581 +}
  582 +
  583 +int SrsRtmp::response_connect_app(SrsRequest *req, const char* server_ip)
  584 +{
  585 + int ret = ERROR_SUCCESS;
  586 +
  587 + SrsCommonMessage* msg = new SrsCommonMessage();
  588 + SrsConnectAppResPacket* pkt = new SrsConnectAppResPacket();
  589 +
  590 + pkt->props->set("fmsVer", new SrsAmf0String("FMS/"RTMP_SIG_FMS_VER));
  591 + pkt->props->set("capabilities", new SrsAmf0Number(127));
  592 + pkt->props->set("mode", new SrsAmf0Number(1));
  593 +
  594 + pkt->info->set(StatusLevel, new SrsAmf0String(StatusLevelStatus));
  595 + pkt->info->set(StatusCode, new SrsAmf0String(StatusCodeConnectSuccess));
  596 + pkt->info->set(StatusDescription, new SrsAmf0String("Connection succeeded"));
  597 + pkt->info->set("objectEncoding", new SrsAmf0Number(req->objectEncoding));
  598 + SrsASrsAmf0EcmaArray* data = new SrsASrsAmf0EcmaArray();
  599 + pkt->info->set("data", data);
  600 +
  601 + data->set("srs_version", new SrsAmf0String(RTMP_SIG_FMS_VER));
  602 + data->set("srs_server", new SrsAmf0String(RTMP_SIG_SRS_KEY" "RTMP_SIG_SRS_VERSION" ("RTMP_SIG_SRS_URL_SHORT")"));
  603 + data->set("srs_license", new SrsAmf0String(RTMP_SIG_SRS_LICENSE));
  604 + data->set("srs_role", new SrsAmf0String(RTMP_SIG_SRS_ROLE));
  605 + data->set("srs_url", new SrsAmf0String(RTMP_SIG_SRS_URL));
  606 + data->set("srs_version", new SrsAmf0String(RTMP_SIG_SRS_VERSION));
  607 + data->set("srs_site", new SrsAmf0String(RTMP_SIG_SRS_WEB));
  608 + data->set("srs_email", new SrsAmf0String(RTMP_SIG_SRS_EMAIL));
  609 + data->set("srs_copyright", new SrsAmf0String(RTMP_SIG_SRS_COPYRIGHT));
  610 + data->set("srs_primary_authors", new SrsAmf0String(RTMP_SIG_SRS_PRIMARY_AUTHROS));
  611 +
  612 + if (server_ip) {
  613 + data->set("srs_server_ip", new SrsAmf0String(server_ip));
  614 + }
  615 +
  616 + msg->set_packet(pkt, 0);
  617 +
  618 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  619 + srs_error("send connect app response message failed. ret=%d", ret);
  620 + return ret;
  621 + }
  622 + srs_info("send connect app response message success.");
  623 +
  624 + return ret;
  625 +}
  626 +
  627 +void SrsRtmp::response_connect_reject(SrsRequest *req, const char* desc)
  628 +{
  629 + int ret = ERROR_SUCCESS;
  630 +
  631 + SrsConnectAppResPacket* pkt = new SrsConnectAppResPacket();
  632 + pkt->command_name = "_error";
  633 + pkt->props->set(StatusLevel, new SrsAmf0String(StatusLevelError));
  634 + pkt->props->set(StatusCode, new SrsAmf0String(StatusCodeConnectRejected));
  635 + pkt->props->set(StatusDescription, new SrsAmf0String(desc));
  636 + //pkt->props->set("objectEncoding", new SrsAmf0Number(req->objectEncoding));
  637 +
  638 + SrsCommonMessage* msg = (new SrsCommonMessage())->set_packet(pkt, 0);
  639 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  640 + srs_error("send connect app response rejected message failed. ret=%d", ret);
  641 + return;
  642 + }
  643 + srs_info("send connect app response rejected message success.");
  644 +
  645 + return;
  646 +}
  647 +
  648 +int SrsRtmp::on_bw_done()
  649 +{
  650 + int ret = ERROR_SUCCESS;
  651 +
  652 + SrsCommonMessage* msg = new SrsCommonMessage();
  653 + SrsOnBWDonePacket* pkt = new SrsOnBWDonePacket();
  654 +
  655 + msg->set_packet(pkt, 0);
  656 +
  657 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  658 + srs_error("send onBWDone message failed. ret=%d", ret);
  659 + return ret;
  660 + }
  661 + srs_info("send onBWDone message success.");
  662 +
  663 + return ret;
  664 +}
  665 +
  666 +int SrsRtmp::identify_client(int stream_id, SrsClientType& type, std::string& stream_name)
  667 +{
  668 + type = SrsClientUnknown;
  669 + int ret = ERROR_SUCCESS;
  670 +
  671 + while (true) {
  672 + SrsCommonMessage* msg = NULL;
  673 + if ((ret = protocol->recv_message(&msg)) != ERROR_SUCCESS) {
  674 + srs_error("recv identify client message failed. ret=%d", ret);
  675 + return ret;
  676 + }
  677 +
  678 + SrsAutoFree(SrsCommonMessage, msg, false);
  679 +
  680 + if (!msg->header.is_amf0_command() && !msg->header.is_amf3_command()) {
  681 + srs_trace("identify ignore messages except "
  682 + "AMF0/AMF3 command message. type=%#x", msg->header.message_type);
  683 + continue;
  684 + }
  685 +
  686 + if ((ret = msg->decode_packet(protocol)) != ERROR_SUCCESS) {
  687 + srs_error("identify decode message failed. ret=%d", ret);
  688 + return ret;
  689 + }
  690 +
  691 + SrsPacket* pkt = msg->get_packet();
  692 + if (dynamic_cast<SrsCreateStreamPacket*>(pkt)) {
  693 + srs_info("identify client by create stream, play or flash publish.");
  694 + return identify_create_stream_client(
  695 + dynamic_cast<SrsCreateStreamPacket*>(pkt), stream_id, type, stream_name);
  696 + }
  697 + if (dynamic_cast<SrsFMLEStartPacket*>(pkt)) {
  698 + srs_info("identify client by releaseStream, fmle publish.");
  699 + return identify_fmle_publish_client(
  700 + dynamic_cast<SrsFMLEStartPacket*>(pkt), type, stream_name);
  701 + }
  702 +
  703 + srs_trace("ignore AMF0/AMF3 command message.");
  704 + }
  705 +
  706 + return ret;
  707 +}
  708 +
  709 +int SrsRtmp::set_chunk_size(int chunk_size)
  710 +{
  711 + int ret = ERROR_SUCCESS;
  712 +
  713 + SrsCommonMessage* msg = new SrsCommonMessage();
  714 + SrsSetChunkSizePacket* pkt = new SrsSetChunkSizePacket();
  715 +
  716 + pkt->chunk_size = chunk_size;
  717 + msg->set_packet(pkt, 0);
  718 +
  719 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  720 + srs_error("send set chunk size message failed. ret=%d", ret);
  721 + return ret;
  722 + }
  723 + srs_info("send set chunk size message success. chunk_size=%d", chunk_size);
  724 +
  725 + return ret;
  726 +}
  727 +
  728 +int SrsRtmp::start_play(int stream_id)
  729 +{
  730 + int ret = ERROR_SUCCESS;
  731 +
  732 + // StreamBegin
  733 + if (true) {
  734 + SrsCommonMessage* msg = new SrsCommonMessage();
  735 + SrsUserControlPacket* pkt = new SrsUserControlPacket();
  736 +
  737 + pkt->event_type = SrcPCUCStreamBegin;
  738 + pkt->event_data = stream_id;
  739 + msg->set_packet(pkt, 0);
  740 +
  741 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  742 + srs_error("send PCUC(StreamBegin) message failed. ret=%d", ret);
  743 + return ret;
  744 + }
  745 + srs_info("send PCUC(StreamBegin) message success.");
  746 + }
  747 +
  748 + // onStatus(NetStream.Play.Reset)
  749 + if (true) {
  750 + SrsCommonMessage* msg = new SrsCommonMessage();
  751 + SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket();
  752 +
  753 + pkt->data->set(StatusLevel, new SrsAmf0String(StatusLevelStatus));
  754 + pkt->data->set(StatusCode, new SrsAmf0String(StatusCodeStreamReset));
  755 + pkt->data->set(StatusDescription, new SrsAmf0String("Playing and resetting stream."));
  756 + pkt->data->set(StatusDetails, new SrsAmf0String("stream"));
  757 + pkt->data->set(StatusClientId, new SrsAmf0String(RTMP_SIG_CLIENT_ID));
  758 +
  759 + msg->set_packet(pkt, stream_id);
  760 +
  761 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  762 + srs_error("send onStatus(NetStream.Play.Reset) message failed. ret=%d", ret);
  763 + return ret;
  764 + }
  765 + srs_info("send onStatus(NetStream.Play.Reset) message success.");
  766 + }
  767 +
  768 + // onStatus(NetStream.Play.Start)
  769 + if (true) {
  770 + SrsCommonMessage* msg = new SrsCommonMessage();
  771 + SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket();
  772 +
  773 + pkt->data->set(StatusLevel, new SrsAmf0String(StatusLevelStatus));
  774 + pkt->data->set(StatusCode, new SrsAmf0String(StatusCodeStreamStart));
  775 + pkt->data->set(StatusDescription, new SrsAmf0String("Started playing stream."));
  776 + pkt->data->set(StatusDetails, new SrsAmf0String("stream"));
  777 + pkt->data->set(StatusClientId, new SrsAmf0String(RTMP_SIG_CLIENT_ID));
  778 +
  779 + msg->set_packet(pkt, stream_id);
  780 +
  781 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  782 + srs_error("send onStatus(NetStream.Play.Reset) message failed. ret=%d", ret);
  783 + return ret;
  784 + }
  785 + srs_info("send onStatus(NetStream.Play.Reset) message success.");
  786 + }
  787 +
  788 + // |RtmpSampleAccess(false, false)
  789 + if (true) {
  790 + SrsCommonMessage* msg = new SrsCommonMessage();
  791 + SrsSampleAccessPacket* pkt = new SrsSampleAccessPacket();
  792 +
  793 + msg->set_packet(pkt, stream_id);
  794 +
  795 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  796 + srs_error("send |RtmpSampleAccess(false, false) message failed. ret=%d", ret);
  797 + return ret;
  798 + }
  799 + srs_info("send |RtmpSampleAccess(false, false) message success.");
  800 + }
  801 +
  802 + // onStatus(NetStream.Data.Start)
  803 + if (true) {
  804 + SrsCommonMessage* msg = new SrsCommonMessage();
  805 + SrsOnStatusDataPacket* pkt = new SrsOnStatusDataPacket();
  806 +
  807 + pkt->data->set(StatusCode, new SrsAmf0String(StatusCodeDataStart));
  808 +
  809 + msg->set_packet(pkt, stream_id);
  810 +
  811 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  812 + srs_error("send onStatus(NetStream.Data.Start) message failed. ret=%d", ret);
  813 + return ret;
  814 + }
  815 + srs_info("send onStatus(NetStream.Data.Start) message success.");
  816 + }
  817 +
  818 + srs_info("start play success.");
  819 +
  820 + return ret;
  821 +}
  822 +
  823 +int SrsRtmp::on_play_client_pause(int stream_id, bool is_pause)
  824 +{
  825 + int ret = ERROR_SUCCESS;
  826 +
  827 + if (is_pause) {
  828 + // onStatus(NetStream.Pause.Notify)
  829 + if (true) {
  830 + SrsCommonMessage* msg = new SrsCommonMessage();
  831 + SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket();
  832 +
  833 + pkt->data->set(StatusLevel, new SrsAmf0String(StatusLevelStatus));
  834 + pkt->data->set(StatusCode, new SrsAmf0String(StatusCodeStreamPause));
  835 + pkt->data->set(StatusDescription, new SrsAmf0String("Paused stream."));
  836 +
  837 + msg->set_packet(pkt, stream_id);
  838 +
  839 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  840 + srs_error("send onStatus(NetStream.Pause.Notify) message failed. ret=%d", ret);
  841 + return ret;
  842 + }
  843 + srs_info("send onStatus(NetStream.Pause.Notify) message success.");
  844 + }
  845 + // StreamEOF
  846 + if (true) {
  847 + SrsCommonMessage* msg = new SrsCommonMessage();
  848 + SrsUserControlPacket* pkt = new SrsUserControlPacket();
  849 +
  850 + pkt->event_type = SrcPCUCStreamEOF;
  851 + pkt->event_data = stream_id;
  852 + msg->set_packet(pkt, 0);
  853 +
  854 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  855 + srs_error("send PCUC(StreamEOF) message failed. ret=%d", ret);
  856 + return ret;
  857 + }
  858 + srs_info("send PCUC(StreamEOF) message success.");
  859 + }
  860 + } else {
  861 + // onStatus(NetStream.Unpause.Notify)
  862 + if (true) {
  863 + SrsCommonMessage* msg = new SrsCommonMessage();
  864 + SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket();
  865 +
  866 + pkt->data->set(StatusLevel, new SrsAmf0String(StatusLevelStatus));
  867 + pkt->data->set(StatusCode, new SrsAmf0String(StatusCodeStreamUnpause));
  868 + pkt->data->set(StatusDescription, new SrsAmf0String("Unpaused stream."));
  869 +
  870 + msg->set_packet(pkt, stream_id);
  871 +
  872 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  873 + srs_error("send onStatus(NetStream.Unpause.Notify) message failed. ret=%d", ret);
  874 + return ret;
  875 + }
  876 + srs_info("send onStatus(NetStream.Unpause.Notify) message success.");
  877 + }
  878 + // StreanBegin
  879 + if (true) {
  880 + SrsCommonMessage* msg = new SrsCommonMessage();
  881 + SrsUserControlPacket* pkt = new SrsUserControlPacket();
  882 +
  883 + pkt->event_type = SrcPCUCStreamBegin;
  884 + pkt->event_data = stream_id;
  885 + msg->set_packet(pkt, 0);
  886 +
  887 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  888 + srs_error("send PCUC(StreanBegin) message failed. ret=%d", ret);
  889 + return ret;
  890 + }
  891 + srs_info("send PCUC(StreanBegin) message success.");
  892 + }
  893 + }
  894 +
  895 + return ret;
  896 +}
  897 +
  898 +int SrsRtmp::start_fmle_publish(int stream_id)
  899 +{
  900 + int ret = ERROR_SUCCESS;
  901 +
  902 + // FCPublish
  903 + double fc_publish_tid = 0;
  904 + if (true) {
  905 + SrsCommonMessage* msg = NULL;
  906 + SrsFMLEStartPacket* pkt = NULL;
  907 + if ((ret = srs_rtmp_expect_message<SrsFMLEStartPacket>(protocol, &msg, &pkt)) != ERROR_SUCCESS) {
  908 + srs_error("recv FCPublish message failed. ret=%d", ret);
  909 + return ret;
  910 + }
  911 + srs_info("recv FCPublish request message success.");
  912 +
  913 + SrsAutoFree(SrsCommonMessage, msg, false);
  914 + fc_publish_tid = pkt->transaction_id;
  915 + }
  916 + // FCPublish response
  917 + if (true) {
  918 + SrsCommonMessage* msg = new SrsCommonMessage();
  919 + SrsFMLEStartResPacket* pkt = new SrsFMLEStartResPacket(fc_publish_tid);
  920 +
  921 + msg->set_packet(pkt, 0);
  922 +
  923 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  924 + srs_error("send FCPublish response message failed. ret=%d", ret);
  925 + return ret;
  926 + }
  927 + srs_info("send FCPublish response message success.");
  928 + }
  929 +
  930 + // createStream
  931 + double create_stream_tid = 0;
  932 + if (true) {
  933 + SrsCommonMessage* msg = NULL;
  934 + SrsCreateStreamPacket* pkt = NULL;
  935 + if ((ret = srs_rtmp_expect_message<SrsCreateStreamPacket>(protocol, &msg, &pkt)) != ERROR_SUCCESS) {
  936 + srs_error("recv createStream message failed. ret=%d", ret);
  937 + return ret;
  938 + }
  939 + srs_info("recv createStream request message success.");
  940 +
  941 + SrsAutoFree(SrsCommonMessage, msg, false);
  942 + create_stream_tid = pkt->transaction_id;
  943 + }
  944 + // createStream response
  945 + if (true) {
  946 + SrsCommonMessage* msg = new SrsCommonMessage();
  947 + SrsCreateStreamResPacket* pkt = new SrsCreateStreamResPacket(create_stream_tid, stream_id);
  948 +
  949 + msg->set_packet(pkt, 0);
  950 +
  951 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  952 + srs_error("send createStream response message failed. ret=%d", ret);
  953 + return ret;
  954 + }
  955 + srs_info("send createStream response message success.");
  956 + }
  957 +
  958 + // publish
  959 + if (true) {
  960 + SrsCommonMessage* msg = NULL;
  961 + SrsPublishPacket* pkt = NULL;
  962 + if ((ret = srs_rtmp_expect_message<SrsPublishPacket>(protocol, &msg, &pkt)) != ERROR_SUCCESS) {
  963 + srs_error("recv publish message failed. ret=%d", ret);
  964 + return ret;
  965 + }
  966 + srs_info("recv publish request message success.");
  967 +
  968 + SrsAutoFree(SrsCommonMessage, msg, false);
  969 + }
  970 + // publish response onFCPublish(NetStream.Publish.Start)
  971 + if (true) {
  972 + SrsCommonMessage* msg = new SrsCommonMessage();
  973 + SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket();
  974 +
  975 + pkt->command_name = RTMP_AMF0_COMMAND_ON_FC_PUBLISH;
  976 + pkt->data->set(StatusCode, new SrsAmf0String(StatusCodePublishStart));
  977 + pkt->data->set(StatusDescription, new SrsAmf0String("Started publishing stream."));
  978 +
  979 + msg->set_packet(pkt, stream_id);
  980 +
  981 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  982 + srs_error("send onFCPublish(NetStream.Publish.Start) message failed. ret=%d", ret);
  983 + return ret;
  984 + }
  985 + srs_info("send onFCPublish(NetStream.Publish.Start) message success.");
  986 + }
  987 + // publish response onStatus(NetStream.Publish.Start)
  988 + if (true) {
  989 + SrsCommonMessage* msg = new SrsCommonMessage();
  990 + SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket();
  991 +
  992 + pkt->data->set(StatusLevel, new SrsAmf0String(StatusLevelStatus));
  993 + pkt->data->set(StatusCode, new SrsAmf0String(StatusCodePublishStart));
  994 + pkt->data->set(StatusDescription, new SrsAmf0String("Started publishing stream."));
  995 + pkt->data->set(StatusClientId, new SrsAmf0String(RTMP_SIG_CLIENT_ID));
  996 +
  997 + msg->set_packet(pkt, stream_id);
  998 +
  999 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  1000 + srs_error("send onStatus(NetStream.Publish.Start) message failed. ret=%d", ret);
  1001 + return ret;
  1002 + }
  1003 + srs_info("send onStatus(NetStream.Publish.Start) message success.");
  1004 + }
  1005 +
  1006 + srs_info("FMLE publish success.");
  1007 +
  1008 + return ret;
  1009 +}
  1010 +
  1011 +int SrsRtmp::fmle_unpublish(int stream_id, double unpublish_tid)
  1012 +{
  1013 + int ret = ERROR_SUCCESS;
  1014 +
  1015 + // publish response onFCUnpublish(NetStream.unpublish.Success)
  1016 + if (true) {
  1017 + SrsCommonMessage* msg = new SrsCommonMessage();
  1018 + SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket();
  1019 +
  1020 + pkt->command_name = RTMP_AMF0_COMMAND_ON_FC_UNPUBLISH;
  1021 + pkt->data->set(StatusCode, new SrsAmf0String(StatusCodeUnpublishSuccess));
  1022 + pkt->data->set(StatusDescription, new SrsAmf0String("Stop publishing stream."));
  1023 +
  1024 + msg->set_packet(pkt, stream_id);
  1025 +
  1026 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  1027 + srs_error("send onFCUnpublish(NetStream.unpublish.Success) message failed. ret=%d", ret);
  1028 + return ret;
  1029 + }
  1030 + srs_info("send onFCUnpublish(NetStream.unpublish.Success) message success.");
  1031 + }
  1032 + // FCUnpublish response
  1033 + if (true) {
  1034 + SrsCommonMessage* msg = new SrsCommonMessage();
  1035 + SrsFMLEStartResPacket* pkt = new SrsFMLEStartResPacket(unpublish_tid);
  1036 +
  1037 + msg->set_packet(pkt, stream_id);
  1038 +
  1039 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  1040 + srs_error("send FCUnpublish response message failed. ret=%d", ret);
  1041 + return ret;
  1042 + }
  1043 + srs_info("send FCUnpublish response message success.");
  1044 + }
  1045 + // publish response onStatus(NetStream.Unpublish.Success)
  1046 + if (true) {
  1047 + SrsCommonMessage* msg = new SrsCommonMessage();
  1048 + SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket();
  1049 +
  1050 + pkt->data->set(StatusLevel, new SrsAmf0String(StatusLevelStatus));
  1051 + pkt->data->set(StatusCode, new SrsAmf0String(StatusCodeUnpublishSuccess));
  1052 + pkt->data->set(StatusDescription, new SrsAmf0String("Stream is now unpublished"));
  1053 + pkt->data->set(StatusClientId, new SrsAmf0String(RTMP_SIG_CLIENT_ID));
  1054 +
  1055 + msg->set_packet(pkt, stream_id);
  1056 +
  1057 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  1058 + srs_error("send onStatus(NetStream.Unpublish.Success) message failed. ret=%d", ret);
  1059 + return ret;
  1060 + }
  1061 + srs_info("send onStatus(NetStream.Unpublish.Success) message success.");
  1062 + }
  1063 +
  1064 + srs_info("FMLE unpublish success.");
  1065 +
  1066 + return ret;
  1067 +}
  1068 +
  1069 +int SrsRtmp::start_flash_publish(int stream_id)
  1070 +{
  1071 + int ret = ERROR_SUCCESS;
  1072 +
  1073 + // publish response onStatus(NetStream.Publish.Start)
  1074 + if (true) {
  1075 + SrsCommonMessage* msg = new SrsCommonMessage();
  1076 + SrsOnStatusCallPacket* pkt = new SrsOnStatusCallPacket();
  1077 +
  1078 + pkt->data->set(StatusLevel, new SrsAmf0String(StatusLevelStatus));
  1079 + pkt->data->set(StatusCode, new SrsAmf0String(StatusCodePublishStart));
  1080 + pkt->data->set(StatusDescription, new SrsAmf0String("Started publishing stream."));
  1081 + pkt->data->set(StatusClientId, new SrsAmf0String(RTMP_SIG_CLIENT_ID));
  1082 +
  1083 + msg->set_packet(pkt, stream_id);
  1084 +
  1085 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  1086 + srs_error("send onStatus(NetStream.Publish.Start) message failed. ret=%d", ret);
  1087 + return ret;
  1088 + }
  1089 + srs_info("send onStatus(NetStream.Publish.Start) message success.");
  1090 + }
  1091 +
  1092 + srs_info("flash publish success.");
  1093 +
  1094 + return ret;
  1095 +}
  1096 +
  1097 +int SrsRtmp::identify_create_stream_client(SrsCreateStreamPacket* req, int stream_id, SrsClientType& type, string& stream_name)
  1098 +{
  1099 + int ret = ERROR_SUCCESS;
  1100 +
  1101 + if (true) {
  1102 + SrsCommonMessage* msg = new SrsCommonMessage();
  1103 + SrsCreateStreamResPacket* pkt = new SrsCreateStreamResPacket(req->transaction_id, stream_id);
  1104 +
  1105 + msg->set_packet(pkt, 0);
  1106 +
  1107 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  1108 + srs_error("send createStream response message failed. ret=%d", ret);
  1109 + return ret;
  1110 + }
  1111 + srs_info("send createStream response message success.");
  1112 + }
  1113 +
  1114 + while (true) {
  1115 + SrsCommonMessage* msg = NULL;
  1116 + if ((ret = protocol->recv_message(&msg)) != ERROR_SUCCESS) {
  1117 + srs_error("recv identify client message failed. ret=%d", ret);
  1118 + return ret;
  1119 + }
  1120 +
  1121 + SrsAutoFree(SrsCommonMessage, msg, false);
  1122 +
  1123 + if (!msg->header.is_amf0_command() && !msg->header.is_amf3_command()) {
  1124 + srs_trace("identify ignore messages except "
  1125 + "AMF0/AMF3 command message. type=%#x", msg->header.message_type);
  1126 + continue;
  1127 + }
  1128 +
  1129 + if ((ret = msg->decode_packet(protocol)) != ERROR_SUCCESS) {
  1130 + srs_error("identify decode message failed. ret=%d", ret);
  1131 + return ret;
  1132 + }
  1133 +
  1134 + SrsPacket* pkt = msg->get_packet();
  1135 + if (dynamic_cast<SrsPlayPacket*>(pkt)) {
  1136 + SrsPlayPacket* play = dynamic_cast<SrsPlayPacket*>(pkt);
  1137 + type = SrsClientPlay;
  1138 + stream_name = play->stream_name;
  1139 + srs_trace("identity client type=play, stream_name=%s", stream_name.c_str());
  1140 + return ret;
  1141 + }
  1142 + if (dynamic_cast<SrsPublishPacket*>(pkt)) {
  1143 + srs_info("identify client by publish, falsh publish.");
  1144 + return identify_flash_publish_client(
  1145 + dynamic_cast<SrsPublishPacket*>(pkt), type, stream_name);
  1146 + }
  1147 +
  1148 + srs_trace("ignore AMF0/AMF3 command message.");
  1149 + }
  1150 +
  1151 + return ret;
  1152 +}
  1153 +
  1154 +int SrsRtmp::identify_fmle_publish_client(SrsFMLEStartPacket* req, SrsClientType& type, string& stream_name)
  1155 +{
  1156 + int ret = ERROR_SUCCESS;
  1157 +
  1158 + type = SrsClientFMLEPublish;
  1159 + stream_name = req->stream_name;
  1160 +
  1161 + // releaseStream response
  1162 + if (true) {
  1163 + SrsCommonMessage* msg = new SrsCommonMessage();
  1164 + SrsFMLEStartResPacket* pkt = new SrsFMLEStartResPacket(req->transaction_id);
  1165 +
  1166 + msg->set_packet(pkt, 0);
  1167 +
  1168 + if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
  1169 + srs_error("send releaseStream response message failed. ret=%d", ret);
  1170 + return ret;
  1171 + }
  1172 + srs_info("send releaseStream response message success.");
  1173 + }
  1174 +
  1175 + return ret;
  1176 +}
  1177 +
  1178 +int SrsRtmp::identify_flash_publish_client(SrsPublishPacket* req, SrsClientType& type, string& stream_name)
  1179 +{
  1180 + int ret = ERROR_SUCCESS;
  1181 +
  1182 + type = SrsClientFlashPublish;
  1183 + stream_name = req->stream_name;
  1184 +
  1185 + return ret;
  1186 +}
  1187 +
@@ -642,7 +642,7 @@ int SrsSource::on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata @@ -642,7 +642,7 @@ int SrsSource::on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata
642 metadata->metadata->set("server", new SrsAmf0String( 642 metadata->metadata->set("server", new SrsAmf0String(
643 RTMP_SIG_SRS_KEY" "RTMP_SIG_SRS_VERSION" ("RTMP_SIG_SRS_URL_SHORT")")); 643 RTMP_SIG_SRS_KEY" "RTMP_SIG_SRS_VERSION" ("RTMP_SIG_SRS_URL_SHORT")"));
644 metadata->metadata->set("contributor", 644 metadata->metadata->set("contributor",
645 - new SrsAmf0String(RTMP_SIG_SRS_CONTRIBUTOR)); 645 + new SrsAmf0String(RTMP_SIG_SRS_PRIMARY_AUTHROS));
646 646
647 SrsAmf0Any* prop = NULL; 647 SrsAmf0Any* prop = NULL;
648 if ((prop = metadata->metadata->get_property("audiosamplerate")) != NULL) { 648 if ((prop = metadata->metadata->get_property("audiosamplerate")) != NULL) {