wenjiegit

merged master

要显示太多修改。

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

@@ -3,7 +3,7 @@ simple-rtmp-server @@ -3,7 +3,7 @@ simple-rtmp-server
3 3
4 srs(simple rtmp origin live server) over state-threads.<br/> 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/> 5 srs is a simple, high-performance, running in single process, origin live server.<br/>
6 -srs supports rtmp, HLS, transcoding, forward, http hooks. <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/> 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/> 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) 9 see also: [http://winlinvip.github.io/simple-rtmp-server](http://winlinvip.github.io/simple-rtmp-server)
@@ -12,30 +12,36 @@ see also: [http://winlinvip.github.io/simple-rtmp-server](http://winlinvip.githu @@ -12,30 +12,36 @@ see also: [http://winlinvip.github.io/simple-rtmp-server](http://winlinvip.githu
12 winlin(winterserver): [http://blog.csdn.net/win_lin](http://blog.csdn.net/win_lin) 12 winlin(winterserver): [http://blog.csdn.net/win_lin](http://blog.csdn.net/win_lin)
13 13
14 ### Usage 14 ### Usage
15 -step 1: build srs <br/> 15 +<strong>step 1:</strong> build srs <br/>
16 <pre> 16 <pre>
17 tar xf simple-rtmp-server-*.*.tar.gz 17 tar xf simple-rtmp-server-*.*.tar.gz
18 cd simple-rtmp-server-*.*/trunk 18 cd simple-rtmp-server-*.*/trunk
19 ./configure --with-ssl --with-hls --with-ffmpeg --with-http 19 ./configure --with-ssl --with-hls --with-ffmpeg --with-http
20 make 20 make
21 </pre> 21 </pre>
22 -step 2: start srs <br/> 22 +or get the latest code:<br/>
23 <pre> 23 <pre>
24 -./objs/simple_rtmp_server -c conf/srs.conf 24 +git clone https://github.com/winlinvip/simple-rtmp-server
  25 +cd simple-rtmp-server/trunk
  26 +./configure --with-ssl --with-hls --with-ffmpeg --with-http
  27 +</pre>
  28 +<strong>step 2:</strong> start srs <br/>
  29 +<pre>
  30 +./objs/srs -c conf/srs.conf
25 </pre> 31 </pre>
26 -step 3(optinal): start srs listen at 19350 to forward to<br/> 32 +<strong>step 3(optinal):</strong> start srs listen at 19350 to forward to<br/>
27 <pre> 33 <pre>
28 -./objs/simple_rtmp_server -c conf/srs.19350.conf 34 +./objs/srs -c conf/srs.19350.conf
29 </pre> 35 </pre>
30 -step 4(optional): start nginx for HLS <br/> 36 +<strong>step 4(optinal):</strong> start nginx for HLS <br/>
31 <pre> 37 <pre>
32 sudo ./objs/nginx/sbin/nginx 38 sudo ./objs/nginx/sbin/nginx
33 </pre> 39 </pre>
34 -step 5(optional): start http hooks for srs callback <br/> 40 +<strong>step 5(optinal):</strong> start http hooks for srs callback <br/>
35 <pre> 41 <pre>
36 python ./research/api-server/server.py 8085 42 python ./research/api-server/server.py 8085
37 </pre> 43 </pre>
38 -step 6: publish live stream <br/> 44 +<strong>step 6:</strong> publish live stream <br/>
39 <pre> 45 <pre>
40 FMS URL: rtmp://127.0.0.1:1935/live 46 FMS URL: rtmp://127.0.0.1:1935/live
41 Stream: livestream 47 Stream: livestream
@@ -47,7 +53,7 @@ For example, use ffmpeg to publish: @@ -47,7 +53,7 @@ For example, use ffmpeg to publish:
47 sleep 1; \ 53 sleep 1; \
48 done 54 done
49 </pre> 55 </pre>
50 -step 7: add server ip to client hosts as demo. <br/> 56 +<strong>step 7:</strong> add server ip to client hosts as demo. <br/>
51 <pre> 57 <pre>
52 # edit the folowing file: 58 # edit the folowing file:
53 # linux: /etc/hosts 59 # linux: /etc/hosts
@@ -55,26 +61,41 @@ step 7: add server ip to client hosts as demo. <br/> @@ -55,26 +61,41 @@ step 7: add server ip to client hosts as demo. <br/>
55 # where server ip is 192.168.2.111 61 # where server ip is 192.168.2.111
56 192.168.2.111 demo 62 192.168.2.111 demo
57 </pre> 63 </pre>
58 -step 8: play live stream. <br/> 64 +<strong>step 8:</strong> play live stream. <br/>
59 <pre> 65 <pre>
  66 +players: http://demo:80/players
60 rtmp url: rtmp://demo:1935/live/livestream 67 rtmp url: rtmp://demo:1935/live/livestream
61 m3u8 url: http://demo:80/live/livestream.m3u8 68 m3u8 url: http://demo:80/live/livestream.m3u8
  69 +for android: http://demo:80/live/livestream.html
62 </pre> 70 </pre>
63 -step 9: play live stream auto transcoded<br/> 71 +<strong>step 9(optinal):</strong> play live stream auto transcoded<br/>
64 <pre> 72 <pre>
65 rtmp url: rtmp://demo:1935/live/livestream_ld 73 rtmp url: rtmp://demo:1935/live/livestream_ld
66 m3u8 url: http://demo:80/live/livestream_ld.m3u8 74 m3u8 url: http://demo:80/live/livestream_ld.m3u8
  75 +for android: http://demo:80/live/livestream_ld.html
67 rtmp url: rtmp://demo:1935/live/livestream_sd 76 rtmp url: rtmp://demo:1935/live/livestream_sd
68 m3u8 url: http://demo:80/live/livestream_sd.m3u8 77 m3u8 url: http://demo:80/live/livestream_sd.m3u8
  78 +for android: http://demo:80/live/livestream_sd.html
69 </pre> 79 </pre>
70 -step 10: play live stream auto forwarded, the hls dir change to /forward<br/> 80 +<strong>step 10(optinal):</strong> play live stream auto forwarded, the hls dir change to /forward<br/>
71 <pre> 81 <pre>
72 rtmp url: rtmp://demo:19350/live/livestream 82 rtmp url: rtmp://demo:19350/live/livestream
73 m3u8 url: http://demo:80/forward/live/livestream.m3u8 83 m3u8 url: http://demo:80/forward/live/livestream.m3u8
  84 +for android: http://demo:80/forward/live/livestream.html
74 rtmp url: rtmp://demo:19350/live/livestream_ld 85 rtmp url: rtmp://demo:19350/live/livestream_ld
75 m3u8 url: http://demo:80/forward/live/livestream_ld.m3u8 86 m3u8 url: http://demo:80/forward/live/livestream_ld.m3u8
  87 +for android: http://demo:80/forward/live/livestream_ld.html
76 rtmp url: rtmp://demo:19350/live/livestream_sd 88 rtmp url: rtmp://demo:19350/live/livestream_sd
77 m3u8 url: http://demo:80/forward/live/livestream_sd.m3u8 89 m3u8 url: http://demo:80/forward/live/livestream_sd.m3u8
  90 +for android: http://demo:80/forward/live/livestream_sd.html
  91 +</pre>
  92 +<strong>step 11(optinal):</strong> modify the config and reload it (all features support reload)<br/>
  93 +<pre>
  94 +killall -1 srs
  95 +</pre>
  96 +or use specified signal to reload:<br/>
  97 +<pre>
  98 +killall -s SIGHUP srs
78 </pre> 99 </pre>
79 100
80 ### Architecture 101 ### Architecture
@@ -192,7 +213,15 @@ usr sys idl wai hiq siq| read writ| recv send| in out | int csw @@ -192,7 +213,15 @@ usr sys idl wai hiq siq| read writ| recv send| in out | int csw
192 * nginx v1.5.0: 139524 lines <br/> 213 * nginx v1.5.0: 139524 lines <br/>
193 214
194 ### History 215 ### History
195 -* v0.8, 2013-12-08, v0.8 released. 19186 lines. 216 +* v0.9, 2013-12-15, ensure the HLS(ts) is continous when republish stream.
  217 +* v0.9, 2013-12-15, fix the hls reload bug, feed it the sequence header.
  218 +* v0.9, 2013-12-15, refine protocol, use int64_t timestamp for ts and jitter.
  219 +* v0.9, 2013-12-15, support set the live queue length(in seconds), drop when full.
  220 +* v0.9, 2013-12-15, fix the forwarder reconnect bug, feed it the sequence header.
  221 +* v0.9, 2013-12-15, support reload the hls/forwarder/transcoder.
  222 +* v0.9, 2013-12-14, refine the thread model for the retry threads.
  223 +* v0.9, 2013-12-10, auto install depends tools/libs on centos/ubuntu.
  224 +* v0.8, 2013-12-08, [v0.8](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.8) released. 19186 lines.
196 * v0.8, 2013-12-08, support http hooks: on_connect/close/publish/unpublish/play/stop. 225 * v0.8, 2013-12-08, support http hooks: on_connect/close/publish/unpublish/play/stop.
197 * v0.8, 2013-12-08, support multiple http hooks for a event. 226 * v0.8, 2013-12-08, support multiple http hooks for a event.
198 * v0.8, 2013-12-07, support http callback hooks, on_connect. 227 * v0.8, 2013-12-07, support http callback hooks, on_connect.
@@ -201,32 +230,32 @@ usr sys idl wai hiq siq| read writ| recv send| in out | int csw @@ -201,32 +230,32 @@ usr sys idl wai hiq siq| read writ| recv send| in out | int csw
201 * v0.8, 2013-12-06, support max_connections, drop if exceed. 230 * v0.8, 2013-12-06, support max_connections, drop if exceed.
202 * v0.8, 2013-12-05, support log_dir, write ffmpeg log to file. 231 * v0.8, 2013-12-05, support log_dir, write ffmpeg log to file.
203 * v0.8, 2013-12-05, fix the forward/hls/encoder bug. 232 * v0.8, 2013-12-05, fix the forward/hls/encoder bug.
204 -* v0.7, 2013-12-03, v0.7 released. 17605 lines. 233 +* v0.7, 2013-12-03, [v0.7](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.7) released. 17605 lines.
205 * v0.7, 2013-12-01, support dead-loop detect for forwarder and transcoder. 234 * v0.7, 2013-12-01, support dead-loop detect for forwarder and transcoder.
206 * v0.7, 2013-12-01, support all ffmpeg filters and params. 235 * v0.7, 2013-12-01, support all ffmpeg filters and params.
207 * v0.7, 2013-11-30, support live stream transcoder by ffmpeg. 236 * v0.7, 2013-11-30, support live stream transcoder by ffmpeg.
208 * v0.7, 2013-11-30, support --with/without -ffmpeg, build ffmpeg-2.1. 237 * v0.7, 2013-11-30, support --with/without -ffmpeg, build ffmpeg-2.1.
209 * v0.7, 2013-11-30, add ffmpeg-2.1, x264-core138, lame-3.99.5, libaacplus-2.0.2. 238 * v0.7, 2013-11-30, add ffmpeg-2.1, x264-core138, lame-3.99.5, libaacplus-2.0.2.
210 -* v0.6, 2013-11-29, v0.6 released. 16094 lines. 239 +* v0.6, 2013-11-29, [v0.6](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.6) released. 16094 lines.
211 * v0.6, 2013-11-29, add performance summary, 1800 clients, 900Mbps, CPU 90.2%, 41MB. 240 * v0.6, 2013-11-29, add performance summary, 1800 clients, 900Mbps, CPU 90.2%, 41MB.
212 * v0.6, 2013-11-29, support forward stream to other edge server. 241 * v0.6, 2013-11-29, support forward stream to other edge server.
213 * v0.6, 2013-11-29, support forward stream to other origin server. 242 * v0.6, 2013-11-29, support forward stream to other origin server.
214 * v0.6, 2013-11-28, fix memory leak bug, aac decode bug. 243 * v0.6, 2013-11-28, fix memory leak bug, aac decode bug.
215 * v0.6, 2013-11-27, support --with or --without -hls and -ssl options. 244 * v0.6, 2013-11-27, support --with or --without -hls and -ssl options.
216 * v0.6, 2013-11-27, support AAC 44100HZ sample rate for iphone, adjust the timestamp. 245 * v0.6, 2013-11-27, support AAC 44100HZ sample rate for iphone, adjust the timestamp.
217 -* v0.5, 2013-11-26, v0.5 released. 14449 lines. 246 +* v0.5, 2013-11-26, [v0.5](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.5) released. 14449 lines.
218 * v0.5, 2013-11-24, support HLS(m3u8), fragment and window. 247 * v0.5, 2013-11-24, support HLS(m3u8), fragment and window.
219 * v0.5, 2013-11-24, support record to ts file for HLS. 248 * v0.5, 2013-11-24, support record to ts file for HLS.
220 * v0.5, 2013-11-21, add ts_info tool to demux ts file. 249 * v0.5, 2013-11-21, add ts_info tool to demux ts file.
221 * v0.5, 2013-11-16, add rtmp players(OSMF/jwplayer5/jwplayer6). 250 * v0.5, 2013-11-16, add rtmp players(OSMF/jwplayer5/jwplayer6).
222 -* v0.4, 2013-11-10, v0.4 released. 12500 lines. 251 +* v0.4, 2013-11-10, [v0.4](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.4) released. 12500 lines.
223 * v0.4, 2013-11-10, support config and reload the pithy print. 252 * v0.4, 2013-11-10, support config and reload the pithy print.
224 * v0.4, 2013-11-09, support reload config(vhost and its detail). 253 * v0.4, 2013-11-09, support reload config(vhost and its detail).
225 * v0.4, 2013-11-09, support reload config(listen and chunk_size) by SIGHUP(1). 254 * v0.4, 2013-11-09, support reload config(listen and chunk_size) by SIGHUP(1).
226 * v0.4, 2013-11-09, support longtime(>4.6hours) publish/play. 255 * v0.4, 2013-11-09, support longtime(>4.6hours) publish/play.
227 * v0.4, 2013-11-09, support config the chunk_size. 256 * v0.4, 2013-11-09, support config the chunk_size.
228 * v0.4, 2013-11-09, support pause for live stream. 257 * v0.4, 2013-11-09, support pause for live stream.
229 -* v0.3, 2013-11-04, v0.3 released. 11773 lines. 258 +* v0.3, 2013-11-04, [v0.3](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.3) released. 11773 lines.
230 * v0.3, 2013-11-04, support refer/play-refer/publish-refer. 259 * v0.3, 2013-11-04, support refer/play-refer/publish-refer.
231 * v0.3, 2013-11-04, support vhosts specified config. 260 * v0.3, 2013-11-04, support vhosts specified config.
232 * v0.3, 2013-11-02, support listen multiple ports. 261 * v0.3, 2013-11-02, support listen multiple ports.
@@ -234,12 +263,12 @@ usr sys idl wai hiq siq| read writ| recv send| in out | int csw @@ -234,12 +263,12 @@ usr sys idl wai hiq siq| read writ| recv send| in out | int csw
234 * v0.3, 2013-10-29, support pithy print log message specified by stage. 263 * v0.3, 2013-10-29, support pithy print log message specified by stage.
235 * v0.3, 2013-10-28, support librtmp without extended-timestamp in 0xCX chunk packet. 264 * v0.3, 2013-10-28, support librtmp without extended-timestamp in 0xCX chunk packet.
236 * v0.3, 2013-10-27, support cache last gop for client fast startup. 265 * v0.3, 2013-10-27, support cache last gop for client fast startup.
237 -* v0.2, 2013-10-25, v0.2 released. 10125 lines. 266 +* v0.2, 2013-10-25, [v0.2](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.2) released. 10125 lines.
238 * v0.2, 2013-10-25, support flash publish. 267 * v0.2, 2013-10-25, support flash publish.
239 * v0.2, 2013-10-25, support h264/avc codec by rtmp complex handshake. 268 * v0.2, 2013-10-25, support h264/avc codec by rtmp complex handshake.
240 * v0.2, 2013-10-24, support time jitter detect and correct algorithm 269 * v0.2, 2013-10-24, support time jitter detect and correct algorithm
241 * v0.2, 2013-10-24, support decode codec type to cache the h264/avc sequence header. 270 * v0.2, 2013-10-24, support decode codec type to cache the h264/avc sequence header.
242 -* v0.1, 2013-10-23, v0.1 released. 8287 lines. 271 +* v0.1, 2013-10-23, [v0.1](https://github.com/winlinvip/simple-rtmp-server/releases/tag/0.1) released. 8287 lines.
243 * v0.1, 2013-10-23, support basic amf0 codec, simplify the api using c-style api. 272 * v0.1, 2013-10-23, support basic amf0 codec, simplify the api using c-style api.
244 * v0.1, 2013-10-23, support shared ptr msg for zero memory copy. 273 * v0.1, 2013-10-23, support shared ptr msg for zero memory copy.
245 * v0.1, 2013-10-22, support vp6 codec with rtmp protocol specified simple handshake. 274 * v0.1, 2013-10-22, support vp6 codec with rtmp protocol specified simple handshake.
@@ -59,7 +59,9 @@ else @@ -59,7 +59,9 @@ else
59 echo "build x264" 59 echo "build x264"
60 cd $ff_current_dir && 60 cd $ff_current_dir &&
61 rm -rf x264-snapshot-20131129-2245-stable && unzip -q ${ff_src_dir}/x264-snapshot-20131129-2245-stable.zip && 61 rm -rf x264-snapshot-20131129-2245-stable && unzip -q ${ff_src_dir}/x264-snapshot-20131129-2245-stable.zip &&
62 - cd x264-snapshot-20131129-2245-stable && ./configure --prefix=${ff_release_dir} --bit-depth=8 --enable-static && make && make install 62 + cd x264-snapshot-20131129-2245-stable &&
  63 + ./configure --prefix=${ff_release_dir} --disable-opencl --bit-depth=8 --enable-static &&
  64 + make && make install
63 ret=$?; if [[ 0 -ne ${ret} ]]; then echo "build x264 failed"; exit 1; fi 65 ret=$?; if [[ 0 -ne ${ret} ]]; then echo "build x264 failed"; exit 1; fi
64 fi 66 fi
65 67
@@ -86,7 +88,8 @@ else @@ -86,7 +88,8 @@ else
86 --enable-postproc --enable-bzlib --enable-zlib --enable-parsers \ 88 --enable-postproc --enable-bzlib --enable-zlib --enable-parsers \
87 --enable-libfreetype \ 89 --enable-libfreetype \
88 --enable-libx264 --enable-libmp3lame --enable-libaacplus \ 90 --enable-libx264 --enable-libmp3lame --enable-libaacplus \
89 - --enable-pthreads --extra-libs=-lpthread --enable-encoders --enable-decoders --enable-avfilter --enable-muxers --enable-demuxers && 91 + --enable-pthreads --extra-libs=-lpthread \
  92 + --enable-encoders --enable-decoders --enable-avfilter --enable-muxers --enable-demuxers &&
90 make && make install 93 make && make install
91 - ret=$?; if [[ 0 -ne ${ret} ]]; then echo "build x264 failed"; exit 1; fi 94 + ret=$?; if [[ 0 -ne ${ret} ]]; then echo "build ffmpeg failed"; exit 1; fi
92 fi 95 fi
@@ -3,6 +3,168 @@ @@ -3,6 +3,168 @@
3 # TODO: check gcc/g++ 3 # TODO: check gcc/g++
4 echo "check gcc/g++/gdb/make/openssl-devel" 4 echo "check gcc/g++/gdb/make/openssl-devel"
5 echo "depends tools are ok" 5 echo "depends tools are ok"
  6 +#####################################################################################
  7 +# for Ubuntu
  8 +#####################################################################################
  9 +function Ubuntu_prepare()
  10 +{
  11 + uname -v|grep Ubuntu >/dev/null 2>&1
  12 + ret=$?; if [[ 0 -ne $ret ]]; then
  13 + return;
  14 + fi
  15 +
  16 + echo "Ubuntu detected, install tools if needed"
  17 +
  18 + gcc --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
  19 + echo "install gcc"
  20 + require_sudoer "sudo apt-get install -y gcc"
  21 + sudo apt-get install -y gcc
  22 + echo "install gcc success"
  23 + fi
  24 +
  25 + g++ --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
  26 + echo "install g++"
  27 + require_sudoer "sudo apt-get install -y g++"
  28 + sudo apt-get install -y g++
  29 + echo "install g++ success"
  30 + fi
  31 +
  32 + make --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
  33 + echo "install make"
  34 + require_sudoer "sudo apt-get install -y make"
  35 + sudo apt-get install -y make
  36 + echo "install make success"
  37 + fi
  38 +
  39 + autoconf --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
  40 + echo "install autoconf"
  41 + require_sudoer "sudo apt-get install -y autoconf"
  42 + sudo apt-get install -y autoconf
  43 + echo "install autoconf success"
  44 + fi
  45 +
  46 + libtool --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
  47 + echo "install libtool"
  48 + require_sudoer "sudo apt-get install -y libtool"
  49 + sudo apt-get install -y libtool
  50 + echo "install libtool success"
  51 + fi
  52 +
  53 + if [[ ! -f /usr/include/pcre.h ]]; then
  54 + echo "install libpcre3-dev"
  55 + require_sudoer "sudo apt-get install -y libpcre3-dev"
  56 + sudo apt-get install -y libpcre3-dev
  57 + echo "install libpcre3-dev success"
  58 + fi
  59 +
  60 + if [[ ! -f /usr/include/zlib.h ]]; then
  61 + echo "install zlib1g-dev"
  62 + require_sudoer "sudo apt-get install -y zlib1g-dev"
  63 + sudo apt-get install -y zlib1g-dev
  64 + echo "install zlib1g-dev success"
  65 + fi
  66 +
  67 + if [[ ! -d /usr/include/freetype2 ]]; then
  68 + echo "install libfreetype6-dev"
  69 + require_sudoer "sudo apt-get install -y libfreetype6-dev"
  70 + sudo apt-get install -y libfreetype6-dev
  71 + echo "install libfreetype6-dev success"
  72 + fi
  73 +
  74 + if [[ ! -d /usr/include/openssl ]]; then
  75 + echo "install libssl-dev"
  76 + require_sudoer "sudo apt-get install -y libssl-dev"
  77 + sudo apt-get install -y libssl-dev
  78 + echo "install libssl-dev success"
  79 + fi
  80 +
  81 + echo "Ubuntu install tools success"
  82 +}
  83 +Ubuntu_prepare
  84 +#####################################################################################
  85 +# for Centos
  86 +#####################################################################################
  87 +function Centos_prepare()
  88 +{
  89 + if [[ ! -f /etc/redhat-release ]]; then
  90 + return;
  91 + fi
  92 +
  93 + echo "Centos detected, install tools if needed"
  94 +
  95 + gcc --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
  96 + echo "install gcc"
  97 + require_sudoer "sudo yum install -y gcc"
  98 + sudo yum install -y gcc
  99 + echo "install gcc success"
  100 + fi
  101 +
  102 + g++ --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
  103 + echo "install gcc-c++"
  104 + require_sudoer "sudo yum install -y gcc-c++"
  105 + sudo yum install -y gcc-c++
  106 + echo "install gcc-c++ success"
  107 + fi
  108 +
  109 + make --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
  110 + echo "install make"
  111 + require_sudoer "sudo yum install -y make"
  112 + sudo yum install -y make
  113 + echo "install make success"
  114 + fi
  115 +
  116 + automake --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
  117 + echo "install automake"
  118 + require_sudoer "sudo yum install -y automake"
  119 + sudo yum install -y automake
  120 + echo "install automake success"
  121 + fi
  122 +
  123 + autoconf --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
  124 + echo "install autoconf"
  125 + require_sudoer "sudo yum install -y autoconf"
  126 + sudo yum install -y autoconf
  127 + echo "install autoconf success"
  128 + fi
  129 +
  130 + libtool --help >/dev/null 2>&1; ret=$?; if [[ 0 -ne $ret ]]; then
  131 + echo "install libtool"
  132 + require_sudoer "sudo yum install -y libtool"
  133 + sudo yum install -y libtool
  134 + echo "install libtool success"
  135 + fi
  136 +
  137 + if [[ ! -f /usr/include/pcre.h ]]; then
  138 + echo "install pcre-devel"
  139 + require_sudoer "sudo yum install -y pcre-devel"
  140 + sudo yum install -y pcre-devel
  141 + echo "install pcre-devel success"
  142 + fi
  143 +
  144 + if [[ ! -f /usr/include/zlib.h ]]; then
  145 + echo "install zlib-devel"
  146 + require_sudoer "sudo yum install -y zlib-devel"
  147 + sudo yum install -y zlib-devel
  148 + echo "install zlib-devel success"
  149 + fi
  150 +
  151 + if [[ ! -d /usr/include/freetype2 ]]; then
  152 + echo "install freetype-devel"
  153 + require_sudoer "sudo yum install -y freetype-devel"
  154 + sudo yum install -y freetype-devel
  155 + echo "install freetype-devel success"
  156 + fi
  157 +
  158 + if [[ ! -d /usr/include/openssl ]]; then
  159 + echo "install openssl-devel"
  160 + require_sudoer "sudo yum install -y openssl-devel"
  161 + sudo yum install -y openssl-devel
  162 + echo "install openssl-devel success"
  163 + fi
  164 +
  165 + echo "Centos install tools success"
  166 +}
  167 +Centos_prepare
6 168
7 ##################################################################################### 169 #####################################################################################
8 # st-1.9 170 # st-1.9
@@ -48,6 +210,16 @@ fi @@ -48,6 +210,16 @@ fi
48 ##################################################################################### 210 #####################################################################################
49 # nginx for HLS, nginx-1.5.0 211 # nginx for HLS, nginx-1.5.0
50 ##################################################################################### 212 #####################################################################################
  213 +function write_nginx_html5()
  214 +{
  215 + cat<<END >> ${html_file}
  216 +<video width="640" height="360"
  217 + autoplay controls autobuffer
  218 + src="${hls_stream}"
  219 + type="application/vnd.apple.mpegurl">
  220 +</video>
  221 +END
  222 +}
51 if [ $SRS_HLS = YES ]; then 223 if [ $SRS_HLS = YES ]; then
52 if [[ -f ${SRS_OBJS}/nginx/sbin/nginx ]]; then 224 if [[ -f ${SRS_OBJS}/nginx/sbin/nginx ]]; then
53 echo "nginx-1.5.7 is ok."; 225 echo "nginx-1.5.7 is ok.";
@@ -72,6 +244,17 @@ if [ $SRS_HLS = YES ]; then @@ -72,6 +244,17 @@ if [ $SRS_HLS = YES ]; then
72 244
73 # create forward dir 245 # create forward dir
74 mkdir -p ${SRS_OBJS}/nginx/html/forward 246 mkdir -p ${SRS_OBJS}/nginx/html/forward
  247 +
  248 + # generate default html pages for android.
  249 + html_file=${SRS_OBJS}/nginx/html/live/livestream.html && hls_stream=livestream.m3u8 && write_nginx_html5
  250 + html_file=${SRS_OBJS}/nginx/html/live/livestream_ld.html && hls_stream=livestream_ld.m3u8 && write_nginx_html5
  251 + html_file=${SRS_OBJS}/nginx/html/live/livestream_sd.html && hls_stream=livestream_sd.m3u8 && write_nginx_html5
  252 + html_file=${SRS_OBJS}/nginx/html/forward/live/livestream.html && hls_stream=livestream.m3u8 && write_nginx_html5
  253 + html_file=${SRS_OBJS}/nginx/html/forward/live/livestream_ld.html && hls_stream=livestream_ld.m3u8 && write_nginx_html5
  254 + html_file=${SRS_OBJS}/nginx/html/forward/live/livestream_sd.html && hls_stream=livestream_sd.m3u8 && write_nginx_html5
  255 +
  256 + # copy players to nginx html dir.
  257 + cp research/players ${SRS_OBJS}/nginx/html/ -r
75 fi 258 fi
76 259
77 if [ $SRS_HLS = YES ]; then 260 if [ $SRS_HLS = YES ]; then
@@ -87,6 +270,7 @@ if [ $SRS_HTTP = YES ]; then @@ -87,6 +270,7 @@ if [ $SRS_HTTP = YES ]; then
87 if [[ -f ${SRS_OBJS}/CherryPy-3.2.4/setup.py ]]; then 270 if [[ -f ${SRS_OBJS}/CherryPy-3.2.4/setup.py ]]; then
88 echo "CherryPy-3.2.4 is ok."; 271 echo "CherryPy-3.2.4 is ok.";
89 else 272 else
  273 + require_sudoer "configure --with-http"
90 echo "install CherryPy-3.2.4"; 274 echo "install CherryPy-3.2.4";
91 ( 275 (
92 sudo rm -rf ${SRS_OBJS}/CherryPy-3.2.4 && cd ${SRS_OBJS} && 276 sudo rm -rf ${SRS_OBJS}/CherryPy-3.2.4 && cd ${SRS_OBJS} &&
1 # the listen ports, split by space. 1 # the listen ports, split by space.
2 listen 1935; 2 listen 1935;
  3 +<<<<<<< HEAD
  4 +=======
  5 +# the default chunk size is 128, max is 65536,
  6 +# some client does not support chunk size change,
  7 +# however, most clients supports it and it can improve
  8 +# performance about 10%.
  9 +# default: 4096
  10 +chunk_size 65000;
  11 +>>>>>>> upstream/master
3 # the logs dir. 12 # the logs dir.
4 # if enabled ffmpeg, each stracoding stream will create a log file. 13 # if enabled ffmpeg, each stracoding stream will create a log file.
5 # default: ./objs/logs 14 # default: ./objs/logs
@@ -21,14 +30,26 @@ vhost __defaultVhost__ { @@ -21,14 +30,26 @@ vhost __defaultVhost__ {
21 chunk_size 65000; 30 chunk_size 65000;
22 enabled on; 31 enabled on;
23 gop_cache on; 32 gop_cache on;
24 - hls on;  
25 - hls_path ./objs/nginx/html;  
26 - hls_fragment 5;  
27 - hls_window 30; 33 + queue_length 30;
28 forward 127.0.0.1:19350; 34 forward 127.0.0.1:19350;
  35 + hls {
  36 + enabled on;
  37 + hls_path ./objs/nginx/html;
  38 + hls_fragment 5;
  39 + hls_window 30;
  40 + }
  41 + http_hooks {
  42 + enabled off;
  43 + on_connect http://127.0.0.1:8085/api/v1/clients;
  44 + on_close http://127.0.0.1:8085/api/v1/clients;
  45 + on_publish http://127.0.0.1:8085/api/v1/streams;
  46 + on_unpublish http://127.0.0.1:8085/api/v1/streams;
  47 + on_play http://127.0.0.1:8085/api/v1/sessions;
  48 + on_stop http://127.0.0.1:8085/api/v1/sessions;
  49 + }
29 transcode { 50 transcode {
30 - enabled on;  
31 - ffmpeg ./objs/ffmpeg/bin/ffmpeg; 51 + enabled on;
  52 + ffmpeg ./objs/ffmpeg/bin/ffmpeg;
32 engine ld { 53 engine ld {
33 enabled on; 54 enabled on;
34 vfilter { 55 vfilter {
@@ -82,11 +103,17 @@ vhost dev { @@ -82,11 +103,17 @@ vhost dev {
82 chunk_size 65000; 103 chunk_size 65000;
83 enabled on; 104 enabled on;
84 gop_cache on; 105 gop_cache on;
85 - hls on;  
86 - hls_path ./objs/nginx/html;  
87 - hls_fragment 5;  
88 - hls_window 30; 106 + queue_length 10;
89 forward 127.0.0.1:19350; 107 forward 127.0.0.1:19350;
  108 +<<<<<<< HEAD
  109 +=======
  110 + hls {
  111 + enabled on;
  112 + hls_path ./objs/nginx/html;
  113 + hls_fragment 5;
  114 + hls_window 30;
  115 + }
  116 +>>>>>>> upstream/master
90 http_hooks { 117 http_hooks {
91 enabled off; 118 enabled off;
92 on_connect http://127.0.0.1:8085/api/v1/clients; 119 on_connect http://127.0.0.1:8085/api/v1/clients;
@@ -97,7 +124,7 @@ vhost dev { @@ -97,7 +124,7 @@ vhost dev {
97 on_stop http://127.0.0.1:8085/api/v1/sessions; 124 on_stop http://127.0.0.1:8085/api/v1/sessions;
98 } 125 }
99 transcode { 126 transcode {
100 - enabled on; 127 + enabled off;
101 ffmpeg ./objs/ffmpeg/bin/ffmpeg; 128 ffmpeg ./objs/ffmpeg/bin/ffmpeg;
102 engine dev { 129 engine dev {
103 enabled on; 130 enabled on;
@@ -641,36 +668,40 @@ vhost removed.vhost.com { @@ -641,36 +668,40 @@ vhost removed.vhost.com {
641 enabled off; 668 enabled off;
642 } 669 }
643 # the vhost with hls specified. 670 # the vhost with hls specified.
644 -vhost no-hls.vhost.com {  
645 - # whether the hls is enabled.  
646 - # if off, donot write hls(ts and m3u8) when publish.  
647 - # default: on  
648 - hls on;  
649 - # the hls output path.  
650 - # the app dir is auto created under the hls_path.  
651 - # for example, for rtmp stream:  
652 - # rtmp://127.0.0.1/live/livestream  
653 - # http://127.0.0.1/live/livestream.m3u8  
654 - # where hls_path is /hls, srs will create the following files:  
655 - # /hls/live the app dir for all streams.  
656 - # /hls/live/livestream.m3u8 the HLS m3u8 file.  
657 - # /hls/live/livestream-1.ts the HLS media/ts file.  
658 - # in a word, the hls_path is for vhost.  
659 - # default: ./objs/nginx/html  
660 - hls_path /data/nginx/html;  
661 - # the hls fragment in seconds, the duration of a piece of ts.  
662 - # default: 10  
663 - hls_fragment 10;  
664 - # the hls window in seconds, the number of ts in m3u8.  
665 - # default: 60  
666 - hls_window 60; 671 +vhost with-hls.vhost.com {
  672 + hls {
  673 + # whether the hls is enabled.
  674 + # if off, donot write hls(ts and m3u8) when publish.
  675 + # default: off
  676 + enabled on;
  677 + # the hls output path.
  678 + # the app dir is auto created under the hls_path.
  679 + # for example, for rtmp stream:
  680 + # rtmp://127.0.0.1/live/livestream
  681 + # http://127.0.0.1/live/livestream.m3u8
  682 + # where hls_path is /hls, srs will create the following files:
  683 + # /hls/live the app dir for all streams.
  684 + # /hls/live/livestream.m3u8 the HLS m3u8 file.
  685 + # /hls/live/livestream-1.ts the HLS media/ts file.
  686 + # in a word, the hls_path is for vhost.
  687 + # default: ./objs/nginx/html
  688 + hls_path /data/nginx/html;
  689 + # the hls fragment in seconds, the duration of a piece of ts.
  690 + # default: 10
  691 + hls_fragment 10;
  692 + # the hls window in seconds, the number of ts in m3u8.
  693 + # default: 60
  694 + hls_window 60;
  695 + }
667 } 696 }
668 # the vhost with hls disabled. 697 # the vhost with hls disabled.
669 vhost no-hls.vhost.com { 698 vhost no-hls.vhost.com {
670 - # whether the hls is enabled.  
671 - # if off, donot write hls(ts and m3u8) when publish.  
672 - # default: on  
673 - hls off; 699 + hls {
  700 + # whether the hls is enabled.
  701 + # if off, donot write hls(ts and m3u8) when publish.
  702 + # default: off
  703 + enabled off;
  704 + }
674 } 705 }
675 # the vhost for min delay, donot cache any stream. 706 # the vhost for min delay, donot cache any stream.
676 vhost min.delay.com { 707 vhost min.delay.com {
@@ -683,6 +714,11 @@ vhost min.delay.com { @@ -683,6 +714,11 @@ vhost min.delay.com {
683 # set to on if requires client fast startup. 714 # set to on if requires client fast startup.
684 # default: on 715 # default: on
685 gop_cache off; 716 gop_cache off;
  717 + # the max live queue length in seconds.
  718 + # if the messages in the queue exceed the max length,
  719 + # drop the old whole gop.
  720 + # default: 30
  721 + queue_length 10;
686 } 722 }
687 # the vhost for antisuck. 723 # the vhost for antisuck.
688 vhost refer.anti_suck.com { 724 vhost refer.anti_suck.com {
@@ -15,14 +15,15 @@ BLACK="\\e[0m" @@ -15,14 +15,15 @@ BLACK="\\e[0m"
15 # parse user options. 15 # parse user options.
16 . auto/options.sh 16 . auto/options.sh
17 17
18 -# if specifies http, requires sudo to install the CherryPy.  
19 -if [ $SRS_HTTP = YES ]; then 18 +function require_sudoer()
  19 +{
20 sudo echo "" >/dev/null 2>&1 20 sudo echo "" >/dev/null 2>&1
21 - ret=$?; if [[ 0 -ne $ret ]]; then echo  
22 - "--with-http requires sudoer, ret=$ret"; 21 +
  22 + ret=$?; if [[ 0 -ne $ret ]]; then
  23 + echo "\"$1\" require sudoer failed. ret=$ret";
23 exit $ret; 24 exit $ret;
24 fi 25 fi
25 -fi 26 +}
26 27
27 # clean the exists 28 # clean the exists
28 if [[ -f Makefile ]]; then 29 if [[ -f Makefile ]]; then
@@ -56,11 +57,11 @@ help: @@ -56,11 +57,11 @@ help:
56 @echo " server build the srs(simple rtmp server) over st(state-threads)" 57 @echo " server build the srs(simple rtmp server) over st(state-threads)"
57 58
58 clean: 59 clean:
59 - (rm -f Makefile; cd ${SRS_OBJS}; rm -rf Makefile *.hpp src st_*_load) 60 + (rm -f Makefile; cd ${SRS_OBJS}; rm -rf srs Makefile *.hpp src st_*_load)
60 61
61 server: _prepare_dir 62 server: _prepare_dir
62 @echo "build the srs(simple rtmp server) over st(state-threads)" 63 @echo "build the srs(simple rtmp server) over st(state-threads)"
63 - \$(MAKE) -f ${SRS_OBJS}/${SRS_MAKEFILE} simple_rtmp_server 64 + \$(MAKE) -f ${SRS_OBJS}/${SRS_MAKEFILE} srs
64 65
65 # the ./configure will generate it. 66 # the ./configure will generate it.
66 _prepare_dir: 67 _prepare_dir:
@@ -86,7 +87,7 @@ GCC = g++ @@ -86,7 +87,7 @@ GCC = g++
86 LINK = \$(GCC) 87 LINK = \$(GCC)
87 AR = ar 88 AR = ar
88 89
89 -.PHONY: default simple_rtmp_server 90 +.PHONY: default srs
90 91
91 default: 92 default:
92 93
@@ -115,7 +116,7 @@ MODULE_FILES=("srs_core" "srs_core_log" "srs_core_server" @@ -115,7 +116,7 @@ MODULE_FILES=("srs_core" "srs_core_log" "srs_core_server"
115 "srs_core_handshake" "srs_core_pithy_print" 116 "srs_core_handshake" "srs_core_pithy_print"
116 "srs_core_config" "srs_core_refer" "srs_core_reload" 117 "srs_core_config" "srs_core_refer" "srs_core_reload"
117 "srs_core_hls" "srs_core_forward" "srs_core_encoder" 118 "srs_core_hls" "srs_core_forward" "srs_core_encoder"
118 - "srs_core_http") 119 + "srs_core_http" "srs_core_thread")
119 MODULE_DIR="src/core" . auto/modules.sh 120 MODULE_DIR="src/core" . auto/modules.sh
120 CORE_OBJS="${MODULE_OBJS[@]}" 121 CORE_OBJS="${MODULE_OBJS[@]}"
121 122
@@ -141,7 +142,7 @@ if [ $SRS_SSL = YES ]; then @@ -141,7 +142,7 @@ if [ $SRS_SSL = YES ]; then
141 else 142 else
142 LINK_OPTIONS="-ldl" 143 LINK_OPTIONS="-ldl"
143 fi 144 fi
144 -BUILD_KEY="simple_rtmp_server" APP_MAIN="srs_main_server" APP_NAME="simple_rtmp_server" SO_PATH="" . auto/apps.sh 145 +BUILD_KEY="srs" APP_MAIN="srs_main_server" APP_NAME="srs" SO_PATH="" . auto/apps.sh
145 146
146 echo 'configure ok! ' 147 echo 'configure ok! '
147 148
@@ -179,6 +180,7 @@ echo "\" make \" to build the srs(simple rtmp server)." @@ -179,6 +180,7 @@ echo "\" make \" to build the srs(simple rtmp server)."
179 echo "\" make help \" to get the usage of make" 180 echo "\" make help \" to get the usage of make"
180 if [ $SRS_HLS = YES ]; then 181 if [ $SRS_HLS = YES ]; then
181 echo "\" sudo ./objs/nginx/sbin/nginx \" to start the nginx http server for hls" 182 echo "\" sudo ./objs/nginx/sbin/nginx \" to start the nginx http server for hls"
  183 + echo "\" http://demo:80/players \" rtmp players(OSMF/JWPlayer)"
182 fi 184 fi
183 if [ $SRS_FFMPEG = YES ]; then 185 if [ $SRS_FFMPEG = YES ]; then
184 echo -e "\" ./objs/ffmpeg/bin/ffmpeg \" is used for live stream transcoding" 186 echo -e "\" ./objs/ffmpeg/bin/ffmpeg \" is used for live stream transcoding"
@@ -186,4 +188,4 @@ fi @@ -186,4 +188,4 @@ fi
186 if [ $SRS_HTTP = YES ]; then 188 if [ $SRS_HTTP = YES ]; then
187 echo -e "\" python ./research/api-server/server.py 8085 \" to start the api-server" 189 echo -e "\" python ./research/api-server/server.py 8085 \" to start the api-server"
188 fi 190 fi
189 -echo "\" ./objs/simple_rtmp_server -c conf/srs.conf \" to start the srs live server" 191 +echo "\" ./objs/srs -c conf/srs.conf \" to start the srs live server"
@@ -9,4 +9,5 @@ @@ -9,4 +9,5 @@
9 <p><a href="osmf/index.html">OSMF播放器</a></p> 9 <p><a href="osmf/index.html">OSMF播放器</a></p>
10 <p><a href="jwplayer5/index.html">JWPlayer5</a></p> 10 <p><a href="jwplayer5/index.html">JWPlayer5</a></p>
11 <p><a href="jwplayer6/index.html">JWPlayer6</a></p> 11 <p><a href="jwplayer6/index.html">JWPlayer6</a></p>
  12 + <p><a href="http://www.videolan.org/vlc/">VLC for HLS/rtmp/rtsp/http....</a></p>
12 </body> 13 </body>
@@ -17,7 +17,7 @@ @@ -17,7 +17,7 @@
17 <div class="main"> 17 <div class="main">
18 <div id="player"></div> 18 <div id="player"></div>
19 <div class="control" id="control"> 19 <div class="control" id="control">
20 - Url(RTMP/HTTP): <input id="url" type="text" class="url" value="rtmp://dev:1935/live/livestream"></input> 20 + Url(RTMP/HTTP): <input id="url" type="text" class="url" value="rtmp://demo:1935/live/livestream"></input>
21 <input type="button" class="play" value="Play" onclick="play()"></input> 21 <input type="button" class="play" value="Play" onclick="play()"></input>
22 </div> 22 </div>
23 </div> 23 </div>
@@ -17,7 +17,7 @@ @@ -17,7 +17,7 @@
17 <div class="main"> 17 <div class="main">
18 <div id="player"></div> 18 <div id="player"></div>
19 <div class="control" id="control"> 19 <div class="control" id="control">
20 - Url(RTMP/HTTP): <input id="url" type="text" class="url" value="rtmp://dev:1935/live/livestream"></input> 20 + Url(RTMP/HTTP): <input id="url" type="text" class="url" value="rtmp://demo:1935/live/livestream"></input>
21 <input type="button" class="play" value="Play" onclick="play()"></input> 21 <input type="button" class="play" value="Play" onclick="play()"></input>
22 </div> 22 </div>
23 </div> 23 </div>
@@ -19,7 +19,7 @@ div.control{padding-bottom:10px; background-color:#333333; } @@ -19,7 +19,7 @@ div.control{padding-bottom:10px; background-color:#333333; }
19 <div class="main" id="main"> 19 <div class="main" id="main">
20 <div id="player" class="player"></div> 20 <div id="player" class="player"></div>
21 <div class="control" id="control"> 21 <div class="control" id="control">
22 - Url(RTMP/HTTP): <input id="url" type="text" class="url" value="rtmp://dev:1935/live/livestream"></input> 22 + Url(RTMP/HTTP): <input id="url" type="text" class="url" value="rtmp://demo:1935/live/livestream"></input>
23 <select class="type" id="type"> 23 <select class="type" id="type">
24 <option value="live" selected>live</option> 24 <option value="live" selected>live</option>
25 <option value="recorded">vod</option> 25 <option value="recorded">vod</option>
不能预览此文件类型
@@ -21,7 +21,7 @@ @@ -21,7 +21,7 @@
21 <script type="text/javascript"> 21 <script type="text/javascript">
22 var o = new RtmpPlayer("player", "RtmpPlayer.swf", 1350, 1050); 22 var o = new RtmpPlayer("player", "RtmpPlayer.swf", 1350, 1050);
23 23
24 - o.setRtmpUrl("rtmp://dev:1935/live/livestream"); 24 + o.setRtmpUrl("rtmp://demo:1935/live/livestream");
25 o.admin = "admin"; 25 o.admin = "admin";
26 o.password = "123456"; 26 o.password = "123456";
27 o.loop = false; 27 o.loop = false;
@@ -111,3 +111,17 @@ void srs_vhost_resolve(std::string& vhost, std::string& app) @@ -111,3 +111,17 @@ void srs_vhost_resolve(std::string& vhost, std::string& app)
111 } 111 }
112 } 112 }
113 } 113 }
  114 +
  115 +void srs_close_stfd(st_netfd_t& stfd)
  116 +{
  117 + if (stfd) {
  118 + int fd = st_netfd_fileno(stfd);
  119 + st_netfd_close(stfd);
  120 + stfd = NULL;
  121 +
  122 + // st does not close it sometimes,
  123 + // close it manually.
  124 + close(fd);
  125 + }
  126 +}
  127 +
@@ -46,6 +46,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -46,6 +46,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
46 #include <stddef.h> 46 #include <stddef.h>
47 #include <sys/types.h> 47 #include <sys/types.h>
48 48
  49 +#include <st.h>
  50 +
49 // generated by configure. 51 // generated by configure.
50 #include <srs_auto_headers.hpp> 52 #include <srs_auto_headers.hpp>
51 53
@@ -102,4 +104,7 @@ extern std::string srs_dns_resolve(std::string host); @@ -102,4 +104,7 @@ extern std::string srs_dns_resolve(std::string host);
102 // app...vhost...request_vhost 104 // app...vhost...request_vhost
103 extern void srs_vhost_resolve(std::string& vhost, std::string& app); 105 extern void srs_vhost_resolve(std::string& vhost, std::string& app);
104 106
  107 +// close the netfd, and close the underlayer fd.
  108 +extern void srs_close_stfd(st_netfd_t& stfd);
  109 +
105 #endif 110 #endif
@@ -26,6 +26,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -26,6 +26,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 #include <arpa/inet.h> 26 #include <arpa/inet.h>
27 #include <stdlib.h> 27 #include <stdlib.h>
28 28
  29 +using namespace std;
  30 +
29 #include <srs_core_error.hpp> 31 #include <srs_core_error.hpp>
30 #include <srs_core_log.hpp> 32 #include <srs_core_log.hpp>
31 #include <srs_core_rtmp.hpp> 33 #include <srs_core_rtmp.hpp>
@@ -55,10 +57,14 @@ SrsClient::SrsClient(SrsServer* srs_server, st_netfd_t client_stfd) @@ -55,10 +57,14 @@ SrsClient::SrsClient(SrsServer* srs_server, st_netfd_t client_stfd)
55 #ifdef SRS_HTTP 57 #ifdef SRS_HTTP
56 http_hooks = new SrsHttpHooks(); 58 http_hooks = new SrsHttpHooks();
57 #endif 59 #endif
  60 +
  61 + config->subscribe(this);
58 } 62 }
59 63
60 SrsClient::~SrsClient() 64 SrsClient::~SrsClient()
61 { 65 {
  66 + config->unsubscribe(this);
  67 +
62 srs_freepa(ip); 68 srs_freepa(ip);
63 srs_freep(req); 69 srs_freep(req);
64 srs_freep(res); 70 srs_freep(res);
@@ -113,6 +119,23 @@ int SrsClient::do_cycle() @@ -113,6 +119,23 @@ int SrsClient::do_cycle()
113 119
114 return ret; 120 return ret;
115 } 121 }
  122 +
  123 +int SrsClient::on_reload_vhost_removed(string vhost)
  124 +{
  125 + int ret = ERROR_SUCCESS;
  126 +
  127 + if (req->vhost != vhost) {
  128 + return ret;
  129 + }
  130 +
  131 + // if the vhost connected is removed, disconnect the client.
  132 + srs_trace("vhost %s removed/disabled, close client url=%s",
  133 + vhost.c_str(), req->get_stream_url().c_str());
  134 +
  135 + srs_close_stfd(stfd);
  136 +
  137 + return ret;
  138 +}
116 139
117 int SrsClient::service_cycle() 140 int SrsClient::service_cycle()
118 { 141 {
@@ -180,11 +203,7 @@ int SrsClient::service_cycle() @@ -180,11 +203,7 @@ int SrsClient::service_cycle()
180 req->strip(); 203 req->strip();
181 srs_trace("identify client success. type=%d, stream_name=%s", type, req->stream.c_str()); 204 srs_trace("identify client success. type=%d, stream_name=%s", type, req->stream.c_str());
182 205
183 - int chunk_size = 4096;  
184 - SrsConfDirective* conf = config->get_chunk_size(req->vhost);  
185 - if (conf && !conf->arg0().empty()) {  
186 - chunk_size = ::atoi(conf->arg0().c_str());  
187 - } 206 + int chunk_size = config->get_chunk_size();
188 if ((ret = rtmp->set_chunk_size(chunk_size)) != ERROR_SUCCESS) { 207 if ((ret = rtmp->set_chunk_size(chunk_size)) != ERROR_SUCCESS) {
189 srs_error("set chunk_size=%d failed. ret=%d", chunk_size, ret); 208 srs_error("set chunk_size=%d failed. ret=%d", chunk_size, ret);
190 return ret; 209 return ret;
@@ -192,7 +211,7 @@ int SrsClient::service_cycle() @@ -192,7 +211,7 @@ int SrsClient::service_cycle()
192 srs_trace("set chunk_size=%d success", chunk_size); 211 srs_trace("set chunk_size=%d success", chunk_size);
193 212
194 // find a source to publish. 213 // find a source to publish.
195 - SrsSource* source = SrsSource::find(req->get_stream_url()); 214 + SrsSource* source = SrsSource::find(req);
196 srs_assert(source != NULL); 215 srs_assert(source != NULL);
197 216
198 // check publish available. 217 // check publish available.
@@ -205,14 +224,9 @@ int SrsClient::service_cycle() @@ -205,14 +224,9 @@ int SrsClient::service_cycle()
205 return ret; 224 return ret;
206 } 225 }
207 226
208 - bool enabled_cache = true;  
209 - conf = config->get_gop_cache(req->vhost);  
210 - if (conf && conf->arg0() == "off") {  
211 - enabled_cache = false;  
212 - }  
213 - source->set_cache(enabled_cache);  
214 - 227 + bool enabled_cache = config->get_gop_cache(req->vhost);
215 srs_info("source found, url=%s, enabled_cache=%d", req->get_stream_url().c_str(), enabled_cache); 228 srs_info("source found, url=%s, enabled_cache=%d", req->get_stream_url().c_str(), enabled_cache);
  229 + source->set_cache(enabled_cache);
216 230
217 switch (type) { 231 switch (type) {
218 case SrsClientPlay: { 232 case SrsClientPlay: {
@@ -31,6 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -31,6 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 #include <srs_core.hpp> 31 #include <srs_core.hpp>
32 32
33 #include <srs_core_conn.hpp> 33 #include <srs_core_conn.hpp>
  34 +#include <srs_core_reload.hpp>
34 35
35 class SrsRtmp; 36 class SrsRtmp;
36 class SrsRequest; 37 class SrsRequest;
@@ -46,7 +47,7 @@ class SrsHttpHooks; @@ -46,7 +47,7 @@ class SrsHttpHooks;
46 /** 47 /**
47 * the client provides the main logic control for RTMP clients. 48 * the client provides the main logic control for RTMP clients.
48 */ 49 */
49 -class SrsClient : public SrsConnection 50 +class SrsClient : public SrsConnection, public ISrsReloadHandler
50 { 51 {
51 private: 52 private:
52 char* ip; 53 char* ip;
@@ -62,6 +63,9 @@ public: @@ -62,6 +63,9 @@ public:
62 virtual ~SrsClient(); 63 virtual ~SrsClient();
63 protected: 64 protected:
64 virtual int do_cycle(); 65 virtual int do_cycle();
  66 +// interface ISrsReloadHandler
  67 +public:
  68 + virtual int on_reload_vhost_removed(std::string vhost);
65 private: 69 private:
66 // when valid and connected to vhost/app, service the client. 70 // when valid and connected to vhost/app, service the client.
67 virtual int service_cycle(); 71 virtual int service_cycle();
@@ -35,6 +35,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -35,6 +35,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 35
36 #include <vector> 36 #include <vector>
37 #include <algorithm> 37 #include <algorithm>
  38 +using namespace std;
38 39
39 #include <srs_core_error.hpp> 40 #include <srs_core_error.hpp>
40 #include <srs_core_log.hpp> 41 #include <srs_core_log.hpp>
@@ -58,37 +59,84 @@ bool is_common_space(char ch) @@ -58,37 +59,84 @@ bool is_common_space(char ch)
58 return (ch == ' ' || ch == '\t' || ch == CR || ch == LF); 59 return (ch == ' ' || ch == '\t' || ch == CR || ch == LF);
59 } 60 }
60 61
61 -#define CONF_BUFFER_SIZE 1024 * 1024 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 +};
62 82
63 SrsFileBuffer::SrsFileBuffer() 83 SrsFileBuffer::SrsFileBuffer()
64 { 84 {
65 - fd = -1;  
66 line = 0; 85 line = 0;
67 86
68 - pos = last = start = new char[CONF_BUFFER_SIZE];  
69 - end = start + CONF_BUFFER_SIZE; 87 + pos = last = start = NULL;
  88 + end = start;
70 } 89 }
71 90
72 SrsFileBuffer::~SrsFileBuffer() 91 SrsFileBuffer::~SrsFileBuffer()
73 { 92 {
74 - if (fd > 0) {  
75 - close(fd);  
76 - }  
77 srs_freepa(start); 93 srs_freepa(start);
78 } 94 }
79 95
80 -int SrsFileBuffer::open(const char* filename) 96 +int SrsFileBuffer::fullfill(const char* filename)
81 { 97 {
82 - assert(fd == -1); 98 + int ret = ERROR_SUCCESS;
  99 +
  100 + int fd = -1;
  101 + int nread = 0;
  102 + int filesize = 0;
83 103
84 if ((fd = ::open(filename, O_RDONLY, 0)) < 0) { 104 if ((fd = ::open(filename, O_RDONLY, 0)) < 0) {
85 - srs_error("open conf file error. errno=%d(%s)", errno, strerror(errno));  
86 - return ERROR_SYSTEM_CONFIG_INVALID; 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;
87 } 125 }
88 126
89 line = 1; 127 line = 1;
90 128
91 - return ERROR_SUCCESS; 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;
92 } 140 }
93 141
94 SrsConfDirective::SrsConfDirective() 142 SrsConfDirective::SrsConfDirective()
@@ -105,7 +153,7 @@ SrsConfDirective::~SrsConfDirective() @@ -105,7 +153,7 @@ SrsConfDirective::~SrsConfDirective()
105 directives.clear(); 153 directives.clear();
106 } 154 }
107 155
108 -std::string SrsConfDirective::arg0() 156 +string SrsConfDirective::arg0()
109 { 157 {
110 if (args.size() > 0) { 158 if (args.size() > 0) {
111 return args.at(0); 159 return args.at(0);
@@ -114,7 +162,7 @@ std::string SrsConfDirective::arg0() @@ -114,7 +162,7 @@ std::string SrsConfDirective::arg0()
114 return ""; 162 return "";
115 } 163 }
116 164
117 -std::string SrsConfDirective::arg1() 165 +string SrsConfDirective::arg1()
118 { 166 {
119 if (args.size() > 1) { 167 if (args.size() > 1) {
120 return args.at(1); 168 return args.at(1);
@@ -123,7 +171,7 @@ std::string SrsConfDirective::arg1() @@ -123,7 +171,7 @@ std::string SrsConfDirective::arg1()
123 return ""; 171 return "";
124 } 172 }
125 173
126 -std::string SrsConfDirective::arg2() 174 +string SrsConfDirective::arg2()
127 { 175 {
128 if (args.size() > 2) { 176 if (args.size() > 2) {
129 return args.at(2); 177 return args.at(2);
@@ -137,7 +185,7 @@ SrsConfDirective* SrsConfDirective::at(int index) @@ -137,7 +185,7 @@ SrsConfDirective* SrsConfDirective::at(int index)
137 return directives.at(index); 185 return directives.at(index);
138 } 186 }
139 187
140 -SrsConfDirective* SrsConfDirective::get(std::string _name) 188 +SrsConfDirective* SrsConfDirective::get(string _name)
141 { 189 {
142 std::vector<SrsConfDirective*>::iterator it; 190 std::vector<SrsConfDirective*>::iterator it;
143 for (it = directives.begin(); it != directives.end(); ++it) { 191 for (it = directives.begin(); it != directives.end(); ++it) {
@@ -150,13 +198,26 @@ SrsConfDirective* SrsConfDirective::get(std::string _name) @@ -150,13 +198,26 @@ SrsConfDirective* SrsConfDirective::get(std::string _name)
150 return NULL; 198 return NULL;
151 } 199 }
152 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 +
153 int SrsConfDirective::parse(const char* filename) 214 int SrsConfDirective::parse(const char* filename)
154 { 215 {
155 int ret = ERROR_SUCCESS; 216 int ret = ERROR_SUCCESS;
156 217
157 SrsFileBuffer buffer; 218 SrsFileBuffer buffer;
158 219
159 - if ((ret = buffer.open(filename)) != ERROR_SUCCESS) { 220 + if ((ret = buffer.fullfill(filename)) != ERROR_SUCCESS) {
160 return ret; 221 return ret;
161 } 222 }
162 223
@@ -169,7 +230,7 @@ int SrsConfDirective::parse_conf(SrsFileBuffer* buffer, SrsDirectiveType type) @@ -169,7 +230,7 @@ int SrsConfDirective::parse_conf(SrsFileBuffer* buffer, SrsDirectiveType type)
169 int ret = ERROR_SUCCESS; 230 int ret = ERROR_SUCCESS;
170 231
171 while (true) { 232 while (true) {
172 - std::vector<std::string> args; 233 + std::vector<string> args;
173 ret = read_token(buffer, args); 234 ret = read_token(buffer, args);
174 235
175 /** 236 /**
@@ -224,7 +285,7 @@ int SrsConfDirective::parse_conf(SrsFileBuffer* buffer, SrsDirectiveType type) @@ -224,7 +285,7 @@ int SrsConfDirective::parse_conf(SrsFileBuffer* buffer, SrsDirectiveType type)
224 } 285 }
225 286
226 // see: ngx_conf_read_token 287 // see: ngx_conf_read_token
227 -int SrsConfDirective::read_token(SrsFileBuffer* buffer, std::vector<std::string>& args) 288 +int SrsConfDirective::read_token(SrsFileBuffer* buffer, std::vector<string>& args)
228 { 289 {
229 int ret = ERROR_SUCCESS; 290 int ret = ERROR_SUCCESS;
230 291
@@ -240,11 +301,15 @@ int SrsConfDirective::read_token(SrsFileBuffer* buffer, std::vector<std::string> @@ -240,11 +301,15 @@ int SrsConfDirective::read_token(SrsFileBuffer* buffer, std::vector<std::string>
240 bool last_space = true; 301 bool last_space = true;
241 302
242 while (true) { 303 while (true) {
243 - if ((ret = refill_buffer(buffer, d_quoted, s_quoted, startline, pstart)) != ERROR_SUCCESS) { 304 + if (buffer->empty()) {
  305 + ret = ERROR_SYSTEM_CONFIG_EOF;
  306 +
244 if (!args.empty() || !last_space) { 307 if (!args.empty() || !last_space) {
245 srs_error("line %d: unexpected end of file, expecting ; or \"}\"", buffer->line); 308 srs_error("line %d: unexpected end of file, expecting ; or \"}\"", buffer->line);
246 return ERROR_SYSTEM_CONFIG_INVALID; 309 return ERROR_SYSTEM_CONFIG_INVALID;
247 } 310 }
  311 + srs_error("end of file. ret=%d", ret);
  312 +
248 return ret; 313 return ret;
249 } 314 }
250 315
@@ -344,7 +409,7 @@ int SrsConfDirective::read_token(SrsFileBuffer* buffer, std::vector<std::string> @@ -344,7 +409,7 @@ int SrsConfDirective::read_token(SrsFileBuffer* buffer, std::vector<std::string>
344 memcpy(word, pstart, len); 409 memcpy(word, pstart, len);
345 word[len - 1] = 0; 410 word[len - 1] = 0;
346 411
347 - std::string word_str = word; 412 + string word_str = word;
348 if (!word_str.empty()) { 413 if (!word_str.empty()) {
349 args.push_back(word_str); 414 args.push_back(word_str);
350 } 415 }
@@ -363,59 +428,6 @@ int SrsConfDirective::read_token(SrsFileBuffer* buffer, std::vector<std::string> @@ -363,59 +428,6 @@ int SrsConfDirective::read_token(SrsFileBuffer* buffer, std::vector<std::string>
363 return ret; 428 return ret;
364 } 429 }
365 430
366 -int SrsConfDirective::refill_buffer(SrsFileBuffer* buffer, bool d_quoted, bool s_quoted, int startline, char*& pstart)  
367 -{  
368 - int ret = ERROR_SUCCESS;  
369 -  
370 - if (buffer->pos < buffer->last) {  
371 - return ret;  
372 - }  
373 -  
374 - int size = FILE_SIZE(buffer->fd) - FILE_OFFSET(buffer->fd);  
375 - if (size > CONF_BUFFER_SIZE) {  
376 - ret = ERROR_SYSTEM_CONFIG_TOO_LARGE;  
377 - srs_error("config file too large, max=%d, actual=%d, ret=%d",  
378 - CONF_BUFFER_SIZE, size, ret);  
379 - return ret;  
380 - }  
381 -  
382 - if (size <= 0) {  
383 - return ERROR_SYSTEM_CONFIG_EOF;  
384 - }  
385 -  
386 - int len = buffer->pos - buffer->start;  
387 - if (len >= CONF_BUFFER_SIZE) {  
388 - buffer->line = startline;  
389 -  
390 - if (!d_quoted && !s_quoted) {  
391 - srs_error("line %d: too long parameter \"%*s...\" started",  
392 - buffer->line, 10, buffer->start);  
393 -  
394 - } else {  
395 - srs_error("line %d: too long parameter, "  
396 - "probably missing terminating '%c' character", buffer->line, d_quoted? '"':'\'');  
397 - }  
398 - return ERROR_SYSTEM_CONFIG_INVALID;  
399 - }  
400 -  
401 - if (len) {  
402 - memmove(buffer->start, pstart, len);  
403 - }  
404 -  
405 - size = srs_min(size, buffer->end - (buffer->start + len));  
406 - int n = read(buffer->fd, buffer->start + len, size);  
407 - if (n != size) {  
408 - srs_error("read file read error. expect %d, actual %d bytes.", size, n);  
409 - return ERROR_SYSTEM_CONFIG_INVALID;  
410 - }  
411 -  
412 - buffer->pos = buffer->start + len;  
413 - buffer->last = buffer->pos + n;  
414 - pstart = buffer->start;  
415 -  
416 - return ret;  
417 -}  
418 -  
419 SrsConfig* config = new SrsConfig(); 431 SrsConfig* config = new SrsConfig();
420 432
421 SrsConfig::SrsConfig() 433 SrsConfig::SrsConfig()
@@ -453,12 +465,12 @@ int SrsConfig::reload() @@ -453,12 +465,12 @@ int SrsConfig::reload()
453 conf.root = NULL; 465 conf.root = NULL;
454 466
455 // merge config. 467 // merge config.
456 - std::vector<SrsReloadHandler*>::iterator it; 468 + std::vector<ISrsReloadHandler*>::iterator it;
457 469
458 // merge config: listen 470 // merge config: listen
459 if (!srs_directive_equals(root->get("listen"), old_root->get("listen"))) { 471 if (!srs_directive_equals(root->get("listen"), old_root->get("listen"))) {
460 for (it = subscribes.begin(); it != subscribes.end(); ++it) { 472 for (it = subscribes.begin(); it != subscribes.end(); ++it) {
461 - SrsReloadHandler* subscribe = *it; 473 + ISrsReloadHandler* subscribe = *it;
462 if ((ret = subscribe->on_reload_listen()) != ERROR_SUCCESS) { 474 if ((ret = subscribe->on_reload_listen()) != ERROR_SUCCESS) {
463 srs_error("notify subscribes reload listen failed. ret=%d", ret); 475 srs_error("notify subscribes reload listen failed. ret=%d", ret);
464 return ret; 476 return ret;
@@ -466,10 +478,11 @@ int SrsConfig::reload() @@ -466,10 +478,11 @@ int SrsConfig::reload()
466 } 478 }
467 srs_trace("reload listen success."); 479 srs_trace("reload listen success.");
468 } 480 }
  481 +
469 // merge config: pithy_print 482 // merge config: pithy_print
470 if (!srs_directive_equals(root->get("pithy_print"), old_root->get("pithy_print"))) { 483 if (!srs_directive_equals(root->get("pithy_print"), old_root->get("pithy_print"))) {
471 for (it = subscribes.begin(); it != subscribes.end(); ++it) { 484 for (it = subscribes.begin(); it != subscribes.end(); ++it) {
472 - SrsReloadHandler* subscribe = *it; 485 + ISrsReloadHandler* subscribe = *it;
473 if ((ret = subscribe->on_reload_pithy_print()) != ERROR_SUCCESS) { 486 if ((ret = subscribe->on_reload_pithy_print()) != ERROR_SUCCESS) {
474 srs_error("notify subscribes pithy_print listen failed. ret=%d", ret); 487 srs_error("notify subscribes pithy_print listen failed. ret=%d", ret);
475 return ret; 488 return ret;
@@ -477,15 +490,121 @@ int SrsConfig::reload() @@ -477,15 +490,121 @@ int SrsConfig::reload()
477 } 490 }
478 srs_trace("reload pithy_print success."); 491 srs_trace("reload pithy_print success.");
479 } 492 }
480 -  
481 - // TODO: suppor reload hls/forward/ffmpeg/http 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 + }
482 601
483 return ret; 602 return ret;
484 } 603 }
485 604
486 -void SrsConfig::subscribe(SrsReloadHandler* handler) 605 +void SrsConfig::subscribe(ISrsReloadHandler* handler)
487 { 606 {
488 - std::vector<SrsReloadHandler*>::iterator it; 607 + std::vector<ISrsReloadHandler*>::iterator it;
489 608
490 it = std::find(subscribes.begin(), subscribes.end(), handler); 609 it = std::find(subscribes.begin(), subscribes.end(), handler);
491 if (it != subscribes.end()) { 610 if (it != subscribes.end()) {
@@ -495,9 +614,9 @@ void SrsConfig::subscribe(SrsReloadHandler* handler) @@ -495,9 +614,9 @@ void SrsConfig::subscribe(SrsReloadHandler* handler)
495 subscribes.push_back(handler); 614 subscribes.push_back(handler);
496 } 615 }
497 616
498 -void SrsConfig::unsubscribe(SrsReloadHandler* handler) 617 +void SrsConfig::unsubscribe(ISrsReloadHandler* handler)
499 { 618 {
500 - std::vector<SrsReloadHandler*>::iterator it; 619 + std::vector<ISrsReloadHandler*>::iterator it;
501 620
502 it = std::find(subscribes.begin(), subscribes.end(), handler); 621 it = std::find(subscribes.begin(), subscribes.end(), handler);
503 if (it == subscribes.end()) { 622 if (it == subscribes.end()) {
@@ -539,7 +658,102 @@ int SrsConfig::parse_options(int argc, char** argv) @@ -539,7 +658,102 @@ int SrsConfig::parse_options(int argc, char** argv)
539 return parse_file(config_file.c_str()); 658 return parse_file(config_file.c_str());
540 } 659 }
541 660
542 -SrsConfDirective* SrsConfig::get_vhost(const std::string& vhost) 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 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)
543 { 757 {
544 srs_assert(root); 758 srs_assert(root);
545 759
@@ -562,7 +776,7 @@ SrsConfDirective* SrsConfig::get_vhost(const std::string& vhost) @@ -562,7 +776,7 @@ SrsConfDirective* SrsConfig::get_vhost(const std::string& vhost)
562 return NULL; 776 return NULL;
563 } 777 }
564 778
565 -SrsConfDirective* SrsConfig::get_vhost_on_connect(const std::string &vhost) 779 +SrsConfDirective* SrsConfig::get_vhost_on_connect(string vhost)
566 { 780 {
567 SrsConfDirective* conf = get_vhost(vhost); 781 SrsConfDirective* conf = get_vhost(vhost);
568 782
@@ -583,7 +797,7 @@ SrsConfDirective* SrsConfig::get_vhost_on_connect(const std::string &vhost) @@ -583,7 +797,7 @@ SrsConfDirective* SrsConfig::get_vhost_on_connect(const std::string &vhost)
583 return conf->get("on_connect"); 797 return conf->get("on_connect");
584 } 798 }
585 799
586 -SrsConfDirective* SrsConfig::get_vhost_on_close(const std::string &vhost) 800 +SrsConfDirective* SrsConfig::get_vhost_on_close(string vhost)
587 { 801 {
588 SrsConfDirective* conf = get_vhost(vhost); 802 SrsConfDirective* conf = get_vhost(vhost);
589 803
@@ -604,7 +818,7 @@ SrsConfDirective* SrsConfig::get_vhost_on_close(const std::string &vhost) @@ -604,7 +818,7 @@ SrsConfDirective* SrsConfig::get_vhost_on_close(const std::string &vhost)
604 return conf->get("on_close"); 818 return conf->get("on_close");
605 } 819 }
606 820
607 -SrsConfDirective* SrsConfig::get_vhost_on_publish(const std::string &vhost) 821 +SrsConfDirective* SrsConfig::get_vhost_on_publish(string vhost)
608 { 822 {
609 SrsConfDirective* conf = get_vhost(vhost); 823 SrsConfDirective* conf = get_vhost(vhost);
610 824
@@ -625,7 +839,7 @@ SrsConfDirective* SrsConfig::get_vhost_on_publish(const std::string &vhost) @@ -625,7 +839,7 @@ SrsConfDirective* SrsConfig::get_vhost_on_publish(const std::string &vhost)
625 return conf->get("on_publish"); 839 return conf->get("on_publish");
626 } 840 }
627 841
628 -SrsConfDirective* SrsConfig::get_vhost_on_unpublish(const std::string &vhost) 842 +SrsConfDirective* SrsConfig::get_vhost_on_unpublish(string vhost)
629 { 843 {
630 SrsConfDirective* conf = get_vhost(vhost); 844 SrsConfDirective* conf = get_vhost(vhost);
631 845
@@ -646,7 +860,7 @@ SrsConfDirective* SrsConfig::get_vhost_on_unpublish(const std::string &vhost) @@ -646,7 +860,7 @@ SrsConfDirective* SrsConfig::get_vhost_on_unpublish(const std::string &vhost)
646 return conf->get("on_unpublish"); 860 return conf->get("on_unpublish");
647 } 861 }
648 862
649 -SrsConfDirective* SrsConfig::get_vhost_on_play(const std::string &vhost) 863 +SrsConfDirective* SrsConfig::get_vhost_on_play(string vhost)
650 { 864 {
651 SrsConfDirective* conf = get_vhost(vhost); 865 SrsConfDirective* conf = get_vhost(vhost);
652 866
@@ -667,7 +881,7 @@ SrsConfDirective* SrsConfig::get_vhost_on_play(const std::string &vhost) @@ -667,7 +881,7 @@ SrsConfDirective* SrsConfig::get_vhost_on_play(const std::string &vhost)
667 return conf->get("on_play"); 881 return conf->get("on_play");
668 } 882 }
669 883
670 -SrsConfDirective* SrsConfig::get_vhost_on_stop(const std::string &vhost) 884 +SrsConfDirective* SrsConfig::get_vhost_on_stop(string vhost)
671 { 885 {
672 SrsConfDirective* conf = get_vhost(vhost); 886 SrsConfDirective* conf = get_vhost(vhost);
673 887
@@ -688,15 +902,20 @@ SrsConfDirective* SrsConfig::get_vhost_on_stop(const std::string &vhost) @@ -688,15 +902,20 @@ SrsConfDirective* SrsConfig::get_vhost_on_stop(const std::string &vhost)
688 return conf->get("on_stop"); 902 return conf->get("on_stop");
689 } 903 }
690 904
691 -bool SrsConfig::get_vhost_enabled(const std::string &vhost) 905 +bool SrsConfig::get_vhost_enabled(string vhost)
692 { 906 {
693 SrsConfDirective* vhost_conf = get_vhost(vhost); 907 SrsConfDirective* vhost_conf = get_vhost(vhost);
  908 +
  909 + return get_vhost_enabled(vhost_conf);
  910 +}
694 911
695 - if (!vhost_conf) {  
696 - return true; 912 +bool SrsConfig::get_vhost_enabled(SrsConfDirective* vhost)
  913 +{
  914 + if (!vhost) {
  915 + return false;
697 } 916 }
698 917
699 - SrsConfDirective* conf = vhost_conf->get("enabled"); 918 + SrsConfDirective* conf = vhost->get("enabled");
700 if (!conf) { 919 if (!conf) {
701 return true; 920 return true;
702 } 921 }
@@ -708,7 +927,7 @@ bool SrsConfig::get_vhost_enabled(const std::string &vhost) @@ -708,7 +927,7 @@ bool SrsConfig::get_vhost_enabled(const std::string &vhost)
708 return true; 927 return true;
709 } 928 }
710 929
711 -SrsConfDirective* SrsConfig::get_transcode(const std::string &vhost, const std::string &scope) 930 +SrsConfDirective* SrsConfig::get_transcode(string vhost, string scope)
712 { 931 {
713 SrsConfDirective* conf = get_vhost(vhost); 932 SrsConfDirective* conf = get_vhost(vhost);
714 933
@@ -742,7 +961,7 @@ bool SrsConfig::get_transcode_enabled(SrsConfDirective* transcode) @@ -742,7 +961,7 @@ bool SrsConfig::get_transcode_enabled(SrsConfDirective* transcode)
742 return true; 961 return true;
743 } 962 }
744 963
745 -std::string SrsConfig::get_transcode_ffmpeg(SrsConfDirective* transcode) 964 +string SrsConfig::get_transcode_ffmpeg(SrsConfDirective* transcode)
746 { 965 {
747 if (!transcode) { 966 if (!transcode) {
748 return ""; 967 return "";
@@ -787,7 +1006,7 @@ bool SrsConfig::get_engine_enabled(SrsConfDirective* engine) @@ -787,7 +1006,7 @@ bool SrsConfig::get_engine_enabled(SrsConfDirective* engine)
787 return true; 1006 return true;
788 } 1007 }
789 1008
790 -std::string SrsConfig::get_engine_vcodec(SrsConfDirective* engine) 1009 +string SrsConfig::get_engine_vcodec(SrsConfDirective* engine)
791 { 1010 {
792 if (!engine) { 1011 if (!engine) {
793 return ""; 1012 return "";
@@ -871,7 +1090,7 @@ int SrsConfig::get_engine_vthreads(SrsConfDirective* engine) @@ -871,7 +1090,7 @@ int SrsConfig::get_engine_vthreads(SrsConfDirective* engine)
871 return ::atoi(conf->arg0().c_str()); 1090 return ::atoi(conf->arg0().c_str());
872 } 1091 }
873 1092
874 -std::string SrsConfig::get_engine_vprofile(SrsConfDirective* engine) 1093 +string SrsConfig::get_engine_vprofile(SrsConfDirective* engine)
875 { 1094 {
876 if (!engine) { 1095 if (!engine) {
877 return ""; 1096 return "";
@@ -885,7 +1104,7 @@ std::string SrsConfig::get_engine_vprofile(SrsConfDirective* engine) @@ -885,7 +1104,7 @@ std::string SrsConfig::get_engine_vprofile(SrsConfDirective* engine)
885 return conf->arg0(); 1104 return conf->arg0();
886 } 1105 }
887 1106
888 -std::string SrsConfig::get_engine_vpreset(SrsConfDirective* engine) 1107 +string SrsConfig::get_engine_vpreset(SrsConfDirective* engine)
889 { 1108 {
890 if (!engine) { 1109 if (!engine) {
891 return ""; 1110 return "";
@@ -899,7 +1118,7 @@ std::string SrsConfig::get_engine_vpreset(SrsConfDirective* engine) @@ -899,7 +1118,7 @@ std::string SrsConfig::get_engine_vpreset(SrsConfDirective* engine)
899 return conf->arg0(); 1118 return conf->arg0();
900 } 1119 }
901 1120
902 -void SrsConfig::get_engine_vparams(SrsConfDirective* engine, std::vector<std::string>& vparams) 1121 +void SrsConfig::get_engine_vparams(SrsConfDirective* engine, std::vector<string>& vparams)
903 { 1122 {
904 if (!engine) { 1123 if (!engine) {
905 return; 1124 return;
@@ -921,7 +1140,7 @@ void SrsConfig::get_engine_vparams(SrsConfDirective* engine, std::vector<std::st @@ -921,7 +1140,7 @@ void SrsConfig::get_engine_vparams(SrsConfDirective* engine, std::vector<std::st
921 } 1140 }
922 } 1141 }
923 1142
924 -void SrsConfig::get_engine_vfilter(SrsConfDirective* engine, std::vector<std::string>& vfilter) 1143 +void SrsConfig::get_engine_vfilter(SrsConfDirective* engine, std::vector<string>& vfilter)
925 { 1144 {
926 if (!engine) { 1145 if (!engine) {
927 return; 1146 return;
@@ -943,7 +1162,7 @@ void SrsConfig::get_engine_vfilter(SrsConfDirective* engine, std::vector<std::st @@ -943,7 +1162,7 @@ void SrsConfig::get_engine_vfilter(SrsConfDirective* engine, std::vector<std::st
943 } 1162 }
944 } 1163 }
945 1164
946 -std::string SrsConfig::get_engine_acodec(SrsConfDirective* engine) 1165 +string SrsConfig::get_engine_acodec(SrsConfDirective* engine)
947 { 1166 {
948 if (!engine) { 1167 if (!engine) {
949 return ""; 1168 return "";
@@ -999,7 +1218,7 @@ int SrsConfig::get_engine_achannels(SrsConfDirective* engine) @@ -999,7 +1218,7 @@ int SrsConfig::get_engine_achannels(SrsConfDirective* engine)
999 return ::atoi(conf->arg0().c_str()); 1218 return ::atoi(conf->arg0().c_str());
1000 } 1219 }
1001 1220
1002 -void SrsConfig::get_engine_aparams(SrsConfDirective* engine, std::vector<std::string>& aparams) 1221 +void SrsConfig::get_engine_aparams(SrsConfDirective* engine, std::vector<string>& aparams)
1003 { 1222 {
1004 if (!engine) { 1223 if (!engine) {
1005 return; 1224 return;
@@ -1021,7 +1240,7 @@ void SrsConfig::get_engine_aparams(SrsConfDirective* engine, std::vector<std::st @@ -1021,7 +1240,7 @@ void SrsConfig::get_engine_aparams(SrsConfDirective* engine, std::vector<std::st
1021 } 1240 }
1022 } 1241 }
1023 1242
1024 -std::string SrsConfig::get_engine_output(SrsConfDirective* engine) 1243 +string SrsConfig::get_engine_output(SrsConfDirective* engine)
1025 { 1244 {
1026 if (!engine) { 1245 if (!engine) {
1027 return ""; 1246 return "";
@@ -1035,7 +1254,7 @@ std::string SrsConfig::get_engine_output(SrsConfDirective* engine) @@ -1035,7 +1254,7 @@ std::string SrsConfig::get_engine_output(SrsConfDirective* engine)
1035 return conf->arg0(); 1254 return conf->arg0();
1036 } 1255 }
1037 1256
1038 -std::string SrsConfig::get_log_dir() 1257 +string SrsConfig::get_log_dir()
1039 { 1258 {
1040 srs_assert(root); 1259 srs_assert(root);
1041 1260
@@ -1059,18 +1278,39 @@ int SrsConfig::get_max_connections() @@ -1059,18 +1278,39 @@ int SrsConfig::get_max_connections()
1059 return ::atoi(conf->arg0().c_str()); 1278 return ::atoi(conf->arg0().c_str());
1060 } 1279 }
1061 1280
1062 -SrsConfDirective* SrsConfig::get_gop_cache(const std::string &vhost) 1281 +bool SrsConfig::get_gop_cache(string vhost)
1063 { 1282 {
1064 SrsConfDirective* conf = get_vhost(vhost); 1283 SrsConfDirective* conf = get_vhost(vhost);
1065 1284
1066 if (!conf) { 1285 if (!conf) {
1067 - return NULL; 1286 + return true;
  1287 + }
  1288 +
  1289 + conf = conf->get("gop_cache");
  1290 + if (conf && conf->arg0() == "off") {
  1291 + return false;
1068 } 1292 }
1069 1293
1070 - return conf->get("gop_cache"); 1294 + return true;
1071 } 1295 }
1072 1296
1073 -SrsConfDirective* SrsConfig::get_forward(const std::string &vhost) 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)
1074 { 1314 {
1075 SrsConfDirective* conf = get_vhost(vhost); 1315 SrsConfDirective* conf = get_vhost(vhost);
1076 1316
@@ -1081,7 +1321,7 @@ SrsConfDirective* SrsConfig::get_forward(const std::string &vhost) @@ -1081,7 +1321,7 @@ SrsConfDirective* SrsConfig::get_forward(const std::string &vhost)
1081 return conf->get("forward"); 1321 return conf->get("forward");
1082 } 1322 }
1083 1323
1084 -SrsConfDirective* SrsConfig::get_hls(const std::string &vhost) 1324 +SrsConfDirective* SrsConfig::get_hls(string vhost)
1085 { 1325 {
1086 SrsConfDirective* conf = get_vhost(vhost); 1326 SrsConfDirective* conf = get_vhost(vhost);
1087 1327
@@ -1092,55 +1332,79 @@ SrsConfDirective* SrsConfig::get_hls(const std::string &vhost) @@ -1092,55 +1332,79 @@ SrsConfDirective* SrsConfig::get_hls(const std::string &vhost)
1092 return conf->get("hls"); 1332 return conf->get("hls");
1093 } 1333 }
1094 1334
1095 -bool SrsConfig::get_hls_enabled(const std::string &vhost) 1335 +bool SrsConfig::get_hls_enabled(string vhost)
1096 { 1336 {
1097 SrsConfDirective* hls = get_hls(vhost); 1337 SrsConfDirective* hls = get_hls(vhost);
1098 1338
1099 if (!hls) { 1339 if (!hls) {
1100 - return true; 1340 + return false;
1101 } 1341 }
1102 1342
1103 - if (hls->arg0() == "off") { 1343 + SrsConfDirective* conf = hls->get("enabled");
  1344 +
  1345 + if (!conf) {
1104 return false; 1346 return false;
1105 } 1347 }
1106 1348
1107 - return true; 1349 + if (conf->arg0() == "on") {
  1350 + return true;
  1351 + }
  1352 +
  1353 + return false;
1108 } 1354 }
1109 1355
1110 -SrsConfDirective* SrsConfig::get_hls_path(const std::string &vhost) 1356 +string SrsConfig::get_hls_path(string vhost)
1111 { 1357 {
1112 - SrsConfDirective* conf = get_vhost(vhost);  
1113 -  
1114 - if (!conf) {  
1115 - return NULL; 1358 + SrsConfDirective* hls = get_hls(vhost);
  1359 +
  1360 + if (!hls) {
  1361 + return SRS_CONF_DEFAULT_HLS_PATH;
1116 } 1362 }
1117 1363
1118 - return conf->get("hls_path"); 1364 + SrsConfDirective* conf = hls->get("hls_path");
  1365 +
  1366 + if (!conf) {
  1367 + return SRS_CONF_DEFAULT_HLS_PATH;
  1368 + }
  1369 +
  1370 + return conf->arg0();
1119 } 1371 }
1120 1372
1121 -SrsConfDirective* SrsConfig::get_hls_fragment(const std::string &vhost) 1373 +double SrsConfig::get_hls_fragment(string vhost)
1122 { 1374 {
1123 - SrsConfDirective* conf = get_vhost(vhost);  
1124 -  
1125 - if (!conf) {  
1126 - return NULL; 1375 + SrsConfDirective* hls = get_hls(vhost);
  1376 +
  1377 + if (!hls) {
  1378 + return SRS_CONF_DEFAULT_HLS_FRAGMENT;
1127 } 1379 }
1128 1380
1129 - return conf->get("hls_fragment"); 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());
1130 } 1388 }
1131 1389
1132 -SrsConfDirective* SrsConfig::get_hls_window(const std::string &vhost) 1390 +double SrsConfig::get_hls_window(string vhost)
1133 { 1391 {
1134 - SrsConfDirective* conf = get_vhost(vhost);  
1135 -  
1136 - if (!conf) {  
1137 - return NULL; 1392 + SrsConfDirective* hls = get_hls(vhost);
  1393 +
  1394 + if (!hls) {
  1395 + return SRS_CONF_DEFAULT_HLS_WINDOW;
1138 } 1396 }
1139 1397
1140 - return conf->get("hls_window"); 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());
1141 } 1405 }
1142 1406
1143 -SrsConfDirective* SrsConfig::get_refer(const std::string &vhost) 1407 +SrsConfDirective* SrsConfig::get_refer(string vhost)
1144 { 1408 {
1145 SrsConfDirective* conf = get_vhost(vhost); 1409 SrsConfDirective* conf = get_vhost(vhost);
1146 1410
@@ -1151,7 +1415,7 @@ SrsConfDirective* SrsConfig::get_refer(const std::string &vhost) @@ -1151,7 +1415,7 @@ SrsConfDirective* SrsConfig::get_refer(const std::string &vhost)
1151 return conf->get("refer"); 1415 return conf->get("refer");
1152 } 1416 }
1153 1417
1154 -SrsConfDirective* SrsConfig::get_refer_play(const std::string &vhost) 1418 +SrsConfDirective* SrsConfig::get_refer_play(string vhost)
1155 { 1419 {
1156 SrsConfDirective* conf = get_vhost(vhost); 1420 SrsConfDirective* conf = get_vhost(vhost);
1157 1421
@@ -1162,7 +1426,7 @@ SrsConfDirective* SrsConfig::get_refer_play(const std::string &vhost) @@ -1162,7 +1426,7 @@ SrsConfDirective* SrsConfig::get_refer_play(const std::string &vhost)
1162 return conf->get("refer_play"); 1426 return conf->get("refer_play");
1163 } 1427 }
1164 1428
1165 -SrsConfDirective* SrsConfig::get_refer_publish(const std::string &vhost) 1429 +SrsConfDirective* SrsConfig::get_refer_publish(string vhost)
1166 { 1430 {
1167 SrsConfDirective* conf = get_vhost(vhost); 1431 SrsConfDirective* conf = get_vhost(vhost);
1168 1432
@@ -1178,65 +1442,59 @@ SrsConfDirective* SrsConfig::get_listen() @@ -1178,65 +1442,59 @@ SrsConfDirective* SrsConfig::get_listen()
1178 return root->get("listen"); 1442 return root->get("listen");
1179 } 1443 }
1180 1444
1181 -SrsConfDirective* SrsConfig::get_chunk_size(const std::string &vhost) 1445 +int SrsConfig::get_chunk_size()
1182 { 1446 {
1183 - SrsConfDirective* conf = get_vhost(vhost);  
1184 -  
1185 - if (!conf) {  
1186 - return NULL;  
1187 - }  
1188 -  
1189 - return conf->get("chunk_size"); 1447 + SrsConfDirective* conf = root->get("chunk_size");
  1448 + if (!conf) {
  1449 + return SRS_CONF_DEFAULT_CHUNK_SIZE;
  1450 + }
  1451 +
  1452 + return ::atoi(conf->arg0().c_str());
1190 } 1453 }
1191 1454
1192 -SrsConfDirective* SrsConfig::get_pithy_print_publish() 1455 +int SrsConfig::get_pithy_print_publish()
1193 { 1456 {
1194 SrsConfDirective* pithy = root->get("pithy_print"); 1457 SrsConfDirective* pithy = root->get("pithy_print");
1195 if (!pithy) { 1458 if (!pithy) {
1196 - return NULL; 1459 + return SRS_STAGE_PUBLISH_USER_INTERVAL_MS;
1197 } 1460 }
1198 1461
1199 - return pithy->get("publish");  
1200 -}  
1201 -  
1202 -SrsConfDirective* SrsConfig::get_pithy_print_forwarder()  
1203 -{  
1204 - SrsConfDirective* pithy = root->get("pithy_print"); 1462 + pithy = pithy->get("publish");
1205 if (!pithy) { 1463 if (!pithy) {
1206 - return NULL; 1464 + return SRS_STAGE_PUBLISH_USER_INTERVAL_MS;
1207 } 1465 }
1208 1466
1209 - return pithy->get("forwarder"); 1467 + return ::atoi(pithy->arg0().c_str());
1210 } 1468 }
1211 1469
1212 -SrsConfDirective* SrsConfig::get_pithy_print_hls() 1470 +int SrsConfig::get_pithy_print_forwarder()
1213 { 1471 {
1214 SrsConfDirective* pithy = root->get("pithy_print"); 1472 SrsConfDirective* pithy = root->get("pithy_print");
1215 if (!pithy) { 1473 if (!pithy) {
1216 - return NULL; 1474 + return SRS_STAGE_FORWARDER_INTERVAL_MS;
1217 } 1475 }
1218 1476
1219 - return pithy->get("hls");  
1220 -}  
1221 -  
1222 -SrsConfDirective* SrsConfig::get_pithy_print_encoder()  
1223 -{  
1224 - SrsConfDirective* pithy = root->get("encoder"); 1477 + pithy = pithy->get("forwarder");
1225 if (!pithy) { 1478 if (!pithy) {
1226 - return NULL; 1479 + return SRS_STAGE_FORWARDER_INTERVAL_MS;
1227 } 1480 }
1228 1481
1229 - return pithy->get("forwarder"); 1482 + return ::atoi(pithy->arg0().c_str());
1230 } 1483 }
1231 1484
1232 -SrsConfDirective* SrsConfig::get_pithy_print_play() 1485 +int SrsConfig::get_pithy_print_hls()
1233 { 1486 {
1234 SrsConfDirective* pithy = root->get("pithy_print"); 1487 SrsConfDirective* pithy = root->get("pithy_print");
1235 if (!pithy) { 1488 if (!pithy) {
1236 - return NULL; 1489 + return SRS_STAGE_HLS_INTERVAL_MS;
  1490 + }
  1491 +
  1492 + pithy = pithy->get("hls");
  1493 + if (!pithy) {
  1494 + return SRS_STAGE_HLS_INTERVAL_MS;
1237 } 1495 }
1238 1496
1239 - return pithy->get("play"); 1497 + return ::atoi(pithy->arg0().c_str());
1240 } 1498 }
1241 1499
1242 bool SrsConfig::get_bw_check_enabled(const std::string &vhost, const std::string &key) 1500 bool SrsConfig::get_bw_check_enabled(const std::string &vhost, const std::string &key)
@@ -1295,104 +1553,43 @@ void SrsConfig::get_bw_check_settings(const std::string &vhost, int64_t &interva @@ -1295,104 +1553,43 @@ void SrsConfig::get_bw_check_settings(const std::string &vhost, int64_t &interva
1295 pub_kbps = ::atoi(pub_conf->arg0().c_str()); 1553 pub_kbps = ::atoi(pub_conf->arg0().c_str());
1296 } 1554 }
1297 1555
1298 -int SrsConfig::parse_file(const char* filename) 1556 +int SrsConfig::get_pithy_print_encoder()
1299 { 1557 {
1300 - int ret = ERROR_SUCCESS;  
1301 -  
1302 - config_file = filename;  
1303 -  
1304 - if (config_file.empty()) {  
1305 - return ERROR_SYSTEM_CONFIG_INVALID;  
1306 - }  
1307 -  
1308 - if ((ret = root->parse(config_file.c_str())) != ERROR_SUCCESS) {  
1309 - return ret; 1558 + SrsConfDirective* pithy = root->get("encoder");
  1559 + if (!pithy) {
  1560 + return SRS_STAGE_ENCODER_INTERVAL_MS;
1310 } 1561 }
1311 1562
1312 - SrsConfDirective* conf = NULL;  
1313 - if ((conf = get_listen()) == NULL || conf->args.size() == 0) {  
1314 - ret = ERROR_SYSTEM_CONFIG_INVALID;  
1315 - srs_error("line %d: conf error, "  
1316 - "directive \"listen\" is empty, ret=%d", (conf? conf->conf_line:0), ret);  
1317 - return ret; 1563 + pithy = pithy->get("forwarder");
  1564 + if (!pithy) {
  1565 + return SRS_STAGE_ENCODER_INTERVAL_MS;
1318 } 1566 }
1319 - // TODO: check the hls.  
1320 - // TODO: check other config.  
1321 - // TODO: check hls.  
1322 - // TODO: check ssl.  
1323 - // TODO: check ffmpeg.  
1324 - // TODO: check http.  
1325 1567
1326 - return ret; 1568 + return ::atoi(pithy->arg0().c_str());
1327 } 1569 }
1328 1570
1329 -int SrsConfig::parse_argv(int& i, char** argv) 1571 +int SrsConfig::get_pithy_print_play()
1330 { 1572 {
1331 - int ret = ERROR_SUCCESS;  
1332 -  
1333 - char* p = argv[i];  
1334 -  
1335 - if (*p++ != '-') {  
1336 - ret = ERROR_SYSTEM_CONFIG_INVALID;  
1337 - srs_error("invalid options(index=%d, value=%s), "  
1338 - "must starts with -, see help: %s -h, ret=%d", i, argv[i], argv[0], ret);  
1339 - return ret; 1573 + SrsConfDirective* pithy = root->get("pithy_print");
  1574 + if (!pithy) {
  1575 + return SRS_STAGE_PLAY_USER_INTERVAL_MS;
1340 } 1576 }
1341 1577
1342 - while (*p) {  
1343 - switch (*p++) {  
1344 - case '?':  
1345 - case 'h':  
1346 - show_help = true;  
1347 - break;  
1348 - case 'v':  
1349 - case 'V':  
1350 - show_version = true;  
1351 - break;  
1352 - case 'c':  
1353 - if (*p) {  
1354 - config_file = p;  
1355 - return ret;  
1356 - }  
1357 - if (argv[++i]) {  
1358 - config_file = argv[i];  
1359 - return ret;  
1360 - }  
1361 - ret = ERROR_SYSTEM_CONFIG_INVALID;  
1362 - srs_error("option \"-c\" requires parameter, ret=%d", ret);  
1363 - return ret;  
1364 - default:  
1365 - ret = ERROR_SYSTEM_CONFIG_INVALID;  
1366 - srs_error("invalid option: \"%c\", see help: %s -h, ret=%d", *(p - 1), argv[0], ret);  
1367 - return ret;  
1368 - } 1578 + pithy = pithy->get("play");
  1579 + if (!pithy) {
  1580 + return SRS_STAGE_PLAY_USER_INTERVAL_MS;
1369 } 1581 }
1370 1582
1371 - return ret;  
1372 -}  
1373 -  
1374 -void SrsConfig::print_help(char** argv)  
1375 -{  
1376 - printf(RTMP_SIG_SRS_NAME" "RTMP_SIG_SRS_VERSION  
1377 - " Copyright (c) 2013 winlin\n"  
1378 - "Contributors: "RTMP_SIG_SRS_CONTRIBUTOR"\n"  
1379 - "Build: "SRS_BUILD_DATE" Configuration: "SRS_CONFIGURE"\n"  
1380 - "Usage: %s [-h?vV] [-c <filename>]\n"  
1381 - "\n"  
1382 - "Options:\n"  
1383 - " -?-h : show help\n"  
1384 - " -v-V : show version and exit\n"  
1385 - " -c filename : set configuration file\n"  
1386 - "\n"  
1387 - RTMP_SIG_SRS_WEB"\n"  
1388 - RTMP_SIG_SRS_URL"\n"  
1389 - "Email: "RTMP_SIG_SRS_EMAIL"\n"  
1390 - "\n",  
1391 - argv[0]); 1583 + return ::atoi(pithy->arg0().c_str());
1392 } 1584 }
1393 1585
1394 bool srs_directive_equals(SrsConfDirective* a, SrsConfDirective* b) 1586 bool srs_directive_equals(SrsConfDirective* a, SrsConfDirective* b)
1395 { 1587 {
  1588 + // both NULL, equal.
  1589 + if (!a && !b) {
  1590 + return true;
  1591 + }
  1592 +
1396 if (!a || !b) { 1593 if (!a || !b) {
1397 return false; 1594 return false;
1398 } 1595 }
@@ -48,25 +48,20 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -48,25 +48,20 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
48 #define SRS_CONF_DEFAULT_AAC_SYNC 100 48 #define SRS_CONF_DEFAULT_AAC_SYNC 100
49 // in ms, for HLS aac flush the audio 49 // in ms, for HLS aac flush the audio
50 #define SRS_CONF_DEFAULT_AAC_DELAY 300 50 #define SRS_CONF_DEFAULT_AAC_DELAY 300
  51 +// in seconds, the live queue length.
  52 +#define SRS_CONF_DEFAULT_QUEUE_LENGTH 30
  53 +// in seconds, the paused queue length.
  54 +#define SRS_CONF_DEFAULT_PAUSED_LENGTH 10
51 55
52 -class SrsFileBuffer  
53 -{  
54 -public:  
55 - int fd;  
56 - int line;  
57 - // start of buffer.  
58 - char* start;  
59 - // end of buffer.  
60 - char* end;  
61 - // current consumed position.  
62 - char* pos;  
63 - // last available position.  
64 - char* last;  
65 -  
66 - SrsFileBuffer();  
67 - virtual ~SrsFileBuffer();  
68 - virtual int open(const char* filename);  
69 -}; 56 +#define SRS_CONF_DEFAULT_CHUNK_SIZE 4096
  57 +
  58 +#define SRS_STAGE_PLAY_USER_INTERVAL_MS 1300
  59 +#define SRS_STAGE_PUBLISH_USER_INTERVAL_MS 1100
  60 +#define SRS_STAGE_FORWARDER_INTERVAL_MS 2000
  61 +#define SRS_STAGE_ENCODER_INTERVAL_MS 2000
  62 +#define SRS_STAGE_HLS_INTERVAL_MS 2000
  63 +
  64 +class SrsFileBuffer;
70 65
71 class SrsConfDirective 66 class SrsConfDirective
72 { 67 {
@@ -83,13 +78,13 @@ public: @@ -83,13 +78,13 @@ public:
83 std::string arg2(); 78 std::string arg2();
84 SrsConfDirective* at(int index); 79 SrsConfDirective* at(int index);
85 SrsConfDirective* get(std::string _name); 80 SrsConfDirective* get(std::string _name);
  81 + SrsConfDirective* get(std::string _name, std::string _arg0);
86 public: 82 public:
87 virtual int parse(const char* filename); 83 virtual int parse(const char* filename);
88 public: 84 public:
89 enum SrsDirectiveType{parse_file, parse_block}; 85 enum SrsDirectiveType{parse_file, parse_block};
90 virtual int parse_conf(SrsFileBuffer* buffer, SrsDirectiveType type); 86 virtual int parse_conf(SrsFileBuffer* buffer, SrsDirectiveType type);
91 virtual int read_token(SrsFileBuffer* buffer, std::vector<std::string>& args); 87 virtual int read_token(SrsFileBuffer* buffer, std::vector<std::string>& args);
92 - virtual int refill_buffer(SrsFileBuffer* buffer, bool d_quoted, bool s_quoted, int startline, char*& pstart);  
93 }; 88 };
94 89
95 /** 90 /**
@@ -106,71 +101,76 @@ private: @@ -106,71 +101,76 @@ private:
106 bool show_version; 101 bool show_version;
107 std::string config_file; 102 std::string config_file;
108 SrsConfDirective* root; 103 SrsConfDirective* root;
109 - std::vector<SrsReloadHandler*> subscribes; 104 + std::vector<ISrsReloadHandler*> subscribes;
110 public: 105 public:
111 SrsConfig(); 106 SrsConfig();
112 virtual ~SrsConfig(); 107 virtual ~SrsConfig();
113 public: 108 public:
114 virtual int reload(); 109 virtual int reload();
115 - virtual void subscribe(SrsReloadHandler* handler);  
116 - virtual void unsubscribe(SrsReloadHandler* handler); 110 + virtual void subscribe(ISrsReloadHandler* handler);
  111 + virtual void unsubscribe(ISrsReloadHandler* handler);
117 public: 112 public:
118 virtual int parse_options(int argc, char** argv); 113 virtual int parse_options(int argc, char** argv);
119 -public:  
120 - virtual SrsConfDirective* get_vhost(const std::string &vhost);  
121 - virtual bool get_vhost_enabled(const std::string& vhost);  
122 - virtual SrsConfDirective* get_vhost_on_connect(const std::string& vhost);  
123 - virtual SrsConfDirective* get_vhost_on_close(const std::string& vhost);  
124 - virtual SrsConfDirective* get_vhost_on_publish(const std::string& vhost);  
125 - virtual SrsConfDirective* get_vhost_on_unpublish(const std::string& vhost);  
126 - virtual SrsConfDirective* get_vhost_on_play(const std::string& vhost);  
127 - virtual SrsConfDirective* get_vhost_on_stop(const std::string& vhost);  
128 - virtual SrsConfDirective* get_transcode(const std::string& vhost, const std::string& scope);  
129 - virtual bool get_transcode_enabled(SrsConfDirective* transcode);  
130 - virtual std::string get_transcode_ffmpeg(SrsConfDirective* transcode);  
131 - virtual void get_transcode_engines(SrsConfDirective* transcode, std::vector<SrsConfDirective*>& engines);  
132 - virtual bool get_engine_enabled(SrsConfDirective* engine);  
133 - virtual std::string get_engine_vcodec(SrsConfDirective* engine);  
134 - virtual int get_engine_vbitrate(SrsConfDirective* engine);  
135 - virtual double get_engine_vfps(SrsConfDirective* engine);  
136 - virtual int get_engine_vwidth(SrsConfDirective* engine);  
137 - virtual int get_engine_vheight(SrsConfDirective* engine);  
138 - virtual int get_engine_vthreads(SrsConfDirective* engine);  
139 - virtual std::string get_engine_vprofile(SrsConfDirective* engine);  
140 - virtual std::string get_engine_vpreset(SrsConfDirective* engine);  
141 - virtual void get_engine_vparams(SrsConfDirective* engine, std::vector<std::string>& vparams);  
142 - virtual void get_engine_vfilter(SrsConfDirective* engine, std::vector<std::string>& vfilter);  
143 - virtual std::string get_engine_acodec(SrsConfDirective* engine);  
144 - virtual int get_engine_abitrate(SrsConfDirective* engine);  
145 - virtual int get_engine_asample_rate(SrsConfDirective* engine);  
146 - virtual int get_engine_achannels(SrsConfDirective* engine);  
147 - virtual void get_engine_aparams(SrsConfDirective* engine, std::vector<std::string>& aparams);  
148 - virtual std::string get_engine_output(SrsConfDirective* engine);  
149 - virtual std::string get_log_dir();  
150 - virtual int get_max_connections();  
151 - virtual SrsConfDirective* get_gop_cache(const std::string& vhost);  
152 - virtual SrsConfDirective* get_forward(const std::string& vhost);  
153 - virtual SrsConfDirective* get_hls(const std::string &vhost);  
154 - virtual bool get_hls_enabled(const std::string& vhost);  
155 - virtual SrsConfDirective* get_hls_path(const std::string& vhost);  
156 - virtual SrsConfDirective* get_hls_fragment(const std::string& vhost);  
157 - virtual SrsConfDirective* get_hls_window(const std::string& vhost);  
158 - virtual SrsConfDirective* get_refer(const std::string& vhost);  
159 - virtual SrsConfDirective* get_refer_play(const std::string& vhost);  
160 - virtual SrsConfDirective* get_refer_publish(const std::string& vhost);  
161 - virtual SrsConfDirective* get_listen();  
162 - virtual SrsConfDirective* get_chunk_size(const std::string &vhost);  
163 - virtual SrsConfDirective* get_pithy_print_publish();  
164 - virtual SrsConfDirective* get_pithy_print_forwarder();  
165 - virtual SrsConfDirective* get_pithy_print_encoder();  
166 - virtual SrsConfDirective* get_pithy_print_hls();  
167 - virtual SrsConfDirective* get_pithy_print_play();  
168 - virtual bool get_bw_check_enabled(const std::string &vhost, const std::string &key);  
169 - virtual void get_bw_check_settings(const std::string &vhost, int64_t &interval_ms, int &play_kbps, int &pub_kbps); 114 +
170 private: 115 private:
171 virtual int parse_file(const char* filename); 116 virtual int parse_file(const char* filename);
172 virtual int parse_argv(int& i, char** argv); 117 virtual int parse_argv(int& i, char** argv);
173 virtual void print_help(char** argv); 118 virtual void print_help(char** argv);
  119 +public:
  120 + virtual SrsConfDirective* get_vhost(std::string vhost);
  121 + virtual bool get_vhost_enabled(std::string vhost);
  122 + virtual bool get_vhost_enabled(SrsConfDirective* vhost);
  123 + virtual SrsConfDirective* get_vhost_on_connect(std::string vhost);
  124 + virtual SrsConfDirective* get_vhost_on_close(std::string vhost);
  125 + virtual SrsConfDirective* get_vhost_on_publish(std::string vhost);
  126 + virtual SrsConfDirective* get_vhost_on_unpublish(std::string vhost);
  127 + virtual SrsConfDirective* get_vhost_on_play(std::string vhost);
  128 + virtual SrsConfDirective* get_vhost_on_stop(std::string vhost);
  129 + virtual SrsConfDirective* get_transcode(std::string vhost, std::string scope);
  130 + virtual bool get_transcode_enabled(SrsConfDirective* transcode);
  131 + virtual std::string get_transcode_ffmpeg(SrsConfDirective* transcode);
  132 + virtual void get_transcode_engines(SrsConfDirective* transcode, std::vector<SrsConfDirective*>& engines);
  133 + virtual bool get_engine_enabled(SrsConfDirective* engine);
  134 + virtual std::string get_engine_vcodec(SrsConfDirective* engine);
  135 + virtual int get_engine_vbitrate(SrsConfDirective* engine);
  136 + virtual double get_engine_vfps(SrsConfDirective* engine);
  137 + virtual int get_engine_vwidth(SrsConfDirective* engine);
  138 + virtual int get_engine_vheight(SrsConfDirective* engine);
  139 + virtual int get_engine_vthreads(SrsConfDirective* engine);
  140 + virtual std::string get_engine_vprofile(SrsConfDirective* engine);
  141 + virtual std::string get_engine_vpreset(SrsConfDirective* engine);
  142 + virtual void get_engine_vparams(SrsConfDirective* engine, std::vector<std::string>& vparams);
  143 + virtual void get_engine_vfilter(SrsConfDirective* engine, std::vector<std::string>& vfilter);
  144 + virtual std::string get_engine_acodec(SrsConfDirective* engine);
  145 + virtual int get_engine_abitrate(SrsConfDirective* engine);
  146 + virtual int get_engine_asample_rate(SrsConfDirective* engine);
  147 + virtual int get_engine_achannels(SrsConfDirective* engine);
  148 + virtual void get_engine_aparams(SrsConfDirective* engine, std::vector<std::string>& aparams);
  149 + virtual std::string get_engine_output(SrsConfDirective* engine);
  150 + virtual std::string get_log_dir();
  151 + virtual int get_max_connections();
  152 + virtual bool get_gop_cache(std::string vhost);
  153 + virtual double get_queue_length(std::string vhost);
  154 + virtual SrsConfDirective* get_forward(std::string vhost);
  155 +private:
  156 + virtual SrsConfDirective* get_hls(std::string vhost);
  157 +public:
  158 + virtual bool get_hls_enabled(std::string vhost);
  159 + virtual std::string get_hls_path(std::string vhost);
  160 + virtual double get_hls_fragment(std::string vhost);
  161 + virtual double get_hls_window(std::string vhost);
  162 + virtual SrsConfDirective* get_refer(std::string vhost);
  163 + virtual SrsConfDirective* get_refer_play(std::string vhost);
  164 + virtual SrsConfDirective* get_refer_publish(std::string vhost);
  165 + virtual SrsConfDirective* get_listen();
  166 + virtual int get_chunk_size();
  167 + virtual int get_pithy_print_publish();
  168 + virtual int get_pithy_print_forwarder();
  169 + virtual int get_pithy_print_encoder();
  170 + virtual int get_pithy_print_hls();
  171 + virtual int get_pithy_print_play();
  172 + virtual bool get_bw_check_enabled(const std::string &vhost, const std::string &key);
  173 + virtual void get_bw_check_settings(const std::string &vhost, int64_t &interval_ms, int &play_kbps, int &pub_kbps);
174 }; 174 };
175 175
176 /** 176 /**
@@ -36,15 +36,7 @@ SrsConnection::SrsConnection(SrsServer* srs_server, st_netfd_t client_stfd) @@ -36,15 +36,7 @@ SrsConnection::SrsConnection(SrsServer* srs_server, st_netfd_t client_stfd)
36 36
37 SrsConnection::~SrsConnection() 37 SrsConnection::~SrsConnection()
38 { 38 {
39 - if (stfd) {  
40 - int fd = st_netfd_fileno(stfd);  
41 - st_netfd_close(stfd);  
42 - stfd = NULL;  
43 -  
44 - // st does not close it sometimes,  
45 - // close it manually.  
46 - close(fd);  
47 - } 39 + srs_close_stfd(stfd);
48 } 40 }
49 41
50 int SrsConnection::start() 42 int SrsConnection::start()
@@ -30,8 +30,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -30,8 +30,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 30
31 #include <srs_core.hpp> 31 #include <srs_core.hpp>
32 32
33 -#include <st.h>  
34 -  
35 class SrsServer; 33 class SrsServer;
36 class SrsConnection 34 class SrsConnection
37 { 35 {
@@ -483,52 +483,15 @@ void SrsFFMPEG::stop() @@ -483,52 +483,15 @@ void SrsFFMPEG::stop()
483 483
484 SrsEncoder::SrsEncoder() 484 SrsEncoder::SrsEncoder()
485 { 485 {
486 - tid = NULL;  
487 - loop = false; 486 + pthread = new SrsThread(this, SRS_ENCODER_SLEEP_MS);
  487 + pithy_print = new SrsPithyPrint(SRS_STAGE_ENCODER);
488 } 488 }
489 489
490 SrsEncoder::~SrsEncoder() 490 SrsEncoder::~SrsEncoder()
491 { 491 {
492 on_unpublish(); 492 on_unpublish();
493 -}  
494 -  
495 -int SrsEncoder::parse_scope_engines(SrsRequest* req)  
496 -{  
497 - int ret = ERROR_SUCCESS;  
498 493
499 - // parse all transcode engines.  
500 - SrsConfDirective* conf = NULL;  
501 -  
502 - // parse vhost scope engines  
503 - std::string scope = "";  
504 - if ((conf = config->get_transcode(req->vhost, scope)) != NULL) {  
505 - if ((ret = parse_transcode(req, conf)) != ERROR_SUCCESS) {  
506 - srs_error("parse vhost scope=%s transcode engines failed. "  
507 - "ret=%d", scope.c_str(), ret);  
508 - return ret;  
509 - }  
510 - }  
511 - // parse app scope engines  
512 - scope = req->app;  
513 - if ((conf = config->get_transcode(req->vhost, scope)) != NULL) {  
514 - if ((ret = parse_transcode(req, conf)) != ERROR_SUCCESS) {  
515 - srs_error("parse app scope=%s transcode engines failed. "  
516 - "ret=%d", scope.c_str(), ret);  
517 - return ret;  
518 - }  
519 - }  
520 - // parse stream scope engines  
521 - scope += "/";  
522 - scope += req->stream;  
523 - if ((conf = config->get_transcode(req->vhost, scope)) != NULL) {  
524 - if ((ret = parse_transcode(req, conf)) != ERROR_SUCCESS) {  
525 - srs_error("parse stream scope=%s transcode engines failed. "  
526 - "ret=%d", scope.c_str(), ret);  
527 - return ret;  
528 - }  
529 - }  
530 -  
531 - return ret; 494 + srs_freep(pthread);
532 } 495 }
533 496
534 int SrsEncoder::on_publish(SrsRequest* req) 497 int SrsEncoder::on_publish(SrsRequest* req)
@@ -539,6 +502,7 @@ int SrsEncoder::on_publish(SrsRequest* req) @@ -539,6 +502,7 @@ int SrsEncoder::on_publish(SrsRequest* req)
539 502
540 // ignore the loop encoder 503 // ignore the loop encoder
541 if (ret == ERROR_ENCODER_LOOP) { 504 if (ret == ERROR_ENCODER_LOOP) {
  505 + clear_engines();
542 ret = ERROR_SUCCESS; 506 ret = ERROR_SUCCESS;
543 } 507 }
544 508
@@ -548,9 +512,7 @@ int SrsEncoder::on_publish(SrsRequest* req) @@ -548,9 +512,7 @@ int SrsEncoder::on_publish(SrsRequest* req)
548 } 512 }
549 513
550 // start thread to run all encoding engines. 514 // start thread to run all encoding engines.
551 - srs_assert(!tid);  
552 - if((tid = st_thread_create(encoder_thread, this, 1, 0)) == NULL) {  
553 - ret = ERROR_ST_CREATE_FORWARD_THREAD; 515 + if ((ret = pthread->start()) != ERROR_SUCCESS) {
554 srs_error("st_thread_create failed. ret=%d", ret); 516 srs_error("st_thread_create failed. ret=%d", ret);
555 return ret; 517 return ret;
556 } 518 }
@@ -560,23 +522,58 @@ int SrsEncoder::on_publish(SrsRequest* req) @@ -560,23 +522,58 @@ int SrsEncoder::on_publish(SrsRequest* req)
560 522
561 void SrsEncoder::on_unpublish() 523 void SrsEncoder::on_unpublish()
562 { 524 {
563 - if (tid) {  
564 - loop = false;  
565 - st_thread_interrupt(tid);  
566 - st_thread_join(tid, NULL);  
567 - tid = NULL; 525 + pthread->stop();
  526 + clear_engines();
  527 +}
  528 +
  529 +int SrsEncoder::cycle()
  530 +{
  531 + int ret = ERROR_SUCCESS;
  532 +
  533 + std::vector<SrsFFMPEG*>::iterator it;
  534 + for (it = ffmpegs.begin(); it != ffmpegs.end(); ++it) {
  535 + SrsFFMPEG* ffmpeg = *it;
  536 +
  537 + // start all ffmpegs.
  538 + if ((ret = ffmpeg->start()) != ERROR_SUCCESS) {
  539 + srs_error("ffmpeg start failed. ret=%d", ret);
  540 + return ret;
  541 + }
  542 +
  543 + // check ffmpeg status.
  544 + if ((ret = ffmpeg->cycle()) != ERROR_SUCCESS) {
  545 + srs_error("ffmpeg cycle failed. ret=%d", ret);
  546 + return ret;
  547 + }
568 } 548 }
569 549
570 - clear_engines(); 550 + // pithy print
  551 + encoder();
  552 + pithy_print->elapse(SRS_ENCODER_SLEEP_MS);
  553 +
  554 + return ret;
  555 +}
  556 +
  557 +void SrsEncoder::on_leave_loop()
  558 +{
  559 + // kill ffmpeg when finished and it alive
  560 + std::vector<SrsFFMPEG*>::iterator it;
  561 +
  562 + for (it = ffmpegs.begin(); it != ffmpegs.end(); ++it) {
  563 + SrsFFMPEG* ffmpeg = *it;
  564 + ffmpeg->stop();
  565 + }
571 } 566 }
572 567
573 void SrsEncoder::clear_engines() 568 void SrsEncoder::clear_engines()
574 { 569 {
575 std::vector<SrsFFMPEG*>::iterator it; 570 std::vector<SrsFFMPEG*>::iterator it;
  571 +
576 for (it = ffmpegs.begin(); it != ffmpegs.end(); ++it) { 572 for (it = ffmpegs.begin(); it != ffmpegs.end(); ++it) {
577 SrsFFMPEG* ffmpeg = *it; 573 SrsFFMPEG* ffmpeg = *it;
578 srs_freep(ffmpeg); 574 srs_freep(ffmpeg);
579 } 575 }
  576 +
580 ffmpegs.clear(); 577 ffmpegs.clear();
581 } 578 }
582 579
@@ -585,6 +582,45 @@ SrsFFMPEG* SrsEncoder::at(int index) @@ -585,6 +582,45 @@ SrsFFMPEG* SrsEncoder::at(int index)
585 return ffmpegs[index]; 582 return ffmpegs[index];
586 } 583 }
587 584
  585 +int SrsEncoder::parse_scope_engines(SrsRequest* req)
  586 +{
  587 + int ret = ERROR_SUCCESS;
  588 +
  589 + // parse all transcode engines.
  590 + SrsConfDirective* conf = NULL;
  591 +
  592 + // parse vhost scope engines
  593 + std::string scope = "";
  594 + if ((conf = config->get_transcode(req->vhost, scope)) != NULL) {
  595 + if ((ret = parse_transcode(req, conf)) != ERROR_SUCCESS) {
  596 + srs_error("parse vhost scope=%s transcode engines failed. "
  597 + "ret=%d", scope.c_str(), ret);
  598 + return ret;
  599 + }
  600 + }
  601 + // parse app scope engines
  602 + scope = req->app;
  603 + if ((conf = config->get_transcode(req->vhost, scope)) != NULL) {
  604 + if ((ret = parse_transcode(req, conf)) != ERROR_SUCCESS) {
  605 + srs_error("parse app scope=%s transcode engines failed. "
  606 + "ret=%d", scope.c_str(), ret);
  607 + return ret;
  608 + }
  609 + }
  610 + // parse stream scope engines
  611 + scope += "/";
  612 + scope += req->stream;
  613 + if ((conf = config->get_transcode(req->vhost, scope)) != NULL) {
  614 + if ((ret = parse_transcode(req, conf)) != ERROR_SUCCESS) {
  615 + srs_error("parse stream scope=%s transcode engines failed. "
  616 + "ret=%d", scope.c_str(), ret);
  617 + return ret;
  618 + }
  619 + }
  620 +
  621 + return ret;
  622 +}
  623 +
588 int SrsEncoder::parse_transcode(SrsRequest* req, SrsConfDirective* conf) 624 int SrsEncoder::parse_transcode(SrsRequest* req, SrsConfDirective* conf)
589 { 625 {
590 int ret = ERROR_SUCCESS; 626 int ret = ERROR_SUCCESS;
@@ -631,7 +667,6 @@ int SrsEncoder::parse_transcode(SrsRequest* req, SrsConfDirective* conf) @@ -631,7 +667,6 @@ int SrsEncoder::parse_transcode(SrsRequest* req, SrsConfDirective* conf)
631 667
632 // if got a loop, donot transcode the whole stream. 668 // if got a loop, donot transcode the whole stream.
633 if (ret == ERROR_ENCODER_LOOP) { 669 if (ret == ERROR_ENCODER_LOOP) {
634 - clear_engines();  
635 break; 670 break;
636 } 671 }
637 672
@@ -646,85 +681,14 @@ int SrsEncoder::parse_transcode(SrsRequest* req, SrsConfDirective* conf) @@ -646,85 +681,14 @@ int SrsEncoder::parse_transcode(SrsRequest* req, SrsConfDirective* conf)
646 return ret; 681 return ret;
647 } 682 }
648 683
649 -int SrsEncoder::cycle()  
650 -{  
651 - int ret = ERROR_SUCCESS;  
652 -  
653 - std::vector<SrsFFMPEG*>::iterator it;  
654 - for (it = ffmpegs.begin(); it != ffmpegs.end(); ++it) {  
655 - SrsFFMPEG* ffmpeg = *it;  
656 -  
657 - // start all ffmpegs.  
658 - if ((ret = ffmpeg->start()) != ERROR_SUCCESS) {  
659 - srs_error("ffmpeg start failed. ret=%d", ret);  
660 - return ret;  
661 - }  
662 -  
663 - // check ffmpeg status.  
664 - if ((ret = ffmpeg->cycle()) != ERROR_SUCCESS) {  
665 - srs_error("ffmpeg cycle failed. ret=%d", ret);  
666 - return ret;  
667 - }  
668 - }  
669 -  
670 - return ret;  
671 -}  
672 -  
673 -void SrsEncoder::encoder_cycle()  
674 -{  
675 - int ret = ERROR_SUCCESS;  
676 -  
677 - log_context->generate_id();  
678 - srs_trace("encoder cycle start");  
679 -  
680 - SrsPithyPrint pithy_print(SRS_STAGE_ENCODER);  
681 -  
682 - while (loop) {  
683 - if ((ret = cycle()) != ERROR_SUCCESS) {  
684 - srs_warn("encoder cycle failed, ignored and retry, ret=%d", ret);  
685 - } else {  
686 - srs_info("encoder cycle success, retry");  
687 - }  
688 -  
689 - if (!loop) {  
690 - break;  
691 - }  
692 -  
693 - encoder(&pithy_print);  
694 - pithy_print.elapse(SRS_ENCODER_SLEEP_MS);  
695 -  
696 - st_usleep(SRS_ENCODER_SLEEP_MS * 1000);  
697 - }  
698 -  
699 - // kill ffmpeg when finished and it alive  
700 - std::vector<SrsFFMPEG*>::iterator it;  
701 - for (it = ffmpegs.begin(); it != ffmpegs.end(); ++it) {  
702 - SrsFFMPEG* ffmpeg = *it;  
703 - ffmpeg->stop();  
704 - }  
705 -  
706 - srs_trace("encoder cycle finished");  
707 -}  
708 -  
709 -void SrsEncoder::encoder(SrsPithyPrint* pithy_print) 684 +void SrsEncoder::encoder()
710 { 685 {
711 // reportable 686 // reportable
712 if (pithy_print->can_print()) { 687 if (pithy_print->can_print()) {
713 - srs_trace("-> time=%"PRId64", encoders=%d",  
714 - pithy_print->get_age(), (int)ffmpegs.size()); 688 + // TODO: FIXME: show more info.
  689 + srs_trace("-> time=%"PRId64", encoders=%d", pithy_print->get_age(), (int)ffmpegs.size());
715 } 690 }
716 } 691 }
717 692
718 -void* SrsEncoder::encoder_thread(void* arg)  
719 -{  
720 - SrsEncoder* obj = (SrsEncoder*)arg;  
721 - srs_assert(obj != NULL);  
722 -  
723 - obj->loop = true;  
724 - obj->encoder_cycle();  
725 -  
726 - return NULL;  
727 -}  
728 -  
729 #endif 693 #endif
730 694
@@ -32,7 +32,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -32,7 +32,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 #include <string> 32 #include <string>
33 #include <vector> 33 #include <vector>
34 34
35 -#include <st.h> 35 +#include <srs_core_thread.hpp>
36 36
37 class SrsConfDirective; 37 class SrsConfDirective;
38 class SrsRequest; 38 class SrsRequest;
@@ -85,28 +85,29 @@ public: @@ -85,28 +85,29 @@ public:
85 * the encoder for a stream, 85 * the encoder for a stream,
86 * may use multiple ffmpegs to transcode the specified stream. 86 * may use multiple ffmpegs to transcode the specified stream.
87 */ 87 */
88 -class SrsEncoder 88 +class SrsEncoder : public ISrsThreadHandler
89 { 89 {
90 private: 90 private:
91 std::vector<SrsFFMPEG*> ffmpegs; 91 std::vector<SrsFFMPEG*> ffmpegs;
92 private: 92 private:
93 - st_thread_t tid;  
94 - bool loop; 93 + SrsThread* pthread;
  94 + SrsPithyPrint* pithy_print;
95 public: 95 public:
96 SrsEncoder(); 96 SrsEncoder();
97 virtual ~SrsEncoder(); 97 virtual ~SrsEncoder();
98 public: 98 public:
99 virtual int on_publish(SrsRequest* req); 99 virtual int on_publish(SrsRequest* req);
100 virtual void on_unpublish(); 100 virtual void on_unpublish();
  101 +// interface ISrsThreadHandler.
  102 +public:
  103 + virtual int cycle();
  104 + virtual void on_leave_loop();
101 private: 105 private:
102 - virtual int parse_scope_engines(SrsRequest* req);  
103 virtual void clear_engines(); 106 virtual void clear_engines();
104 virtual SrsFFMPEG* at(int index); 107 virtual SrsFFMPEG* at(int index);
  108 + virtual int parse_scope_engines(SrsRequest* req);
105 virtual int parse_transcode(SrsRequest* req, SrsConfDirective* conf); 109 virtual int parse_transcode(SrsRequest* req, SrsConfDirective* conf);
106 - virtual int cycle();  
107 - virtual void encoder_cycle();  
108 - virtual void encoder(SrsPithyPrint* pithy_print);  
109 - static void* encoder_thread(void* arg); 110 + virtual void encoder();
110 }; 111 };
111 112
112 #endif 113 #endif
@@ -37,8 +37,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -37,8 +37,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 #define ERROR_ST_OPEN_SOCKET 102 37 #define ERROR_ST_OPEN_SOCKET 102
38 #define ERROR_ST_CREATE_LISTEN_THREAD 103 38 #define ERROR_ST_CREATE_LISTEN_THREAD 103
39 #define ERROR_ST_CREATE_CYCLE_THREAD 104 39 #define ERROR_ST_CREATE_CYCLE_THREAD 104
40 -#define ERROR_ST_CREATE_FORWARD_THREAD 105  
41 -#define ERROR_ST_CONNECT 106 40 +#define ERROR_ST_CONNECT 105
42 41
43 #define ERROR_SOCKET_CREATE 200 42 #define ERROR_SOCKET_CREATE 200
44 #define ERROR_SOCKET_SETREUSE 201 43 #define ERROR_SOCKET_SETREUSE 201
@@ -85,9 +84,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -85,9 +84,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
85 #define ERROR_SYSTEM_CONFIG_EOF 409 84 #define ERROR_SYSTEM_CONFIG_EOF 409
86 #define ERROR_SYSTEM_STREAM_BUSY 410 85 #define ERROR_SYSTEM_STREAM_BUSY 410
87 #define ERROR_SYSTEM_IP_INVALID 411 86 #define ERROR_SYSTEM_IP_INVALID 411
88 -#define ERROR_SYSTEM_CONFIG_TOO_LARGE 412  
89 -#define ERROR_SYSTEM_FORWARD_LOOP 413  
90 -#define ERROR_SYSTEM_WAITPID 414 87 +#define ERROR_SYSTEM_FORWARD_LOOP 412
  88 +#define ERROR_SYSTEM_WAITPID 413
91 89
92 // see librtmp. 90 // see librtmp.
93 // failed when open ssl create the dh 91 // failed when open ssl create the dh
@@ -35,32 +35,39 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -35,32 +35,39 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 #include <srs_core_pithy_print.hpp> 35 #include <srs_core_pithy_print.hpp>
36 #include <srs_core_rtmp.hpp> 36 #include <srs_core_rtmp.hpp>
37 #include <srs_core_config.hpp> 37 #include <srs_core_config.hpp>
  38 +#include <srs_core_source.hpp>
  39 +#include <srs_core_autofree.hpp>
38 40
39 #define SRS_PULSE_TIMEOUT_MS 100 41 #define SRS_PULSE_TIMEOUT_MS 100
40 #define SRS_FORWARDER_SLEEP_MS 2000 42 #define SRS_FORWARDER_SLEEP_MS 2000
41 #define SRS_SEND_TIMEOUT_US 3000000L 43 #define SRS_SEND_TIMEOUT_US 3000000L
42 #define SRS_RECV_TIMEOUT_US SRS_SEND_TIMEOUT_US 44 #define SRS_RECV_TIMEOUT_US SRS_SEND_TIMEOUT_US
43 45
44 -SrsForwarder::SrsForwarder() 46 +SrsForwarder::SrsForwarder(SrsSource* _source)
45 { 47 {
  48 + source = _source;
  49 +
46 client = NULL; 50 client = NULL;
47 stfd = NULL; 51 stfd = NULL;
48 stream_id = 0; 52 stream_id = 0;
49 -  
50 - tid = NULL;  
51 - loop = false; 53 +
  54 + pthread = new SrsThread(this, SRS_FORWARDER_SLEEP_MS);
  55 + queue = new SrsMessageQueue();
  56 + jitter = new SrsRtmpJitter();
52 } 57 }
53 58
54 SrsForwarder::~SrsForwarder() 59 SrsForwarder::~SrsForwarder()
55 { 60 {
56 on_unpublish(); 61 on_unpublish();
57 62
58 - std::vector<SrsSharedPtrMessage*>::iterator it;  
59 - for (it = msgs.begin(); it != msgs.end(); ++it) {  
60 - SrsSharedPtrMessage* msg = *it;  
61 - srs_freep(msg);  
62 - }  
63 - msgs.clear(); 63 + srs_freep(pthread);
  64 + srs_freep(queue);
  65 + srs_freep(jitter);
  66 +}
  67 +
  68 +void SrsForwarder::set_queue_size(double queue_size)
  69 +{
  70 + queue->set_queue_size(queue_size);
64 } 71 }
65 72
66 int SrsForwarder::on_publish(SrsRequest* req, std::string forward_server) 73 int SrsForwarder::on_publish(SrsRequest* req, std::string forward_server)
@@ -110,41 +117,19 @@ int SrsForwarder::on_publish(SrsRequest* req, std::string forward_server) @@ -110,41 +117,19 @@ int SrsForwarder::on_publish(SrsRequest* req, std::string forward_server)
110 source_ep.c_str(), dest_ep.c_str(), tc_url.c_str(), 117 source_ep.c_str(), dest_ep.c_str(), tc_url.c_str(),
111 stream_name.c_str()); 118 stream_name.c_str());
112 119
113 - // TODO: seems bug when republish and reforward.  
114 -  
115 - // start forward  
116 - if ((ret = open_socket()) != ERROR_SUCCESS) {  
117 - return ret;  
118 - }  
119 -  
120 - srs_assert(!tid);  
121 - if((tid = st_thread_create(forward_thread, this, 1, 0)) == NULL){  
122 - ret = ERROR_ST_CREATE_FORWARD_THREAD;  
123 - srs_error("st_thread_create failed. ret=%d", ret); 120 + if ((ret = pthread->start()) != ERROR_SUCCESS) {
  121 + srs_error("start srs thread failed. ret=%d", ret);
124 return ret; 122 return ret;
125 - } 123 + }
126 124
127 return ret; 125 return ret;
128 } 126 }
129 127
130 void SrsForwarder::on_unpublish() 128 void SrsForwarder::on_unpublish()
131 { 129 {
132 - if (tid) {  
133 - loop = false;  
134 - st_thread_interrupt(tid);  
135 - st_thread_join(tid, NULL);  
136 - tid = NULL;  
137 - } 130 + pthread->stop();
138 131
139 - if (stfd) {  
140 - int fd = st_netfd_fileno(stfd);  
141 - st_netfd_close(stfd);  
142 - stfd = NULL;  
143 -  
144 - // st does not close it sometimes,  
145 - // close it manually.  
146 - close(fd);  
147 - } 132 + close_underlayer_socket();
148 133
149 srs_freep(client); 134 srs_freep(client);
150 } 135 }
@@ -153,7 +138,14 @@ int SrsForwarder::on_meta_data(SrsSharedPtrMessage* metadata) @@ -153,7 +138,14 @@ int SrsForwarder::on_meta_data(SrsSharedPtrMessage* metadata)
153 { 138 {
154 int ret = ERROR_SUCCESS; 139 int ret = ERROR_SUCCESS;
155 140
156 - msgs.push_back(metadata); 141 + if ((ret = jitter->correct(metadata, 0, 0)) != ERROR_SUCCESS) {
  142 + srs_freep(metadata);
  143 + return ret;
  144 + }
  145 +
  146 + if ((ret = queue->enqueue(metadata)) != ERROR_SUCCESS) {
  147 + return ret;
  148 + }
157 149
158 return ret; 150 return ret;
159 } 151 }
@@ -162,7 +154,14 @@ int SrsForwarder::on_audio(SrsSharedPtrMessage* msg) @@ -162,7 +154,14 @@ int SrsForwarder::on_audio(SrsSharedPtrMessage* msg)
162 { 154 {
163 int ret = ERROR_SUCCESS; 155 int ret = ERROR_SUCCESS;
164 156
165 - msgs.push_back(msg); 157 + if ((ret = jitter->correct(msg, 0, 0)) != ERROR_SUCCESS) {
  158 + srs_freep(msg);
  159 + return ret;
  160 + }
  161 +
  162 + if ((ret = queue->enqueue(msg)) != ERROR_SUCCESS) {
  163 + return ret;
  164 + }
166 165
167 return ret; 166 return ret;
168 } 167 }
@@ -171,15 +170,74 @@ int SrsForwarder::on_video(SrsSharedPtrMessage* msg) @@ -171,15 +170,74 @@ int SrsForwarder::on_video(SrsSharedPtrMessage* msg)
171 { 170 {
172 int ret = ERROR_SUCCESS; 171 int ret = ERROR_SUCCESS;
173 172
174 - msgs.push_back(msg); 173 + if ((ret = jitter->correct(msg, 0, 0)) != ERROR_SUCCESS) {
  174 + srs_freep(msg);
  175 + return ret;
  176 + }
  177 +
  178 + if ((ret = queue->enqueue(msg)) != ERROR_SUCCESS) {
  179 + return ret;
  180 + }
175 181
176 return ret; 182 return ret;
177 } 183 }
178 184
179 -int SrsForwarder::open_socket() 185 +int SrsForwarder::cycle()
  186 +{
  187 + int ret = ERROR_SUCCESS;
  188 +
  189 + if ((ret = connect_server()) != ERROR_SUCCESS) {
  190 + return ret;
  191 + }
  192 + srs_assert(client);
  193 +
  194 + client->set_recv_timeout(SRS_RECV_TIMEOUT_US);
  195 + client->set_send_timeout(SRS_SEND_TIMEOUT_US);
  196 +
  197 + if ((ret = client->handshake()) != ERROR_SUCCESS) {
  198 + srs_error("handshake with server failed. ret=%d", ret);
  199 + return ret;
  200 + }
  201 + if ((ret = client->connect_app(app, tc_url)) != ERROR_SUCCESS) {
  202 + srs_error("connect with server failed, tcUrl=%s. ret=%d", tc_url.c_str(), ret);
  203 + return ret;
  204 + }
  205 + if ((ret = client->create_stream(stream_id)) != ERROR_SUCCESS) {
  206 + srs_error("connect with server failed, stream_id=%d. ret=%d", stream_id, ret);
  207 + return ret;
  208 + }
  209 +
  210 + if ((ret = client->publish(stream_name, stream_id)) != ERROR_SUCCESS) {
  211 + srs_error("connect with server failed, stream_name=%s, stream_id=%d. ret=%d",
  212 + stream_name.c_str(), stream_id, ret);
  213 + return ret;
  214 + }
  215 +
  216 + if ((ret = source->on_forwarder_start(this)) != ERROR_SUCCESS) {
  217 + srs_error("callback the source to feed the sequence header failed. ret=%d", ret);
  218 + return ret;
  219 + }
  220 +
  221 + if ((ret = forward()) != ERROR_SUCCESS) {
  222 + return ret;
  223 + }
  224 +
  225 + return ret;
  226 +}
  227 +
  228 +void SrsForwarder::close_underlayer_socket()
  229 +{
  230 + srs_close_stfd(stfd);
  231 +}
  232 +
  233 +int SrsForwarder::connect_server()
180 { 234 {
181 int ret = ERROR_SUCCESS; 235 int ret = ERROR_SUCCESS;
182 236
  237 + // reopen
  238 + close_underlayer_socket();
  239 +
  240 + // open socket.
183 srs_trace("forward stream=%s, tcUrl=%s to server=%s, port=%d", 241 srs_trace("forward stream=%s, tcUrl=%s to server=%s, port=%d",
184 stream_name.c_str(), tc_url.c_str(), server.c_str(), port); 242 stream_name.c_str(), tc_url.c_str(), server.c_str(), port);
185 243
@@ -190,6 +248,7 @@ int SrsForwarder::open_socket() @@ -190,6 +248,7 @@ int SrsForwarder::open_socket()
190 return ret; 248 return ret;
191 } 249 }
192 250
  251 + srs_assert(!stfd);
193 stfd = st_netfd_open_socket(sock); 252 stfd = st_netfd_open_socket(sock);
194 if(stfd == NULL){ 253 if(stfd == NULL){
195 ret = ERROR_ST_OPEN_SOCKET; 254 ret = ERROR_ST_OPEN_SOCKET;
@@ -200,13 +259,7 @@ int SrsForwarder::open_socket() @@ -200,13 +259,7 @@ int SrsForwarder::open_socket()
200 srs_freep(client); 259 srs_freep(client);
201 client = new SrsRtmpClient(stfd); 260 client = new SrsRtmpClient(stfd);
202 261
203 - return ret;  
204 -}  
205 -  
206 -int SrsForwarder::connect_server()  
207 -{  
208 - int ret = ERROR_SUCCESS;  
209 - 262 + // connect to server.
210 std::string ip = srs_dns_resolve(server); 263 std::string ip = srs_dns_resolve(server);
211 if (ip.empty()) { 264 if (ip.empty()) {
212 ret = ERROR_SYSTEM_IP_INVALID; 265 ret = ERROR_SYSTEM_IP_INVALID;
@@ -229,43 +282,6 @@ int SrsForwarder::connect_server() @@ -229,43 +282,6 @@ int SrsForwarder::connect_server()
229 return ret; 282 return ret;
230 } 283 }
231 284
232 -int SrsForwarder::cycle()  
233 -{  
234 - int ret = ERROR_SUCCESS;  
235 -  
236 - client->set_recv_timeout(SRS_RECV_TIMEOUT_US);  
237 - client->set_send_timeout(SRS_SEND_TIMEOUT_US);  
238 -  
239 - if ((ret = connect_server()) != ERROR_SUCCESS) {  
240 - return ret;  
241 - }  
242 - srs_assert(client);  
243 -  
244 - if ((ret = client->handshake()) != ERROR_SUCCESS) {  
245 - srs_error("handshake with server failed. ret=%d", ret);  
246 - return ret;  
247 - }  
248 - if ((ret = client->connect_app(app, tc_url)) != ERROR_SUCCESS) {  
249 - srs_error("connect with server failed, tcUrl=%s. ret=%d", tc_url.c_str(), ret);  
250 - return ret;  
251 - }  
252 - if ((ret = client->create_stream(stream_id)) != ERROR_SUCCESS) {  
253 - srs_error("connect with server failed, stream_id=%d. ret=%d", stream_id, ret);  
254 - return ret;  
255 - }  
256 - if ((ret = client->publish(stream_name, stream_id)) != ERROR_SUCCESS) {  
257 - srs_error("connect with server failed, stream_name=%s, stream_id=%d. ret=%d",  
258 - stream_name.c_str(), stream_id, ret);  
259 - return ret;  
260 - }  
261 -  
262 - if ((ret = forward()) != ERROR_SUCCESS) {  
263 - return ret;  
264 - }  
265 -  
266 - return ret;  
267 -}  
268 -  
269 int SrsForwarder::forward() 285 int SrsForwarder::forward()
270 { 286 {
271 int ret = ERROR_SUCCESS; 287 int ret = ERROR_SUCCESS;
@@ -274,9 +290,7 @@ int SrsForwarder::forward() @@ -274,9 +290,7 @@ int SrsForwarder::forward()
274 290
275 SrsPithyPrint pithy_print(SRS_STAGE_FORWARDER); 291 SrsPithyPrint pithy_print(SRS_STAGE_FORWARDER);
276 292
277 - while (loop) {  
278 - pithy_print.elapse(SRS_PULSE_TIMEOUT_MS);  
279 - 293 + while (true) {
280 // switch to other st-threads. 294 // switch to other st-threads.
281 st_usleep(0); 295 st_usleep(0);
282 296
@@ -292,91 +306,42 @@ int SrsForwarder::forward() @@ -292,91 +306,42 @@ int SrsForwarder::forward()
292 } 306 }
293 } 307 }
294 308
  309 + // forward all messages.
  310 + int count = 0;
  311 + SrsSharedPtrMessage** msgs = NULL;
  312 + if ((ret = queue->get_packets(0, msgs, count)) != ERROR_SUCCESS) {
  313 + srs_error("get message to forward failed. ret=%d", ret);
  314 + return ret;
  315 + }
  316 +
295 // ignore when no messages. 317 // ignore when no messages.
296 - int count = (int)msgs.size();  
297 - if (msgs.empty()) { 318 + if (count <= 0) {
  319 + srs_verbose("no packets to forward.");
298 continue; 320 continue;
299 } 321 }
  322 + SrsAutoFree(SrsSharedPtrMessage*, msgs, true);
300 323
301 - // reportable 324 + // pithy print
  325 + pithy_print.elapse(SRS_PULSE_TIMEOUT_MS);
302 if (pithy_print.can_print()) { 326 if (pithy_print.can_print()) {
303 srs_trace("-> time=%"PRId64", msgs=%d, obytes=%"PRId64", ibytes=%"PRId64", okbps=%d, ikbps=%d", 327 srs_trace("-> time=%"PRId64", msgs=%d, obytes=%"PRId64", ibytes=%"PRId64", okbps=%d, ikbps=%d",
304 pithy_print.get_age(), count, client->get_send_bytes(), client->get_recv_bytes(), client->get_send_kbps(), client->get_recv_kbps()); 328 pithy_print.get_age(), count, client->get_send_bytes(), client->get_recv_bytes(), client->get_send_kbps(), client->get_recv_kbps());
305 } 329 }
306 330
307 // all msgs to forward. 331 // all msgs to forward.
308 - int i = 0;  
309 - for (i = 0; i < count; i++) { 332 + for (int i = 0; i < count; i++) {
310 SrsSharedPtrMessage* msg = msgs[i]; 333 SrsSharedPtrMessage* msg = msgs[i];
311 - msgs[i] = NULL;  
312 -  
313 - // we erased the sendout messages, the msg must not be NULL. 334 +
314 srs_assert(msg); 335 srs_assert(msg);
  336 + msgs[i] = NULL;
315 337
316 - ret = client->send_message(msg);  
317 - if (ret != ERROR_SUCCESS) { 338 + if ((ret = client->send_message(msg)) != ERROR_SUCCESS) {
318 srs_error("forwarder send message to server failed. ret=%d", ret); 339 srs_error("forwarder send message to server failed. ret=%d", ret);
319 -  
320 - // convert the index to count when error.  
321 - i++;  
322 -  
323 - break; 340 + return ret;
324 } 341 }
325 } 342 }
326 -  
327 - // clear sendout mesages.  
328 - if (i < count) {  
329 - srs_warn("clear forwarded msg, total=%d, forwarded=%d, ret=%d", count, i, ret);  
330 - } else {  
331 - srs_info("clear forwarded msg, total=%d, forwarded=%d, ret=%d", count, i, ret);  
332 - }  
333 - msgs.erase(msgs.begin(), msgs.begin() + i);  
334 -  
335 - if (ret != ERROR_SUCCESS) {  
336 - break;  
337 - }  
338 } 343 }
339 344
340 return ret; 345 return ret;
341 } 346 }
342 347
343 -void SrsForwarder::forward_cycle()  
344 -{  
345 - int ret = ERROR_SUCCESS;  
346 -  
347 - log_context->generate_id();  
348 - srs_trace("forward cycle start");  
349 -  
350 - while (loop) {  
351 - if ((ret = cycle()) != ERROR_SUCCESS) {  
352 - srs_warn("forward cycle failed, ignored and retry, ret=%d", ret);  
353 - } else {  
354 - srs_info("forward cycle success, retry");  
355 - }  
356 -  
357 - if (!loop) {  
358 - break;  
359 - }  
360 -  
361 - st_usleep(SRS_FORWARDER_SLEEP_MS * 1000);  
362 -  
363 - if ((ret = open_socket()) != ERROR_SUCCESS) {  
364 - srs_warn("forward cycle reopen failed, ignored and retry, ret=%d", ret);  
365 - } else {  
366 - srs_info("forward cycle reopen success");  
367 - }  
368 - }  
369 - srs_trace("forward cycle finished");  
370 -}  
371 -  
372 -void* SrsForwarder::forward_thread(void* arg)  
373 -{  
374 - SrsForwarder* obj = (SrsForwarder*)arg;  
375 - srs_assert(obj != NULL);  
376 -  
377 - obj->loop = true;  
378 - obj->forward_cycle();  
379 -  
380 - return NULL;  
381 -}  
382 -  
@@ -30,19 +30,21 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -30,19 +30,21 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 #include <srs_core.hpp> 30 #include <srs_core.hpp>
31 31
32 #include <string> 32 #include <string>
33 -#include <vector>  
34 33
35 -#include <st.h> 34 +#include <srs_core_thread.hpp>
36 35
37 class SrsSharedPtrMessage; 36 class SrsSharedPtrMessage;
38 class SrsOnMetaDataPacket; 37 class SrsOnMetaDataPacket;
  38 +class SrsMessageQueue;
  39 +class SrsRtmpJitter;
39 class SrsRtmpClient; 40 class SrsRtmpClient;
40 class SrsRequest; 41 class SrsRequest;
  42 +class SrsSource;
41 43
42 /** 44 /**
43 * forward the stream to other servers. 45 * forward the stream to other servers.
44 */ 46 */
45 -class SrsForwarder 47 +class SrsForwarder : public ISrsThreadHandler
46 { 48 {
47 private: 49 private:
48 std::string app; 50 std::string app;
@@ -53,28 +55,30 @@ private: @@ -53,28 +55,30 @@ private:
53 int port; 55 int port;
54 private: 56 private:
55 st_netfd_t stfd; 57 st_netfd_t stfd;
56 - st_thread_t tid;  
57 - bool loop; 58 + SrsThread* pthread;
58 private: 59 private:
  60 + SrsSource* source;
59 SrsRtmpClient* client; 61 SrsRtmpClient* client;
60 - std::vector<SrsSharedPtrMessage*> msgs; 62 + SrsRtmpJitter* jitter;
  63 + SrsMessageQueue* queue;
61 public: 64 public:
62 - SrsForwarder(); 65 + SrsForwarder(SrsSource* _source);
63 virtual ~SrsForwarder(); 66 virtual ~SrsForwarder();
64 public: 67 public:
  68 + virtual void set_queue_size(double queue_size);
  69 +public:
65 virtual int on_publish(SrsRequest* req, std::string forward_server); 70 virtual int on_publish(SrsRequest* req, std::string forward_server);
66 virtual void on_unpublish(); 71 virtual void on_unpublish();
67 virtual int on_meta_data(SrsSharedPtrMessage* metadata); 72 virtual int on_meta_data(SrsSharedPtrMessage* metadata);
68 virtual int on_audio(SrsSharedPtrMessage* msg); 73 virtual int on_audio(SrsSharedPtrMessage* msg);
69 virtual int on_video(SrsSharedPtrMessage* msg); 74 virtual int on_video(SrsSharedPtrMessage* msg);
  75 +// interface ISrsThreadHandler.
  76 +public:
  77 + virtual int cycle();
70 private: 78 private:
71 - virtual int open_socket(); 79 + virtual void close_underlayer_socket();
72 virtual int connect_server(); 80 virtual int connect_server();
73 -private:  
74 - virtual int cycle();  
75 virtual int forward(); 81 virtual int forward();
76 - virtual void forward_cycle();  
77 - static void* forward_thread(void* arg);  
78 }; 82 };
79 83
80 #endif 84 #endif
@@ -1109,10 +1109,11 @@ int SrsTSCache::cache_video(SrsCodec* codec, SrsCodecSample* sample) @@ -1109,10 +1109,11 @@ int SrsTSCache::cache_video(SrsCodec* codec, SrsCodecSample* sample)
1109 return ret; 1109 return ret;
1110 } 1110 }
1111 1111
1112 -SrsHls::SrsHls() 1112 +SrsHls::SrsHls(SrsSource* _source)
1113 { 1113 {
1114 hls_enabled = false; 1114 hls_enabled = false;
1115 1115
  1116 + source = _source;
1116 codec = new SrsCodec(); 1117 codec = new SrsCodec();
1117 sample = new SrsCodecSample(); 1118 sample = new SrsCodecSample();
1118 jitter = new SrsRtmpJitter(); 1119 jitter = new SrsRtmpJitter();
@@ -1148,7 +1149,6 @@ int SrsHls::on_publish(SrsRequest* req) @@ -1148,7 +1149,6 @@ int SrsHls::on_publish(SrsRequest* req)
1148 std::string stream = req->stream; 1149 std::string stream = req->stream;
1149 std::string app = req->app; 1150 std::string app = req->app;
1150 1151
1151 - // TODO: support reload.  
1152 if (!config->get_hls_enabled(vhost)) { 1152 if (!config->get_hls_enabled(vhost)) {
1153 return ret; 1153 return ret;
1154 } 1154 }
@@ -1156,30 +1156,11 @@ int SrsHls::on_publish(SrsRequest* req) @@ -1156,30 +1156,11 @@ int SrsHls::on_publish(SrsRequest* req)
1156 // if enabled, open the muxer. 1156 // if enabled, open the muxer.
1157 hls_enabled = true; 1157 hls_enabled = true;
1158 1158
1159 - // TODO: subscribe the reload event.  
1160 - int hls_fragment = 0;  
1161 - int hls_window = 0;  
1162 -  
1163 - SrsConfDirective* conf = NULL;  
1164 - if ((conf = config->get_hls_fragment(vhost)) != NULL && !conf->arg0().empty()) {  
1165 - hls_fragment = ::atoi(conf->arg0().c_str());  
1166 - }  
1167 - if (hls_fragment <= 0) {  
1168 - hls_fragment = SRS_CONF_DEFAULT_HLS_FRAGMENT;  
1169 - }  
1170 -  
1171 - if ((conf = config->get_hls_window(vhost)) != NULL && !conf->arg0().empty()) {  
1172 - hls_window = ::atoi(conf->arg0().c_str());  
1173 - }  
1174 - if (hls_window <= 0) {  
1175 - hls_window = SRS_CONF_DEFAULT_HLS_WINDOW;  
1176 - } 1159 + int hls_fragment = config->get_hls_fragment(vhost);
  1160 + int hls_window = config->get_hls_window(vhost);
1177 1161
1178 // get the hls path config 1162 // get the hls path config
1179 - std::string hls_path = SRS_CONF_DEFAULT_HLS_PATH;  
1180 - if ((conf = config->get_hls_path(vhost)) != NULL) {  
1181 - hls_path = conf->arg0();  
1182 - } 1163 + std::string hls_path = config->get_hls_path(vhost);
1183 1164
1184 // open muxer 1165 // open muxer
1185 if ((ret = muxer->update_config(app, stream, hls_path, hls_fragment, hls_window)) != ERROR_SUCCESS) { 1166 if ((ret = muxer->update_config(app, stream, hls_path, hls_fragment, hls_window)) != ERROR_SUCCESS) {
@@ -1191,6 +1172,12 @@ int SrsHls::on_publish(SrsRequest* req) @@ -1191,6 +1172,12 @@ int SrsHls::on_publish(SrsRequest* req)
1191 srs_error("m3u8 muxer open segment failed. ret=%d", ret); 1172 srs_error("m3u8 muxer open segment failed. ret=%d", ret);
1192 return ret; 1173 return ret;
1193 } 1174 }
  1175 +
  1176 + // notice the source to get the cached sequence header.
  1177 + if ((ret = source->on_hls_start()) != ERROR_SUCCESS) {
  1178 + srs_error("callback source hls start failed. ret=%d", ret);
  1179 + return ret;
  1180 + }
1194 1181
1195 return ret; 1182 return ret;
1196 } 1183 }
@@ -1215,16 +1202,16 @@ void SrsHls::on_unpublish() @@ -1215,16 +1202,16 @@ void SrsHls::on_unpublish()
1215 hls_enabled = false; 1202 hls_enabled = false;
1216 } 1203 }
1217 1204
1218 -int SrsHls::on_meta_data(SrsOnMetaDataPacket* metadata) 1205 +int SrsHls::on_meta_data(SrsAmf0Object* metadata)
1219 { 1206 {
1220 int ret = ERROR_SUCCESS; 1207 int ret = ERROR_SUCCESS;
1221 1208
1222 - if (!metadata || !metadata->metadata) { 1209 + if (!metadata) {
1223 srs_trace("no metadata persent, hls ignored it."); 1210 srs_trace("no metadata persent, hls ignored it.");
1224 return ret; 1211 return ret;
1225 } 1212 }
1226 1213
1227 - SrsAmf0Object* obj = metadata->metadata; 1214 + SrsAmf0Object* obj = metadata;
1228 if (obj->size() <= 0) { 1215 if (obj->size() <= 0) {
1229 srs_trace("no metadata persent, hls ignored it."); 1216 srs_trace("no metadata persent, hls ignored it.");
1230 return ret; 1217 return ret;
@@ -1273,7 +1260,6 @@ int SrsHls::on_audio(SrsSharedPtrMessage* audio) @@ -1273,7 +1260,6 @@ int SrsHls::on_audio(SrsSharedPtrMessage* audio)
1273 1260
1274 SrsAutoFree(SrsSharedPtrMessage, audio, false); 1261 SrsAutoFree(SrsSharedPtrMessage, audio, false);
1275 1262
1276 - // TODO: maybe donot need to demux the aac?  
1277 if (!hls_enabled) { 1263 if (!hls_enabled) {
1278 return ret; 1264 return ret;
1279 } 1265 }
@@ -1293,14 +1279,13 @@ int SrsHls::on_audio(SrsSharedPtrMessage* audio) @@ -1293,14 +1279,13 @@ int SrsHls::on_audio(SrsSharedPtrMessage* audio)
1293 return ret; 1279 return ret;
1294 } 1280 }
1295 1281
1296 - int64_t corrected_time = 0;  
1297 - if ((ret = jitter->correct(audio, 0, 0, &corrected_time)) != ERROR_SUCCESS) { 1282 + if ((ret = jitter->correct(audio, 0, 0)) != ERROR_SUCCESS) {
1298 srs_error("rtmp jitter correct audio failed. ret=%d", ret); 1283 srs_error("rtmp jitter correct audio failed. ret=%d", ret);
1299 return ret; 1284 return ret;
1300 } 1285 }
1301 1286
1302 // the pts calc from rtmp/flv header. 1287 // the pts calc from rtmp/flv header.
1303 - int64_t pts = corrected_time * 90; 1288 + int64_t pts = audio->header.timestamp * 90;
1304 1289
1305 if ((ret = ts_cache->write_audio(codec, muxer, pts, sample)) != ERROR_SUCCESS) { 1290 if ((ret = ts_cache->write_audio(codec, muxer, pts, sample)) != ERROR_SUCCESS) {
1306 srs_error("ts cache write audio failed. ret=%d", ret); 1291 srs_error("ts cache write audio failed. ret=%d", ret);
@@ -1316,7 +1301,6 @@ int SrsHls::on_video(SrsSharedPtrMessage* video) @@ -1316,7 +1301,6 @@ int SrsHls::on_video(SrsSharedPtrMessage* video)
1316 1301
1317 SrsAutoFree(SrsSharedPtrMessage, video, false); 1302 SrsAutoFree(SrsSharedPtrMessage, video, false);
1318 1303
1319 - // TODO: maybe donot need to demux the avc?  
1320 if (!hls_enabled) { 1304 if (!hls_enabled) {
1321 return ret; 1305 return ret;
1322 } 1306 }
@@ -1337,24 +1321,23 @@ int SrsHls::on_video(SrsSharedPtrMessage* video) @@ -1337,24 +1321,23 @@ int SrsHls::on_video(SrsSharedPtrMessage* video)
1337 return ret; 1321 return ret;
1338 } 1322 }
1339 1323
1340 - int64_t corrected_time = 0;  
1341 - if ((ret = jitter->correct(video, 0, 0, &corrected_time)) != ERROR_SUCCESS) { 1324 + if ((ret = jitter->correct(video, 0, 0)) != ERROR_SUCCESS) {
1342 srs_error("rtmp jitter correct video failed. ret=%d", ret); 1325 srs_error("rtmp jitter correct video failed. ret=%d", ret);
1343 return ret; 1326 return ret;
1344 } 1327 }
1345 1328
1346 - int64_t dts = corrected_time * 90; 1329 + int64_t dts = video->header.timestamp * 90;
1347 if ((ret = ts_cache->write_video(codec, muxer, dts, sample)) != ERROR_SUCCESS) { 1330 if ((ret = ts_cache->write_video(codec, muxer, dts, sample)) != ERROR_SUCCESS) {
1348 srs_error("ts cache write video failed. ret=%d", ret); 1331 srs_error("ts cache write video failed. ret=%d", ret);
1349 return ret; 1332 return ret;
1350 } 1333 }
1351 1334
1352 - _mpegts(); 1335 + hls_mux();
1353 1336
1354 return ret; 1337 return ret;
1355 } 1338 }
1356 1339
1357 -void SrsHls::_mpegts() 1340 +void SrsHls::hls_mux()
1358 { 1341 {
1359 // reportable 1342 // reportable
1360 if (pithy_print->can_print()) { 1343 if (pithy_print->can_print()) {
@@ -34,16 +34,17 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -34,16 +34,17 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 #include <string> 34 #include <string>
35 #include <vector> 35 #include <vector>
36 36
37 -class SrsOnMetaDataPacket;  
38 class SrsSharedPtrMessage; 37 class SrsSharedPtrMessage;
39 class SrsCodecSample; 38 class SrsCodecSample;
40 class SrsCodecBuffer; 39 class SrsCodecBuffer;
41 class SrsMpegtsFrame; 40 class SrsMpegtsFrame;
  41 +class SrsAmf0Object;
42 class SrsRtmpJitter; 42 class SrsRtmpJitter;
43 class SrsTSMuxer; 43 class SrsTSMuxer;
44 class SrsCodec; 44 class SrsCodec;
45 class SrsRequest; 45 class SrsRequest;
46 class SrsPithyPrint; 46 class SrsPithyPrint;
  47 +class SrsSource;
47 48
48 /** 49 /**
49 * jitter correct for audio, 50 * jitter correct for audio,
@@ -207,21 +208,39 @@ private: @@ -207,21 +208,39 @@ private:
207 SrsTSCache* ts_cache; 208 SrsTSCache* ts_cache;
208 private: 209 private:
209 bool hls_enabled; 210 bool hls_enabled;
  211 + SrsSource* source;
210 SrsCodec* codec; 212 SrsCodec* codec;
211 SrsCodecSample* sample; 213 SrsCodecSample* sample;
212 SrsRtmpJitter* jitter; 214 SrsRtmpJitter* jitter;
213 SrsPithyPrint* pithy_print; 215 SrsPithyPrint* pithy_print;
214 public: 216 public:
215 - SrsHls(); 217 + SrsHls(SrsSource* _source);
216 virtual ~SrsHls(); 218 virtual ~SrsHls();
217 public: 219 public:
  220 + /**
  221 + * publish stream event, continue to write the m3u8,
  222 + * for the muxer object not destroyed.
  223 + */
218 virtual int on_publish(SrsRequest* req); 224 virtual int on_publish(SrsRequest* req);
  225 + /**
  226 + * the unpublish event, only close the muxer, donot destroy the
  227 + * muxer, for when we continue to publish, the m3u8 will continue.
  228 + */
219 virtual void on_unpublish(); 229 virtual void on_unpublish();
220 - virtual int on_meta_data(SrsOnMetaDataPacket* metadata); 230 + /**
  231 + * get some information from metadata, it's optinal.
  232 + */
  233 + virtual int on_meta_data(SrsAmf0Object* metadata);
  234 + /**
  235 + * mux the audio packets to ts.
  236 + */
221 virtual int on_audio(SrsSharedPtrMessage* audio); 237 virtual int on_audio(SrsSharedPtrMessage* audio);
  238 + /**
  239 + * mux the video packets to ts.
  240 + */
222 virtual int on_video(SrsSharedPtrMessage* video); 241 virtual int on_video(SrsSharedPtrMessage* video);
223 private: 242 private:
224 - virtual void _mpegts(); 243 + virtual void hls_mux();
225 }; 244 };
226 245
227 #endif 246 #endif
@@ -184,15 +184,7 @@ void SrsHttpClient::disconnect() @@ -184,15 +184,7 @@ void SrsHttpClient::disconnect()
184 { 184 {
185 connected = false; 185 connected = false;
186 186
187 - if (stfd) {  
188 - int fd = st_netfd_fileno(stfd);  
189 - st_netfd_close(stfd);  
190 - stfd = NULL;  
191 -  
192 - // st does not close it sometimes,  
193 - // close it manually.  
194 - ::close(fd);  
195 - } 187 + srs_close_stfd(stfd);
196 } 188 }
197 189
198 int SrsHttpClient::connect(SrsHttpUri* uri) 190 int SrsHttpClient::connect(SrsHttpUri* uri)
@@ -36,7 +36,6 @@ class SrsSocket; @@ -36,7 +36,6 @@ class SrsSocket;
36 36
37 #include <string> 37 #include <string>
38 38
39 -#include <st.h>  
40 #include <http_parser.h> 39 #include <http_parser.h>
41 40
42 #define SRS_HTTP_HEADER_BUFFER 1024 41 #define SRS_HTTP_HEADER_BUFFER 1024
@@ -29,8 +29,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -29,8 +29,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 #include <string> 29 #include <string>
30 #include <map> 30 #include <map>
31 31
32 -#include <st.h>  
33 -  
34 ILogContext::ILogContext() 32 ILogContext::ILogContext()
35 { 33 {
36 } 34 }
@@ -32,13 +32,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -32,13 +32,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 #include <srs_core_error.hpp> 32 #include <srs_core_error.hpp>
33 33
34 #define SRS_STAGE_DEFAULT_INTERVAL_MS 1200 34 #define SRS_STAGE_DEFAULT_INTERVAL_MS 1200
35 -#define SRS_STAGE_PLAY_USER_INTERVAL_MS 1300  
36 -#define SRS_STAGE_PUBLISH_USER_INTERVAL_MS 1100  
37 -#define SRS_STAGE_FORWARDER_INTERVAL_MS 2000  
38 -#define SRS_STAGE_ENCODER_INTERVAL_MS 2000  
39 -#define SRS_STAGE_HLS_INTERVAL_MS 2000  
40 35
41 -struct SrsStageInfo : public SrsReloadHandler 36 +struct SrsStageInfo : public ISrsReloadHandler
42 { 37 {
43 int stage_id; 38 int stage_id;
44 int pithy_print_time_ms; 39 int pithy_print_time_ms;
@@ -61,43 +56,23 @@ struct SrsStageInfo : public SrsReloadHandler @@ -61,43 +56,23 @@ struct SrsStageInfo : public SrsReloadHandler
61 { 56 {
62 switch (stage_id) { 57 switch (stage_id) {
63 case SRS_STAGE_PLAY_USER: { 58 case SRS_STAGE_PLAY_USER: {
64 - pithy_print_time_ms = SRS_STAGE_PLAY_USER_INTERVAL_MS;  
65 - SrsConfDirective* conf = config->get_pithy_print_play();  
66 - if (conf && !conf->arg0().empty()) {  
67 - pithy_print_time_ms = ::atoi(conf->arg0().c_str());  
68 - } 59 + pithy_print_time_ms = config->get_pithy_print_play();
69 break; 60 break;
70 } 61 }
71 case SRS_STAGE_PUBLISH_USER: { 62 case SRS_STAGE_PUBLISH_USER: {
72 - pithy_print_time_ms = SRS_STAGE_PUBLISH_USER_INTERVAL_MS;  
73 - SrsConfDirective* conf = config->get_pithy_print_publish();  
74 - if (conf && !conf->arg0().empty()) {  
75 - pithy_print_time_ms = ::atoi(conf->arg0().c_str());  
76 - } 63 + pithy_print_time_ms = config->get_pithy_print_publish();
77 break; 64 break;
78 } 65 }
79 case SRS_STAGE_FORWARDER: { 66 case SRS_STAGE_FORWARDER: {
80 - pithy_print_time_ms = SRS_STAGE_FORWARDER_INTERVAL_MS;  
81 - SrsConfDirective* conf = config->get_pithy_print_forwarder();  
82 - if (conf && !conf->arg0().empty()) {  
83 - pithy_print_time_ms = ::atoi(conf->arg0().c_str());  
84 - } 67 + pithy_print_time_ms = config->get_pithy_print_forwarder();
85 break; 68 break;
86 } 69 }
87 case SRS_STAGE_ENCODER: { 70 case SRS_STAGE_ENCODER: {
88 - pithy_print_time_ms = SRS_STAGE_ENCODER_INTERVAL_MS;  
89 - SrsConfDirective* conf = config->get_pithy_print_encoder();  
90 - if (conf && !conf->arg0().empty()) {  
91 - pithy_print_time_ms = ::atoi(conf->arg0().c_str());  
92 - } 71 + pithy_print_time_ms = config->get_pithy_print_encoder();
93 break; 72 break;
94 } 73 }
95 case SRS_STAGE_HLS: { 74 case SRS_STAGE_HLS: {
96 - pithy_print_time_ms = SRS_STAGE_HLS_INTERVAL_MS;  
97 - SrsConfDirective* conf = config->get_pithy_print_hls();  
98 - if (conf && !conf->arg0().empty()) {  
99 - pithy_print_time_ms = ::atoi(conf->arg0().c_str());  
100 - } 75 + pithy_print_time_ms = config->get_pithy_print_hls();
101 break; 76 break;
102 } 77 }
103 default: { 78 default: {
@@ -307,6 +307,11 @@ void SrsProtocol::set_send_timeout(int64_t timeout_us) @@ -307,6 +307,11 @@ void SrsProtocol::set_send_timeout(int64_t timeout_us)
307 return skt->set_send_timeout(timeout_us); 307 return skt->set_send_timeout(timeout_us);
308 } 308 }
309 309
  310 +int64_t SrsProtocol::get_send_timeout()
  311 +{
  312 + return skt->get_send_timeout();
  313 +}
  314 +
310 int64_t SrsProtocol::get_recv_bytes() 315 int64_t SrsProtocol::get_recv_bytes()
311 { 316 {
312 return skt->get_recv_bytes(); 317 return skt->get_recv_bytes();
@@ -349,7 +354,7 @@ int SrsProtocol::recv_message(SrsCommonMessage** pmsg) @@ -349,7 +354,7 @@ int SrsProtocol::recv_message(SrsCommonMessage** pmsg)
349 } 354 }
350 355
351 if (msg->size <= 0 || msg->header.payload_length <= 0) { 356 if (msg->size <= 0 || msg->header.payload_length <= 0) {
352 - srs_trace("ignore empty message(type=%d, size=%d, time=%d, sid=%d).", 357 + srs_trace("ignore empty message(type=%d, size=%d, time=%"PRId64", sid=%d).",
353 msg->header.message_type, msg->header.payload_length, 358 msg->header.message_type, msg->header.payload_length,
354 msg->header.timestamp, msg->header.stream_id); 359 msg->header.timestamp, msg->header.stream_id);
355 srs_freep(msg); 360 srs_freep(msg);
@@ -400,12 +405,13 @@ int SrsProtocol::send_message(ISrsMessage* msg) @@ -400,12 +405,13 @@ int SrsProtocol::send_message(ISrsMessage* msg)
400 405
401 // chunk message header, 11 bytes 406 // chunk message header, 11 bytes
402 // timestamp, 3bytes, big-endian 407 // timestamp, 3bytes, big-endian
403 - if (msg->header.timestamp >= RTMP_EXTENDED_TIMESTAMP) { 408 + u_int32_t timestamp = (u_int32_t)msg->header.timestamp;
  409 + if (timestamp >= RTMP_EXTENDED_TIMESTAMP) {
404 *pheader++ = 0xFF; 410 *pheader++ = 0xFF;
405 *pheader++ = 0xFF; 411 *pheader++ = 0xFF;
406 *pheader++ = 0xFF; 412 *pheader++ = 0xFF;
407 } else { 413 } else {
408 - pp = (char*)&msg->header.timestamp; 414 + pp = (char*)&timestamp;
409 *pheader++ = pp[2]; 415 *pheader++ = pp[2];
410 *pheader++ = pp[1]; 416 *pheader++ = pp[1];
411 *pheader++ = pp[0]; 417 *pheader++ = pp[0];
@@ -428,8 +434,8 @@ int SrsProtocol::send_message(ISrsMessage* msg) @@ -428,8 +434,8 @@ int SrsProtocol::send_message(ISrsMessage* msg)
428 *pheader++ = pp[3]; 434 *pheader++ = pp[3];
429 435
430 // chunk extended timestamp header, 0 or 4 bytes, big-endian 436 // chunk extended timestamp header, 0 or 4 bytes, big-endian
431 - if(msg->header.timestamp >= RTMP_EXTENDED_TIMESTAMP){  
432 - pp = (char*)&msg->header.timestamp; 437 + if(timestamp >= RTMP_EXTENDED_TIMESTAMP){
  438 + pp = (char*)&timestamp;
433 *pheader++ = pp[3]; 439 *pheader++ = pp[3];
434 *pheader++ = pp[2]; 440 *pheader++ = pp[2];
435 *pheader++ = pp[1]; 441 *pheader++ = pp[1];
@@ -456,8 +462,9 @@ int SrsProtocol::send_message(ISrsMessage* msg) @@ -456,8 +462,9 @@ int SrsProtocol::send_message(ISrsMessage* msg)
456 // must send the extended-timestamp to flash-player. 462 // must send the extended-timestamp to flash-player.
457 // @see: ngx_rtmp_prepare_message 463 // @see: ngx_rtmp_prepare_message
458 // @see: http://blog.csdn.net/win_lin/article/details/13363699 464 // @see: http://blog.csdn.net/win_lin/article/details/13363699
459 - if(msg->header.timestamp >= RTMP_EXTENDED_TIMESTAMP){  
460 - pp = (char*)&msg->header.timestamp; 465 + u_int32_t timestamp = (u_int32_t)msg->header.timestamp;
  466 + if(timestamp >= RTMP_EXTENDED_TIMESTAMP){
  467 + pp = (char*)&timestamp;
461 *pheader++ = pp[3]; 468 *pheader++ = pp[3];
462 *pheader++ = pp[2]; 469 *pheader++ = pp[2];
463 *pheader++ = pp[1]; 470 *pheader++ = pp[1];
@@ -697,7 +704,7 @@ int SrsProtocol::recv_interlaced_message(SrsCommonMessage** pmsg) @@ -697,7 +704,7 @@ int SrsProtocol::recv_interlaced_message(SrsCommonMessage** pmsg)
697 srs_verbose("cache new chunk stream: fmt=%d, cid=%d", fmt, cid); 704 srs_verbose("cache new chunk stream: fmt=%d, cid=%d", fmt, cid);
698 } else { 705 } else {
699 chunk = chunk_streams[cid]; 706 chunk = chunk_streams[cid];
700 - srs_verbose("cached chunk stream: fmt=%d, cid=%d, size=%d, message(type=%d, size=%d, time=%d, sid=%d)", 707 + srs_verbose("cached chunk stream: fmt=%d, cid=%d, size=%d, message(type=%d, size=%d, time=%"PRId64", sid=%d)",
701 chunk->fmt, chunk->cid, (chunk->msg? chunk->msg->size : 0), chunk->header.message_type, chunk->header.payload_length, 708 chunk->fmt, chunk->cid, (chunk->msg? chunk->msg->size : 0), chunk->header.message_type, chunk->header.payload_length,
702 chunk->header.timestamp, chunk->header.stream_id); 709 chunk->header.timestamp, chunk->header.stream_id);
703 } 710 }
@@ -711,7 +718,7 @@ int SrsProtocol::recv_interlaced_message(SrsCommonMessage** pmsg) @@ -711,7 +718,7 @@ int SrsProtocol::recv_interlaced_message(SrsCommonMessage** pmsg)
711 return ret; 718 return ret;
712 } 719 }
713 srs_verbose("read message header success. " 720 srs_verbose("read message header success. "
714 - "fmt=%d, mh_size=%d, ext_time=%d, size=%d, message(type=%d, size=%d, time=%d, sid=%d)", 721 + "fmt=%d, mh_size=%d, ext_time=%d, size=%d, message(type=%d, size=%d, time=%"PRId64", sid=%d)",
715 fmt, mh_size, chunk->extended_timestamp, (chunk->msg? chunk->msg->size : 0), chunk->header.message_type, 722 fmt, mh_size, chunk->extended_timestamp, (chunk->msg? chunk->msg->size : 0), chunk->header.message_type,
716 chunk->header.payload_length, chunk->header.timestamp, chunk->header.stream_id); 723 chunk->header.payload_length, chunk->header.timestamp, chunk->header.stream_id);
717 724
@@ -733,14 +740,14 @@ int SrsProtocol::recv_interlaced_message(SrsCommonMessage** pmsg) @@ -733,14 +740,14 @@ int SrsProtocol::recv_interlaced_message(SrsCommonMessage** pmsg)
733 740
734 // not got an entire RTMP message, try next chunk. 741 // not got an entire RTMP message, try next chunk.
735 if (!msg) { 742 if (!msg) {
736 - srs_verbose("get partial message success. chunk_payload_size=%d, size=%d, message(type=%d, size=%d, time=%d, sid=%d)", 743 + srs_verbose("get partial message success. chunk_payload_size=%d, size=%d, message(type=%d, size=%d, time=%"PRId64", sid=%d)",
737 payload_size, (msg? msg->size : (chunk->msg? chunk->msg->size : 0)), chunk->header.message_type, chunk->header.payload_length, 744 payload_size, (msg? msg->size : (chunk->msg? chunk->msg->size : 0)), chunk->header.message_type, chunk->header.payload_length,
738 chunk->header.timestamp, chunk->header.stream_id); 745 chunk->header.timestamp, chunk->header.stream_id);
739 return ret; 746 return ret;
740 } 747 }
741 748
742 *pmsg = msg; 749 *pmsg = msg;
743 - srs_info("get entire message success. chunk_payload_size=%d, size=%d, message(type=%d, size=%d, time=%d, sid=%d)", 750 + srs_info("get entire message success. chunk_payload_size=%d, size=%d, message(type=%d, size=%d, time=%"PRId64", sid=%d)",
744 payload_size, (msg? msg->size : (chunk->msg? chunk->msg->size : 0)), chunk->header.message_type, chunk->header.payload_length, 751 payload_size, (msg? msg->size : (chunk->msg? chunk->msg->size : 0)), chunk->header.message_type, chunk->header.payload_length,
745 chunk->header.timestamp, chunk->header.stream_id); 752 chunk->header.timestamp, chunk->header.stream_id);
746 753
@@ -947,16 +954,16 @@ int SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt, int bh_siz @@ -947,16 +954,16 @@ int SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt, int bh_siz
947 pp[1] = *p++; 954 pp[1] = *p++;
948 pp[2] = *p++; 955 pp[2] = *p++;
949 pp[3] = *p++; 956 pp[3] = *p++;
950 - srs_verbose("header read completed. fmt=%d, mh_size=%d, ext_time=%d, time=%d, payload=%d, type=%d, sid=%d", 957 + srs_verbose("header read completed. fmt=%d, mh_size=%d, ext_time=%d, time=%"PRId64", payload=%d, type=%d, sid=%d",
951 fmt, mh_size, chunk->extended_timestamp, chunk->header.timestamp, chunk->header.payload_length, 958 fmt, mh_size, chunk->extended_timestamp, chunk->header.timestamp, chunk->header.payload_length,
952 chunk->header.message_type, chunk->header.stream_id); 959 chunk->header.message_type, chunk->header.stream_id);
953 } else { 960 } else {
954 - srs_verbose("header read completed. fmt=%d, mh_size=%d, ext_time=%d, time=%d, payload=%d, type=%d", 961 + srs_verbose("header read completed. fmt=%d, mh_size=%d, ext_time=%d, time=%"PRId64", payload=%d, type=%d",
955 fmt, mh_size, chunk->extended_timestamp, chunk->header.timestamp, chunk->header.payload_length, 962 fmt, mh_size, chunk->extended_timestamp, chunk->header.timestamp, chunk->header.payload_length,
956 chunk->header.message_type); 963 chunk->header.message_type);
957 } 964 }
958 } else { 965 } else {
959 - srs_verbose("header read completed. fmt=%d, mh_size=%d, ext_time=%d, time=%d", 966 + srs_verbose("header read completed. fmt=%d, mh_size=%d, ext_time=%d, time=%"PRId64"",
960 fmt, mh_size, chunk->extended_timestamp, chunk->header.timestamp); 967 fmt, mh_size, chunk->extended_timestamp, chunk->header.timestamp);
961 } 968 }
962 } else { 969 } else {
@@ -981,7 +988,7 @@ int SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt, int bh_siz @@ -981,7 +988,7 @@ int SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt, int bh_siz
981 988
982 // ffmpeg/librtmp may donot send this filed, need to detect the value. 989 // ffmpeg/librtmp may donot send this filed, need to detect the value.
983 // @see also: http://blog.csdn.net/win_lin/article/details/13363699 990 // @see also: http://blog.csdn.net/win_lin/article/details/13363699
984 - int32_t timestamp = 0x00; 991 + u_int32_t timestamp = 0x00;
985 char* pp = (char*)&timestamp; 992 char* pp = (char*)&timestamp;
986 pp[3] = *p++; 993 pp[3] = *p++;
987 pp[2] = *p++; 994 pp[2] = *p++;
@@ -990,14 +997,14 @@ int SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt, int bh_siz @@ -990,14 +997,14 @@ int SrsProtocol::read_message_header(SrsChunkStream* chunk, char fmt, int bh_siz
990 997
991 // compare to the chunk timestamp, which is set by chunk message header 998 // compare to the chunk timestamp, which is set by chunk message header
992 // type 0,1 or 2. 999 // type 0,1 or 2.
993 - int32_t chunk_timestamp = chunk->header.timestamp; 1000 + u_int32_t chunk_timestamp = chunk->header.timestamp;
994 if (chunk_timestamp > RTMP_EXTENDED_TIMESTAMP && chunk_timestamp != timestamp) { 1001 if (chunk_timestamp > RTMP_EXTENDED_TIMESTAMP && chunk_timestamp != timestamp) {
995 mh_size -= 4; 1002 mh_size -= 4;
996 srs_verbose("ignore the 4bytes extended timestamp. mh_size=%d", mh_size); 1003 srs_verbose("ignore the 4bytes extended timestamp. mh_size=%d", mh_size);
997 } else { 1004 } else {
998 chunk->header.timestamp = timestamp; 1005 chunk->header.timestamp = timestamp;
999 } 1006 }
1000 - srs_verbose("header read ext_time completed. time=%d", chunk->header.timestamp); 1007 + srs_verbose("header read ext_time completed. time=%"PRId64"", chunk->header.timestamp);
1001 } 1008 }
1002 1009
1003 // valid message 1010 // valid message
@@ -1027,7 +1034,7 @@ int SrsProtocol::read_message_payload(SrsChunkStream* chunk, int bh_size, int mh @@ -1027,7 +1034,7 @@ int SrsProtocol::read_message_payload(SrsChunkStream* chunk, int bh_size, int mh
1027 buffer->erase(bh_size + mh_size); 1034 buffer->erase(bh_size + mh_size);
1028 1035
1029 srs_trace("get an empty RTMP " 1036 srs_trace("get an empty RTMP "
1030 - "message(type=%d, size=%d, time=%d, sid=%d)", chunk->header.message_type, 1037 + "message(type=%d, size=%d, time=%"PRId64", sid=%d)", chunk->header.message_type,
1031 chunk->header.payload_length, chunk->header.timestamp, chunk->header.stream_id); 1038 chunk->header.payload_length, chunk->header.timestamp, chunk->header.stream_id);
1032 1039
1033 *pmsg = chunk->msg; 1040 *pmsg = chunk->msg;
@@ -1068,13 +1075,13 @@ int SrsProtocol::read_message_payload(SrsChunkStream* chunk, int bh_size, int mh @@ -1068,13 +1075,13 @@ int SrsProtocol::read_message_payload(SrsChunkStream* chunk, int bh_size, int mh
1068 if (chunk->header.payload_length == chunk->msg->size) { 1075 if (chunk->header.payload_length == chunk->msg->size) {
1069 *pmsg = chunk->msg; 1076 *pmsg = chunk->msg;
1070 chunk->msg = NULL; 1077 chunk->msg = NULL;
1071 - srs_verbose("get entire RTMP message(type=%d, size=%d, time=%d, sid=%d)", 1078 + srs_verbose("get entire RTMP message(type=%d, size=%d, time=%"PRId64", sid=%d)",
1072 chunk->header.message_type, chunk->header.payload_length, 1079 chunk->header.message_type, chunk->header.payload_length,
1073 chunk->header.timestamp, chunk->header.stream_id); 1080 chunk->header.timestamp, chunk->header.stream_id);
1074 return ret; 1081 return ret;
1075 } 1082 }
1076 1083
1077 - srs_verbose("get partial RTMP message(type=%d, size=%d, time=%d, sid=%d), partial size=%d", 1084 + srs_verbose("get partial RTMP message(type=%d, size=%d, time=%"PRId64", sid=%d), partial size=%d",
1078 chunk->header.message_type, chunk->header.payload_length, 1085 chunk->header.message_type, chunk->header.payload_length,
1079 chunk->header.timestamp, chunk->header.stream_id, 1086 chunk->header.timestamp, chunk->header.stream_id,
1080 chunk->msg->size); 1087 chunk->msg->size);
@@ -33,8 +33,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -33,8 +33,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 #include <map> 33 #include <map>
34 #include <string> 34 #include <string>
35 35
36 -#include <st.h>  
37 -  
38 #include <srs_core_log.hpp> 36 #include <srs_core_log.hpp>
39 #include <srs_core_error.hpp> 37 #include <srs_core_error.hpp>
40 38
@@ -117,6 +115,7 @@ public: @@ -117,6 +115,7 @@ public:
117 virtual void set_recv_timeout(int64_t timeout_us); 115 virtual void set_recv_timeout(int64_t timeout_us);
118 virtual int64_t get_recv_timeout(); 116 virtual int64_t get_recv_timeout();
119 virtual void set_send_timeout(int64_t timeout_us); 117 virtual void set_send_timeout(int64_t timeout_us);
  118 + virtual int64_t get_send_timeout();
120 virtual int64_t get_recv_bytes(); 119 virtual int64_t get_recv_bytes();
121 virtual int64_t get_send_bytes(); 120 virtual int64_t get_send_bytes();
122 virtual int get_recv_kbps(); 121 virtual int get_recv_kbps();
@@ -205,8 +204,9 @@ struct SrsMessageHeader @@ -205,8 +204,9 @@ struct SrsMessageHeader
205 * Four-byte field that contains a timestamp of the message. 204 * Four-byte field that contains a timestamp of the message.
206 * The 4 bytes are packed in the big-endian order. 205 * The 4 bytes are packed in the big-endian order.
207 * @remark, used as calc timestamp when decode and encode time. 206 * @remark, used as calc timestamp when decode and encode time.
  207 + * @remark, we use 64bits for large time for jitter detect and hls.
208 */ 208 */
209 - u_int32_t timestamp; 209 + int64_t timestamp;
210 210
211 SrsMessageHeader(); 211 SrsMessageHeader();
212 virtual ~SrsMessageHeader(); 212 virtual ~SrsMessageHeader();
@@ -1156,7 +1156,7 @@ int srs_rtmp_expect_message(SrsProtocol* protocol, SrsCommonMessage** pmsg, T** @@ -1156,7 +1156,7 @@ int srs_rtmp_expect_message(SrsProtocol* protocol, SrsCommonMessage** pmsg, T**
1156 T* pkt = dynamic_cast<T*>(msg->get_packet()); 1156 T* pkt = dynamic_cast<T*>(msg->get_packet());
1157 if (!pkt) { 1157 if (!pkt) {
1158 delete msg; 1158 delete msg;
1159 - srs_trace("drop message(type=%d, size=%d, time=%d, sid=%d).", 1159 + srs_trace("drop message(type=%d, size=%d, time=%"PRId64", sid=%d).",
1160 msg->header.message_type, msg->header.payload_length, 1160 msg->header.message_type, msg->header.payload_length,
1161 msg->header.timestamp, msg->header.stream_id); 1161 msg->header.timestamp, msg->header.stream_id);
1162 continue; 1162 continue;
@@ -23,22 +23,54 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -23,22 +23,54 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 23
24 #include <srs_core_reload.hpp> 24 #include <srs_core_reload.hpp>
25 25
  26 +using namespace std;
  27 +
26 #include <srs_core_error.hpp> 28 #include <srs_core_error.hpp>
27 29
28 -SrsReloadHandler::SrsReloadHandler() 30 +ISrsReloadHandler::ISrsReloadHandler()
  31 +{
  32 +}
  33 +
  34 +ISrsReloadHandler::~ISrsReloadHandler()
29 { 35 {
30 } 36 }
31 37
32 -SrsReloadHandler::~SrsReloadHandler() 38 +int ISrsReloadHandler::on_reload_listen()
33 { 39 {
  40 + return ERROR_SUCCESS;
  41 +}
  42 +
  43 +int ISrsReloadHandler::on_reload_pithy_print()
  44 +{
  45 + return ERROR_SUCCESS;
  46 +}
  47 +
  48 +int ISrsReloadHandler::on_reload_vhost_removed(string /*vhost*/)
  49 +{
  50 + return ERROR_SUCCESS;
  51 +}
  52 +
  53 +int ISrsReloadHandler::on_reload_gop_cache(string /*vhost*/)
  54 +{
  55 + return ERROR_SUCCESS;
  56 +}
  57 +
  58 +int ISrsReloadHandler::on_reload_queue_length(string /*vhost*/)
  59 +{
  60 + return ERROR_SUCCESS;
  61 +}
  62 +
  63 +int ISrsReloadHandler::on_reload_forward(string /*vhost*/)
  64 +{
  65 + return ERROR_SUCCESS;
34 } 66 }
35 67
36 -int SrsReloadHandler::on_reload_listen() 68 +int ISrsReloadHandler::on_reload_hls(string /*vhost*/)
37 { 69 {
38 return ERROR_SUCCESS; 70 return ERROR_SUCCESS;
39 } 71 }
40 72
41 -int SrsReloadHandler::on_reload_pithy_print() 73 +int ISrsReloadHandler::on_reload_transcode(string /*vhost*/)
42 { 74 {
43 return ERROR_SUCCESS; 75 return ERROR_SUCCESS;
44 } 76 }
@@ -29,17 +29,25 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -29,17 +29,25 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 */ 29 */
30 #include <srs_core.hpp> 30 #include <srs_core.hpp>
31 31
  32 +#include <string>
  33 +
32 /** 34 /**
33 * the handler for config reload. 35 * the handler for config reload.
34 */ 36 */
35 -class SrsReloadHandler 37 +class ISrsReloadHandler
36 { 38 {
37 public: 39 public:
38 - SrsReloadHandler();  
39 - virtual ~SrsReloadHandler(); 40 + ISrsReloadHandler();
  41 + virtual ~ISrsReloadHandler();
40 public: 42 public:
41 virtual int on_reload_listen(); 43 virtual int on_reload_listen();
42 virtual int on_reload_pithy_print(); 44 virtual int on_reload_pithy_print();
  45 + virtual int on_reload_vhost_removed(std::string vhost);
  46 + virtual int on_reload_gop_cache(std::string vhost);
  47 + virtual int on_reload_queue_length(std::string vhost);
  48 + virtual int on_reload_forward(std::string vhost);
  49 + virtual int on_reload_hls(std::string vhost);
  50 + virtual int on_reload_transcode(std::string vhost);
43 }; 51 };
44 52
45 #endif 53 #endif
@@ -33,6 +33,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -33,6 +33,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 #include <srs_core_handshake.hpp> 33 #include <srs_core_handshake.hpp>
34 #include <srs_core_config.hpp> 34 #include <srs_core_config.hpp>
35 35
  36 +using namespace std;
  37 +
36 /** 38 /**
37 * the signature for packets to client. 39 * the signature for packets to client.
38 */ 40 */
@@ -79,6 +81,23 @@ SrsRequest::~SrsRequest() @@ -79,6 +81,23 @@ SrsRequest::~SrsRequest()
79 { 81 {
80 } 82 }
81 83
  84 +SrsRequest* SrsRequest::copy()
  85 +{
  86 + SrsRequest* cp = new SrsRequest();
  87 +
  88 + cp->app = app;
  89 + cp->objectEncoding = objectEncoding;
  90 + cp->pageUrl = pageUrl;
  91 + cp->port = port;
  92 + cp->schema = schema;
  93 + cp->stream = stream;
  94 + cp->swfUrl = swfUrl;
  95 + cp->tcUrl = tcUrl;
  96 + cp->vhost = vhost;
  97 +
  98 + return cp;
  99 +}
  100 +
82 int SrsRequest::discovery_app() 101 int SrsRequest::discovery_app()
83 { 102 {
84 int ret = ERROR_SUCCESS; 103 int ret = ERROR_SUCCESS;
@@ -125,6 +144,8 @@ int SrsRequest::discovery_app() @@ -125,6 +144,8 @@ int SrsRequest::discovery_app()
125 if (parsed_vhost) { 144 if (parsed_vhost) {
126 vhost = parsed_vhost->arg0(); 145 vhost = parsed_vhost->arg0();
127 } 146 }
  147 +
  148 + // TODO: discovery the params of vhost.
128 149
129 srs_info("discovery app success. schema=%s, vhost=%s, port=%s, app=%s", 150 srs_info("discovery app success. schema=%s, vhost=%s, port=%s, app=%s",
130 schema.c_str(), vhost.c_str(), port.c_str(), app.c_str()); 151 schema.c_str(), vhost.c_str(), port.c_str(), app.c_str());
@@ -142,7 +163,7 @@ int SrsRequest::discovery_app() @@ -142,7 +163,7 @@ int SrsRequest::discovery_app()
142 return ret; 163 return ret;
143 } 164 }
144 165
145 -std::string SrsRequest::get_stream_url() 166 +string SrsRequest::get_stream_url()
146 { 167 {
147 std::string url = ""; 168 std::string url = "";
148 169
@@ -162,7 +183,7 @@ void SrsRequest::strip() @@ -162,7 +183,7 @@ void SrsRequest::strip()
162 trim(stream, "/ \n\r\t"); 183 trim(stream, "/ \n\r\t");
163 } 184 }
164 185
165 -std::string& SrsRequest::trim(std::string& str, std::string chs) 186 +std::string& SrsRequest::trim(string& str, string chs)
166 { 187 {
167 for (int i = 0; i < (int)chs.length(); i++) { 188 for (int i = 0; i < (int)chs.length(); i++) {
168 char ch = chs.at(i); 189 char ch = chs.at(i);
@@ -245,6 +266,9 @@ int SrsRtmpClient::handshake() @@ -245,6 +266,9 @@ int SrsRtmpClient::handshake()
245 266
246 SrsSocket skt(stfd); 267 SrsSocket skt(stfd);
247 268
  269 + skt.set_recv_timeout(protocol->get_recv_timeout());
  270 + skt.set_send_timeout(protocol->get_send_timeout());
  271 +
248 SrsComplexHandshake complex_hs; 272 SrsComplexHandshake complex_hs;
249 SrsSimpleHandshake simple_hs; 273 SrsSimpleHandshake simple_hs;
250 if ((ret = simple_hs.handshake_with_server(skt, complex_hs)) != ERROR_SUCCESS) { 274 if ((ret = simple_hs.handshake_with_server(skt, complex_hs)) != ERROR_SUCCESS) {
@@ -436,6 +460,11 @@ void SrsRtmp::set_send_timeout(int64_t timeout_us) @@ -436,6 +460,11 @@ void SrsRtmp::set_send_timeout(int64_t timeout_us)
436 protocol->set_send_timeout(timeout_us); 460 protocol->set_send_timeout(timeout_us);
437 } 461 }
438 462
  463 +int64_t SrsRtmp::get_send_timeout()
  464 +{
  465 + return protocol->get_send_timeout();
  466 +}
  467 +
439 int64_t SrsRtmp::get_recv_bytes() 468 int64_t SrsRtmp::get_recv_bytes()
440 { 469 {
441 return protocol->get_recv_bytes(); 470 return protocol->get_recv_bytes();
@@ -472,6 +501,9 @@ int SrsRtmp::handshake() @@ -472,6 +501,9 @@ int SrsRtmp::handshake()
472 501
473 SrsSocket skt(stfd); 502 SrsSocket skt(stfd);
474 503
  504 + skt.set_recv_timeout(protocol->get_recv_timeout());
  505 + skt.set_send_timeout(protocol->get_send_timeout());
  506 +
475 SrsComplexHandshake complex_hs; 507 SrsComplexHandshake complex_hs;
476 SrsSimpleHandshake simple_hs; 508 SrsSimpleHandshake simple_hs;
477 if ((ret = simple_hs.handshake_with_client(skt, complex_hs)) != ERROR_SUCCESS) { 509 if ((ret = simple_hs.handshake_with_client(skt, complex_hs)) != ERROR_SUCCESS) {
@@ -1127,7 +1159,7 @@ int SrsRtmp::start_bandwidth_check(int max_play_kbps, int max_pub_kbps) @@ -1127,7 +1159,7 @@ int SrsRtmp::start_bandwidth_check(int max_play_kbps, int max_pub_kbps)
1127 return ret; 1159 return ret;
1128 } 1160 }
1129 1161
1130 -int SrsRtmp::identify_create_stream_client(SrsCreateStreamPacket* req, int stream_id, SrsClientType& type, std::string& stream_name) 1162 +int SrsRtmp::identify_create_stream_client(SrsCreateStreamPacket* req, int stream_id, SrsClientType& type, string& stream_name)
1131 { 1163 {
1132 int ret = ERROR_SUCCESS; 1164 int ret = ERROR_SUCCESS;
1133 1165
@@ -1184,7 +1216,7 @@ int SrsRtmp::identify_create_stream_client(SrsCreateStreamPacket* req, int strea @@ -1184,7 +1216,7 @@ int SrsRtmp::identify_create_stream_client(SrsCreateStreamPacket* req, int strea
1184 return ret; 1216 return ret;
1185 } 1217 }
1186 1218
1187 -int SrsRtmp::identify_fmle_publish_client(SrsFMLEStartPacket* req, SrsClientType& type, std::string& stream_name) 1219 +int SrsRtmp::identify_fmle_publish_client(SrsFMLEStartPacket* req, SrsClientType& type, string& stream_name)
1188 { 1220 {
1189 int ret = ERROR_SUCCESS; 1221 int ret = ERROR_SUCCESS;
1190 1222
@@ -1208,7 +1240,7 @@ int SrsRtmp::identify_fmle_publish_client(SrsFMLEStartPacket* req, SrsClientType @@ -1208,7 +1240,7 @@ int SrsRtmp::identify_fmle_publish_client(SrsFMLEStartPacket* req, SrsClientType
1208 return ret; 1240 return ret;
1209 } 1241 }
1210 1242
1211 -int SrsRtmp::identify_flash_publish_client(SrsPublishPacket* req, SrsClientType& type, std::string& stream_name) 1243 +int SrsRtmp::identify_flash_publish_client(SrsPublishPacket* req, SrsClientType& type, string& stream_name)
1212 { 1244 {
1213 int ret = ERROR_SUCCESS; 1245 int ret = ERROR_SUCCESS;
1214 1246
@@ -33,8 +33,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -33,8 +33,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 33
34 #include <string> 34 #include <string>
35 35
36 -#include <st.h>  
37 -  
38 class SrsProtocol; 36 class SrsProtocol;
39 class ISrsMessage; 37 class ISrsMessage;
40 class SrsCommonMessage; 38 class SrsCommonMessage;
@@ -69,6 +67,13 @@ struct SrsRequest @@ -69,6 +67,13 @@ struct SrsRequest
69 67
70 SrsRequest(); 68 SrsRequest();
71 virtual ~SrsRequest(); 69 virtual ~SrsRequest();
  70 +
  71 + /**
  72 + * deep copy the request, for source to use it to support reload,
  73 + * for when initialize the source, the request is valid,
  74 + * when reload it, the request maybe invalid, so need to copy it.
  75 + */
  76 + virtual SrsRequest* copy();
72 77
73 /** 78 /**
74 * disconvery vhost/app from tcUrl. 79 * disconvery vhost/app from tcUrl.
@@ -148,6 +153,7 @@ public: @@ -148,6 +153,7 @@ public:
148 virtual void set_recv_timeout(int64_t timeout_us); 153 virtual void set_recv_timeout(int64_t timeout_us);
149 virtual int64_t get_recv_timeout(); 154 virtual int64_t get_recv_timeout();
150 virtual void set_send_timeout(int64_t timeout_us); 155 virtual void set_send_timeout(int64_t timeout_us);
  156 + virtual int64_t get_send_timeout();
151 virtual int64_t get_recv_bytes(); 157 virtual int64_t get_recv_bytes();
152 virtual int64_t get_send_bytes(); 158 virtual int64_t get_send_bytes();
153 virtual int get_recv_kbps(); 159 virtual int get_recv_kbps();
@@ -30,8 +30,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -30,8 +30,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 30
31 #include <algorithm> 31 #include <algorithm>
32 32
33 -#include <st.h>  
34 -  
35 #include <srs_core_log.hpp> 33 #include <srs_core_log.hpp>
36 #include <srs_core_error.hpp> 34 #include <srs_core_error.hpp>
37 #include <srs_core_client.hpp> 35 #include <srs_core_client.hpp>
@@ -48,24 +46,16 @@ SrsListener::SrsListener(SrsServer* _server, SrsListenerType _type) @@ -48,24 +46,16 @@ SrsListener::SrsListener(SrsServer* _server, SrsListenerType _type)
48 port = 0; 46 port = 0;
49 server = _server; 47 server = _server;
50 type = _type; 48 type = _type;
51 -  
52 - tid = NULL;  
53 - loop = false; 49 +
  50 + pthread = new SrsThread(this, 0);
54 } 51 }
55 52
56 SrsListener::~SrsListener() 53 SrsListener::~SrsListener()
57 { 54 {
58 - if (stfd) {  
59 - st_netfd_close(stfd);  
60 - stfd = NULL;  
61 - } 55 + srs_close_stfd(stfd);
62 56
63 - if (tid) {  
64 - loop = false;  
65 - st_thread_interrupt(tid);  
66 - st_thread_join(tid, NULL);  
67 - tid = NULL;  
68 - } 57 + pthread->stop();
  58 + srs_freep(pthread);
69 59
70 // st does not close it sometimes, 60 // st does not close it sometimes,
71 // close it manually. 61 // close it manually.
@@ -118,8 +108,7 @@ int SrsListener::listen(int _port) @@ -118,8 +108,7 @@ int SrsListener::listen(int _port)
118 } 108 }
119 srs_verbose("st open socket success. fd=%d", fd); 109 srs_verbose("st open socket success. fd=%d", fd);
120 110
121 - if ((tid = st_thread_create(listen_thread, this, 1, 0)) == NULL) {  
122 - ret = ERROR_ST_CREATE_LISTEN_THREAD; 111 + if ((ret = pthread->start()) != ERROR_SUCCESS) {
123 srs_error("st_thread_create listen thread error. ret=%d", ret); 112 srs_error("st_thread_create listen thread error. ret=%d", ret);
124 return ret; 113 return ret;
125 } 114 }
@@ -130,41 +119,32 @@ int SrsListener::listen(int _port) @@ -130,41 +119,32 @@ int SrsListener::listen(int _port)
130 return ret; 119 return ret;
131 } 120 }
132 121
133 -void SrsListener::listen_cycle() 122 +void SrsListener::on_enter_loop()
134 { 123 {
135 - int ret = ERROR_SUCCESS;  
136 -  
137 - log_context->generate_id();  
138 srs_trace("listen cycle start, port=%d, type=%d, fd=%d", port, type, fd); 124 srs_trace("listen cycle start, port=%d, type=%d, fd=%d", port, type, fd);
139 -  
140 - while (loop) {  
141 - st_netfd_t client_stfd = st_accept(stfd, NULL, NULL, ST_UTIME_NO_TIMEOUT);  
142 -  
143 - if(client_stfd == NULL){  
144 - // ignore error.  
145 - srs_warn("ignore accept thread stoppped for accept client error");  
146 - continue;  
147 - }  
148 - srs_verbose("get a client. fd=%d", st_netfd_fileno(client_stfd));  
149 -  
150 - if ((ret = server->accept_client(type, client_stfd)) != ERROR_SUCCESS) {  
151 - srs_warn("accept client error. ret=%d", ret);  
152 - continue;  
153 - }  
154 -  
155 - srs_verbose("accept client finished. conns=%d, ret=%d", (int)conns.size(), ret);  
156 - }  
157 } 125 }
158 126
159 -void* SrsListener::listen_thread(void* arg) 127 +int SrsListener::cycle()
160 { 128 {
161 - SrsListener* obj = (SrsListener*)arg;  
162 - srs_assert(obj != NULL); 129 + int ret = ERROR_SUCCESS;
  130 +
  131 + st_netfd_t client_stfd = st_accept(stfd, NULL, NULL, ST_UTIME_NO_TIMEOUT);
  132 +
  133 + if(client_stfd == NULL){
  134 + // ignore error.
  135 + srs_warn("ignore accept thread stoppped for accept client error");
  136 + return ret;
  137 + }
  138 + srs_verbose("get a client. fd=%d", st_netfd_fileno(client_stfd));
163 139
164 - obj->loop = true;  
165 - obj->listen_cycle(); 140 + if ((ret = server->accept_client(type, client_stfd)) != ERROR_SUCCESS) {
  141 + srs_warn("accept client error. ret=%d", ret);
  142 + return ret;
  143 + }
166 144
167 - return NULL; 145 + srs_verbose("accept client finished. conns=%d, ret=%d", (int)conns.size(), ret);
  146 +
  147 + return ret;
168 } 148 }
169 149
170 SrsServer::SrsServer() 150 SrsServer::SrsServer()
@@ -312,8 +292,7 @@ int SrsServer::accept_client(SrsListenerType type, st_netfd_t client_stfd) @@ -312,8 +292,7 @@ int SrsServer::accept_client(SrsListenerType type, st_netfd_t client_stfd)
312 srs_error("exceed the max connections, drop client: " 292 srs_error("exceed the max connections, drop client: "
313 "clients=%d, max=%d, fd=%d", (int)conns.size(), max_connections, fd); 293 "clients=%d, max=%d, fd=%d", (int)conns.size(), max_connections, fd);
314 294
315 - st_netfd_close(client_stfd);  
316 - ::close(fd); 295 + srs_close_stfd(client_stfd);
317 296
318 return ret; 297 return ret;
319 } 298 }
@@ -32,9 +32,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -32,9 +32,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 32
33 #include <vector> 33 #include <vector>
34 34
35 -#include <st.h>  
36 -  
37 #include <srs_core_reload.hpp> 35 #include <srs_core_reload.hpp>
  36 +#include <srs_core_thread.hpp>
38 37
39 class SrsServer; 38 class SrsServer;
40 class SrsConnection; 39 class SrsConnection;
@@ -45,7 +44,7 @@ enum SrsListenerType @@ -45,7 +44,7 @@ enum SrsListenerType
45 SrsListenerApi 44 SrsListenerApi
46 }; 45 };
47 46
48 -class SrsListener 47 +class SrsListener : public ISrsThreadHandler
49 { 48 {
50 public: 49 public:
51 SrsListenerType type; 50 SrsListenerType type;
@@ -54,19 +53,19 @@ private: @@ -54,19 +53,19 @@ private:
54 st_netfd_t stfd; 53 st_netfd_t stfd;
55 int port; 54 int port;
56 SrsServer* server; 55 SrsServer* server;
57 - st_thread_t tid;  
58 - bool loop; 56 + SrsThread* pthread;
59 public: 57 public:
60 SrsListener(SrsServer* _server, SrsListenerType _type); 58 SrsListener(SrsServer* _server, SrsListenerType _type);
61 virtual ~SrsListener(); 59 virtual ~SrsListener();
62 public: 60 public:
63 virtual int listen(int port); 61 virtual int listen(int port);
64 -private:  
65 - virtual void listen_cycle();  
66 - static void* listen_thread(void* arg); 62 +// interface ISrsThreadHandler.
  63 +public:
  64 + virtual void on_enter_loop();
  65 + virtual int cycle();
67 }; 66 };
68 67
69 -class SrsServer : public SrsReloadHandler 68 +class SrsServer : public ISrsReloadHandler
70 { 69 {
71 friend class SrsListener; 70 friend class SrsListener;
72 private: 71 private:
@@ -52,6 +52,11 @@ void SrsSocket::set_send_timeout(int64_t timeout_us) @@ -52,6 +52,11 @@ void SrsSocket::set_send_timeout(int64_t timeout_us)
52 send_timeout = timeout_us; 52 send_timeout = timeout_us;
53 } 53 }
54 54
  55 +int64_t SrsSocket::get_send_timeout()
  56 +{
  57 + return send_timeout;
  58 +}
  59 +
55 int64_t SrsSocket::get_recv_bytes() 60 int64_t SrsSocket::get_recv_bytes()
56 { 61 {
57 return recv_bytes; 62 return recv_bytes;
@@ -30,8 +30,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -30,8 +30,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 30
31 #include <srs_core.hpp> 31 #include <srs_core.hpp>
32 32
33 -#include <st.h>  
34 -  
35 /** 33 /**
36 * the socket provides TCP socket over st, 34 * the socket provides TCP socket over st,
37 * that is, the sync socket mechanism. 35 * that is, the sync socket mechanism.
@@ -52,6 +50,7 @@ public: @@ -52,6 +50,7 @@ public:
52 virtual void set_recv_timeout(int64_t timeout_us); 50 virtual void set_recv_timeout(int64_t timeout_us);
53 virtual int64_t get_recv_timeout(); 51 virtual int64_t get_recv_timeout();
54 virtual void set_send_timeout(int64_t timeout_us); 52 virtual void set_send_timeout(int64_t timeout_us);
  53 + virtual int64_t get_send_timeout();
55 virtual int64_t get_recv_bytes(); 54 virtual int64_t get_recv_bytes();
56 virtual int64_t get_send_bytes(); 55 virtual int64_t get_send_bytes();
57 virtual int get_recv_kbps(); 56 virtual int get_recv_kbps();
@@ -24,6 +24,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -24,6 +24,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 #include <srs_core_source.hpp> 24 #include <srs_core_source.hpp>
25 25
26 #include <algorithm> 26 #include <algorithm>
  27 +using namespace std;
27 28
28 #include <srs_core_log.hpp> 29 #include <srs_core_log.hpp>
29 #include <srs_core_protocol.hpp> 30 #include <srs_core_protocol.hpp>
@@ -37,8 +38,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -37,8 +38,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
37 #include <srs_core_rtmp.hpp> 38 #include <srs_core_rtmp.hpp>
38 39
39 #define CONST_MAX_JITTER_MS 500 40 #define CONST_MAX_JITTER_MS 500
40 -#define DEFAULT_FRAME_TIME_MS 10  
41 -#define PAUSED_SHRINK_SIZE 250 41 +#define DEFAULT_FRAME_TIME_MS 40
42 42
43 SrsRtmpJitter::SrsRtmpJitter() 43 SrsRtmpJitter::SrsRtmpJitter()
44 { 44 {
@@ -49,9 +49,15 @@ SrsRtmpJitter::~SrsRtmpJitter() @@ -49,9 +49,15 @@ SrsRtmpJitter::~SrsRtmpJitter()
49 { 49 {
50 } 50 }
51 51
52 -int SrsRtmpJitter::correct(SrsSharedPtrMessage* msg, int tba, int tbv, int64_t* corrected_time) 52 +int SrsRtmpJitter::correct(SrsSharedPtrMessage* msg, int tba, int tbv)
53 { 53 {
54 int ret = ERROR_SUCCESS; 54 int ret = ERROR_SUCCESS;
  55 +
  56 + // set to 0 for metadata.
  57 + if (!msg->header.is_video() && !msg->header.is_audio()) {
  58 + msg->header.timestamp = 0;
  59 + return ret;
  60 + }
55 61
56 int sample_rate = tba; 62 int sample_rate = tba;
57 int frame_rate = tbv; 63 int frame_rate = tbv;
@@ -66,16 +72,16 @@ int SrsRtmpJitter::correct(SrsSharedPtrMessage* msg, int tba, int tbv, int64_t* @@ -66,16 +72,16 @@ int SrsRtmpJitter::correct(SrsSharedPtrMessage* msg, int tba, int tbv, int64_t*
66 * 3. last_pkt_correct_time: simply add the positive delta, 72 * 3. last_pkt_correct_time: simply add the positive delta,
67 * and enforce the time monotonically. 73 * and enforce the time monotonically.
68 */ 74 */
69 - u_int32_t time = msg->header.timestamp;  
70 - int32_t delta = time - last_pkt_time; 75 + int64_t time = msg->header.timestamp;
  76 + int64_t delta = time - last_pkt_time;
71 77
72 // if jitter detected, reset the delta. 78 // if jitter detected, reset the delta.
73 if (delta < 0 || delta > CONST_MAX_JITTER_MS) { 79 if (delta < 0 || delta > CONST_MAX_JITTER_MS) {
74 // calc the right diff by audio sample rate 80 // calc the right diff by audio sample rate
75 if (msg->header.is_audio() && sample_rate > 0) { 81 if (msg->header.is_audio() && sample_rate > 0) {
76 - delta = (int32_t)(delta * 1000.0 / sample_rate); 82 + delta = (int64_t)(delta * 1000.0 / sample_rate);
77 } else if (msg->header.is_video() && frame_rate > 0) { 83 } else if (msg->header.is_video() && frame_rate > 0) {
78 - delta = (int32_t)(delta * 1.0 / frame_rate); 84 + delta = (int64_t)(delta * 1.0 / frame_rate);
79 } else { 85 } else {
80 delta = DEFAULT_FRAME_TIME_MS; 86 delta = DEFAULT_FRAME_TIME_MS;
81 } 87 }
@@ -85,20 +91,16 @@ int SrsRtmpJitter::correct(SrsSharedPtrMessage* msg, int tba, int tbv, int64_t* @@ -85,20 +91,16 @@ int SrsRtmpJitter::correct(SrsSharedPtrMessage* msg, int tba, int tbv, int64_t*
85 delta = DEFAULT_FRAME_TIME_MS; 91 delta = DEFAULT_FRAME_TIME_MS;
86 } 92 }
87 93
88 - srs_info("jitter detected, last_pts=%d, pts=%d, diff=%d, last_time=%d, time=%d, diff=%d", 94 + srs_info("jitter detected, last_pts=%"PRId64", pts=%"PRId64", diff=%"PRId64", last_time=%"PRId64", time=%"PRId64", diff=%"PRId64"",
89 last_pkt_time, time, time - last_pkt_time, last_pkt_correct_time, last_pkt_correct_time + delta, delta); 95 last_pkt_time, time, time - last_pkt_time, last_pkt_correct_time, last_pkt_correct_time + delta, delta);
90 } else { 96 } else {
91 - srs_verbose("timestamp no jitter. time=%d, last_pkt=%d, correct_to=%d", 97 + srs_verbose("timestamp no jitter. time=%"PRId64", last_pkt=%"PRId64", correct_to=%"PRId64"",
92 time, last_pkt_time, last_pkt_correct_time + delta); 98 time, last_pkt_time, last_pkt_correct_time + delta);
93 } 99 }
94 100
95 last_pkt_correct_time = srs_max(0, last_pkt_correct_time + delta); 101 last_pkt_correct_time = srs_max(0, last_pkt_correct_time + delta);
96 102
97 - if (corrected_time) {  
98 - *corrected_time = last_pkt_correct_time;  
99 - }  
100 msg->header.timestamp = last_pkt_correct_time; 103 msg->header.timestamp = last_pkt_correct_time;
101 -  
102 last_pkt_time = time; 104 last_pkt_time = time;
103 105
104 return ret; 106 return ret;
@@ -109,61 +111,60 @@ int SrsRtmpJitter::get_time() @@ -109,61 +111,60 @@ int SrsRtmpJitter::get_time()
109 return (int)last_pkt_correct_time; 111 return (int)last_pkt_correct_time;
110 } 112 }
111 113
112 -SrsConsumer::SrsConsumer(SrsSource* _source) 114 +SrsMessageQueue::SrsMessageQueue()
113 { 115 {
114 - source = _source;  
115 - paused = false;  
116 - jitter = new SrsRtmpJitter(); 116 + queue_size_ms = 0;
  117 + av_start_time = av_end_time = -1;
117 } 118 }
118 119
119 -SrsConsumer::~SrsConsumer() 120 +SrsMessageQueue::~SrsMessageQueue()
120 { 121 {
121 clear(); 122 clear();
122 -  
123 - source->on_consumer_destroy(this);  
124 - srs_freep(jitter);  
125 } 123 }
126 124
127 -int SrsConsumer::get_time() 125 +void SrsMessageQueue::set_queue_size(double queue_size)
128 { 126 {
129 - return jitter->get_time(); 127 + queue_size_ms = (int)(queue_size * 1000);
130 } 128 }
131 129
132 -int SrsConsumer::enqueue(SrsSharedPtrMessage* msg, int tba, int tbv) 130 +int SrsMessageQueue::enqueue(SrsSharedPtrMessage* msg)
133 { 131 {
134 int ret = ERROR_SUCCESS; 132 int ret = ERROR_SUCCESS;
135 133
136 - if ((ret = jitter->correct(msg, tba, tbv)) != ERROR_SUCCESS) {  
137 - srs_freep(msg);  
138 - return ret; 134 + if (msg->header.is_video() || msg->header.is_audio()) {
  135 + if (av_start_time == -1) {
  136 + av_start_time = msg->header.timestamp;
  137 + }
  138 +
  139 + av_end_time = msg->header.timestamp;
139 } 140 }
140 141
141 - // TODO: check the queue size and drop packets if overflow.  
142 msgs.push_back(msg); 142 msgs.push_back(msg);
  143 +
  144 + while (av_end_time - av_start_time > queue_size_ms) {
  145 + shrink();
  146 + }
143 147
144 return ret; 148 return ret;
145 } 149 }
146 150
147 -int SrsConsumer::get_packets(int max_count, SrsSharedPtrMessage**& pmsgs, int& count) 151 +int SrsMessageQueue::get_packets(int max_count, SrsSharedPtrMessage**& pmsgs, int& count)
148 { 152 {
149 int ret = ERROR_SUCCESS; 153 int ret = ERROR_SUCCESS;
150 154
151 if (msgs.empty()) { 155 if (msgs.empty()) {
152 return ret; 156 return ret;
153 } 157 }
154 -  
155 - if (paused) {  
156 - if ((int)msgs.size() >= PAUSED_SHRINK_SIZE) {  
157 - shrink();  
158 - }  
159 - return ret;  
160 - }  
161 158
162 if (max_count == 0) { 159 if (max_count == 0) {
163 count = (int)msgs.size(); 160 count = (int)msgs.size();
164 } else { 161 } else {
165 count = srs_min(max_count, (int)msgs.size()); 162 count = srs_min(max_count, (int)msgs.size());
166 } 163 }
  164 +
  165 + if (count <= 0) {
  166 + return ret;
  167 + }
167 168
168 pmsgs = new SrsSharedPtrMessage*[count]; 169 pmsgs = new SrsSharedPtrMessage*[count];
169 170
@@ -171,6 +172,9 @@ int SrsConsumer::get_packets(int max_count, SrsSharedPtrMessage**& pmsgs, int& c @@ -171,6 +172,9 @@ int SrsConsumer::get_packets(int max_count, SrsSharedPtrMessage**& pmsgs, int& c
171 pmsgs[i] = msgs[i]; 172 pmsgs[i] = msgs[i];
172 } 173 }
173 174
  175 + SrsSharedPtrMessage* last = msgs[count - 1];
  176 + av_start_time = last->header.timestamp;
  177 +
174 if (count == (int)msgs.size()) { 178 if (count == (int)msgs.size()) {
175 msgs.clear(); 179 msgs.clear();
176 } else { 180 } else {
@@ -180,76 +184,120 @@ int SrsConsumer::get_packets(int max_count, SrsSharedPtrMessage**& pmsgs, int& c @@ -180,76 +184,120 @@ int SrsConsumer::get_packets(int max_count, SrsSharedPtrMessage**& pmsgs, int& c
180 return ret; 184 return ret;
181 } 185 }
182 186
183 -int SrsConsumer::on_play_client_pause(bool is_pause) 187 +void SrsMessageQueue::shrink()
184 { 188 {
185 - int ret = ERROR_SUCCESS;  
186 -  
187 - srs_trace("stream consumer change pause state %d=>%d", paused, is_pause);  
188 - paused = is_pause;  
189 -  
190 - return ret;  
191 -}  
192 -  
193 -void SrsConsumer::shrink()  
194 -{  
195 - int i = 0;  
196 - std::vector<SrsSharedPtrMessage*>::iterator it;  
197 -  
198 - // issue the last video iframe.  
199 - bool has_video = false;  
200 - int frame_to_remove = 0;  
201 - std::vector<SrsSharedPtrMessage*>::iterator iframe = msgs.end();  
202 - for (i = 0, it = msgs.begin(); it != msgs.end(); ++it, i++) {  
203 - SrsSharedPtrMessage* msg = *it; 189 + int iframe_index = -1;
  190 +
  191 + // issue the first iframe.
  192 + // skip the first frame, whatever the type of it,
  193 + // for when we shrinked, the first is the iframe,
  194 + // we will directly remove the gop next time.
  195 + for (int i = 1; i < (int)msgs.size(); i++) {
  196 + SrsSharedPtrMessage* msg = msgs[i];
  197 +
204 if (msg->header.is_video()) { 198 if (msg->header.is_video()) {
205 - has_video = true;  
206 if (SrsCodec::video_is_keyframe(msg->payload, msg->size)) { 199 if (SrsCodec::video_is_keyframe(msg->payload, msg->size)) {
207 - iframe = it;  
208 - frame_to_remove = i + 1; 200 + // the max frame index to remove.
  201 + iframe_index = i;
  202 +
  203 + // set the start time, we will remove until this frame.
  204 + av_start_time = msg->header.timestamp;
  205 +
  206 + break;
209 } 207 }
210 } 208 }
211 } 209 }
212 210
213 - // last iframe is the first elem, ignore it.  
214 - if (iframe == msgs.begin()) {  
215 - return;  
216 - }  
217 -  
218 - // recalc the frame to remove  
219 - if (iframe == msgs.end()) {  
220 - frame_to_remove = 0;  
221 - }  
222 - if (!has_video) {  
223 - frame_to_remove = (int)msgs.size();  
224 - }  
225 -  
226 - srs_trace("shrink the cache queue, has_video=%d, has_iframe=%d, size=%d, removed=%d",  
227 - has_video, iframe != msgs.end(), (int)msgs.size(), frame_to_remove);  
228 -  
229 - // if no video, remove all audio.  
230 - if (!has_video) { 211 + // no iframe, clear the queue.
  212 + if (iframe_index < 0) {
231 clear(); 213 clear();
232 return; 214 return;
233 } 215 }
234 216
235 - // if exists video Iframe, remove the frames before it.  
236 - if (iframe != msgs.end()) {  
237 - for (it = msgs.begin(); it != iframe; ++it) {  
238 - SrsSharedPtrMessage* msg = *it;  
239 - srs_freep(msg);  
240 - }  
241 - msgs.erase(msgs.begin(), iframe); 217 + srs_trace("shrink the cache queue, size=%d, removed=%d, max=%.2f",
  218 + (int)msgs.size(), iframe_index, queue_size_ms / 1000.0);
  219 +
  220 + // remove the first gop from the front
  221 + for (int i = 0; i < iframe_index; i++) {
  222 + SrsSharedPtrMessage* msg = msgs[i];
  223 + srs_freep(msg);
242 } 224 }
  225 + msgs.erase(msgs.begin(), msgs.begin() + iframe_index);
243 } 226 }
244 227
245 -void SrsConsumer::clear() 228 +void SrsMessageQueue::clear()
246 { 229 {
247 std::vector<SrsSharedPtrMessage*>::iterator it; 230 std::vector<SrsSharedPtrMessage*>::iterator it;
  231 +
248 for (it = msgs.begin(); it != msgs.end(); ++it) { 232 for (it = msgs.begin(); it != msgs.end(); ++it) {
249 SrsSharedPtrMessage* msg = *it; 233 SrsSharedPtrMessage* msg = *it;
250 srs_freep(msg); 234 srs_freep(msg);
251 } 235 }
  236 +
252 msgs.clear(); 237 msgs.clear();
  238 +
  239 + av_start_time = av_end_time = -1;
  240 +}
  241 +
  242 +SrsConsumer::SrsConsumer(SrsSource* _source)
  243 +{
  244 + source = _source;
  245 + paused = false;
  246 + jitter = new SrsRtmpJitter();
  247 + queue = new SrsMessageQueue();
  248 +}
  249 +
  250 +SrsConsumer::~SrsConsumer()
  251 +{
  252 + source->on_consumer_destroy(this);
  253 + srs_freep(jitter);
  254 + srs_freep(queue);
  255 +}
  256 +
  257 +void SrsConsumer::set_queue_size(double queue_size)
  258 +{
  259 + queue->set_queue_size(queue_size);
  260 +}
  261 +
  262 +int SrsConsumer::get_time()
  263 +{
  264 + return jitter->get_time();
  265 +}
  266 +
  267 +int SrsConsumer::enqueue(SrsSharedPtrMessage* msg, int tba, int tbv)
  268 +{
  269 + int ret = ERROR_SUCCESS;
  270 +
  271 + if ((ret = jitter->correct(msg, tba, tbv)) != ERROR_SUCCESS) {
  272 + srs_freep(msg);
  273 + return ret;
  274 + }
  275 +
  276 + if ((ret = queue->enqueue(msg)) != ERROR_SUCCESS) {
  277 + return ret;
  278 + }
  279 +
  280 + return ret;
  281 +}
  282 +
  283 +int SrsConsumer::get_packets(int max_count, SrsSharedPtrMessage**& pmsgs, int& count)
  284 +{
  285 + // paused, return nothing.
  286 + if (paused) {
  287 + return ERROR_SUCCESS;
  288 + }
  289 +
  290 + return queue->get_packets(max_count, pmsgs, count);
  291 +}
  292 +
  293 +int SrsConsumer::on_play_client_pause(bool is_pause)
  294 +{
  295 + int ret = ERROR_SUCCESS;
  296 +
  297 + srs_trace("stream consumer change pause state %d=>%d", paused, is_pause);
  298 + paused = is_pause;
  299 +
  300 + return ret;
253 } 301 }
254 302
255 SrsGopCache::SrsGopCache() 303 SrsGopCache::SrsGopCache()
@@ -344,22 +392,25 @@ int SrsGopCache::dump(SrsConsumer* consumer, int tba, int tbv) @@ -344,22 +392,25 @@ int SrsGopCache::dump(SrsConsumer* consumer, int tba, int tbv)
344 392
345 std::map<std::string, SrsSource*> SrsSource::pool; 393 std::map<std::string, SrsSource*> SrsSource::pool;
346 394
347 -SrsSource* SrsSource::find(const std::string &stream_url) 395 +SrsSource* SrsSource::find(SrsRequest* req)
348 { 396 {
  397 + string stream_url = req->get_stream_url();
  398 + string vhost = req->vhost;
  399 +
349 if (pool.find(stream_url) == pool.end()) { 400 if (pool.find(stream_url) == pool.end()) {
350 - pool[stream_url] = new SrsSource(stream_url);  
351 - srs_verbose("create new source for url=%s", stream_url.c_str()); 401 + pool[stream_url] = new SrsSource(req);
  402 + srs_verbose("create new source for url=%s, vhost=%s", stream_url.c_str(), vhost.c_str());
352 } 403 }
353 404
354 return pool[stream_url]; 405 return pool[stream_url];
355 } 406 }
356 407
357 -SrsSource::SrsSource(std::string _stream_url) 408 +SrsSource::SrsSource(SrsRequest* _req)
358 { 409 {
359 - stream_url = _stream_url; 410 + req = _req->copy();
360 411
361 #ifdef SRS_HLS 412 #ifdef SRS_HLS
362 - hls = new SrsHls(); 413 + hls = new SrsHls(this);
363 #endif 414 #endif
364 #ifdef SRS_FFMPEG 415 #ifdef SRS_FFMPEG
365 encoder = new SrsEncoder(); 416 encoder = new SrsEncoder();
@@ -371,10 +422,14 @@ SrsSource::SrsSource(std::string _stream_url) @@ -371,10 +422,14 @@ SrsSource::SrsSource(std::string _stream_url)
371 _can_publish = true; 422 _can_publish = true;
372 423
373 gop_cache = new SrsGopCache(); 424 gop_cache = new SrsGopCache();
  425 +
  426 + config->subscribe(this);
374 } 427 }
375 428
376 SrsSource::~SrsSource() 429 SrsSource::~SrsSource()
377 { 430 {
  431 + config->unsubscribe(this);
  432 +
378 if (true) { 433 if (true) {
379 std::vector<SrsConsumer*>::iterator it; 434 std::vector<SrsConsumer*>::iterator it;
380 for (it = consumers.begin(); it != consumers.end(); ++it) { 435 for (it = consumers.begin(); it != consumers.end(); ++it) {
@@ -405,6 +460,167 @@ SrsSource::~SrsSource() @@ -405,6 +460,167 @@ SrsSource::~SrsSource()
405 #ifdef SRS_FFMPEG 460 #ifdef SRS_FFMPEG
406 srs_freep(encoder); 461 srs_freep(encoder);
407 #endif 462 #endif
  463 +
  464 + srs_freep(req);
  465 +}
  466 +
  467 +int SrsSource::on_reload_gop_cache(string vhost)
  468 +{
  469 + int ret = ERROR_SUCCESS;
  470 +
  471 + if (req->vhost != vhost) {
  472 + return ret;
  473 + }
  474 +
  475 + // gop cache changed.
  476 + bool enabled_cache = config->get_gop_cache(vhost);
  477 +
  478 + srs_trace("vhost %s gop_cache changed to %d, source url=%s",
  479 + vhost.c_str(), enabled_cache, req->get_stream_url().c_str());
  480 +
  481 + set_cache(enabled_cache);
  482 +
  483 + return ret;
  484 +}
  485 +
  486 +int SrsSource::on_reload_queue_length(string vhost)
  487 +{
  488 + int ret = ERROR_SUCCESS;
  489 +
  490 + if (req->vhost != vhost) {
  491 + return ret;
  492 + }
  493 +
  494 + double queue_size = config->get_queue_length(req->vhost);
  495 +
  496 + if (true) {
  497 + std::vector<SrsConsumer*>::iterator it;
  498 +
  499 + for (it = consumers.begin(); it != consumers.end(); ++it) {
  500 + SrsConsumer* consumer = *it;
  501 + consumer->set_queue_size(queue_size);
  502 + }
  503 +
  504 + srs_trace("consumers reload queue size success.");
  505 + }
  506 +
  507 + if (true) {
  508 + std::vector<SrsForwarder*>::iterator it;
  509 +
  510 + for (it = forwarders.begin(); it != forwarders.end(); ++it) {
  511 + SrsForwarder* forwarder = *it;
  512 + forwarder->set_queue_size(queue_size);
  513 + }
  514 +
  515 + srs_trace("forwarders reload queue size success.");
  516 + }
  517 +
  518 + return ret;
  519 +}
  520 +
  521 +int SrsSource::on_reload_forward(string vhost)
  522 +{
  523 + int ret = ERROR_SUCCESS;
  524 +
  525 + if (req->vhost != vhost) {
  526 + return ret;
  527 + }
  528 +
  529 + // forwarders
  530 + destroy_forwarders();
  531 + if ((ret = create_forwarders()) != ERROR_SUCCESS) {
  532 + srs_error("create forwarders failed. ret=%d", ret);
  533 + return ret;
  534 + }
  535 +
  536 + srs_trace("vhost %s forwarders reload success", vhost.c_str());
  537 +
  538 + return ret;
  539 +}
  540 +
  541 +int SrsSource::on_reload_hls(string vhost)
  542 +{
  543 + int ret = ERROR_SUCCESS;
  544 +
  545 + if (req->vhost != vhost) {
  546 + return ret;
  547 + }
  548 +
  549 +#ifdef SRS_HLS
  550 + hls->on_unpublish();
  551 + if ((ret = hls->on_publish(req)) != ERROR_SUCCESS) {
  552 + srs_error("hls publish failed. ret=%d", ret);
  553 + return ret;
  554 + }
  555 + srs_trace("vhost %s hls reload success", vhost.c_str());
  556 +#endif
  557 +
  558 + return ret;
  559 +}
  560 +
  561 +int SrsSource::on_reload_transcode(string vhost)
  562 +{
  563 + int ret = ERROR_SUCCESS;
  564 +
  565 + if (req->vhost != vhost) {
  566 + return ret;
  567 + }
  568 +
  569 +#ifdef SRS_FFMPEG
  570 + encoder->on_unpublish();
  571 + if ((ret = encoder->on_publish(req)) != ERROR_SUCCESS) {
  572 + srs_error("start encoder failed. ret=%d", ret);
  573 + return ret;
  574 + }
  575 + srs_trace("vhost %s transcode reload success", vhost.c_str());
  576 +#endif
  577 +
  578 + return ret;
  579 +}
  580 +
  581 +int SrsSource::on_forwarder_start(SrsForwarder* forwarder)
  582 +{
  583 + int ret = ERROR_SUCCESS;
  584 +
  585 + // feed the forwarder the metadata/sequence header,
  586 + // when reload to enable the forwarder.
  587 + if (cache_metadata && (ret = forwarder->on_meta_data(cache_metadata->copy())) != ERROR_SUCCESS) {
  588 + srs_error("forwarder process onMetaData message failed. ret=%d", ret);
  589 + return ret;
  590 + }
  591 + if (cache_sh_video && (ret = forwarder->on_video(cache_sh_video->copy())) != ERROR_SUCCESS) {
  592 + srs_error("forwarder process video sequence header message failed. ret=%d", ret);
  593 + return ret;
  594 + }
  595 + if (cache_sh_audio && (ret = forwarder->on_audio(cache_sh_audio->copy())) != ERROR_SUCCESS) {
  596 + srs_error("forwarder process audio sequence header message failed. ret=%d", ret);
  597 + return ret;
  598 + }
  599 +
  600 + return ret;
  601 +}
  602 +
  603 +int SrsSource::on_hls_start()
  604 +{
  605 + int ret = ERROR_SUCCESS;
  606 +
  607 +#ifdef SRS_HLS
  608 +
  609 + // feed the hls the metadata/sequence header,
  610 + // when reload to enable the hls.
  611 + // TODO: maybe need to decode the metadata?
  612 + if (cache_sh_video && (ret = hls->on_video(cache_sh_video->copy())) != ERROR_SUCCESS) {
  613 + srs_error("hls process video sequence header message failed. ret=%d", ret);
  614 + return ret;
  615 + }
  616 + if (cache_sh_audio && (ret = hls->on_audio(cache_sh_audio->copy())) != ERROR_SUCCESS) {
  617 + srs_error("hls process audio sequence header message failed. ret=%d", ret);
  618 + return ret;
  619 + }
  620 +
  621 +#endif
  622 +
  623 + return ret;
408 } 624 }
409 625
410 bool SrsSource::can_publish() 626 bool SrsSource::can_publish()
@@ -417,7 +633,7 @@ int SrsSource::on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata @@ -417,7 +633,7 @@ int SrsSource::on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata
417 int ret = ERROR_SUCCESS; 633 int ret = ERROR_SUCCESS;
418 634
419 #ifdef SRS_HLS 635 #ifdef SRS_HLS
420 - if ((ret = hls->on_meta_data(metadata)) != ERROR_SUCCESS) { 636 + if (metadata && (ret = hls->on_meta_data(metadata->metadata)) != ERROR_SUCCESS) {
421 srs_error("hls process onMetaData message failed. ret=%d", ret); 637 srs_error("hls process onMetaData message failed. ret=%d", ret);
422 return ret; 638 return ret;
423 } 639 }
@@ -425,6 +641,8 @@ int SrsSource::on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata @@ -425,6 +641,8 @@ int SrsSource::on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata
425 641
426 metadata->metadata->set("server", new SrsAmf0String( 642 metadata->metadata->set("server", new SrsAmf0String(
427 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",
  645 + new SrsAmf0String(RTMP_SIG_SRS_CONTRIBUTOR));
428 646
429 SrsAmf0Any* prop = NULL; 647 SrsAmf0Any* prop = NULL;
430 if ((prop = metadata->metadata->get_property("audiosamplerate")) != NULL) { 648 if ((prop = metadata->metadata->get_property("audiosamplerate")) != NULL) {
@@ -620,7 +838,7 @@ int SrsSource::on_video(SrsCommonMessage* video) @@ -620,7 +838,7 @@ int SrsSource::on_video(SrsCommonMessage* video)
620 838
621 // cache the last gop packets 839 // cache the last gop packets
622 if ((ret = gop_cache->cache(msg)) != ERROR_SUCCESS) { 840 if ((ret = gop_cache->cache(msg)) != ERROR_SUCCESS) {
623 - srs_error("shrink gop cache failed. ret=%d", ret); 841 + srs_error("gop cache msg failed. ret=%d", ret);
624 return ret; 842 return ret;
625 } 843 }
626 srs_verbose("cache gop success."); 844 srs_verbose("cache gop success.");
@@ -628,39 +846,33 @@ int SrsSource::on_video(SrsCommonMessage* video) @@ -628,39 +846,33 @@ int SrsSource::on_video(SrsCommonMessage* video)
628 return ret; 846 return ret;
629 } 847 }
630 848
631 -int SrsSource::on_publish(SrsRequest* req) 849 +int SrsSource::on_publish(SrsRequest* _req)
632 { 850 {
633 int ret = ERROR_SUCCESS; 851 int ret = ERROR_SUCCESS;
634 852
  853 + // update the request object.
  854 + srs_freep(req);
  855 + req = _req->copy();
  856 + srs_assert(req);
  857 +
635 _can_publish = false; 858 _can_publish = false;
636 -  
637 - // TODO: support reload.  
638 859
639 // create forwarders 860 // create forwarders
640 - SrsConfDirective* conf = config->get_forward(req->vhost);  
641 - for (int i = 0; conf && i < (int)conf->args.size(); i++) {  
642 - std::string forward_server = conf->args.at(i);  
643 -  
644 - SrsForwarder* forwarder = new SrsForwarder();  
645 - forwarders.push_back(forwarder);  
646 -  
647 - if ((ret = forwarder->on_publish(req, forward_server)) != ERROR_SUCCESS) {  
648 - srs_error("start forwarder failed. "  
649 - "vhost=%s, app=%s, stream=%s, forward-to=%s",  
650 - req->vhost.c_str(), req->app.c_str(), req->stream.c_str(),  
651 - forward_server.c_str());  
652 - return ret;  
653 - } 861 + if ((ret = create_forwarders()) != ERROR_SUCCESS) {
  862 + srs_error("create forwarders failed. ret=%d", ret);
  863 + return ret;
654 } 864 }
655 - 865 +
656 #ifdef SRS_FFMPEG 866 #ifdef SRS_FFMPEG
657 if ((ret = encoder->on_publish(req)) != ERROR_SUCCESS) { 867 if ((ret = encoder->on_publish(req)) != ERROR_SUCCESS) {
  868 + srs_error("start encoder failed. ret=%d", ret);
658 return ret; 869 return ret;
659 } 870 }
660 #endif 871 #endif
661 872
662 #ifdef SRS_HLS 873 #ifdef SRS_HLS
663 if ((ret = hls->on_publish(req)) != ERROR_SUCCESS) { 874 if ((ret = hls->on_publish(req)) != ERROR_SUCCESS) {
  875 + srs_error("start hls failed. ret=%d", ret);
664 return ret; 876 return ret;
665 } 877 }
666 #endif 878 #endif
@@ -670,19 +882,14 @@ int SrsSource::on_publish(SrsRequest* req) @@ -670,19 +882,14 @@ int SrsSource::on_publish(SrsRequest* req)
670 882
671 void SrsSource::on_unpublish() 883 void SrsSource::on_unpublish()
672 { 884 {
673 - // close all forwarders  
674 - std::vector<SrsForwarder*>::iterator it;  
675 - for (it = forwarders.begin(); it != forwarders.end(); ++it) {  
676 - SrsForwarder* forwarder = *it;  
677 - forwarder->on_unpublish();  
678 - srs_freep(forwarder);  
679 - }  
680 - forwarders.clear(); 885 + // destroy all forwarders
  886 + destroy_forwarders();
681 887
682 #ifdef SRS_FFMPEG 888 #ifdef SRS_FFMPEG
683 encoder->on_unpublish(); 889 encoder->on_unpublish();
684 #endif 890 #endif
685 891
  892 + // TODO: HLS should continue previous sequence and stream.
686 #ifdef SRS_HLS 893 #ifdef SRS_HLS
687 hls->on_unpublish(); 894 hls->on_unpublish();
688 #endif 895 #endif
@@ -706,6 +913,9 @@ void SrsSource::on_unpublish() @@ -706,6 +913,9 @@ void SrsSource::on_unpublish()
706 913
707 consumer = new SrsConsumer(this); 914 consumer = new SrsConsumer(this);
708 consumers.push_back(consumer); 915 consumers.push_back(consumer);
  916 +
  917 + double queue_size = config->get_queue_length(req->vhost);
  918 + consumer->set_queue_size(queue_size);
709 919
710 if (cache_metadata && (ret = consumer->enqueue(cache_metadata->copy(), sample_rate, frame_rate)) != ERROR_SUCCESS) { 920 if (cache_metadata && (ret = consumer->enqueue(cache_metadata->copy(), sample_rate, frame_rate)) != ERROR_SUCCESS) {
711 srs_error("dispatch metadata failed. ret=%d", ret); 921 srs_error("dispatch metadata failed. ret=%d", ret);
@@ -729,6 +939,8 @@ void SrsSource::on_unpublish() @@ -729,6 +939,8 @@ void SrsSource::on_unpublish()
729 return ret; 939 return ret;
730 } 940 }
731 941
  942 + srs_trace("create consumer, queue_size=%.2f, tba=%d, tbv=%d", queue_size, sample_rate, frame_rate);
  943 +
732 return ret; 944 return ret;
733 } 945 }
734 946
@@ -747,3 +959,40 @@ void SrsSource::set_cache(bool enabled) @@ -747,3 +959,40 @@ void SrsSource::set_cache(bool enabled)
747 gop_cache->set(enabled); 959 gop_cache->set(enabled);
748 } 960 }
749 961
  962 +int SrsSource::create_forwarders()
  963 +{
  964 + int ret = ERROR_SUCCESS;
  965 +
  966 + SrsConfDirective* conf = config->get_forward(req->vhost);
  967 + for (int i = 0; conf && i < (int)conf->args.size(); i++) {
  968 + std::string forward_server = conf->args.at(i);
  969 +
  970 + SrsForwarder* forwarder = new SrsForwarder(this);
  971 + forwarders.push_back(forwarder);
  972 +
  973 + double queue_size = config->get_queue_length(req->vhost);
  974 + forwarder->set_queue_size(queue_size);
  975 +
  976 + if ((ret = forwarder->on_publish(req, forward_server)) != ERROR_SUCCESS) {
  977 + srs_error("start forwarder failed. "
  978 + "vhost=%s, app=%s, stream=%s, forward-to=%s",
  979 + req->vhost.c_str(), req->app.c_str(), req->stream.c_str(),
  980 + forward_server.c_str());
  981 + return ret;
  982 + }
  983 + }
  984 +
  985 + return ret;
  986 +}
  987 +
  988 +void SrsSource::destroy_forwarders()
  989 +{
  990 + std::vector<SrsForwarder*>::iterator it;
  991 + for (it = forwarders.begin(); it != forwarders.end(); ++it) {
  992 + SrsForwarder* forwarder = *it;
  993 + forwarder->on_unpublish();
  994 + srs_freep(forwarder);
  995 + }
  996 + forwarders.clear();
  997 +}
  998 +
@@ -34,6 +34,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -34,6 +34,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 #include <vector> 34 #include <vector>
35 #include <string> 35 #include <string>
36 36
  37 +#include <srs_core_reload.hpp>
  38 +
37 class SrsSource; 39 class SrsSource;
38 class SrsCommonMessage; 40 class SrsCommonMessage;
39 class SrsOnMetaDataPacket; 41 class SrsOnMetaDataPacket;
@@ -54,18 +56,16 @@ class SrsEncoder; @@ -54,18 +56,16 @@ class SrsEncoder;
54 class SrsRtmpJitter 56 class SrsRtmpJitter
55 { 57 {
56 private: 58 private:
57 - u_int32_t last_pkt_time;  
58 - u_int32_t last_pkt_correct_time; 59 + int64_t last_pkt_time;
  60 + int64_t last_pkt_correct_time;
59 public: 61 public:
60 SrsRtmpJitter(); 62 SrsRtmpJitter();
61 virtual ~SrsRtmpJitter(); 63 virtual ~SrsRtmpJitter();
62 public: 64 public:
63 /** 65 /**
64 * detect the time jitter and correct it. 66 * detect the time jitter and correct it.
65 - * @param corrected_time output the 64bits time.  
66 - * ignore if NULL.  
67 */ 67 */
68 - virtual int correct(SrsSharedPtrMessage* msg, int tba, int tbv, int64_t* corrected_time = NULL); 68 + virtual int correct(SrsSharedPtrMessage* msg, int tba, int tbv);
69 /** 69 /**
70 * get current client time, the last packet time. 70 * get current client time, the last packet time.
71 */ 71 */
@@ -73,6 +73,48 @@ public: @@ -73,6 +73,48 @@ public:
73 }; 73 };
74 74
75 /** 75 /**
  76 +* the message queue for the consumer(client), forwarder.
  77 +* we limit the size in seconds, drop old messages(the whole gop) if full.
  78 +*/
  79 +class SrsMessageQueue
  80 +{
  81 +private:
  82 + int64_t av_start_time;
  83 + int64_t av_end_time;
  84 + int queue_size_ms;
  85 + std::vector<SrsSharedPtrMessage*> msgs;
  86 +public:
  87 + SrsMessageQueue();
  88 + virtual ~SrsMessageQueue();
  89 +public:
  90 + /**
  91 + * set the queue size
  92 + * @param queue_size the queue size in seconds.
  93 + */
  94 + virtual void set_queue_size(double queue_size);
  95 +public:
  96 + /**
  97 + * enqueue the message, the timestamp always monotonically.
  98 + * @param msg, the msg to enqueue, user never free it whatever the return code.
  99 + */
  100 + virtual int enqueue(SrsSharedPtrMessage* msg);
  101 + /**
  102 + * get packets in consumer queue.
  103 + * @pmsgs SrsMessages*[], output the prt array.
  104 + * @count the count in array.
  105 + * @max_count the max count to dequeue, 0 to dequeue all.
  106 + */
  107 + virtual int get_packets(int max_count, SrsSharedPtrMessage**& pmsgs, int& count);
  108 +private:
  109 + /**
  110 + * remove a gop from the front.
  111 + * if no iframe found, clear it.
  112 + */
  113 + virtual void shrink();
  114 + virtual void clear();
  115 +};
  116 +
  117 +/**
76 * the consumer for SrsSource, that is a play client. 118 * the consumer for SrsSource, that is a play client.
77 */ 119 */
78 class SrsConsumer 120 class SrsConsumer
@@ -80,12 +122,14 @@ class SrsConsumer @@ -80,12 +122,14 @@ class SrsConsumer
80 private: 122 private:
81 SrsRtmpJitter* jitter; 123 SrsRtmpJitter* jitter;
82 SrsSource* source; 124 SrsSource* source;
83 - std::vector<SrsSharedPtrMessage*> msgs; 125 + SrsMessageQueue* queue;
84 bool paused; 126 bool paused;
85 public: 127 public:
86 SrsConsumer(SrsSource* _source); 128 SrsConsumer(SrsSource* _source);
87 virtual ~SrsConsumer(); 129 virtual ~SrsConsumer();
88 public: 130 public:
  131 + virtual void set_queue_size(double queue_size);
  132 +public:
89 /** 133 /**
90 * get current client time, the last packet time. 134 * get current client time, the last packet time.
91 */ 135 */
@@ -109,13 +153,6 @@ public: @@ -109,13 +153,6 @@ public:
109 * when client send the pause message. 153 * when client send the pause message.
110 */ 154 */
111 virtual int on_play_client_pause(bool is_pause); 155 virtual int on_play_client_pause(bool is_pause);
112 -private:  
113 - /**  
114 - * when paused, shrink the cache queue,  
115 - * remove to cache only one gop.  
116 - */  
117 - virtual void shrink();  
118 - virtual void clear();  
119 }; 156 };
120 157
121 /** 158 /**
@@ -158,20 +195,21 @@ public: @@ -158,20 +195,21 @@ public:
158 /** 195 /**
159 * live streaming source. 196 * live streaming source.
160 */ 197 */
161 -class SrsSource 198 +class SrsSource : public ISrsReloadHandler
162 { 199 {
163 private: 200 private:
164 static std::map<std::string, SrsSource*> pool; 201 static std::map<std::string, SrsSource*> pool;
165 public: 202 public:
166 /** 203 /**
167 * find stream by vhost/app/stream. 204 * find stream by vhost/app/stream.
168 - * @stream_url the stream url, for example, myserver.xxx.com/app/stream 205 + * @param req the client request.
169 * @return the matched source, never be NULL. 206 * @return the matched source, never be NULL.
170 * @remark stream_url should without port and schema. 207 * @remark stream_url should without port and schema.
171 */ 208 */
172 - static SrsSource* find(const std::string& stream_url); 209 + static SrsSource* find(SrsRequest* req);
173 private: 210 private:
174 - std::string stream_url; 211 + // deep copy of client request.
  212 + SrsRequest* req;
175 // to delivery stream to clients. 213 // to delivery stream to clients.
176 std::vector<SrsConsumer*> consumers; 214 std::vector<SrsConsumer*> consumers;
177 // hls handler. 215 // hls handler.
@@ -206,19 +244,43 @@ private: @@ -206,19 +244,43 @@ private:
206 // the cached audio sequence header. 244 // the cached audio sequence header.
207 SrsSharedPtrMessage* cache_sh_audio; 245 SrsSharedPtrMessage* cache_sh_audio;
208 public: 246 public:
209 - SrsSource(std::string _stream_url); 247 + /**
  248 + * @param _req the client request object,
  249 + * this object will deep copy it for reload.
  250 + */
  251 + SrsSource(SrsRequest* _req);
210 virtual ~SrsSource(); 252 virtual ~SrsSource();
  253 +// interface ISrsReloadHandler
  254 +public:
  255 + virtual int on_reload_gop_cache(std::string vhost);
  256 + virtual int on_reload_queue_length(std::string vhost);
  257 + virtual int on_reload_forward(std::string vhost);
  258 + virtual int on_reload_hls(std::string vhost);
  259 + virtual int on_reload_transcode(std::string vhost);
  260 +public:
  261 + // for the SrsForwarder to callback to request the sequence headers.
  262 + virtual int on_forwarder_start(SrsForwarder* forwarder);
  263 + // for the SrsHls to callback to request the sequence headers.
  264 + virtual int on_hls_start();
211 public: 265 public:
212 virtual bool can_publish(); 266 virtual bool can_publish();
213 virtual int on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata); 267 virtual int on_meta_data(SrsCommonMessage* msg, SrsOnMetaDataPacket* metadata);
214 virtual int on_audio(SrsCommonMessage* audio); 268 virtual int on_audio(SrsCommonMessage* audio);
215 virtual int on_video(SrsCommonMessage* video); 269 virtual int on_video(SrsCommonMessage* video);
216 - virtual int on_publish(SrsRequest* req); 270 + /**
  271 + * publish stream event notify.
  272 + * @param _req the request from client, the source will deep copy it,
  273 + * for when reload the request of client maybe invalid.
  274 + */
  275 + virtual int on_publish(SrsRequest* _req);
217 virtual void on_unpublish(); 276 virtual void on_unpublish();
218 public: 277 public:
219 virtual int create_consumer(SrsConsumer*& consumer); 278 virtual int create_consumer(SrsConsumer*& consumer);
220 virtual void on_consumer_destroy(SrsConsumer* consumer); 279 virtual void on_consumer_destroy(SrsConsumer* consumer);
221 virtual void set_cache(bool enabled); 280 virtual void set_cache(bool enabled);
  281 +private:
  282 + virtual int create_forwarders();
  283 + virtual void destroy_forwarders();
222 }; 284 };
223 285
224 #endif 286 #endif